From 458d023ff4a32ae18a0baf219cfaf191a98e8540 Mon Sep 17 00:00:00 2001 From: Dave Woestenborghs Date: Wed, 28 Mar 2018 17:03:35 +0200 Subject: [PATCH 01/14] U4-11161 set min and max number in default config --- .../propertyeditors/contentpicker/contentpicker.controller.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/contentpicker/contentpicker.controller.js b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/contentpicker/contentpicker.controller.js index 229ec614de..161f989d10 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/contentpicker/contentpicker.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/contentpicker/contentpicker.controller.js @@ -66,6 +66,8 @@ function contentPickerController($scope, entityResource, editorState, iconHelper showOpenButton: false, showEditButton: false, showPathOnHover: false, + maxNumber: 1, + minNumber : 0, startNode: { query: "", type: "content", From d1eb6b1aa85b928e63b928c7b75544fe5740e670 Mon Sep 17 00:00:00 2001 From: Dave Woestenborghs Date: Wed, 28 Mar 2018 17:07:56 +0200 Subject: [PATCH 02/14] U4-11161 don't show help text when it's not a multipicker --- .../src/views/propertyeditors/contentpicker/contentpicker.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/contentpicker/contentpicker.html b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/contentpicker/contentpicker.html index 0ed8657c59..0a2f82e2a2 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/contentpicker/contentpicker.html +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/contentpicker/contentpicker.html @@ -28,7 +28,7 @@ Add -
+
From bdaa70592f7620576adf39163c70ca1bf274e797 Mon Sep 17 00:00:00 2001 From: Warren Date: Wed, 4 Apr 2018 08:28:41 +0100 Subject: [PATCH 03/14] Adds in missing $scope dependency for Dynamic Dashboard Controller --- .../src/views/dashboard/dashboard.tabs.controller.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Umbraco.Web.UI.Client/src/views/dashboard/dashboard.tabs.controller.js b/src/Umbraco.Web.UI.Client/src/views/dashboard/dashboard.tabs.controller.js index a57078bc9e..0dfdfbc3fe 100644 --- a/src/Umbraco.Web.UI.Client/src/views/dashboard/dashboard.tabs.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/dashboard/dashboard.tabs.controller.js @@ -18,7 +18,7 @@ function startUpVideosDashboardController($scope, xmlhelper, $log, $http) { angular.module("umbraco").controller("Umbraco.Dashboard.StartupVideosController", startUpVideosDashboardController); -function startUpDynamicContentController($timeout, dashboardResource, assetsService, tourService, eventsService) { +function startUpDynamicContentController($timeout, $scope, dashboardResource, assetsService, tourService, eventsService) { var vm = this; var evts = []; From 4047fb119dc8c19ae8766ef43388fa02c426e3c2 Mon Sep 17 00:00:00 2001 From: Warren Date: Wed, 4 Apr 2018 08:28:41 +0100 Subject: [PATCH 04/14] Adds in missing $scope dependency for Dynamic Dashboard Controller --- .../src/views/dashboard/dashboard.tabs.controller.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Umbraco.Web.UI.Client/src/views/dashboard/dashboard.tabs.controller.js b/src/Umbraco.Web.UI.Client/src/views/dashboard/dashboard.tabs.controller.js index a57078bc9e..0dfdfbc3fe 100644 --- a/src/Umbraco.Web.UI.Client/src/views/dashboard/dashboard.tabs.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/dashboard/dashboard.tabs.controller.js @@ -18,7 +18,7 @@ function startUpVideosDashboardController($scope, xmlhelper, $log, $http) { angular.module("umbraco").controller("Umbraco.Dashboard.StartupVideosController", startUpVideosDashboardController); -function startUpDynamicContentController($timeout, dashboardResource, assetsService, tourService, eventsService) { +function startUpDynamicContentController($timeout, $scope, dashboardResource, assetsService, tourService, eventsService) { var vm = this; var evts = []; From 612acfac15add24c7e4a5274eac369856a2754ae Mon Sep 17 00:00:00 2001 From: Stephan Date: Wed, 4 Apr 2018 09:59:01 +0200 Subject: [PATCH 05/14] Fix solution --- src/Umbraco.Web.UI/web.Template.config | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Umbraco.Web.UI/web.Template.config b/src/Umbraco.Web.UI/web.Template.config index 7c07f1fece..1a7ebe7ed8 100644 --- a/src/Umbraco.Web.UI/web.Template.config +++ b/src/Umbraco.Web.UI/web.Template.config @@ -255,7 +255,7 @@ - + From f7a14a03f24846f1f160887c886e979b26be872c Mon Sep 17 00:00:00 2001 From: Stephan Date: Wed, 4 Apr 2018 15:14:05 +0200 Subject: [PATCH 06/14] Fix build, still some weird csc.exe versionning --- build/build.ps1 | 15 +++- src/Umbraco.Compat7/Umbraco.Compat7.csproj | 4 +- src/Umbraco.Core/Umbraco.Core.csproj | 1 + src/Umbraco.Examine/Umbraco.Examine.csproj | 5 +- .../Umbraco.Tests.Benchmarks.csproj | 29 +++--- src/Umbraco.Tests/Umbraco.Tests.csproj | 25 +++--- src/Umbraco.Web.UI.Client/package.json | 2 +- src/Umbraco.Web.UI/Umbraco.Web.UI.csproj | 90 +++++++++++-------- src/Umbraco.Web.UI/web.Template.config | 2 +- src/Umbraco.Web/Umbraco.Web.csproj | 1 + 10 files changed, 96 insertions(+), 78 deletions(-) diff --git a/build/build.ps1 b/build/build.ps1 index 6721bc4403..ccaac8efb5 100644 --- a/build/build.ps1 +++ b/build/build.ps1 @@ -106,7 +106,7 @@ if (-not $?) { throw "Failed to report npm version." } Write-Output "### clean npm cache" >> $log 2>&1 - &npm cache clean >> $log 2>&1 + &npm cache clean --force >> $log 2>&1 $error.Clear() # that one can fail 'cos security bug - ignore Write-Output "### npm install" >> $log 2>&1 @@ -121,13 +121,22 @@ &npm install -g gulp >> $log 2>&1 $error.Clear() # that one fails 'cos deprecated stuff - ignore - Write-Output "### nstall gulp-cli" >> $log 2>&1 + Write-Output "### install gulp-cli" >> $log 2>&1 &npm install -g gulp-cli --quiet >> $log 2>&1 if (-not $?) { throw "Failed to install gulp-cli" } # that one is expected to work Write-Output "### gulp build for version $($this.Version.Release)" >> $log 2>&1 &gulp build --buildversion=$this.Version.Release >> $log 2>&1 - if (-not $?) { throw "Failed to build" } # that one is expected to work + #if (-not $?) { throw "Failed to build" } # that one is expected to work + if (-not $?) + { + # fixme - obviously temp! + Write-Output "#################################" + Write-Output "FIXME - BELLE BUILD FAILS - FIXME" + Write-Output "some phantomJS tests fail, etc..." + Write-Output "#################################" + $error.Clear() + } Pop-Location diff --git a/src/Umbraco.Compat7/Umbraco.Compat7.csproj b/src/Umbraco.Compat7/Umbraco.Compat7.csproj index 8cc5df4b42..bd22959264 100644 --- a/src/Umbraco.Compat7/Umbraco.Compat7.csproj +++ b/src/Umbraco.Compat7/Umbraco.Compat7.csproj @@ -1,5 +1,6 @@  + v4.7 false @@ -27,6 +28,7 @@ TRACE;COMPAT7 prompt 4 + bin\Release\Umbraco.Compat7.xml latest @@ -101,8 +103,8 @@ - + \ No newline at end of file diff --git a/src/Umbraco.Core/Umbraco.Core.csproj b/src/Umbraco.Core/Umbraco.Core.csproj index ff09db7409..cf1818f9e3 100644 --- a/src/Umbraco.Core/Umbraco.Core.csproj +++ b/src/Umbraco.Core/Umbraco.Core.csproj @@ -1,5 +1,6 @@  + v4.7 false diff --git a/src/Umbraco.Examine/Umbraco.Examine.csproj b/src/Umbraco.Examine/Umbraco.Examine.csproj index fca8b0ddab..8184b46e88 100644 --- a/src/Umbraco.Examine/Umbraco.Examine.csproj +++ b/src/Umbraco.Examine/Umbraco.Examine.csproj @@ -1,5 +1,6 @@  + v4.7 false @@ -47,9 +48,7 @@ - - 1.0.0-beta025 - + diff --git a/src/Umbraco.Tests.Benchmarks/Umbraco.Tests.Benchmarks.csproj b/src/Umbraco.Tests.Benchmarks/Umbraco.Tests.Benchmarks.csproj index 32051610be..4196a94d99 100644 --- a/src/Umbraco.Tests.Benchmarks/Umbraco.Tests.Benchmarks.csproj +++ b/src/Umbraco.Tests.Benchmarks/Umbraco.Tests.Benchmarks.csproj @@ -1,5 +1,6 @@  - + + Debug AnyCPU @@ -63,10 +64,6 @@ - - All - - @@ -161,21 +158,17 @@ + - REM if not exist "$(TargetDir)x86" md "$(TargetDir)x86" -REM xcopy /s /y "$(NugetPackages)\Microsoft.SqlServer.Compact.4.0.8876.1\NativeBinaries\x86\*.*" "$(TargetDir)x86" -REM if not exist "$(TargetDir)amd64" md "$(TargetDir)amd64" -REM xcopy /s /y "$(NugetPackages)\Microsoft.SqlServer.Compact.4.0.8876.1\NativeBinaries\amd64\*.*" "$(TargetDir)amd64" + $(NuGetPackageFolders.Split(';')[0]) - - REM xcopy "$(NugetPackages)\SqlServerCE.4.0.0.1\amd64\*.* "$(TargetDir)amd64\" /Y /F /E /I /C /D -REM xcopy "$(NugetPackages)\SqlServerCE.4.0.0.1\x86\*.* "$(TargetDir)x86\" /Y /F /E /I /C /D - - \ No newline at end of file diff --git a/src/Umbraco.Tests/Umbraco.Tests.csproj b/src/Umbraco.Tests/Umbraco.Tests.csproj index 737b65bc2d..017df4450d 100644 --- a/src/Umbraco.Tests/Umbraco.Tests.csproj +++ b/src/Umbraco.Tests/Umbraco.Tests.csproj @@ -1,5 +1,6 @@  - + + Debug AnyCPU @@ -602,20 +603,18 @@ - + - - + $(NuGetPackageFolders.Split(';')[0]) - - REM xcopy "$(NugetPackages)\SqlServerCE.4.0.0.1\amd64\*.*" "$(TargetDir)amd64\" /Y /F /E /I /C /D -REM xcopy "$(NugetPackages)\SqlServerCE.4.0.0.1\x86\*.*" "$(TargetDir)x86\" /Y /F /E /I /C /D - - + \ No newline at end of file diff --git a/src/Umbraco.Web.UI.Client/package.json b/src/Umbraco.Web.UI.Client/package.json index a25176927c..2ba4ae1eee 100644 --- a/src/Umbraco.Web.UI.Client/package.json +++ b/src/Umbraco.Web.UI.Client/package.json @@ -2,7 +2,7 @@ "author": "Umbraco HQ", "name": "umbraco", "homepage": "https://github.com/umbraco/umbraco-cms/", - "version": "7.1.2", + "version": "0.0.0", "license": "MIT", "repository": { "type": "git", diff --git a/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj b/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj index 15c5b10a6e..7e98ea1aa6 100644 --- a/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj +++ b/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj @@ -21,6 +21,16 @@ + + Web.config true @@ -109,9 +119,6 @@ - - 2.6.0 - @@ -732,8 +739,7 @@ - - + 11.0 $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v11.0 @@ -741,15 +747,26 @@ $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v14.0 $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v15.0 - + - REM xcopy "$(ProjectDir)"..\packages\SqlServerCE.4.0.0.1\amd64\*.* "$(TargetDir)amd64\" /Y /F /E /I /C /D -REM xcopy "$(ProjectDir)"..\packages\SqlServerCE.4.0.0.1\x86\*.* "$(TargetDir)x86\" /Y /F /E /I /C /D - - + $(MSBuildExtensionsPath)\Microsoft\VisualStudio\v10.0\Web\Microsoft.Web.Publishing.Tasks.dll + $(MSBuildExtensionsPath)\Microsoft\VisualStudio\v11.0\Web\Microsoft.Web.Publishing.Tasks.dll + $(MSBuildExtensionsPath)\Microsoft\VisualStudio\v12.0\Web\Microsoft.Web.Publishing.Tasks.dll + $(MSBuildExtensionsPath)\Microsoft\VisualStudio\v14.0\Web\Microsoft.Web.Publishing.Tasks.dll + $(MSBuildExtensionsPath)\Microsoft\VisualStudio\v15.0\Web\Microsoft.Web.Publishing.Tasks.dll + + + + + $(NuGetPackageFolders.Split(';')[0]) + + + + - + + @@ -768,35 +785,31 @@ REM xcopy "$(ProjectDir)"..\packages\SqlServerCE.4.0.0.1\x86\*.* "$(TargetDir)x8 - - - $(MSBuildExtensionsPath)\Microsoft\VisualStudio\v15.0\Web\Microsoft.Web.Publishing.Tasks.dll - - - $(MSBuildExtensionsPath)\Microsoft\VisualStudio\v14.0\Web\Microsoft.Web.Publishing.Tasks.dll - - - $(MSBuildExtensionsPath)\Microsoft\VisualStudio\v12.0\Web\Microsoft.Web.Publishing.Tasks.dll - - - $(MSBuildExtensionsPath)\Microsoft\VisualStudio\v11.0\Web\Microsoft.Web.Publishing.Tasks.dll - - - $(MSBuildExtensionsPath)\Microsoft\VisualStudio\v10.0\Web\Microsoft.Web.Publishing.Tasks.dll - - - - + + + + + + + + + + + + + + + @@ -804,7 +817,7 @@ REM xcopy "$(ProjectDir)"..\packages\SqlServerCE.4.0.0.1\x86\*.* "$(TargetDir)x8 - + @@ -816,20 +829,21 @@ REM xcopy "$(ProjectDir)"..\packages\SqlServerCE.4.0.0.1\x86\*.* "$(TargetDir)x8 + - - - - - - - + + + + + + + @(ConfigFiles) diff --git a/src/Umbraco.Web.UI/web.Template.config b/src/Umbraco.Web.UI/web.Template.config index 1a7ebe7ed8..2925497804 100644 --- a/src/Umbraco.Web.UI/web.Template.config +++ b/src/Umbraco.Web.UI/web.Template.config @@ -299,7 +299,7 @@ - + diff --git a/src/Umbraco.Web/Umbraco.Web.csproj b/src/Umbraco.Web/Umbraco.Web.csproj index 1ef52a026d..9a8d424708 100644 --- a/src/Umbraco.Web/Umbraco.Web.csproj +++ b/src/Umbraco.Web/Umbraco.Web.csproj @@ -1,5 +1,6 @@  + v4.7 false From a62422fac3c6c03bc61d3bf087a6dd561268af06 Mon Sep 17 00:00:00 2001 From: Shannon Date: Thu, 5 Apr 2018 15:09:12 +1000 Subject: [PATCH 07/14] ensure that debug is true when developing --- src/Umbraco.Web.UI/web.Template.Debug.config | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/Umbraco.Web.UI/web.Template.Debug.config b/src/Umbraco.Web.UI/web.Template.Debug.config index 9431209d3d..72d0ebb2ef 100644 --- a/src/Umbraco.Web.UI/web.Template.Debug.config +++ b/src/Umbraco.Web.UI/web.Template.Debug.config @@ -12,7 +12,10 @@ file everytime Umbraco builds. --> - - \ No newline at end of file + From 9bfe9e6bbf0d0e81970c07210da8e15c6754b291 Mon Sep 17 00:00:00 2001 From: Shannon Date: Thu, 5 Apr 2018 18:11:15 +1000 Subject: [PATCH 08/14] Ensures that the thread culture is set both in owin and in aspnet --- .../Security/AuthenticationExtensions.cs | 21 ++++++++++++++++++ .../BackOfficeCookieAuthenticationProvider.cs | 22 +++++-------------- src/Umbraco.Web/UmbracoModule.cs | 10 +++++++++ 3 files changed, 37 insertions(+), 16 deletions(-) diff --git a/src/Umbraco.Core/Security/AuthenticationExtensions.cs b/src/Umbraco.Core/Security/AuthenticationExtensions.cs index 17bb32675b..5adf163bee 100644 --- a/src/Umbraco.Core/Security/AuthenticationExtensions.cs +++ b/src/Umbraco.Core/Security/AuthenticationExtensions.cs @@ -1,8 +1,10 @@ using System; using System.Collections; +using System.Collections.Concurrent; using System.Collections.Generic; using System.Collections.Specialized; using System.ComponentModel; +using System.Globalization; using System.Linq; using System.Net.Http; using System.Net.Http.Headers; @@ -441,5 +443,24 @@ namespace Umbraco.Core.Security return ticket; } + + /// + /// Ensures that the thread culture is set based on the back office user's culture + /// + /// + internal static void EnsureCulture(this IIdentity identity) + { + if (identity is UmbracoBackOfficeIdentity umbIdentity && umbIdentity.IsAuthenticated) + { + Thread.CurrentThread.CurrentUICulture = + Thread.CurrentThread.CurrentCulture = + UserCultures.GetOrAdd(umbIdentity.Culture, s => new CultureInfo(s)); + } + } + + /// + /// Used so that we aren't creating a new CultureInfo object for every single request + /// + private static readonly ConcurrentDictionary UserCultures = new ConcurrentDictionary(); } } diff --git a/src/Umbraco.Core/Security/BackOfficeCookieAuthenticationProvider.cs b/src/Umbraco.Core/Security/BackOfficeCookieAuthenticationProvider.cs index cb0ce2b147..b75dd76e47 100644 --- a/src/Umbraco.Core/Security/BackOfficeCookieAuthenticationProvider.cs +++ b/src/Umbraco.Core/Security/BackOfficeCookieAuthenticationProvider.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Concurrent; using System.Globalization; +using System.Runtime.CompilerServices; using System.Security.Claims; using System.Threading; using System.Threading.Tasks; @@ -81,12 +82,13 @@ namespace Umbraco.Core.Security /// public override async Task ValidateIdentity(CookieValidateIdentityContext context) { - EnsureCulture(context); + //ensure the thread culture is set + context?.Identity?.EnsureCulture(); await EnsureValidSessionId(context); await base.ValidateIdentity(context); - } + } /// /// Ensures that the user has a valid session id @@ -100,20 +102,8 @@ namespace Umbraco.Core.Security await SessionIdValidator.ValidateSessionAsync(TimeSpan.FromMinutes(1), context); } - private void EnsureCulture(CookieValidateIdentityContext context) - { - var umbIdentity = context.Identity as UmbracoBackOfficeIdentity; - if (umbIdentity != null && umbIdentity.IsAuthenticated) - { - Thread.CurrentThread.CurrentCulture = - Thread.CurrentThread.CurrentUICulture = - UserCultures.GetOrAdd(umbIdentity.Culture, s => new CultureInfo(s)); - } - } + - /// - /// Used so that we aren't creating a new CultureInfo object for every single request - /// - private static readonly ConcurrentDictionary UserCultures = new ConcurrentDictionary(); + } } diff --git a/src/Umbraco.Web/UmbracoModule.cs b/src/Umbraco.Web/UmbracoModule.cs index b1709259c4..ec91509569 100644 --- a/src/Umbraco.Web/UmbracoModule.cs +++ b/src/Umbraco.Web/UmbracoModule.cs @@ -1,8 +1,10 @@ using System; using System.Collections; using System.Collections.Generic; +using System.Globalization; using System.IO; using System.Text; +using System.Threading; using System.Web; using System.Web.Routing; using LightInject; @@ -15,6 +17,7 @@ using Umbraco.Web.Security; using Umbraco.Core.Collections; using Umbraco.Core.Exceptions; using Umbraco.Core.Persistence; +using Umbraco.Core.Security; using Umbraco.Core.Services; using Umbraco.Web.Composing; using Umbraco.Web.PublishedCache; @@ -562,6 +565,13 @@ namespace Umbraco.Web } }; + app.PostAuthenticateRequest += (sender, e) => + { + var httpContext = ((HttpApplication) sender).Context; + //ensure the thread culture is set + httpContext.User?.Identity?.EnsureCulture(); + }; + app.PostResolveRequestCache += (sender, e) => { var httpContext = ((HttpApplication) sender).Context; From 798236dc85459c64f48da93dc3ad48f6d0ceca64 Mon Sep 17 00:00:00 2001 From: Shannon Date: Thu, 5 Apr 2018 18:13:50 +1000 Subject: [PATCH 09/14] removes unused code, cleans up web.confgi --- src/Umbraco.Web.UI/web.Template.config | 12 --------- src/Umbraco.Web/Security/WebSecurity.cs | 35 ++----------------------- 2 files changed, 2 insertions(+), 45 deletions(-) diff --git a/src/Umbraco.Web.UI/web.Template.config b/src/Umbraco.Web.UI/web.Template.config index 2925497804..d7d2355411 100644 --- a/src/Umbraco.Web.UI/web.Template.config +++ b/src/Umbraco.Web.UI/web.Template.config @@ -97,18 +97,6 @@ - - - - - - - diff --git a/src/Umbraco.Web/Security/WebSecurity.cs b/src/Umbraco.Web/Security/WebSecurity.cs index fbf0093c62..e34a5c9a18 100644 --- a/src/Umbraco.Web/Security/WebSecurity.cs +++ b/src/Umbraco.Web/Security/WebSecurity.cs @@ -154,15 +154,7 @@ namespace Umbraco.Web.Security var user = UserManager.FindByNameAsync(username).Result; return user != null && UserManager.CheckPasswordAsync(user, password).Result; } - - [EditorBrowsable(EditorBrowsableState.Never)] - [Obsolete("Back office users shouldn't be resolved from the membership provider, they should be resolved usign the BackOfficeUserManager or the IUserService")] - public virtual MembershipUser GetBackOfficeMembershipUser(string username, bool setOnline) - { - var membershipProvider = Core.Security.MembershipProviderExtensions.GetUsersMembershipProvider(); - return membershipProvider != null ? membershipProvider.GetUser(username, setOnline) : null; - } - + /// /// Validates the current user to see if they have access to the specified app /// @@ -197,18 +189,7 @@ namespace Umbraco.Web.Security var identity = _httpContext.GetCurrentIdentity(false); return identity?.SessionId; } - - /// - /// Validates the user context ID. - /// - /// This doesn't do anything - /// - [Obsolete("This method is no longer used, use the ValidateCurrentUser() method instead")] - public bool ValidateUserContextId(string currentUmbracoUserContextId) - { - return ValidateCurrentUser(); - } - + /// /// Validates the currently logged in user and ensures they are not timed out /// @@ -292,18 +273,6 @@ namespace Umbraco.Web.Security return user.HasSectionAccess(section); } - [Obsolete("Returns the current user's unique umbraco sesion id - this cannot be set and isn't intended to be used in your code")] - public string UmbracoUserContextId - { - get - { - return _httpContext.GetUmbracoAuthTicket() == null ? "" : GetSessionId(); - } - set - { - } - } - /// /// Ensures that a back office user is logged in /// From eb6a08af31f26e9fef89d9993cbbf795c4d31782 Mon Sep 17 00:00:00 2001 From: Stephan Date: Thu, 5 Apr 2018 12:50:00 +0200 Subject: [PATCH 10/14] v7@11d4189c8d --- build/NuSpecs/UmbracoCms.Core.nuspec | 1 + build/build.ps1 | 108 +++++---- src/Umbraco.Core/IO/FileSystems.cs | 6 +- src/Umbraco.Core/IO/IOHelper.cs | 4 +- src/Umbraco.Core/IO/SystemDirectories.cs | 205 +++--------------- .../Upgrade/V_7_7_0/AddUserGroupTables.cs | 4 +- .../src/canvasdesigner.loader.js | 5 +- src/Umbraco.Web/Cache/MediaCacheRefresher.cs | 5 +- src/Umbraco.Web/Editors/PreviewController.cs | 13 +- .../Models/ContentEditing/AuditLog.cs | 4 - .../ContentEditing/BackOfficePreview.cs | 1 + src/Umbraco.Web/Umbraco.Web.csproj | 1 + 12 files changed, 106 insertions(+), 251 deletions(-) diff --git a/build/NuSpecs/UmbracoCms.Core.nuspec b/build/NuSpecs/UmbracoCms.Core.nuspec index 516093ec11..c0fa5368cc 100644 --- a/build/NuSpecs/UmbracoCms.Core.nuspec +++ b/build/NuSpecs/UmbracoCms.Core.nuspec @@ -40,6 +40,7 @@ + diff --git a/build/build.ps1 b/build/build.ps1 index ccaac8efb5..b549ef281f 100644 --- a/build/build.ps1 +++ b/build/build.ps1 @@ -25,7 +25,7 @@ # create and boot the buildsystem $ubuild = &"$PSScriptRoot\build-bootstrap.ps1" if (-not $?) { return } - $ubuild.Boot($PSScriptRoot, + $ubuild.Boot($PSScriptRoot, @{ Local = $local; }, @{ Continue = $continue }) if ($ubuild.OnError()) { return } @@ -36,21 +36,21 @@ # ################################################################ # TASKS # ################################################################ - + $ubuild.DefineMethod("SetMoreUmbracoVersion", { param ( $semver ) $release = "" + $semver.Major + "." + $semver.Minor + "." + $semver.Patch - + Write-Host "Update UmbracoVersion.cs" $this.ReplaceFileText("$($this.SolutionRoot)\src\Umbraco.Core\Configuration\UmbracoVersion.cs", ` "(\d+)\.(\d+)\.(\d+)(.(\d+))?", ` - "$release") + "$release") $this.ReplaceFileText("$($this.SolutionRoot)\src\Umbraco.Core\Configuration\UmbracoVersion.cs", ` "CurrentComment => `"(.+)`"", ` "CurrentComment => `"$($semver.PreRelease)`"") - + Write-Host "Update IIS Express port in csproj" $updater = New-Object "Umbraco.Build.ExpressPortUpdater" $csproj = "$($this.SolutionRoot)\src\Umbraco.Web.UI\Umbraco.Web.UI.csproj" @@ -61,7 +61,7 @@ { $global:node_path = $env:path $nodePath = $this.BuildEnv.NodePath - $gitExe = (Get-Command git).Source + $gitExe = (Get-Command git).Source $gitPath = [System.IO.Path]::GetDirectoryName($gitExe) $env:path = "$nodePath;$gitPath" @@ -73,7 +73,7 @@ $ubuild.DefineMethod("RestoreNode", { $env:path = $node_path - + $this.SetEnvVar("NODEPATH", $node_nodepath) $this.SetEnvVar("NPM_CONFIG_CACHE", $node_npmcache) $this.SetEnvVar("NPM_CONFIG_PREFIX", $node_npmprefix) @@ -83,9 +83,9 @@ { $src = "$($this.SolutionRoot)\src" $log = "$($this.BuildTemp)\belle.log" - + Write-Host "Compile Belle" - Write-Host "Logging to $log" + Write-Host "Logging to $log" # get a temp clean node env (will restore) $this.SandboxNode() @@ -96,7 +96,7 @@ Push-Location "$($this.SolutionRoot)\src\Umbraco.Web.UI.Client" Write-Output "" > $log - + Write-Output "### node version is:" > $log &node -v >> $log 2>&1 if (-not $?) { throw "Failed to report node version." } @@ -116,7 +116,7 @@ Write-Output "### install bower" >> $log 2>&1 &npm install -g bower >> $log 2>&1 $error.Clear() # that one fails 'cos bower is deprecated - ignore - + Write-Output "### install gulp" >> $log 2>&1 &npm install -g gulp >> $log 2>&1 $error.Clear() # that one fails 'cos deprecated stuff - ignore @@ -127,25 +127,16 @@ Write-Output "### gulp build for version $($this.Version.Release)" >> $log 2>&1 &gulp build --buildversion=$this.Version.Release >> $log 2>&1 - #if (-not $?) { throw "Failed to build" } # that one is expected to work - if (-not $?) - { - # fixme - obviously temp! - Write-Output "#################################" - Write-Output "FIXME - BELLE BUILD FAILS - FIXME" - Write-Output "some phantomJS tests fail, etc..." - Write-Output "#################################" - $error.Clear() - } + if (-not $?) { throw "Failed to build" } # that one is expected to work Pop-Location - + # fixme - should we filter the log to find errors? #get-content .\build.tmp\belle.log | %{ if ($_ -match "build") { write $_}} - + # restore $this.RestoreNode() - + # setting node_modules folder to hidden # used to prevent VS13 from crashing on it while loading the websites project # also makes sure aspnet compiler does not try to handle rogue files and chokes @@ -163,15 +154,15 @@ $src = "$($this.SolutionRoot)\src" $log = "$($this.BuildTemp)\msbuild.umbraco.log" $log7 = "$($this.BuildTemp)\msbuild.compat7.log" - + if ($this.BuildEnv.VisualStudio -eq $null) { throw "Build environment does not provide VisualStudio." } - + Write-Host "Compile Umbraco" Write-Host "Logging to $log" - + # beware of the weird double \\ at the end of paths # see http://edgylogic.com/blog/powershell-and-external-commands-done-right/ &$this.BuildEnv.VisualStudio.MsBuild "$src\Umbraco.Web.UI\Umbraco.Web.UI.csproj" ` @@ -189,7 +180,7 @@ > $log if (-not $?) { throw "Failed to compile Umbraco.Web.UI." } - + Write-Host "Logging to $log7" &$this.BuildEnv.VisualStudio.MsBuild "$src\Umbraco.Compat7\Umbraco.Compat7.csproj" ` @@ -207,19 +198,19 @@ > $log7 if (-not $?) { throw "Failed to compile Umbraco.Compat7." } - + # /p:UmbracoBuild tells the csproj that we are building from PS, not VS }) $ubuild.DefineMethod("PrepareTests", { Write-Host "Prepare Tests" - + # fixme - idea is to avoid rebuilding everything for tests # but because of our weird assembly versioning (with .* stuff) # everything gets rebuilt all the time... #Copy-Files "$tmp\bin" "." "$tmp\tests" - + # data Write-Host "Copy data files" if (-not (Test-Path -Path "$($this.BuildTemp)\tests\Packaging" )) @@ -228,8 +219,8 @@ mkdir "$($this.BuildTemp)\tests\Packaging" > $null } $this.CopyFiles("$($this.SolutionRoot)\src\Umbraco.Tests\Packaging\Packages", "*", "$($this.BuildTemp)\tests\Packaging\Packages") - - # required for package install tests + + # required for package install tests if (-not (Test-Path -Path "$($this.BuildTemp)\tests\bin" )) { Write-Host "Create bin directory" @@ -246,10 +237,10 @@ { throw "Build environment does not provide VisualStudio." } - + Write-Host "Compile Tests" Write-Host "Logging to $log" - + # beware of the weird double \\ at the end of paths # see http://edgylogic.com/blog/powershell-and-external-commands-done-right/ &$this.BuildEnv.VisualStudio.MsBuild "$($this.SolutionRoot)\src\Umbraco.Tests\Umbraco.Tests.csproj" ` @@ -273,26 +264,26 @@ $ubuild.DefineMethod("PreparePackages", { - Write-Host "Prepare Packages" - + Write-Host "Prepare Packages" + $src = "$($this.SolutionRoot)\src" $tmp = "$($this.BuildTemp)" $out = "$($this.BuildOutput)" - + $buildConfiguration = "Release" - + # restore web.config $this.TempRestoreFile("$src\Umbraco.Web.UI\web.config") - + # cleanup build Write-Host "Clean build" $this.RemoveFile("$tmp\bin\*.dll.config") $this.RemoveFile("$tmp\WebApp\bin\*.dll.config") - + # cleanup presentation Write-Host "Cleanup presentation" $this.RemoveDirectory("$tmp\WebApp\umbraco.presentation") - + # create directories Write-Host "Create directories" mkdir "$tmp\Configs" > $null @@ -300,11 +291,11 @@ mkdir "$tmp\WebApp\App_Data" > $null #mkdir "$tmp\WebApp\Media" > $null #mkdir "$tmp\WebApp\Views" > $null - + # copy various files Write-Host "Copy xml documentation" Copy-Item -force "$tmp\bin\*.xml" "$tmp\WebApp\bin" - + Write-Host "Copy transformed configs and langs" # note: exclude imageprocessor/*.config as imageprocessor pkg installs them $this.CopyFiles("$tmp\WebApp\config", "*.config", "$tmp\Configs", ` @@ -312,10 +303,10 @@ $this.CopyFiles("$tmp\WebApp\config", "*.js", "$tmp\Configs") $this.CopyFiles("$tmp\WebApp\config\lang", "*.xml", "$tmp\Configs\Lang") $this.CopyFile("$tmp\WebApp\web.config", "$tmp\Configs\web.config.transform") - + Write-Host "Copy transformed web.config" $this.CopyFile("$src\Umbraco.Web.UI\web.$buildConfiguration.Config.transformed", "$tmp\WebApp\web.config") - + # offset the modified timestamps on all umbraco dlls, as WebResources # break if date is in the future, which, due to timezone offsets can happen. Write-Host "Offset dlls timestamps" @@ -323,49 +314,48 @@ $_.CreationTime = $_.CreationTime.AddHours(-11) $_.LastWriteTime = $_.LastWriteTime.AddHours(-11) } - + # copy libs Write-Host "Copy SqlCE libraries" $this.CopyFiles("$src\packages\SqlServerCE.4.0.0.1", "*.*", "$tmp\bin", ` { -not $_.Extension.StartsWith(".nu") -and -not $_.RelativeName.StartsWith("lib\") }) $this.CopyFiles("$src\packages\SqlServerCE.4.0.0.1", "*.*", "$tmp\WebApp\bin", ` { -not $_.Extension.StartsWith(".nu") -and -not $_.RelativeName.StartsWith("lib\") }) - + # copy Belle Write-Host "Copy Belle" $this.CopyFiles("$src\Umbraco.Web.UI\umbraco\assets", "*", "$tmp\WebApp\umbraco\assets") $this.CopyFiles("$src\Umbraco.Web.UI\umbraco\js", "*", "$tmp\WebApp\umbraco\js") $this.CopyFiles("$src\Umbraco.Web.UI\umbraco\lib", "*", "$tmp\WebApp\umbraco\lib") $this.CopyFiles("$src\Umbraco.Web.UI\umbraco\views", "*", "$tmp\WebApp\umbraco\views") - $this.CopyFiles("$src\Umbraco.Web.UI\umbraco\preview", "*", "$tmp\WebApp\umbraco\preview") }) $ubuild.DefineMethod("PackageZip", { - Write-Host "Create Zip packages" + Write-Host "Create Zip packages" $src = "$($this.SolutionRoot)\src" $tmp = $this.BuildTemp $out = $this.BuildOutput - - Write-Host "Zip all binaries" + + Write-Host "Zip all binaries" &$this.BuildEnv.Zip a -r "$out\UmbracoCms.AllBinaries.$($this.Version.Semver).zip" ` "$tmp\bin\*" ` "-x!dotless.Core.*" "-x!Umbraco.Compat7.*" ` > $null - if (-not $?) { throw "Failed to zip UmbracoCms.AllBinaries." } + if (-not $?) { throw "Failed to zip UmbracoCms.AllBinaries." } - Write-Host "Zip cms" + Write-Host "Zip cms" &$this.BuildEnv.Zip a -r "$out\UmbracoCms.$($this.Version.Semver).zip" ` "$tmp\WebApp\*" ` "-x!dotless.Core.*" "-x!Content_Types.xml" "-x!*.pdb" "-x!Umbraco.Compat7.*" ` > $null - if (-not $?) { throw "Failed to zip UmbracoCms." } + if (-not $?) { throw "Failed to zip UmbracoCms." } }) $ubuild.DefineMethod("PrepareBuild", { - Write-Host "Clear folders and files" + Write-Host "Clear folders and files" $this.RemoveDirectory("$($this.SolutionRoot)\src\Umbraco.Web.UI.Client\bower_components") $this.TempStoreFile("$($this.SolutionRoot)\src\Umbraco.Web.UI\web.config") @@ -390,7 +380,7 @@ Write-Host "Restore NuGet" Write-Host "Logging to $($this.BuildTemp)\nuget.restore.log" &$this.BuildEnv.NuGet restore "$($this.SolutionRoot)\src\Umbraco.sln" -ConfigFile $this.BuildEnv.NuGetConfig > "$($this.BuildTemp)\nuget.restore.log" - if (-not $?) { throw "Failed to restore NuGet packages." } + if (-not $?) { throw "Failed to restore NuGet packages." } }) $ubuild.DefineMethod("PackageNuGet", @@ -482,9 +472,9 @@ $ubuild.ReleaseBranches = @( "master" ) # run - if (-not $get) + if (-not $get) { - $ubuild.Build() + $ubuild.Build() if ($ubuild.OnError()) { return } } Write-Host "Done" diff --git a/src/Umbraco.Core/IO/FileSystems.cs b/src/Umbraco.Core/IO/FileSystems.cs index 4d3ef4a605..39e7fa30fc 100644 --- a/src/Umbraco.Core/IO/FileSystems.cs +++ b/src/Umbraco.Core/IO/FileSystems.cs @@ -29,6 +29,7 @@ namespace Umbraco.Core.IO private ShadowWrapper _xsltFileSystem; private ShadowWrapper _masterPagesFileSystem; private ShadowWrapper _mvcViewsFileSystem; + private ShadowWrapper _javaScriptLibraryFileSystem; // well-known file systems lazy initialization private object _wkfsLock = new object(); @@ -165,7 +166,7 @@ namespace Umbraco.Core.IO var xsltFileSystem = new PhysicalFileSystem(SystemDirectories.Xslt); var masterPagesFileSystem = new PhysicalFileSystem(SystemDirectories.Masterpages); var mvcViewsFileSystem = new PhysicalFileSystem(SystemDirectories.MvcViews); - + var javaScriptLibraryFileSystem = new PhysicalFileSystem(SystemDirectories.JavaScriptLibrary); _macroPartialFileSystem = new ShadowWrapper(macroPartialFileSystem, "Views/MacroPartials", () => IsScoped()); _partialViewsFileSystem = new ShadowWrapper(partialViewsFileSystem, "Views/Partials", () => IsScoped()); @@ -174,8 +175,7 @@ namespace Umbraco.Core.IO _xsltFileSystem = new ShadowWrapper(xsltFileSystem, "xslt", () => IsScoped()); _masterPagesFileSystem = new ShadowWrapper(masterPagesFileSystem, "masterpages", () => IsScoped()); _mvcViewsFileSystem = new ShadowWrapper(mvcViewsFileSystem, "Views", () => IsScoped()); - - _javascriptLibraryFileSystem = new PhysicalFileSystem(Path.Combine(SystemDirectories.Umbraco, "lib")); + _javascriptLibraryFileSystem = new ShadowWrapper(javaScriptLibraryFileSystem, "Lib", () => IsScoped()); // filesystems obtained from GetFileSystemProvider are already wrapped and do not need to be wrapped again _mediaFileSystem = GetFileSystemProvider(); diff --git a/src/Umbraco.Core/IO/IOHelper.cs b/src/Umbraco.Core/IO/IOHelper.cs index 5a2928f795..0a61e8e542 100644 --- a/src/Umbraco.Core/IO/IOHelper.cs +++ b/src/Umbraco.Core/IO/IOHelper.cs @@ -131,9 +131,9 @@ namespace Umbraco.Core.IO //use a tilde character instead of the complete path internal static string ReturnPath(string settingsKey, string standardPath, bool useTilde) { - string retval = ConfigurationManager.AppSettings[settingsKey]; + var retval = ConfigurationManager.AppSettings[settingsKey]; - if (String.IsNullOrEmpty(retval)) + if (string.IsNullOrEmpty(retval)) retval = standardPath; return retval.TrimEnd('/'); diff --git a/src/Umbraco.Core/IO/SystemDirectories.cs b/src/Umbraco.Core/IO/SystemDirectories.cs index f2c9a438db..d9f0eba841 100644 --- a/src/Umbraco.Core/IO/SystemDirectories.cs +++ b/src/Umbraco.Core/IO/SystemDirectories.cs @@ -1,11 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Configuration; - -using System.Web; -using System.IO; +using System.Web; namespace Umbraco.Core.IO { @@ -13,179 +6,56 @@ namespace Umbraco.Core.IO public class SystemDirectories { //TODO: Why on earth is this even configurable? You cannot change the /Bin folder in ASP.Net - public static string Bin - { - get - { - return IOHelper.ReturnPath("umbracoBinDirectory", "~/bin"); - } - } + public static string Bin => IOHelper.ReturnPath("umbracoBinDirectory", "~/bin"); - public static string Base - { - get - { - return IOHelper.ReturnPath("umbracoBaseDirectory", "~/base"); - } - } + public static string Base => IOHelper.ReturnPath("umbracoBaseDirectory", "~/base"); - public static string Config - { - get - { - return IOHelper.ReturnPath("umbracoConfigDirectory", "~/config"); - } - } + public static string Config => IOHelper.ReturnPath("umbracoConfigDirectory", "~/config"); - public static string Css - { - get - { - return IOHelper.ReturnPath("umbracoCssDirectory", "~/css"); - } - } + public static string Css => IOHelper.ReturnPath("umbracoCssDirectory", "~/css"); - public static string Data - { - get - { - return IOHelper.ReturnPath("umbracoStorageDirectory", "~/App_Data"); - } - } + public static string Data => IOHelper.ReturnPath("umbracoStorageDirectory", "~/App_Data"); - public static string Install - { - get - { - return IOHelper.ReturnPath("umbracoInstallPath", "~/install"); - } - } + public static string Install => IOHelper.ReturnPath("umbracoInstallPath", "~/install"); - public static string Masterpages - { - get - { - return IOHelper.ReturnPath("umbracoMasterPagesPath", "~/masterpages"); - } - } + public static string Masterpages => IOHelper.ReturnPath("umbracoMasterPagesPath", "~/masterpages"); - public static string AppCode - { - get - { - //NOTE: this is not configurable and shouldn't need to be - return "~/App_Code"; - } - } + //NOTE: this is not configurable and shouldn't need to be + public static string AppCode => "~/App_Code"; - public static string AppPlugins - { - get - { - //NOTE: this is not configurable and shouldn't need to be - return "~/App_Plugins"; - } - } + //NOTE: this is not configurable and shouldn't need to be + public static string AppPlugins => "~/App_Plugins"; - public static string MvcViews - { - get - { - //NOTE: this is not configurable and shouldn't need to be - return "~/Views"; - } - } + //NOTE: this is not configurable and shouldn't need to be + public static string MvcViews => "~/Views"; - public static string PartialViews - { - get - { - return MvcViews + "/Partials/"; - } - } + public static string PartialViews => MvcViews + "/Partials/"; - public static string MacroPartials - { - get - { - return MvcViews + "/MacroPartials/"; + public static string MacroPartials => MvcViews + "/MacroPartials/"; - } - } + public static string Media => IOHelper.ReturnPath("umbracoMediaPath", "~/media"); - public static string Media - { - get - { - return IOHelper.ReturnPath("umbracoMediaPath", "~/media"); - } - } + public static string Scripts => IOHelper.ReturnPath("umbracoScriptsPath", "~/scripts"); - public static string Scripts - { - get - { - return IOHelper.ReturnPath("umbracoScriptsPath", "~/scripts"); - } - } + public static string Umbraco => IOHelper.ReturnPath("umbracoPath", "~/umbraco"); - public static string Umbraco - { - get - { - return IOHelper.ReturnPath("umbracoPath", "~/umbraco"); - } - } + public static string UmbracoClient => IOHelper.ReturnPath("umbracoClientPath", "~/umbraco_client"); - public static string UmbracoClient - { - get - { - return IOHelper.ReturnPath("umbracoClientPath", "~/umbraco_client"); - } - } + public static string UserControls => IOHelper.ReturnPath("umbracoUsercontrolsPath", "~/usercontrols"); - public static string UserControls - { - get - { - return IOHelper.ReturnPath("umbracoUsercontrolsPath", "~/usercontrols"); - } - } + public static string WebServices => IOHelper.ReturnPath("umbracoWebservicesPath", Umbraco.EnsureEndsWith("/") + "webservices"); - public static string WebServices - { - get - { - return IOHelper.ReturnPath("umbracoWebservicesPath", Umbraco.EnsureEndsWith("/") + "webservices"); - } - } + public static string Xslt => IOHelper.ReturnPath("umbracoXsltPath", "~/xslt"); - public static string Xslt - { - get { - return IOHelper.ReturnPath("umbracoXsltPath", "~/xslt"); - } - } + //by default the packages folder should exist in the data folder + public static string Packages => IOHelper.ReturnPath("umbracoPackagesPath", Data + IOHelper.DirSepChar + "packages"); - public static string Packages - { - get - { - //by default the packages folder should exist in the data folder - return IOHelper.ReturnPath("umbracoPackagesPath", Data + IOHelper.DirSepChar + "packages"); - } - } + public static string Preview => IOHelper.ReturnPath("umbracoPreviewPath", Data + IOHelper.DirSepChar + "preview"); + + public static string JavaScriptLibrary => IOHelper.ReturnPath("umbracoJavaScriptLibraryPath", Umbraco + IOHelper.DirSepChar + "lib"); - public static string Preview - { - get - { - return IOHelper.ReturnPath("umbracoPreviewPath", Data + IOHelper.DirSepChar + "preview"); - } - } + private static string _root; - private static string _root; /// /// Gets the root path of the application /// @@ -193,21 +63,16 @@ namespace Umbraco.Core.IO { get { - if (_root == null) - { - string appPath = HttpRuntime.AppDomainAppVirtualPath ?? string.Empty; - if (appPath == "/") - appPath = string.Empty; + if (_root != null) return _root; - _root = appPath; - } + var appPath = HttpRuntime.AppDomainAppVirtualPath; + if (appPath == "/") appPath = string.Empty; + + _root = appPath; return _root; } //Only required for unit tests - internal set { _root = value; } + internal set => _root = value; } } - - - } diff --git a/src/Umbraco.Core/Migrations/Upgrade/V_7_7_0/AddUserGroupTables.cs b/src/Umbraco.Core/Migrations/Upgrade/V_7_7_0/AddUserGroupTables.cs index 1042322dca..35df178672 100644 --- a/src/Umbraco.Core/Migrations/Upgrade/V_7_7_0/AddUserGroupTables.cs +++ b/src/Umbraco.Core/Migrations/Upgrade/V_7_7_0/AddUserGroupTables.cs @@ -2,7 +2,6 @@ using System.Collections.Generic; using System.Data; using System.Linq; -using NPoco; using Umbraco.Core.Persistence; using Umbraco.Core.Persistence.Dtos; using Umbraco.Core.Persistence.SqlSyntax; @@ -216,8 +215,7 @@ namespace Umbraco.Core.Migrations.Upgrade.V_7_7_0 var usersWithApps = new Dictionary>(); foreach (var userApps in userAppsData) { - List apps; - if (usersWithApps.TryGetValue(userApps.id, out apps) == false) + if (usersWithApps.TryGetValue(userApps.id, out List apps) == false) { apps = new List {userApps.app}; usersWithApps.Add(userApps.id, apps); diff --git a/src/Umbraco.Web.UI.Client/src/canvasdesigner.loader.js b/src/Umbraco.Web.UI.Client/src/canvasdesigner.loader.js index f0fa81faee..5d39fb3bcf 100644 --- a/src/Umbraco.Web.UI.Client/src/canvasdesigner.loader.js +++ b/src/Umbraco.Web.UI.Client/src/canvasdesigner.loader.js @@ -1,8 +1,6 @@ LazyLoad.js([ '../lib/jquery/jquery.min.js', - //'../lib/jquery-ui/jquery-ui.min.js', - '/Scripts/jquery-1.6.4.min.js', '../lib/angular/1.1.5/angular.min.js', '../lib/underscore/underscore-min.js', '../lib/umbraco/Extensions.js', @@ -13,9 +11,8 @@ LazyLoad.js([ '../ServerVariables', '../lib/spectrum/spectrum.js', '../lib/signalr/jquery.signalR.js', - '/umbraco/signalr/hubs', + '/umbraco/BackOffice/signalr/hubs', '../js/umbraco.canvasdesigner.js' - '../js/canvasdesigner.panel.js' ], function () { jQuery(document).ready(function () { angular.bootstrap(document, ['Umbraco.canvasdesigner']); diff --git a/src/Umbraco.Web/Cache/MediaCacheRefresher.cs b/src/Umbraco.Web/Cache/MediaCacheRefresher.cs index c4688e1afd..8eeb4abcec 100644 --- a/src/Umbraco.Web/Cache/MediaCacheRefresher.cs +++ b/src/Umbraco.Web/Cache/MediaCacheRefresher.cs @@ -42,9 +42,8 @@ namespace Umbraco.Web.Cache public override void Refresh(JsonPayload[] payloads) { if (payloads == null) return; - - bool anythingChanged; - _publishedSnapshotService.Notify(payloads, out anythingChanged); + + _publishedSnapshotService.Notify(payloads, out var anythingChanged); if (anythingChanged) { diff --git a/src/Umbraco.Web/Editors/PreviewController.cs b/src/Umbraco.Web/Editors/PreviewController.cs index 08de0f83ba..954809eeb6 100644 --- a/src/Umbraco.Web/Editors/PreviewController.cs +++ b/src/Umbraco.Web/Editors/PreviewController.cs @@ -11,13 +11,20 @@ namespace Umbraco.Web.Editors [DisableBrowserCache] public class PreviewController : Controller { + private readonly UmbracoFeatures _features; + + public PreviewController(UmbracoFeatures features) + { + _features = features; + } + [UmbracoAuthorize(redirectToUmbracoLogin: true)] public ActionResult Index() { var model = new BackOfficePreview { - DisableDevicePreview = FeaturesResolver.Current.Features.Disabled.DisableDevicePreview, - PreviewExtendedHeaderView = FeaturesResolver.Current.Features.Enabled.PreviewExtendedView + DisableDevicePreview = _features.Disabled.DisableDevicePreview, + PreviewExtendedHeaderView = _features.Enabled.PreviewExtendedView }; if (model.PreviewExtendedHeaderView.IsNullOrWhiteSpace() == false) @@ -34,7 +41,7 @@ namespace Umbraco.Web.Editors public ActionResult Editors(string editor) { - if (string.IsNullOrEmpty(editor)) throw new ArgumentNullException("editor"); + if (string.IsNullOrEmpty(editor)) throw new ArgumentNullException(nameof(editor)); return View(GlobalSettings.Path.EnsureEndsWith('/') + "Views/Preview/" + editor.Replace(".html", string.Empty) + ".cshtml"); } } diff --git a/src/Umbraco.Web/Models/ContentEditing/AuditLog.cs b/src/Umbraco.Web/Models/ContentEditing/AuditLog.cs index 9210472313..e908359f93 100644 --- a/src/Umbraco.Web/Models/ContentEditing/AuditLog.cs +++ b/src/Umbraco.Web/Models/ContentEditing/AuditLog.cs @@ -1,12 +1,8 @@ using System; using System.Runtime.Serialization; -using Newtonsoft.Json; -using Newtonsoft.Json.Converters; -using Umbraco.Core.Models; namespace Umbraco.Web.Models.ContentEditing { - [DataContract(Name = "auditLog", Namespace = "")] public class AuditLog { diff --git a/src/Umbraco.Web/Models/ContentEditing/BackOfficePreview.cs b/src/Umbraco.Web/Models/ContentEditing/BackOfficePreview.cs index ed2e623226..f8633acdd0 100644 --- a/src/Umbraco.Web/Models/ContentEditing/BackOfficePreview.cs +++ b/src/Umbraco.Web/Models/ContentEditing/BackOfficePreview.cs @@ -6,6 +6,7 @@ public class BackOfficePreview { public string PreviewExtendedHeaderView { get; set; } + //TODO: We could potentially have a 'footer' view public bool DisableDevicePreview { get; set; } } diff --git a/src/Umbraco.Web/Umbraco.Web.csproj b/src/Umbraco.Web/Umbraco.Web.csproj index 9a8d424708..552702cb28 100644 --- a/src/Umbraco.Web/Umbraco.Web.csproj +++ b/src/Umbraco.Web/Umbraco.Web.csproj @@ -150,6 +150,7 @@ + From 262c4afb162e0da71a3bb0e7e818d24906e3f5d0 Mon Sep 17 00:00:00 2001 From: Shannon Date: Thu, 5 Apr 2018 23:10:51 +1000 Subject: [PATCH 11/14] Removes FormsAuthentication cookie format and replaces with standard aspnet identity format, removes a bunch of old obsolete and unused code, fixes the culture setting issue, simplifies the UmbracoBackOfficeIdentity since it no longer needs to be a FormsIdentity and just a straight forward ClaimsIdentity --- .../Security/AuthenticationExtensions.cs | 523 +++--------------- .../BackOfficeClaimsIdentityFactory.cs | 27 +- .../BackOfficeCookieAuthenticationProvider.cs | 6 +- .../Security/BackOfficeUserManager.cs | 44 +- src/Umbraco.Core/Security/OwinExtensions.cs | 3 + .../Security/UmbracoBackOfficeIdentity.cs | 368 +++++------- src/Umbraco.Core/Security/UserData.cs | 74 --- src/Umbraco.Core/Umbraco.Core.csproj | 1 - .../UmbracoBackOfficeIdentityTests.cs | 91 +-- .../AuthenticateEverythingMiddleware.cs | 11 +- .../Editors/CurrentUserController.cs | 1 + .../Security/AuthenticationExtensions.cs | 378 +++++++++++++ .../Security/Identity/AppBuilderExtensions.cs | 24 +- .../Identity/BackOfficeCookieManager.cs | 2 +- .../FormsAuthenticationSecureDataFormat.cs | 90 --- .../Identity/GetUserSecondsMiddleWare.cs | 8 +- .../UmbracoBackOfficeCookieAuthOptions.cs | 37 +- .../Identity/UmbracoSecureDataFormat.cs | 83 +++ .../Security/LegacyDefaultAppMapping.cs | 49 -- src/Umbraco.Web/Security/OwinExtensions.cs | 12 +- .../UmbracoAuthTicketDataProtector.cs | 19 + .../UI/Pages/UmbracoEnsuredPage.cs | 1 + src/Umbraco.Web/Umbraco.Web.csproj | 5 +- .../UmbracoUserTimeoutFilterAttribute.cs | 11 +- .../controls/Tree/CustomTreeService.cs | 1 + .../umbraco/controls/Tree/TreeControl.ascx.cs | 1 + 26 files changed, 766 insertions(+), 1104 deletions(-) delete mode 100644 src/Umbraco.Core/Security/UserData.cs create mode 100644 src/Umbraco.Web/Security/AuthenticationExtensions.cs delete mode 100644 src/Umbraco.Web/Security/Identity/FormsAuthenticationSecureDataFormat.cs create mode 100644 src/Umbraco.Web/Security/Identity/UmbracoSecureDataFormat.cs delete mode 100644 src/Umbraco.Web/Security/LegacyDefaultAppMapping.cs create mode 100644 src/Umbraco.Web/Security/UmbracoAuthTicketDataProtector.cs diff --git a/src/Umbraco.Core/Security/AuthenticationExtensions.cs b/src/Umbraco.Core/Security/AuthenticationExtensions.cs index 5adf163bee..3b497bff86 100644 --- a/src/Umbraco.Core/Security/AuthenticationExtensions.cs +++ b/src/Umbraco.Core/Security/AuthenticationExtensions.cs @@ -1,466 +1,67 @@ -using System; -using System.Collections; -using System.Collections.Concurrent; -using System.Collections.Generic; -using System.Collections.Specialized; -using System.ComponentModel; -using System.Globalization; -using System.Linq; -using System.Net.Http; -using System.Net.Http.Headers; -using System.Security.Claims; -using System.Security.Principal; -using System.Threading; -using System.Web; -using System.Web.Security; -using Microsoft.AspNet.Identity; -using AutoMapper; -using Microsoft.Owin; -using Newtonsoft.Json; -using Umbraco.Core.Configuration; -using Umbraco.Core.Composing; -using Umbraco.Core.Models.Membership; -using Umbraco.Core.Logging; -using IUser = Umbraco.Core.Models.Membership.IUser; - -namespace Umbraco.Core.Security -{ - /// - /// Extensions to create and renew and remove authentication tickets for the Umbraco back office - /// - public static class AuthenticationExtensions - { - /// - /// This will check the ticket to see if it is valid, if it is it will set the current thread's user and culture - /// - /// - /// - /// If true will attempt to renew the ticket - public static bool AuthenticateCurrentRequest(this HttpContextBase http, FormsAuthenticationTicket ticket, bool renewTicket) - { - if (http == null) throw new ArgumentNullException("http"); - - //if there was a ticket, it's not expired, - it should not be renewed or its renewable - if (ticket != null && ticket.Expired == false && (renewTicket == false || http.RenewUmbracoAuthTicket())) - { - try - { - //create the Umbraco user identity - var identity = new UmbracoBackOfficeIdentity(ticket); - - //set the principal object - var principal = new GenericPrincipal(identity, identity.Roles); - - //It is actually not good enough to set this on the current app Context and the thread, it also needs - // to be set explicitly on the HttpContext.Current !! This is a strange web api thing that is actually - // an underlying fault of asp.net not propogating the User correctly. - if (HttpContext.Current != null) - { - HttpContext.Current.User = principal; - } - http.User = principal; - Thread.CurrentPrincipal = principal; - - //This is a back office request, we will also set the culture/ui culture - Thread.CurrentThread.CurrentCulture = - Thread.CurrentThread.CurrentUICulture = - new System.Globalization.CultureInfo(identity.Culture); - - return true; - } - catch (Exception ex) - { - if (ex is FormatException || ex is JsonReaderException) - { - //this will occur if the cookie data is invalid - http.UmbracoLogout(); - } - else - { - throw; - } - - } - } - - return false; - } - - /// - /// This will return the current back office identity if the IPrincipal is the correct type - /// - /// - /// - internal static UmbracoBackOfficeIdentity GetUmbracoIdentity(this IPrincipal user) - { - //If it's already a UmbracoBackOfficeIdentity - var backOfficeIdentity = user.Identity as UmbracoBackOfficeIdentity; - if (backOfficeIdentity != null) return backOfficeIdentity; - - //Check if there's more than one identity assigned and see if it's a UmbracoBackOfficeIdentity and use that - var claimsPrincipal = user as ClaimsPrincipal; - if (claimsPrincipal != null) - { - backOfficeIdentity = claimsPrincipal.Identities.OfType().FirstOrDefault(); - if (backOfficeIdentity != null) return backOfficeIdentity; - } - - //Otherwise convert to a UmbracoBackOfficeIdentity if it's auth'd and has the back office session - var claimsIdentity = user.Identity as ClaimsIdentity; - if (claimsIdentity != null && claimsIdentity.IsAuthenticated && claimsIdentity.HasClaim(x => x.Type == Constants.Security.SessionIdClaimType)) - { - try - { - return UmbracoBackOfficeIdentity.FromClaimsIdentity(claimsIdentity); - } - catch (InvalidOperationException) - { - } - } - - return null; - } - - /// - /// This will return the current back office identity. - /// - /// - /// - /// If set to true and a back office identity is not found and not authenticated, this will attempt to authenticate the - /// request just as is done in the Umbraco module and then set the current identity if it is valid. - /// Just like in the UmbracoModule, if this is true then the user's culture will be assigned to the request. - /// - /// - /// Returns the current back office identity if an admin is authenticated otherwise null - /// - public static UmbracoBackOfficeIdentity GetCurrentIdentity(this HttpContextBase http, bool authenticateRequestIfNotFound) - { - if (http == null) throw new ArgumentNullException("http"); - if (http.User == null) return null; //there's no user at all so no identity - - //If it's already a UmbracoBackOfficeIdentity - var backOfficeIdentity = GetUmbracoIdentity(http.User); - if (backOfficeIdentity != null) return backOfficeIdentity; - - if (authenticateRequestIfNotFound == false) return null; - - //even if authenticateRequestIfNotFound is true we cannot continue if the request is actually authenticated - // which would mean something strange is going on that it is not an umbraco identity. - if (http.User.Identity.IsAuthenticated) return null; - - //So the user is not authed but we've been asked to do the auth if authenticateRequestIfNotFound = true, - // which might occur in old webforms style things or for routes that aren't included as a back office request. - // in this case, we are just reverting to authing using the cookie. - - // TODO: Even though this is in theory legacy, we have legacy bits laying around and we'd need to do the auth based on - // how the Module will eventually do it (by calling in to any registered authenticators). - - var ticket = http.GetUmbracoAuthTicket(); - if (http.AuthenticateCurrentRequest(ticket, true)) - { - //now we 'should have an umbraco identity - return http.User.Identity as UmbracoBackOfficeIdentity; - } - return null; - } - - /// - /// This will return the current back office identity. - /// - /// - /// - /// If set to true and a back office identity is not found and not authenticated, this will attempt to authenticate the - /// request just as is done in the Umbraco module and then set the current identity if it is valid - /// - /// - /// Returns the current back office identity if an admin is authenticated otherwise null - /// - internal static UmbracoBackOfficeIdentity GetCurrentIdentity(this HttpContext http, bool authenticateRequestIfNotFound) - { - if (http == null) throw new ArgumentNullException("http"); - return new HttpContextWrapper(http).GetCurrentIdentity(authenticateRequestIfNotFound); - } - - public static void UmbracoLogout(this HttpContextBase http) - { - if (http == null) throw new ArgumentNullException("http"); - Logout(http, UmbracoConfig.For.UmbracoSettings().Security.AuthCookieName); - } - - /// - /// This clears the forms authentication cookie - /// - /// - internal static void UmbracoLogout(this HttpContext http) - { - if (http == null) throw new ArgumentNullException("http"); - new HttpContextWrapper(http).UmbracoLogout(); - } - - /// - /// This will force ticket renewal in the OWIN pipeline - /// - /// - /// - public static bool RenewUmbracoAuthTicket(this HttpContextBase http) - { - if (http == null) throw new ArgumentNullException("http"); - http.Items[Constants.Security.ForceReAuthFlag] = true; - return true; - } - - /// - /// This will force ticket renewal in the OWIN pipeline - /// - /// - /// - internal static bool RenewUmbracoAuthTicket(this HttpContext http) - { - if (http == null) throw new ArgumentNullException("http"); - http.Items[Constants.Security.ForceReAuthFlag] = true; - return true; - } - - /// - /// Creates the umbraco authentication ticket - /// - /// - /// - public static FormsAuthenticationTicket CreateUmbracoAuthTicket(this HttpContextBase http, UserData userdata) - { - //ONLY used by BasePage.doLogin! - - if (http == null) throw new ArgumentNullException("http"); - if (userdata == null) throw new ArgumentNullException("userdata"); - - var userDataString = JsonConvert.SerializeObject(userdata); - return CreateAuthTicketAndCookie( - http, - userdata.Username, - userDataString, - //use the configuration timeout - this is the same timeout that will be used when renewing the ticket. - GlobalSettings.TimeOutInMinutes, - //Umbraco has always persisted it's original cookie for 1 day so we'll keep it that way - 1440, - UmbracoConfig.For.UmbracoSettings().Security.AuthCookieName, - UmbracoConfig.For.UmbracoSettings().Security.AuthCookieDomain); - } - - /// - /// returns the number of seconds the user has until their auth session times out - /// - /// - /// - public static double GetRemainingAuthSeconds(this HttpContextBase http) - { - if (http == null) throw new ArgumentNullException("http"); - var ticket = http.GetUmbracoAuthTicket(); - return ticket.GetRemainingAuthSeconds(); - } - - /// - /// returns the number of seconds the user has until their auth session times out - /// - /// - /// - public static double GetRemainingAuthSeconds(this FormsAuthenticationTicket ticket) - { - if (ticket == null) - { - return 0; - } - var utcExpired = ticket.Expiration.ToUniversalTime(); - var secondsRemaining = utcExpired.Subtract(DateTime.UtcNow).TotalSeconds; - return secondsRemaining; - } - - /// - /// Gets the umbraco auth ticket - /// - /// - /// - public static FormsAuthenticationTicket GetUmbracoAuthTicket(this HttpContextBase http) - { - if (http == null) throw new ArgumentNullException("http"); - return GetAuthTicket(http, UmbracoConfig.For.UmbracoSettings().Security.AuthCookieName); - } - - internal static FormsAuthenticationTicket GetUmbracoAuthTicket(this HttpContext http) - { - if (http == null) throw new ArgumentNullException("http"); - return new HttpContextWrapper(http).GetUmbracoAuthTicket(); - } - - internal static FormsAuthenticationTicket GetUmbracoAuthTicket(this IOwinContext ctx) - { - if (ctx == null) throw new ArgumentNullException("ctx"); - //get the ticket - try - { - return GetAuthTicket(ctx.Request.Cookies.ToDictionary(x => x.Key, x => x.Value), UmbracoConfig.For.UmbracoSettings().Security.AuthCookieName); - } - catch (Exception) - { - ctx.Authentication.SignOut( - Constants.Security.BackOfficeAuthenticationType, - Constants.Security.BackOfficeExternalAuthenticationType); - return null; - } - } - - /// - /// This clears the forms authentication cookie - /// - /// - /// - private static void Logout(this HttpContextBase http, string cookieName) +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using System.Security.Claims; +using System.Security.Principal; +using System.Text; +using System.Threading; +using System.Threading.Tasks; + +namespace Umbraco.Core.Security +{ + public static class AuthenticationExtensions + { + /// + /// This will return the current back office identity if the IPrincipal is the correct type + /// + /// + /// + internal static UmbracoBackOfficeIdentity GetUmbracoIdentity(this IPrincipal user) { - //We need to clear the sessionId from the database. This is legacy code to do any logging out and shouldn't really be used at all but in any case - //we need to make sure the session is cleared. Due to the legacy nature of this it means we need to use singletons - if (http.User != null) - { - var claimsIdentity = http.User.Identity as ClaimsIdentity; - if (claimsIdentity != null) - { - var sessionId = claimsIdentity.FindFirstValue(Constants.Security.SessionIdClaimType); - Guid guidSession; - if (sessionId.IsNullOrWhiteSpace() == false && Guid.TryParse(sessionId, out guidSession)) - { - Current.Services.UserService.ClearLoginSession(guidSession); - } + //If it's already a UmbracoBackOfficeIdentity + if (user.Identity is UmbracoBackOfficeIdentity backOfficeIdentity) return backOfficeIdentity; + + //Check if there's more than one identity assigned and see if it's a UmbracoBackOfficeIdentity and use that + if (user is ClaimsPrincipal claimsPrincipal) + { + backOfficeIdentity = claimsPrincipal.Identities.OfType().FirstOrDefault(); + if (backOfficeIdentity != null) return backOfficeIdentity; + } + + //Otherwise convert to a UmbracoBackOfficeIdentity if it's auth'd and has the back office session + if (user.Identity is ClaimsIdentity claimsIdentity && claimsIdentity.IsAuthenticated && claimsIdentity.HasClaim(x => x.Type == Constants.Security.SessionIdClaimType)) + { + try + { + return UmbracoBackOfficeIdentity.FromClaimsIdentity(claimsIdentity); + } + catch (InvalidOperationException) + { } } - - if (http == null) throw new ArgumentNullException("http"); - //clear the preview cookie and external login - var cookies = new[] { cookieName, Constants.Web.PreviewCookieName, Constants.Security.BackOfficeExternalCookieName }; - foreach (var c in cookies) - { - //remove from the request - http.Request.Cookies.Remove(c); - - //expire from the response - var formsCookie = http.Response.Cookies[c]; - if (formsCookie != null) - { - //this will expire immediately and be removed from the browser - formsCookie.Expires = DateTime.Now.AddYears(-1); - } - else - { - //ensure there's def an expired cookie - http.Response.Cookies.Add(new HttpCookie(c) { Expires = DateTime.Now.AddYears(-1) }); - } - } - } - - private static FormsAuthenticationTicket GetAuthTicket(this HttpContextBase http, string cookieName) - { - var asDictionary = new Dictionary(); - for (var i = 0; i < http.Request.Cookies.Keys.Count; i++) - { - var key = http.Request.Cookies.Keys.Get(i); - asDictionary[key] = http.Request.Cookies[key].Value; - } - - //get the ticket - try - { - - return GetAuthTicket(asDictionary, cookieName); - } - catch (Exception) - { - //occurs when decryption fails - http.Logout(cookieName); - return null; - } - } - - private static FormsAuthenticationTicket GetAuthTicket(IDictionary cookies, string cookieName) - { - if (cookies == null) throw new ArgumentNullException("cookies"); - - if (cookies.ContainsKey(cookieName) == false) return null; - - var formsCookie = cookies[cookieName]; - if (formsCookie == null) - { - return null; - } - //get the ticket - return FormsAuthentication.Decrypt(formsCookie); - } - - /// - /// Creates a custom FormsAuthentication ticket with the data specified - /// - /// The HTTP. - /// The username. - /// The user data. - /// The login timeout mins. - /// The minutes persisted. - /// Name of the cookie. - /// The cookie domain. - private static FormsAuthenticationTicket CreateAuthTicketAndCookie(this HttpContextBase http, - string username, - string userData, - int loginTimeoutMins, - int minutesPersisted, - string cookieName, - string cookieDomain) - { - if (http == null) throw new ArgumentNullException("http"); - // Create a new ticket used for authentication - var ticket = new FormsAuthenticationTicket( - 4, - username, - DateTime.Now, - DateTime.Now.AddMinutes(loginTimeoutMins), - true, - userData, - "/" - ); - - // Encrypt the cookie using the machine key for secure transport - var hash = FormsAuthentication.Encrypt(ticket); - var cookie = new HttpCookie( - cookieName, - hash) - { - Expires = DateTime.Now.AddMinutes(minutesPersisted), - Domain = cookieDomain, - Path = "/" - }; - - if (GlobalSettings.UseSSL) - cookie.Secure = true; - - //ensure http only, this should only be able to be accessed via the server - cookie.HttpOnly = true; - - http.Response.Cookies.Set(cookie); - - return ticket; - } - /// - /// Ensures that the thread culture is set based on the back office user's culture - /// - /// - internal static void EnsureCulture(this IIdentity identity) - { - if (identity is UmbracoBackOfficeIdentity umbIdentity && umbIdentity.IsAuthenticated) - { - Thread.CurrentThread.CurrentUICulture = - Thread.CurrentThread.CurrentCulture = - UserCultures.GetOrAdd(umbIdentity.Culture, s => new CultureInfo(s)); - } + return null; } - - /// - /// Used so that we aren't creating a new CultureInfo object for every single request - /// - private static readonly ConcurrentDictionary UserCultures = new ConcurrentDictionary(); - } -} + + /// + /// Ensures that the thread culture is set based on the back office user's culture + /// + /// + internal static void EnsureCulture(this IIdentity identity) + { + if (identity is UmbracoBackOfficeIdentity umbIdentity && umbIdentity.IsAuthenticated) + { + Thread.CurrentThread.CurrentUICulture = + Thread.CurrentThread.CurrentCulture = UserCultures.GetOrAdd(umbIdentity.Culture, s => new CultureInfo(s)); + } + } + + + /// + /// Used so that we aren't creating a new CultureInfo object for every single request + /// + private static readonly ConcurrentDictionary UserCultures = new ConcurrentDictionary(); + } +} diff --git a/src/Umbraco.Core/Security/BackOfficeClaimsIdentityFactory.cs b/src/Umbraco.Core/Security/BackOfficeClaimsIdentityFactory.cs index cec1ee6bcb..490e667c17 100644 --- a/src/Umbraco.Core/Security/BackOfficeClaimsIdentityFactory.cs +++ b/src/Umbraco.Core/Security/BackOfficeClaimsIdentityFactory.cs @@ -1,4 +1,5 @@ -using System.Linq; +using System; +using System.Linq; using System.Security.Claims; using System.Threading.Tasks; using Microsoft.AspNet.Identity; @@ -25,22 +26,20 @@ namespace Umbraco.Core.Security var baseIdentity = await base.CreateAsync(manager, user, authenticationType); var umbracoIdentity = new UmbracoBackOfficeIdentity(baseIdentity, + user.Id, + user.UserName, + user.Name, + user.CalculatedContentStartNodeIds, + user.CalculatedMediaStartNodeIds, + user.Culture, //NOTE - there is no session id assigned here, this is just creating the identity, a session id will be generated when the cookie is written - new UserData - { - Id = user.Id, - Username = user.UserName, - RealName = user.Name, - AllowedApplications = user.AllowedSections, - Culture = user.Culture, - Roles = user.Roles.Select(x => x.RoleId).ToArray(), - StartContentNodes = user.CalculatedContentStartNodeIds, - StartMediaNodes = user.CalculatedMediaStartNodeIds, - SecurityStamp = user.SecurityStamp - }); + Guid.NewGuid().ToString(), + user.SecurityStamp, + user.AllowedSections, + user.Roles.Select(x => x.RoleId).ToArray()); return umbracoIdentity; - } + } } public class BackOfficeClaimsIdentityFactory : BackOfficeClaimsIdentityFactory diff --git a/src/Umbraco.Core/Security/BackOfficeCookieAuthenticationProvider.cs b/src/Umbraco.Core/Security/BackOfficeCookieAuthenticationProvider.cs index b75dd76e47..a52f720b53 100644 --- a/src/Umbraco.Core/Security/BackOfficeCookieAuthenticationProvider.cs +++ b/src/Umbraco.Core/Security/BackOfficeCookieAuthenticationProvider.cs @@ -28,11 +28,11 @@ namespace Umbraco.Core.Security //create a session token - if we are configured and not in an upgrade state then use the db, otherwise just generate one var session = RuntimeState.Level == RuntimeLevel.Run - ? UserService.CreateLoginSession((int)backOfficeIdentity.Id, context.OwinContext.GetCurrentRequestIpAddress()) + ? UserService.CreateLoginSession(backOfficeIdentity.Id, context.OwinContext.GetCurrentRequestIpAddress()) : Guid.NewGuid(); - backOfficeIdentity.UserData.SessionId = session.ToString(); - } + backOfficeIdentity.SessionId = session.ToString(); + } base.ResponseSignIn(context); } diff --git a/src/Umbraco.Core/Security/BackOfficeUserManager.cs b/src/Umbraco.Core/Security/BackOfficeUserManager.cs index 32f7d3bd8f..4c651e9432 100644 --- a/src/Umbraco.Core/Security/BackOfficeUserManager.cs +++ b/src/Umbraco.Core/Security/BackOfficeUserManager.cs @@ -31,16 +31,6 @@ namespace Umbraco.Core.Security { } - [EditorBrowsable(EditorBrowsableState.Never)] - [Obsolete("Use the constructor specifying all dependencies instead")] - public BackOfficeUserManager( - IUserStore store, - IdentityFactoryOptions options, - MembershipProviderBase membershipProvider) - : this(store, options, membershipProvider, UmbracoConfig.For.UmbracoSettings().Content) - { - } - public BackOfficeUserManager( IUserStore store, IdentityFactoryOptions options, @@ -84,17 +74,6 @@ namespace Umbraco.Core.Security return manager; } - [EditorBrowsable(EditorBrowsableState.Never)] - [Obsolete("Use the overload specifying all dependencies instead")] - public static BackOfficeUserManager Create( - IdentityFactoryOptions options, - BackOfficeUserStore customUserStore, - MembershipProviderBase membershipProvider) - { - var manager = new BackOfficeUserManager(customUserStore, options, membershipProvider); - return manager; - } - /// /// Creates a BackOfficeUserManager instance with all default options and a custom BackOfficeUserManager instance /// @@ -114,16 +93,6 @@ namespace Umbraco.Core.Security } #endregion - [EditorBrowsable(EditorBrowsableState.Never)] - [Obsolete("Use the overload specifying all dependencies instead")] - protected void InitUserManager( - BackOfficeUserManager manager, - MembershipProviderBase membershipProvider, - IdentityFactoryOptions options) - { - InitUserManager(manager, membershipProvider, UmbracoConfig.For.UmbracoSettings().Content, options); - } - /// /// Initializes the user manager with the correct options /// @@ -154,7 +123,6 @@ namespace Umbraco.Core.Security { } - #region What we support do not currently //TODO: We could support this - but a user claims will mostly just be what is in the auth cookie @@ -183,17 +151,7 @@ namespace Umbraco.Core.Security get { return false; } } #endregion - - [EditorBrowsable(EditorBrowsableState.Never)] - [Obsolete("Use the overload specifying all dependencies instead")] - protected void InitUserManager( - BackOfficeUserManager manager, - MembershipProviderBase membershipProvider, - IDataProtectionProvider dataProtectionProvider) - { - InitUserManager(manager, membershipProvider, dataProtectionProvider, UmbracoConfig.For.UmbracoSettings().Content); - } - + /// /// Initializes the user manager with the correct options /// diff --git a/src/Umbraco.Core/Security/OwinExtensions.cs b/src/Umbraco.Core/Security/OwinExtensions.cs index b3bb5bffda..a4d596855c 100644 --- a/src/Umbraco.Core/Security/OwinExtensions.cs +++ b/src/Umbraco.Core/Security/OwinExtensions.cs @@ -2,6 +2,7 @@ using System.Web; using Microsoft.AspNet.Identity.Owin; using Microsoft.Owin; +using Microsoft.Owin.Security; using Umbraco.Core.Models.Identity; namespace Umbraco.Core.Security @@ -67,5 +68,7 @@ namespace Umbraco.Core.Security return marker.GetManager(owinContext) ?? throw new NullReferenceException($"Could not resolve an instance of {typeof (BackOfficeUserManager)} from the {typeof (IOwinContext)}."); } + } + } diff --git a/src/Umbraco.Core/Security/UmbracoBackOfficeIdentity.cs b/src/Umbraco.Core/Security/UmbracoBackOfficeIdentity.cs index 605c8b4e9d..6cf5eacc97 100644 --- a/src/Umbraco.Core/Security/UmbracoBackOfficeIdentity.cs +++ b/src/Umbraco.Core/Security/UmbracoBackOfficeIdentity.cs @@ -7,6 +7,7 @@ using System.Security.Principal; using System.Web; using System.Web.Security; using Microsoft.AspNet.Identity; +using Microsoft.Owin.Security; using Newtonsoft.Json; using Umbraco.Core.Configuration; @@ -21,10 +22,81 @@ namespace Umbraco.Core.Security /// change over to 'pure' asp.net identity and just inherit from ClaimsIdentity. /// [Serializable] - public class UmbracoBackOfficeIdentity : FormsIdentity + public class UmbracoBackOfficeIdentity : ClaimsIdentity { public static UmbracoBackOfficeIdentity FromClaimsIdentity(ClaimsIdentity identity) { + return new UmbracoBackOfficeIdentity(identity); + } + + /// + /// Creates a new UmbracoBackOfficeIdentity + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + public UmbracoBackOfficeIdentity(int userId, string username, string realName, + IEnumerable startContentNodes, IEnumerable startMediaNodes, string culture, + string sessionId, string securityStamp, IEnumerable allowedApps, IEnumerable roles) + : base(Enumerable.Empty(), Constants.Security.BackOfficeAuthenticationType) //this ctor is used to ensure the IsAuthenticated property is true + { + if (allowedApps == null) throw new ArgumentNullException(nameof(allowedApps)); + if (string.IsNullOrWhiteSpace(username)) throw new ArgumentException("Value cannot be null or whitespace.", nameof(username)); + if (string.IsNullOrWhiteSpace(realName)) throw new ArgumentException("Value cannot be null or whitespace.", nameof(realName)); + if (string.IsNullOrWhiteSpace(culture)) throw new ArgumentException("Value cannot be null or whitespace.", nameof(culture)); + if (string.IsNullOrWhiteSpace(sessionId)) throw new ArgumentException("Value cannot be null or whitespace.", nameof(sessionId)); + if (string.IsNullOrWhiteSpace(securityStamp)) throw new ArgumentException("Value cannot be null or whitespace.", nameof(securityStamp)); + AddRequiredClaims(userId, username, realName, startContentNodes, startMediaNodes, culture, sessionId, securityStamp, allowedApps, roles); + } + + /// + /// Creates a new UmbracoBackOfficeIdentity + /// + /// + /// The original identity created by the ClaimsIdentityFactory + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + public UmbracoBackOfficeIdentity(ClaimsIdentity childIdentity, + int userId, string username, string realName, + IEnumerable startContentNodes, IEnumerable startMediaNodes, string culture, + string sessionId, string securityStamp, IEnumerable allowedApps, IEnumerable roles) + : base(childIdentity.Claims, Constants.Security.BackOfficeAuthenticationType) + { + if (string.IsNullOrWhiteSpace(username)) throw new ArgumentException("Value cannot be null or whitespace.", nameof(username)); + if (string.IsNullOrWhiteSpace(realName)) throw new ArgumentException("Value cannot be null or whitespace.", nameof(realName)); + if (string.IsNullOrWhiteSpace(culture)) throw new ArgumentException("Value cannot be null or whitespace.", nameof(culture)); + if (string.IsNullOrWhiteSpace(sessionId)) throw new ArgumentException("Value cannot be null or whitespace.", nameof(sessionId)); + if (string.IsNullOrWhiteSpace(securityStamp)) throw new ArgumentException("Value cannot be null or whitespace.", nameof(securityStamp)); + Actor = childIdentity; + AddRequiredClaims(userId, username, realName, startContentNodes, startMediaNodes, culture, sessionId, securityStamp, allowedApps, roles); + } + + /// + /// Create a back office identity based on an existing claims identity + /// + /// + private UmbracoBackOfficeIdentity(ClaimsIdentity identity) + : base(identity.Claims, Constants.Security.BackOfficeAuthenticationType) + { + Actor = identity; + + //validate that all claims exist foreach (var t in RequiredBackOfficeIdentityClaimTypes) { //if the identity doesn't have the claim, or the claim value is null @@ -33,145 +105,9 @@ namespace Umbraco.Core.Security throw new InvalidOperationException("Cannot create a " + typeof(UmbracoBackOfficeIdentity) + " from " + typeof(ClaimsIdentity) + " since the required claim " + t + " is missing"); } } - - var username = identity.GetUserName(); - var session = identity.FindFirstValue(Constants.Security.SessionIdClaimType); - var securityStamp = identity.FindFirstValue(Microsoft.AspNet.Identity.Constants.DefaultSecurityStampClaimType); - var startContentId = identity.FindFirstValue(Constants.Security.StartContentNodeIdClaimType); - var startMediaId = identity.FindFirstValue(Constants.Security.StartMediaNodeIdClaimType); - - var culture = identity.FindFirstValue(ClaimTypes.Locality); - var id = identity.FindFirstValue(ClaimTypes.NameIdentifier); - var realName = identity.FindFirstValue(ClaimTypes.GivenName); - - if (username == null || startContentId == null || startMediaId == null - || culture == null || id == null - || realName == null || session == null) - throw new InvalidOperationException("Cannot create a " + typeof(UmbracoBackOfficeIdentity) + " from " + typeof(ClaimsIdentity) + " since there are missing required claims"); - - int[] startContentIdsAsInt; - int[] startMediaIdsAsInt; - if (startContentId.DetectIsJson() == false || startMediaId.DetectIsJson() == false) - throw new InvalidOperationException("Cannot create a " + typeof(UmbracoBackOfficeIdentity) + " from " + typeof(ClaimsIdentity) + " since the data is not formatted correctly - either content or media start Ids are not JSON"); - - try - { - startContentIdsAsInt = JsonConvert.DeserializeObject(startContentId); - startMediaIdsAsInt = JsonConvert.DeserializeObject(startMediaId); - } - catch (Exception e) - { - throw new InvalidOperationException("Cannot create a " + typeof(UmbracoBackOfficeIdentity) + " from " + typeof(ClaimsIdentity) + " since the data is not formatted correctly - either content or media start Ids could not be parsed as JSON", e); - } - - var roles = identity.FindAll(x => x.Type == DefaultRoleClaimType).Select(role => role.Value).ToList(); - var allowedApps = identity.FindAll(x => x.Type == Constants.Security.AllowedApplicationsClaimType).Select(app => app.Value).ToList(); - - var userData = new UserData - { - SecurityStamp = securityStamp, - SessionId = session, - AllowedApplications = allowedApps.ToArray(), - Culture = culture, - Id = id, - Roles = roles.ToArray(), - Username = username, - RealName = realName, - StartContentNodes = startContentIdsAsInt, - StartMediaNodes = startMediaIdsAsInt - }; - - return new UmbracoBackOfficeIdentity(identity, userData); } - /// - /// Create a back office identity based on user data - /// - /// - public UmbracoBackOfficeIdentity(UserData userdata) - //This just creates a temp/fake ticket - : base(new FormsAuthenticationTicket(userdata.Username, true, 10)) - { - if (userdata == null) throw new ArgumentNullException("userdata"); - UserData = userdata; - AddUserDataClaims(); - } - - /// - /// Create a back office identity based on an existing claims identity - /// - /// - /// - public UmbracoBackOfficeIdentity(ClaimsIdentity claimsIdentity, UserData userdata) - //This just creates a temp/fake ticket - : base(new FormsAuthenticationTicket(userdata.Username, true, 10)) - { - if (claimsIdentity == null) throw new ArgumentNullException("claimsIdentity"); - if (userdata == null) throw new ArgumentNullException("userdata"); - - if (claimsIdentity is FormsIdentity) - { - //since it's a forms auth ticket, it is from a cookie so add that claim - AddClaim(new Claim(ClaimTypes.CookiePath, "/", ClaimValueTypes.String, Issuer, Issuer, this)); - } - - _currentIssuer = claimsIdentity.AuthenticationType; - UserData = userdata; - AddExistingClaims(claimsIdentity); - Actor = claimsIdentity; - AddUserDataClaims(); - } - - /// - /// Create a new identity from a forms auth ticket - /// - /// - public UmbracoBackOfficeIdentity(FormsAuthenticationTicket ticket) - : base(ticket) - { - //since it's a forms auth ticket, it is from a cookie so add that claim - AddClaim(new Claim(ClaimTypes.CookiePath, "/", ClaimValueTypes.String, Issuer, Issuer, this)); - - UserData = JsonConvert.DeserializeObject(ticket.UserData); - AddUserDataClaims(); - } - - /// - /// Used for cloning - /// - /// - private UmbracoBackOfficeIdentity(UmbracoBackOfficeIdentity identity) - : base(identity) - { - if (identity.Actor != null) - { - _currentIssuer = identity.AuthenticationType; - AddExistingClaims(identity); - Actor = identity.Clone(); - } - - UserData = identity.UserData; - AddUserDataClaims(); - } - - public const string Issuer = "UmbracoBackOffice"; - private readonly string _currentIssuer = Issuer; - - /// - /// Used during ctor to add existing claims from an existing ClaimsIdentity - /// - /// - private void AddExistingClaims(ClaimsIdentity claimsIdentity) - { - foreach (var claim in claimsIdentity.Claims) - { - //In one special case we will replace a claim if it exists already and that is the - // Forms auth claim for name which automatically gets added - TryRemoveClaim(FindFirst(x => x.Type == claim.Type && x.Issuer == "Forms")); - - AddClaim(claim); - } - } + public const string Issuer = Constants.Security.BackOfficeAuthenticationType; /// /// Returns the required claim types for a back office identity @@ -179,153 +115,125 @@ namespace Umbraco.Core.Security /// /// This does not incude the role claim type or allowed apps type since that is a collection and in theory could be empty /// - public static IEnumerable RequiredBackOfficeIdentityClaimTypes + public static IEnumerable RequiredBackOfficeIdentityClaimTypes => new[] { - get - { - return new[] - { - ClaimTypes.NameIdentifier, //id - ClaimTypes.Name, //username - ClaimTypes.GivenName, - Constants.Security.StartContentNodeIdClaimType, - Constants.Security.StartMediaNodeIdClaimType, - ClaimTypes.Locality, - Constants.Security.SessionIdClaimType, - Microsoft.AspNet.Identity.Constants.DefaultSecurityStampClaimType - }; - } - } + ClaimTypes.NameIdentifier, //id + ClaimTypes.Name, //username + ClaimTypes.GivenName, + Constants.Security.StartContentNodeIdClaimType, + Constants.Security.StartMediaNodeIdClaimType, + ClaimTypes.Locality, + Constants.Security.SessionIdClaimType, + Microsoft.AspNet.Identity.Constants.DefaultSecurityStampClaimType + }; /// - /// Adds claims based on the UserData data + /// Adds claims based on the ctor data /// - private void AddUserDataClaims() + private void AddRequiredClaims(int userId, string username, string realName, + IEnumerable startContentNodes, IEnumerable startMediaNodes, string culture, + string sessionId, string securityStamp, IEnumerable allowedApps, IEnumerable roles) { //This is the id that 'identity' uses to check for the user id if (HasClaim(x => x.Type == ClaimTypes.NameIdentifier) == false) - AddClaim(new Claim(ClaimTypes.NameIdentifier, UserData.Id.ToString(), ClaimValueTypes.Integer32, Issuer, Issuer, this)); + AddClaim(new Claim(ClaimTypes.NameIdentifier, userId.ToInvariantString(), ClaimValueTypes.Integer32, Issuer, Issuer, this)); if (HasClaim(x => x.Type == ClaimTypes.Name) == false) - AddClaim(new Claim(ClaimTypes.Name, UserData.Username, ClaimValueTypes.String, Issuer, Issuer, this)); + AddClaim(new Claim(ClaimTypes.Name, username, ClaimValueTypes.String, Issuer, Issuer, this)); if (HasClaim(x => x.Type == ClaimTypes.GivenName) == false) - AddClaim(new Claim(ClaimTypes.GivenName, UserData.RealName, ClaimValueTypes.String, Issuer, Issuer, this)); + AddClaim(new Claim(ClaimTypes.GivenName, realName, ClaimValueTypes.String, Issuer, Issuer, this)); - if (HasClaim(x => x.Type == Constants.Security.StartContentNodeIdClaimType) == false) - AddClaim(new Claim(Constants.Security.StartContentNodeIdClaimType, JsonConvert.SerializeObject(StartContentNodes), ClaimValueTypes.Integer32, Issuer, Issuer, this)); + if (HasClaim(x => x.Type == Constants.Security.StartContentNodeIdClaimType) == false && startContentNodes != null) + { + foreach (var startContentNode in startContentNodes) + { + AddClaim(new Claim(Constants.Security.StartContentNodeIdClaimType, startContentNode.ToInvariantString(), ClaimValueTypes.Integer32, Issuer, Issuer, this)); + } + } - if (HasClaim(x => x.Type == Constants.Security.StartMediaNodeIdClaimType) == false) - AddClaim(new Claim(Constants.Security.StartMediaNodeIdClaimType, JsonConvert.SerializeObject(StartMediaNodes), ClaimValueTypes.Integer32, Issuer, Issuer, this)); + if (HasClaim(x => x.Type == Constants.Security.StartMediaNodeIdClaimType) == false && startMediaNodes != null) + { + foreach (var startMediaNode in startMediaNodes) + { + AddClaim(new Claim(Constants.Security.StartMediaNodeIdClaimType, startMediaNode.ToInvariantString(), ClaimValueTypes.Integer32, Issuer, Issuer, this)); + } + } if (HasClaim(x => x.Type == ClaimTypes.Locality) == false) - AddClaim(new Claim(ClaimTypes.Locality, Culture, ClaimValueTypes.String, Issuer, Issuer, this)); + AddClaim(new Claim(ClaimTypes.Locality, culture, ClaimValueTypes.String, Issuer, Issuer, this)); if (HasClaim(x => x.Type == Constants.Security.SessionIdClaimType) == false && SessionId.IsNullOrWhiteSpace() == false) - AddClaim(new Claim(Constants.Security.SessionIdClaimType, SessionId, ClaimValueTypes.String, Issuer, Issuer, this)); + AddClaim(new Claim(Constants.Security.SessionIdClaimType, sessionId, ClaimValueTypes.String, Issuer, Issuer, this)); //The security stamp claim is also required... this is because this claim type is hard coded // by the SecurityStampValidator, see: https://katanaproject.codeplex.com/workitem/444 if (HasClaim(x => x.Type == Microsoft.AspNet.Identity.Constants.DefaultSecurityStampClaimType) == false) - AddClaim(new Claim(Microsoft.AspNet.Identity.Constants.DefaultSecurityStampClaimType, SecurityStamp, ClaimValueTypes.String, Issuer, Issuer, this)); + AddClaim(new Claim(Microsoft.AspNet.Identity.Constants.DefaultSecurityStampClaimType, securityStamp, ClaimValueTypes.String, Issuer, Issuer, this)); //Add each app as a separate claim - if (HasClaim(x => x.Type == Constants.Security.AllowedApplicationsClaimType) == false) + if (HasClaim(x => x.Type == Constants.Security.AllowedApplicationsClaimType) == false && allowedApps != null) { - foreach (var application in AllowedApplications) + foreach (var application in allowedApps) { AddClaim(new Claim(Constants.Security.AllowedApplicationsClaimType, application, ClaimValueTypes.String, Issuer, Issuer, this)); } } //Claims are added by the ClaimsIdentityFactory because our UserStore supports roles, however this identity might - // not be made with that factory if it was created with a FormsAuthentication ticket so perform the check - if (HasClaim(x => x.Type == DefaultRoleClaimType) == false) + // not be made with that factory if it was created with a different ticket so perform the check + if (HasClaim(x => x.Type == DefaultRoleClaimType) == false && roles != null) { - //manually add them based on the UserData - foreach (var roleName in UserData.Roles) + //manually add them + foreach (var roleName in roles) { AddClaim(new Claim(RoleClaimType, roleName, ClaimValueTypes.String, Issuer, Issuer, this)); } } - - } - - protected internal UserData UserData { get; private set; } - + + /// /// /// Gets the type of authenticated identity. /// /// /// The type of authenticated identity. This property always returns "UmbracoBackOffice". /// - public override string AuthenticationType - { - get { return _currentIssuer; } - } + public override string AuthenticationType => Issuer; - public int[] StartContentNodes - { - get { return UserData.StartContentNodes; } - } + private int[] _startContentNodes; + public int[] StartContentNodes => _startContentNodes ?? (_startContentNodes = FindAll(x => x.Type == Constants.Security.StartContentNodeIdClaimType).Select(app => int.TryParse(app.Value, out var i) ? i : default).Where(x => x != default).ToArray()); - public int[] StartMediaNodes - { - get { return UserData.StartMediaNodes; } - } + private int[] _startMediaNodes; + public int[] StartMediaNodes => _startMediaNodes ?? (_startMediaNodes = FindAll(x => x.Type == Constants.Security.StartMediaNodeIdClaimType).Select(app => int.TryParse(app.Value, out var i) ? i : default).Where(x => x != default).ToArray()); - public string[] AllowedApplications - { - get { return UserData.AllowedApplications; } - } + private string[] _allowedApplications; + public string[] AllowedApplications => _allowedApplications ?? (_allowedApplications = FindAll(x => x.Type == Constants.Security.AllowedApplicationsClaimType).Select(app => app.Value).ToArray()); - public object Id - { - get { return UserData.Id; } - } + public int Id => int.Parse(this.FindFirstValue(ClaimTypes.NameIdentifier)); - public string RealName - { - get { return UserData.RealName; } - } + public string RealName => this.FindFirstValue(ClaimTypes.GivenName); - public string Username - { - get { return UserData.Username; } - } + public string Username => this.GetUserName(); - public string Culture - { - get { return UserData.Culture; } - } + public string Culture => this.FindFirstValue(ClaimTypes.Locality); public string SessionId { - get { return UserData.SessionId; } + get => this.FindFirstValue(Constants.Security.SessionIdClaimType); + set + { + var existing = FindFirst(Constants.Security.SessionIdClaimType); + if (existing != null) + TryRemoveClaim(existing); + AddClaim(new Claim(Constants.Security.SessionIdClaimType, value, ClaimValueTypes.String, Issuer, Issuer, this)); + } } - public string SecurityStamp - { - get { return UserData.SecurityStamp; } - } - - public string[] Roles - { - get { return UserData.Roles; } - } - - /// - /// Gets a copy of the current instance. - /// - /// - /// A copy of the current instance. - /// - public override ClaimsIdentity Clone() - { - return new UmbracoBackOfficeIdentity(this); - } + public string SecurityStamp => this.FindFirstValue(Microsoft.AspNet.Identity.Constants.DefaultSecurityStampClaimType); + public string[] Roles => this.FindAll(x => x.Type == DefaultRoleClaimType).Select(role => role.Value).ToArray(); + } } diff --git a/src/Umbraco.Core/Security/UserData.cs b/src/Umbraco.Core/Security/UserData.cs deleted file mode 100644 index 7e510ba708..0000000000 --- a/src/Umbraco.Core/Security/UserData.cs +++ /dev/null @@ -1,74 +0,0 @@ -using System; -using System.Runtime.Serialization; - -namespace Umbraco.Core.Security -{ - /// - /// Data structure used to store information in the authentication cookie - /// - [DataContract(Name = "userData", Namespace = "")] - [Serializable] - public class UserData - { - public UserData() - { - AllowedApplications = new string[] {}; - Roles = new string[] {}; - } - - /// - /// Use this constructor to create/assign new UserData to the ticket - /// - /// - /// The current sessionId for the user - /// - public UserData(string sessionId) - { - SessionId = sessionId; - AllowedApplications = new string[] { }; - Roles = new string[] { }; - } - - /// - /// Gets or sets the session identifier. - /// - [DataMember(Name = "sessionId")] - public string SessionId { get; set; } - - /// - /// Gets or sets the security stamp. - /// - [DataMember(Name = "securityStamp")] - public string SecurityStamp { get; set; } - - [DataMember(Name = "id")] - public object Id { get; set; } - - [DataMember(Name = "roles")] - public string[] Roles { get; set; } - - [DataMember(Name = "username")] - public string Username { get; set; } - - [DataMember(Name = "name")] - public string RealName { get; set; } - - /// - /// The start nodes on the UserData object for the auth ticket contains all of the user's start nodes including ones assigned to their user groups - /// - [DataMember(Name = "startContent")] - public int[] StartContentNodes { get; set; } - - /// - /// The start nodes on the UserData object for the auth ticket contains all of the user's start nodes including ones assigned to their user groups - /// - [DataMember(Name = "startMedia")] - public int[] StartMediaNodes { get; set; } - - [DataMember(Name = "allowedApps")] - public string[] AllowedApplications { get; set; } - - [DataMember(Name = "culture")] - public string Culture { get; set; } - } -} diff --git a/src/Umbraco.Core/Umbraco.Core.csproj b/src/Umbraco.Core/Umbraco.Core.csproj index cf1818f9e3..7790b8a769 100644 --- a/src/Umbraco.Core/Umbraco.Core.csproj +++ b/src/Umbraco.Core/Umbraco.Core.csproj @@ -1330,7 +1330,6 @@ - diff --git a/src/Umbraco.Tests/Security/UmbracoBackOfficeIdentityTests.cs b/src/Umbraco.Tests/Security/UmbracoBackOfficeIdentityTests.cs index f71c73d26e..acb53a895a 100644 --- a/src/Umbraco.Tests/Security/UmbracoBackOfficeIdentityTests.cs +++ b/src/Umbraco.Tests/Security/UmbracoBackOfficeIdentityTests.cs @@ -30,8 +30,9 @@ namespace Umbraco.Tests.Security //This is the id that 'identity' uses to check for the username new Claim(ClaimTypes.Name, "testing", ClaimValueTypes.String, TestIssuer, TestIssuer), new Claim(ClaimTypes.GivenName, "hello world", ClaimValueTypes.String, TestIssuer, TestIssuer), - new Claim(Constants.Security.StartContentNodeIdClaimType, "[-1]", ClaimValueTypes.Integer32, TestIssuer, TestIssuer), - new Claim(Constants.Security.StartMediaNodeIdClaimType, "[5543]", ClaimValueTypes.Integer32, TestIssuer, TestIssuer), + new Claim(Constants.Security.StartContentNodeIdClaimType, "-1", ClaimValueTypes.Integer32, TestIssuer, TestIssuer), + new Claim(Constants.Security.StartMediaNodeIdClaimType, "5543", ClaimValueTypes.Integer32, TestIssuer, TestIssuer), + new Claim(Constants.Security.StartMediaNodeIdClaimType, "5555", ClaimValueTypes.Integer32, TestIssuer, TestIssuer), new Claim(Constants.Security.AllowedApplicationsClaimType, "content", ClaimValueTypes.String, TestIssuer, TestIssuer), new Claim(Constants.Security.AllowedApplicationsClaimType, "media", ClaimValueTypes.String, TestIssuer, TestIssuer), new Claim(ClaimTypes.Locality, "en-us", ClaimValueTypes.String, TestIssuer, TestIssuer), @@ -42,18 +43,18 @@ namespace Umbraco.Tests.Security var backofficeIdentity = UmbracoBackOfficeIdentity.FromClaimsIdentity(claimsIdentity); - Assert.AreEqual("1234", backofficeIdentity.Id); + Assert.AreEqual(1234, backofficeIdentity.Id); Assert.AreEqual(sessionId, backofficeIdentity.SessionId); Assert.AreEqual(securityStamp, backofficeIdentity.SecurityStamp); Assert.AreEqual("testing", backofficeIdentity.Username); Assert.AreEqual("hello world", backofficeIdentity.RealName); Assert.AreEqual(1, backofficeIdentity.StartContentNodes.Length); - Assert.IsTrue(backofficeIdentity.StartMediaNodes.UnsortedSequenceEqual(new[] { 5543 })); + Assert.IsTrue(backofficeIdentity.StartMediaNodes.UnsortedSequenceEqual(new[] { 5543, 5555 })); Assert.IsTrue(new[] {"content", "media"}.SequenceEqual(backofficeIdentity.AllowedApplications)); Assert.AreEqual("en-us", backofficeIdentity.Culture); Assert.IsTrue(new[] { "admin" }.SequenceEqual(backofficeIdentity.Roles)); - Assert.AreEqual(11, backofficeIdentity.Claims.Count()); + Assert.AreEqual(12, backofficeIdentity.Claims.Count()); } [Test] @@ -90,102 +91,36 @@ namespace Umbraco.Tests.Security Assert.Throws(() => UmbracoBackOfficeIdentity.FromClaimsIdentity(claimsIdentity)); } - [Test] - public void Create_With_User_Data() - { - var sessionId = Guid.NewGuid().ToString(); - var userData = new UserData(sessionId) - { - SecurityStamp = sessionId, - AllowedApplications = new[] {"content", "media"}, - Culture = "en-us", - Id = 1234, - RealName = "hello world", - Roles = new[] {"admin"}, - StartMediaNodes = new[] { 654 }, - Username = "testing" - }; - - var identity = new UmbracoBackOfficeIdentity(userData); - - Assert.AreEqual(11, identity.Claims.Count()); - } [Test] public void Create_With_Claims_And_User_Data() { var sessionId = Guid.NewGuid().ToString(); - var userData = new UserData(sessionId) - { - SecurityStamp = sessionId, - AllowedApplications = new[] { "content", "media" }, - Culture = "en-us", - Id = 1234, - RealName = "hello world", - Roles = new[] { "admin" }, - StartMediaNodes = new[] { 654 }, - Username = "testing" - }; - + var claimsIdentity = new ClaimsIdentity(new[] { new Claim("TestClaim1", "test", ClaimValueTypes.Integer32, TestIssuer, TestIssuer), new Claim("TestClaim1", "test", ClaimValueTypes.Integer32, TestIssuer, TestIssuer) }); - var backofficeIdentity = new UmbracoBackOfficeIdentity(claimsIdentity, userData); - - Assert.AreEqual(13, backofficeIdentity.Claims.Count()); - } - - [Test] - public void Create_With_Forms_Ticket() - { - var sessionId = Guid.NewGuid().ToString(); - var userData = new UserData(sessionId) - { - SecurityStamp = sessionId, - AllowedApplications = new[] { "content", "media" }, - Culture = "en-us", - Id = 1234, - RealName = "hello world", - Roles = new[] { "admin" }, - StartMediaNodes = new[] { 654 }, - Username = "testing" - }; - - var ticket = new FormsAuthenticationTicket(1, userData.Username, DateTime.Now, DateTime.Now.AddDays(1), true, - JsonConvert.SerializeObject(userData)); - - var identity = new UmbracoBackOfficeIdentity(ticket); + var identity = new UmbracoBackOfficeIdentity(claimsIdentity, + 1234, "testing", "hello world", new[] { 654 }, new[] { 654 }, "en-us", sessionId, sessionId, new[] { "content", "media" }, new[] { "admin" }); Assert.AreEqual(12, identity.Claims.Count()); } + [Test] public void Clone() { var sessionId = Guid.NewGuid().ToString(); - var userData = new UserData(sessionId) - { - SecurityStamp = sessionId, - AllowedApplications = new[] { "content", "media" }, - Culture = "en-us", - Id = 1234, - RealName = "hello world", - Roles = new[] { "admin" }, - StartMediaNodes = new[] { 654 }, - Username = "testing" - }; - var ticket = new FormsAuthenticationTicket(1, userData.Username, DateTime.Now, DateTime.Now.AddDays(1), true, - JsonConvert.SerializeObject(userData)); - - var identity = new UmbracoBackOfficeIdentity(ticket); + var identity = new UmbracoBackOfficeIdentity( + 1234, "testing", "hello world", new[] { 654 }, new[] { 654 }, "en-us", sessionId, sessionId, new[] { "content", "media" }, new[] { "admin" }); var cloned = identity.Clone(); - Assert.AreEqual(12, cloned.Claims.Count()); + Assert.AreEqual(10, cloned.Claims.Count()); } } diff --git a/src/Umbraco.Tests/TestHelpers/ControllerTesting/AuthenticateEverythingMiddleware.cs b/src/Umbraco.Tests/TestHelpers/ControllerTesting/AuthenticateEverythingMiddleware.cs index c456475acc..ab473fd0c0 100644 --- a/src/Umbraco.Tests/TestHelpers/ControllerTesting/AuthenticateEverythingMiddleware.cs +++ b/src/Umbraco.Tests/TestHelpers/ControllerTesting/AuthenticateEverythingMiddleware.cs @@ -26,16 +26,7 @@ namespace Umbraco.Tests.TestHelpers.ControllerTesting { var sessionId = Guid.NewGuid().ToString(); var identity = new UmbracoBackOfficeIdentity( - new UserData(sessionId) - { - SecurityStamp = sessionId, - Id = 0, - Roles = new[] { "admin" }, - AllowedApplications = new[] { "content", "media", "members" }, - Culture = "en-US", - RealName = "Admin", - Username = "admin" - }); + -1, "admin", "Admin", null, null, "en-US", sessionId, sessionId, new[] { "content", "media", "members" }, new[] { "admin" }); return Task.FromResult(new AuthenticationTicket(identity, new AuthenticationProperties() diff --git a/src/Umbraco.Web/Editors/CurrentUserController.cs b/src/Umbraco.Web/Editors/CurrentUserController.cs index a68ad4c813..a7d858c322 100644 --- a/src/Umbraco.Web/Editors/CurrentUserController.cs +++ b/src/Umbraco.Web/Editors/CurrentUserController.cs @@ -15,6 +15,7 @@ using System.Linq; using Newtonsoft.Json; using Umbraco.Core; using Umbraco.Core.Security; +using Umbraco.Web.Security; using Umbraco.Web.WebApi.Filters; diff --git a/src/Umbraco.Web/Security/AuthenticationExtensions.cs b/src/Umbraco.Web/Security/AuthenticationExtensions.cs new file mode 100644 index 0000000000..0eeb840496 --- /dev/null +++ b/src/Umbraco.Web/Security/AuthenticationExtensions.cs @@ -0,0 +1,378 @@ +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using System.Security.Claims; +using System.Security.Principal; +using System.Threading; +using System.Web; +using Microsoft.AspNet.Identity; +using Microsoft.Owin; +using Microsoft.Owin.Security; +using Newtonsoft.Json; +using Umbraco.Core; +using Umbraco.Core.Composing; +using Umbraco.Core.Configuration; +using Umbraco.Core.Security; +using Constants = Umbraco.Core.Constants; + +namespace Umbraco.Web.Security +{ + /// + /// Extensions to create and renew and remove authentication tickets for the Umbraco back office + /// + public static class AuthenticationExtensions + { + /// + /// This will check the ticket to see if it is valid, if it is it will set the current thread's user and culture + /// + /// + /// + /// If true will attempt to renew the ticket + public static bool AuthenticateCurrentRequest(this HttpContextBase http, AuthenticationTicket ticket, bool renewTicket) + { + if (http == null) throw new ArgumentNullException(nameof(http)); + + //if there was a ticket, it's not expired, - it should not be renewed or its renewable + if (ticket?.Properties.ExpiresUtc != null && ticket.Properties.ExpiresUtc.Value > DateTimeOffset.UtcNow && (renewTicket == false || http.RenewUmbracoAuthTicket())) + { + try + { + //get the Umbraco user identity + if (!(ticket.Identity is UmbracoBackOfficeIdentity identity)) + throw new InvalidOperationException("The AuthenticationTicket specified does not contain the correct Identity type"); + + //set the principal object + var principal = new ClaimsPrincipal(identity); + + //It is actually not good enough to set this on the current app Context and the thread, it also needs + // to be set explicitly on the HttpContext.Current !! This is a strange web api thing that is actually + // an underlying fault of asp.net not propogating the User correctly. + if (HttpContext.Current != null) + { + HttpContext.Current.User = principal; + } + http.User = principal; + Thread.CurrentPrincipal = principal; + + //This is a back office request, we will also set the culture/ui culture + Thread.CurrentThread.CurrentCulture = + Thread.CurrentThread.CurrentUICulture = + new System.Globalization.CultureInfo(identity.Culture); + + return true; + } + catch (Exception ex) + { + if (ex is FormatException || ex is JsonReaderException) + { + //this will occur if the cookie data is invalid + http.UmbracoLogout(); + } + else + { + throw; + } + + } + } + + return false; + } + + + /// + /// This will return the current back office identity. + /// + /// + /// + /// If set to true and a back office identity is not found and not authenticated, this will attempt to authenticate the + /// request just as is done in the Umbraco module and then set the current identity if it is valid. + /// Just like in the UmbracoModule, if this is true then the user's culture will be assigned to the request. + /// + /// + /// Returns the current back office identity if an admin is authenticated otherwise null + /// + public static UmbracoBackOfficeIdentity GetCurrentIdentity(this HttpContextBase http, bool authenticateRequestIfNotFound) + { + if (http == null) throw new ArgumentNullException(nameof(http)); + if (http.User == null) return null; //there's no user at all so no identity + + //If it's already a UmbracoBackOfficeIdentity + var backOfficeIdentity = http.User.GetUmbracoIdentity(); + if (backOfficeIdentity != null) return backOfficeIdentity; + + if (authenticateRequestIfNotFound == false) return null; + + //even if authenticateRequestIfNotFound is true we cannot continue if the request is actually authenticated + // which would mean something strange is going on that it is not an umbraco identity. + if (http.User.Identity.IsAuthenticated) return null; + + //So the user is not authed but we've been asked to do the auth if authenticateRequestIfNotFound = true, + // which might occur in old webforms style things or for routes that aren't included as a back office request. + // in this case, we are just reverting to authing using the cookie. + + // TODO: Even though this is in theory legacy, we have legacy bits laying around and we'd need to do the auth based on + // how the Module will eventually do it (by calling in to any registered authenticators). + + var ticket = http.GetUmbracoAuthTicket(); + if (http.AuthenticateCurrentRequest(ticket, true)) + { + //now we 'should have an umbraco identity + return http.User.Identity as UmbracoBackOfficeIdentity; + } + return null; + } + + /// + /// This will return the current back office identity. + /// + /// + /// + /// If set to true and a back office identity is not found and not authenticated, this will attempt to authenticate the + /// request just as is done in the Umbraco module and then set the current identity if it is valid + /// + /// + /// Returns the current back office identity if an admin is authenticated otherwise null + /// + internal static UmbracoBackOfficeIdentity GetCurrentIdentity(this HttpContext http, bool authenticateRequestIfNotFound) + { + if (http == null) throw new ArgumentNullException("http"); + return new HttpContextWrapper(http).GetCurrentIdentity(authenticateRequestIfNotFound); + } + + public static void UmbracoLogout(this HttpContextBase http) + { + if (http == null) throw new ArgumentNullException("http"); + Logout(http, UmbracoConfig.For.UmbracoSettings().Security.AuthCookieName); + } + + /// + /// This clears the forms authentication cookie + /// + /// + internal static void UmbracoLogout(this HttpContext http) + { + if (http == null) throw new ArgumentNullException("http"); + new HttpContextWrapper(http).UmbracoLogout(); + } + + /// + /// This will force ticket renewal in the OWIN pipeline + /// + /// + /// + public static bool RenewUmbracoAuthTicket(this HttpContextBase http) + { + if (http == null) throw new ArgumentNullException("http"); + http.Items[Constants.Security.ForceReAuthFlag] = true; + return true; + } + + /// + /// This will force ticket renewal in the OWIN pipeline + /// + /// + /// + internal static bool RenewUmbracoAuthTicket(this HttpContext http) + { + if (http == null) throw new ArgumentNullException("http"); + http.Items[Constants.Security.ForceReAuthFlag] = true; + return true; + } + + ///// + ///// Creates the umbraco authentication ticket + ///// + ///// + ///// + //public static AuthenticationTicket CreateUmbracoAuthTicket(this HttpContextBase http, UserData userdata) + //{ + // //ONLY used by BasePage.doLogin! + + // if (http == null) throw new ArgumentNullException("http"); + // if (userdata == null) throw new ArgumentNullException("userdata"); + + // var userDataString = JsonConvert.SerializeObject(userdata); + // return CreateAuthTicketAndCookie( + // http, + // userdata.Username, + // userDataString, + // //use the configuration timeout - this is the same timeout that will be used when renewing the ticket. + // GlobalSettings.TimeOutInMinutes, + // //Umbraco has always persisted it's original cookie for 1 day so we'll keep it that way + // 1440, + // UmbracoConfig.For.UmbracoSettings().Security.AuthCookieName, + // UmbracoConfig.For.UmbracoSettings().Security.AuthCookieDomain); + //} + + /// + /// returns the number of seconds the user has until their auth session times out + /// + /// + /// + public static double GetRemainingAuthSeconds(this HttpContextBase http) + { + if (http == null) throw new ArgumentNullException(nameof(http)); + var ticket = http.GetUmbracoAuthTicket(); + return ticket.GetRemainingAuthSeconds(); + } + + public static double GetRemainingAuthSeconds(this IOwinContext owinCtx) + { + if (owinCtx == null) throw new ArgumentNullException(nameof(owinCtx)); + var ticket = owinCtx.GetUmbracoAuthTicket(); + return ticket.GetRemainingAuthSeconds(); + } + + /// + /// returns the number of seconds the user has until their auth session times out + /// + /// + /// + public static double GetRemainingAuthSeconds(this AuthenticationTicket ticket) + { + var utcExpired = ticket?.Properties.ExpiresUtc; + if (utcExpired == null) return 0; + var secondsRemaining = utcExpired.Value.Subtract(DateTimeOffset.UtcNow).TotalSeconds; + return secondsRemaining; + } + + /// + /// Gets the umbraco auth ticket + /// + /// + /// + public static AuthenticationTicket GetUmbracoAuthTicket(this HttpContextBase http) + { + if (http == null) throw new ArgumentNullException(nameof(http)); + return GetAuthTicket(http, UmbracoConfig.For.UmbracoSettings().Security.AuthCookieName); + } + + internal static AuthenticationTicket GetUmbracoAuthTicket(this HttpContext http) + { + if (http == null) throw new ArgumentNullException(nameof(http)); + return new HttpContextWrapper(http).GetUmbracoAuthTicket(); + } + + public static AuthenticationTicket GetUmbracoAuthTicket(this IOwinContext ctx) + { + if (ctx == null) throw new ArgumentNullException(nameof(ctx)); + return GetAuthTicket(ctx, UmbracoConfig.For.UmbracoSettings().Security.AuthCookieName); + } + + /// + /// This clears the forms authentication cookie + /// + /// + /// + private static void Logout(this HttpContextBase http, string cookieName) + { + //We need to clear the sessionId from the database. This is legacy code to do any logging out and shouldn't really be used at all but in any case + //we need to make sure the session is cleared. Due to the legacy nature of this it means we need to use singletons + if (http.User != null) + { + var claimsIdentity = http.User.Identity as ClaimsIdentity; + if (claimsIdentity != null) + { + var sessionId = claimsIdentity.FindFirstValue(Constants.Security.SessionIdClaimType); + Guid guidSession; + if (sessionId.IsNullOrWhiteSpace() == false && Guid.TryParse(sessionId, out guidSession)) + { + Current.Services.UserService.ClearLoginSession(guidSession); + } + } + } + + if (http == null) throw new ArgumentNullException("http"); + //clear the preview cookie and external login + var cookies = new[] { cookieName, Constants.Web.PreviewCookieName, Constants.Security.BackOfficeExternalCookieName }; + foreach (var c in cookies) + { + //remove from the request + http.Request.Cookies.Remove(c); + + //expire from the response + var formsCookie = http.Response.Cookies[c]; + if (formsCookie != null) + { + //this will expire immediately and be removed from the browser + formsCookie.Expires = DateTime.Now.AddYears(-1); + } + else + { + //ensure there's def an expired cookie + http.Response.Cookies.Add(new HttpCookie(c) { Expires = DateTime.Now.AddYears(-1) }); + } + } + } + + private static AuthenticationTicket GetAuthTicket(this IOwinContext owinCtx, string cookieName) + { + var asDictionary = new Dictionary(); + foreach (var requestCookie in owinCtx.Request.Cookies) + { + var key = requestCookie.Key; + asDictionary[key] = requestCookie.Value; + } + + var secureFormat = owinCtx.GetUmbracoAuthTicketDataProtector(); + + //get the ticket + try + { + + return GetAuthTicket(secureFormat, asDictionary, cookieName); + } + catch (Exception) + { + owinCtx.Authentication.SignOut( + Constants.Security.BackOfficeAuthenticationType, + Constants.Security.BackOfficeExternalAuthenticationType); + return null; + } + } + + private static AuthenticationTicket GetAuthTicket(this HttpContextBase http, string cookieName) + { + var asDictionary = new Dictionary(); + for (var i = 0; i < http.Request.Cookies.Keys.Count; i++) + { + var key = http.Request.Cookies.Keys.Get(i); + asDictionary[key] = http.Request.Cookies[key].Value; + } + + var owinCtx = http.GetOwinContext(); + var secureFormat = owinCtx.GetUmbracoAuthTicketDataProtector(); + + //get the ticket + try + { + return GetAuthTicket(secureFormat, asDictionary, cookieName); + } + catch (Exception) + { + //occurs when decryption fails + http.Logout(cookieName); + return null; + } + } + + private static AuthenticationTicket GetAuthTicket(ISecureDataFormat secureDataFormat, IDictionary cookies, string cookieName) + { + if (cookies == null) throw new ArgumentNullException(nameof(cookies)); + + if (cookies.ContainsKey(cookieName) == false) return null; + + var formsCookie = cookies[cookieName]; + if (formsCookie == null) + { + return null; + } + //get the ticket + + return secureDataFormat.Unprotect(formsCookie); + } + } +} diff --git a/src/Umbraco.Web/Security/Identity/AppBuilderExtensions.cs b/src/Umbraco.Web/Security/Identity/AppBuilderExtensions.cs index 02a7208634..260149be84 100644 --- a/src/Umbraco.Web/Security/Identity/AppBuilderExtensions.cs +++ b/src/Umbraco.Web/Security/Identity/AppBuilderExtensions.cs @@ -8,6 +8,8 @@ using Microsoft.Owin.Extensions; using Microsoft.Owin.Logging; using Microsoft.Owin.Security; using Microsoft.Owin.Security.Cookies; +using Microsoft.Owin.Security.DataHandler; +using Microsoft.Owin.Security.DataProtection; using Owin; using Umbraco.Core; using Umbraco.Core.Configuration; @@ -178,17 +180,21 @@ namespace Umbraco.Web.Security.Identity //don't apply if app is not ready if (runtimeState.Level != RuntimeLevel.Upgrade && runtimeState.Level != RuntimeLevel.Run) return app; - var getSecondsOptions = app.CreateUmbracoCookieAuthOptions( + var cookieAuthOptions = app.CreateUmbracoCookieAuthOptions( //This defines the explicit path read cookies from for this middleware - new[] {string.Format("{0}/backoffice/UmbracoApi/Authentication/GetRemainingTimeoutSeconds", GlobalSettings.Path)}); - getSecondsOptions.Provider = cookieOptions.Provider; + new[] {$"{GlobalSettings.Path}/backoffice/UmbracoApi/Authentication/GetRemainingTimeoutSeconds"}); + cookieAuthOptions.Provider = cookieOptions.Provider; //This is a custom middleware, we need to return the user's remaining logged in seconds app.Use( - getSecondsOptions, + cookieAuthOptions, UmbracoConfig.For.UmbracoSettings().Security, app.CreateLogger()); + //This is required so that we can read the auth ticket format outside of this pipeline + app.CreatePerOwinContext( + (options, context) => new UmbracoAuthTicketDataProtector(cookieOptions.TicketDataFormat)); + return app; } @@ -346,11 +352,19 @@ namespace Umbraco.Web.Security.Identity /// public static UmbracoBackOfficeCookieAuthOptions CreateUmbracoCookieAuthOptions(this IAppBuilder app, string[] explicitPaths = null) { + //this is how aspnet wires up the default AuthenticationTicket protector so we'll use the same code + var ticketDataFormat = new TicketDataFormat( + app.CreateDataProtector(typeof (CookieAuthenticationMiddleware).FullName, + Constants.Security.BackOfficeAuthenticationType, + "v1")); + var authOptions = new UmbracoBackOfficeCookieAuthOptions( explicitPaths, UmbracoConfig.For.UmbracoSettings().Security, GlobalSettings.TimeOutInMinutes, - GlobalSettings.UseSSL); + GlobalSettings.UseSSL, + ticketDataFormat); + return authOptions; } } diff --git a/src/Umbraco.Web/Security/Identity/BackOfficeCookieManager.cs b/src/Umbraco.Web/Security/Identity/BackOfficeCookieManager.cs index 98493db1c7..43c84c2ba9 100644 --- a/src/Umbraco.Web/Security/Identity/BackOfficeCookieManager.cs +++ b/src/Umbraco.Web/Security/Identity/BackOfficeCookieManager.cs @@ -6,7 +6,7 @@ using Microsoft.Owin; using Microsoft.Owin.Infrastructure; using Umbraco.Core; using Umbraco.Core.Configuration; -using Umbraco.Core.IO; +using Umbraco.Core.Security; namespace Umbraco.Web.Security.Identity { diff --git a/src/Umbraco.Web/Security/Identity/FormsAuthenticationSecureDataFormat.cs b/src/Umbraco.Web/Security/Identity/FormsAuthenticationSecureDataFormat.cs deleted file mode 100644 index 64da407021..0000000000 --- a/src/Umbraco.Web/Security/Identity/FormsAuthenticationSecureDataFormat.cs +++ /dev/null @@ -1,90 +0,0 @@ -using System; -using System.Security.Claims; -using System.Web.Security; -using Microsoft.Owin; -using Microsoft.Owin.Security; -using Microsoft.Owin.Security.Cookies; -using Newtonsoft.Json; -using Owin; -using Umbraco.Core.Security; - -namespace Umbraco.Web.Security.Identity -{ - - /// - /// Custom secure format that uses the old FormsAuthentication format - /// - internal class FormsAuthenticationSecureDataFormat : ISecureDataFormat - { - private readonly int _loginTimeoutMinutes; - - public FormsAuthenticationSecureDataFormat(int loginTimeoutMinutes) - { - _loginTimeoutMinutes = loginTimeoutMinutes; - } - - public string Protect(AuthenticationTicket data) - { - var backofficeIdentity = (UmbracoBackOfficeIdentity)data.Identity; - var userDataString = JsonConvert.SerializeObject(backofficeIdentity.UserData); - - var ticket = new FormsAuthenticationTicket( - 5, - data.Identity.Name, - data.Properties.IssuedUtc.HasValue - ? data.Properties.IssuedUtc.Value.LocalDateTime - : DateTime.Now, - data.Properties.ExpiresUtc.HasValue - ? data.Properties.ExpiresUtc.Value.LocalDateTime - : DateTime.Now.AddMinutes(_loginTimeoutMinutes), - data.Properties.IsPersistent, - userDataString, - "/" - ); - - return FormsAuthentication.Encrypt(ticket); - } - - /// - /// Unprotects the cookie - /// - /// - /// - public AuthenticationTicket Unprotect(string protectedText) - { - FormsAuthenticationTicket decrypt; - try - { - decrypt = FormsAuthentication.Decrypt(protectedText); - if (decrypt == null) return null; - } - catch (Exception) - { - return null; - } - - UmbracoBackOfficeIdentity identity; - - try - { - identity = new UmbracoBackOfficeIdentity(decrypt); - } - catch (Exception) - { - //if it cannot be created return null, will be due to serialization errors in user data most likely due to corrupt cookies or cookies - //for previous versions of Umbraco - return null; - } - - var ticket = new AuthenticationTicket(identity, new AuthenticationProperties - { - ExpiresUtc = decrypt.Expiration.ToUniversalTime(), - IssuedUtc = decrypt.IssueDate.ToUniversalTime(), - IsPersistent = decrypt.IsPersistent, - AllowRefresh = true - }); - - return ticket; - } - } -} diff --git a/src/Umbraco.Web/Security/Identity/GetUserSecondsMiddleWare.cs b/src/Umbraco.Web/Security/Identity/GetUserSecondsMiddleWare.cs index 0efb0b66a6..075fe89cdc 100644 --- a/src/Umbraco.Web/Security/Identity/GetUserSecondsMiddleWare.cs +++ b/src/Umbraco.Web/Security/Identity/GetUserSecondsMiddleWare.cs @@ -35,11 +35,9 @@ namespace Umbraco.Web.Security.Identity ILogger logger) : base(next) { - if (authOptions == null) throw new ArgumentNullException("authOptions"); - if (logger == null) throw new ArgumentNullException("logger"); - _authOptions = authOptions; + _authOptions = authOptions ?? throw new ArgumentNullException(nameof(authOptions)); _security = security; - _logger = logger; + _logger = logger ?? throw new ArgumentNullException(nameof(logger)); } public override async Task Invoke(IOwinContext context) @@ -49,7 +47,7 @@ namespace Umbraco.Web.Security.Identity if (request.Uri.Scheme.InvariantStartsWith("http") && request.Uri.AbsolutePath.InvariantEquals( - string.Format("{0}/backoffice/UmbracoApi/Authentication/GetRemainingTimeoutSeconds", GlobalSettings.Path))) + $"{GlobalSettings.Path}/backoffice/UmbracoApi/Authentication/GetRemainingTimeoutSeconds")) { var cookie = _authOptions.CookieManager.GetRequestCookie(context, _security.AuthCookieName); if (cookie.IsNullOrWhiteSpace() == false) diff --git a/src/Umbraco.Web/Security/Identity/UmbracoBackOfficeCookieAuthOptions.cs b/src/Umbraco.Web/Security/Identity/UmbracoBackOfficeCookieAuthOptions.cs index 714337fb2d..679e1c8b67 100644 --- a/src/Umbraco.Web/Security/Identity/UmbracoBackOfficeCookieAuthOptions.cs +++ b/src/Umbraco.Web/Security/Identity/UmbracoBackOfficeCookieAuthOptions.cs @@ -14,29 +14,19 @@ namespace Umbraco.Web.Security.Identity /// public sealed class UmbracoBackOfficeCookieAuthOptions : CookieAuthenticationOptions { - public int LoginTimeoutMinutes { get; private set; } - - public UmbracoBackOfficeCookieAuthOptions() - : this(UmbracoConfig.For.UmbracoSettings().Security, GlobalSettings.TimeOutInMinutes, GlobalSettings.UseSSL) - { - } - + public int LoginTimeoutMinutes { get; } + public UmbracoBackOfficeCookieAuthOptions( string[] explicitPaths, ISecuritySection securitySection, int loginTimeoutMinutes, bool forceSsl, - bool useLegacyFormsAuthDataFormat = true) + ISecureDataFormat secureDataFormat) { + var secureDataFormat1 = secureDataFormat ?? throw new ArgumentNullException(nameof(secureDataFormat)); LoginTimeoutMinutes = loginTimeoutMinutes; AuthenticationType = Constants.Security.BackOfficeAuthenticationType; - - if (useLegacyFormsAuthDataFormat) - { - //If this is not explicitly set it will fall back to the default automatically - TicketDataFormat = new FormsAuthenticationSecureDataFormat(LoginTimeoutMinutes); - } - + SlidingExpiration = true; ExpireTimeSpan = TimeSpan.FromMinutes(LoginTimeoutMinutes); CookieDomain = securitySection.AuthCookieDomain; @@ -45,19 +35,12 @@ namespace Umbraco.Web.Security.Identity CookieSecure = forceSsl ? CookieSecureOption.Always : CookieSecureOption.SameAsRequest; CookiePath = "/"; + TicketDataFormat = new UmbracoSecureDataFormat(LoginTimeoutMinutes, secureDataFormat1); + //Custom cookie manager so we can filter requests CookieManager = new BackOfficeCookieManager(Current.UmbracoContextAccessor, Current.RuntimeState, explicitPaths); } - - public UmbracoBackOfficeCookieAuthOptions( - ISecuritySection securitySection, - int loginTimeoutMinutes, - bool forceSsl, - bool useLegacyFormsAuthDataFormat = true) - : this(null, securitySection, loginTimeoutMinutes, forceSsl, useLegacyFormsAuthDataFormat) - { - } - + /// /// Creates the cookie options for saving the auth cookie /// @@ -66,8 +49,8 @@ namespace Umbraco.Web.Security.Identity /// public CookieOptions CreateRequestCookieOptions(IOwinContext ctx, AuthenticationTicket ticket) { - if (ctx == null) throw new ArgumentNullException("ctx"); - if (ticket == null) throw new ArgumentNullException("ticket"); + if (ctx == null) throw new ArgumentNullException(nameof(ctx)); + if (ticket == null) throw new ArgumentNullException(nameof(ticket)); var issuedUtc = ticket.Properties.IssuedUtc ?? SystemClock.UtcNow; var expiresUtc = ticket.Properties.ExpiresUtc ?? issuedUtc.Add(ExpireTimeSpan); diff --git a/src/Umbraco.Web/Security/Identity/UmbracoSecureDataFormat.cs b/src/Umbraco.Web/Security/Identity/UmbracoSecureDataFormat.cs new file mode 100644 index 0000000000..2676a5ee25 --- /dev/null +++ b/src/Umbraco.Web/Security/Identity/UmbracoSecureDataFormat.cs @@ -0,0 +1,83 @@ +using System; +using System.Security.Claims; +using System.Web.Security; +using Microsoft.Owin; +using Microsoft.Owin.Security; +using Microsoft.Owin.Security.Cookies; +using Newtonsoft.Json; +using Owin; +using Umbraco.Core.Security; + +namespace Umbraco.Web.Security.Identity +{ + + /// + /// Custom secure format that ensures the Identity in the ticket is and not just a ClaimsIdentity + /// + internal class UmbracoSecureDataFormat : ISecureDataFormat + { + private readonly int _loginTimeoutMinutes; + private readonly ISecureDataFormat _ticketDataFormat; + + public UmbracoSecureDataFormat(int loginTimeoutMinutes, ISecureDataFormat ticketDataFormat) + { + _loginTimeoutMinutes = loginTimeoutMinutes; + _ticketDataFormat = ticketDataFormat ?? throw new ArgumentNullException(nameof(ticketDataFormat)); + } + + public string Protect(AuthenticationTicket data) + { + var backofficeIdentity = (UmbracoBackOfficeIdentity)data.Identity; + + //create a new ticket based on the passed in tickets details, however, we'll adjust the expires utc based on the specified timeout mins + var ticket = new AuthenticationTicket(backofficeIdentity, + new AuthenticationProperties(data.Properties.Dictionary) + { + IssuedUtc = data.Properties.IssuedUtc, + ExpiresUtc = data.Properties.ExpiresUtc ?? DateTimeOffset.UtcNow.AddMinutes(_loginTimeoutMinutes), + AllowRefresh = data.Properties.AllowRefresh, + IsPersistent = data.Properties.IsPersistent, + RedirectUri = data.Properties.RedirectUri + }); + + return _ticketDataFormat.Protect(ticket); + } + + /// + /// Unprotects the cookie + /// + /// + /// + public AuthenticationTicket Unprotect(string protectedText) + { + AuthenticationTicket decrypt; + try + { + decrypt = _ticketDataFormat.Unprotect(protectedText); + if (decrypt == null) return null; + } + catch (Exception) + { + return null; + } + + UmbracoBackOfficeIdentity identity; + + try + { + identity = UmbracoBackOfficeIdentity.FromClaimsIdentity(decrypt.Identity); + } + catch (Exception) + { + //if it cannot be created return null, will be due to serialization errors in user data most likely due to corrupt cookies or cookies + //for previous versions of Umbraco + return null; + } + + //return the ticket with a UmbracoBackOfficeIdentity + var ticket = new AuthenticationTicket(identity, decrypt.Properties); + + return ticket; + } + } +} diff --git a/src/Umbraco.Web/Security/LegacyDefaultAppMapping.cs b/src/Umbraco.Web/Security/LegacyDefaultAppMapping.cs deleted file mode 100644 index 54ed9aea33..0000000000 --- a/src/Umbraco.Web/Security/LegacyDefaultAppMapping.cs +++ /dev/null @@ -1,49 +0,0 @@ -using System; -using System.Collections.Concurrent; -using System.Collections.Generic; -using System.Linq; -using System.Text; - -namespace Umbraco.Web.Security -{ - /// - /// This is used specifically to assign a default 'app' to a particular section in order to validate the - /// currently logged in user's allowed applications - /// - /// - /// This relates to these issues: - /// http://issues.umbraco.org/issue/U4-2021 - /// http://issues.umbraco.org/issue/U4-529 - /// - /// In order to fix these issues we need to pass in an 'app' parameter but since we don't want to break compatibility - /// we will create this mapping to map a 'default application' to a section action (like creating or deleting) - /// - public static class LegacyDefaultAppMapping - { - /// - /// Constructor that assigns all initial known mappings - /// - static LegacyDefaultAppMapping() - { - } - - private static readonly ConcurrentDictionary NodeTypeAliasMapping = new ConcurrentDictionary(); - - /// - /// Adds the default app mapping to the node type - /// - /// The nodeType is the same nodeType found in the UI.xml - /// The default app associated with this nodeType if the 'app' parameter was not detected - public static void AddNodeTypeMappingForCreateDialog(string nodeType, string defaultApp) - { - NodeTypeAliasMapping.AddOrUpdate(nodeType, s => defaultApp, (s, s1) => defaultApp); - } - - internal static string GetDefaultAppForCreateDialog(string nodeTypeAlias) - { - string app; - return NodeTypeAliasMapping.TryGetValue(nodeTypeAlias, out app) ? app : null; - } - - } -} diff --git a/src/Umbraco.Web/Security/OwinExtensions.cs b/src/Umbraco.Web/Security/OwinExtensions.cs index 0df0c28cf6..c9d3c56513 100644 --- a/src/Umbraco.Web/Security/OwinExtensions.cs +++ b/src/Umbraco.Web/Security/OwinExtensions.cs @@ -1,7 +1,7 @@ -using System; -using System.Web; +using System.Web; using Microsoft.AspNet.Identity.Owin; using Microsoft.Owin; +using Microsoft.Owin.Security; using Umbraco.Core; using Umbraco.Core.Models.Identity; using Umbraco.Core.Security; @@ -11,16 +11,14 @@ namespace Umbraco.Web.Security { internal static class OwinExtensions { - /// - /// Nasty little hack to get httpcontextbase from an owin context + /// Gets the for the Umbraco back office cookie /// /// /// - internal static Attempt TryGetHttpContext(this IOwinContext owinContext) + internal static ISecureDataFormat GetUmbracoAuthTicketDataProtector(this IOwinContext owinContext) { - var ctx = owinContext.Get(typeof(HttpContextBase).FullName); - return ctx == null ? Attempt.Fail() : Attempt.Succeed(ctx); + return owinContext.Get().Protector; } } diff --git a/src/Umbraco.Web/Security/UmbracoAuthTicketDataProtector.cs b/src/Umbraco.Web/Security/UmbracoAuthTicketDataProtector.cs new file mode 100644 index 0000000000..c65c010204 --- /dev/null +++ b/src/Umbraco.Web/Security/UmbracoAuthTicketDataProtector.cs @@ -0,0 +1,19 @@ +using System; +using Microsoft.Owin.Security; +using Umbraco.Core; + +namespace Umbraco.Web.Security +{ + /// + /// This is used so that we can retrive the auth ticket protector from an IOwinContext + /// + internal class UmbracoAuthTicketDataProtector : DisposableObjectSlim + { + public UmbracoAuthTicketDataProtector(ISecureDataFormat protector) + { + Protector = protector ?? throw new ArgumentNullException(nameof(protector)); + } + + public ISecureDataFormat Protector { get; } + } +} diff --git a/src/Umbraco.Web/UI/Pages/UmbracoEnsuredPage.cs b/src/Umbraco.Web/UI/Pages/UmbracoEnsuredPage.cs index 5fcc730f90..3c100a839e 100644 --- a/src/Umbraco.Web/UI/Pages/UmbracoEnsuredPage.cs +++ b/src/Umbraco.Web/UI/Pages/UmbracoEnsuredPage.cs @@ -11,6 +11,7 @@ using Umbraco.Core.Models; using Umbraco.Core.Models.Entities; using Umbraco.Core.Security; using Umbraco.Web.Composing; +using Umbraco.Web.Security; using Umbraco.Web._Legacy.Actions; namespace Umbraco.Web.UI.Pages diff --git a/src/Umbraco.Web/Umbraco.Web.csproj b/src/Umbraco.Web/Umbraco.Web.csproj index 9a8d424708..35c669ebd7 100644 --- a/src/Umbraco.Web/Umbraco.Web.csproj +++ b/src/Umbraco.Web/Umbraco.Web.csproj @@ -404,6 +404,9 @@ + + + @@ -769,7 +772,6 @@ - @@ -1084,7 +1086,6 @@ - diff --git a/src/Umbraco.Web/WebApi/Filters/UmbracoUserTimeoutFilterAttribute.cs b/src/Umbraco.Web/WebApi/Filters/UmbracoUserTimeoutFilterAttribute.cs index 2d938eb6e8..0d54ed99eb 100644 --- a/src/Umbraco.Web/WebApi/Filters/UmbracoUserTimeoutFilterAttribute.cs +++ b/src/Umbraco.Web/WebApi/Filters/UmbracoUserTimeoutFilterAttribute.cs @@ -1,6 +1,8 @@ -using System.Globalization; +using System; +using System.Globalization; using System.Web.Http.Filters; using Umbraco.Core.Security; +using Umbraco.Web.Security; namespace Umbraco.Web.WebApi.Filters { @@ -17,12 +19,13 @@ namespace Umbraco.Web.WebApi.Filters //this can occur if an error has already occurred. if (actionExecutedContext.Response == null) return; - + var httpContextAttempt = actionExecutedContext.Request.TryGetHttpContext(); if (httpContextAttempt.Success) - { + { + var ticket = httpContextAttempt.Result.GetUmbracoAuthTicket(); - if (ticket != null && ticket.Expired == false) + if (ticket?.Properties.ExpiresUtc != null && ticket.Properties.ExpiresUtc.Value < DateTimeOffset.UtcNow) { var remainingSeconds = httpContextAttempt.Result.GetRemainingAuthSeconds(); actionExecutedContext.Response.Headers.Add("X-Umb-User-Seconds", remainingSeconds.ToString(CultureInfo.InvariantCulture)); diff --git a/src/Umbraco.Web/umbraco.presentation/umbraco/controls/Tree/CustomTreeService.cs b/src/Umbraco.Web/umbraco.presentation/umbraco/controls/Tree/CustomTreeService.cs index 70b08fbf0f..f3143bad30 100644 --- a/src/Umbraco.Web/umbraco.presentation/umbraco/controls/Tree/CustomTreeService.cs +++ b/src/Umbraco.Web/umbraco.presentation/umbraco/controls/Tree/CustomTreeService.cs @@ -11,6 +11,7 @@ using umbraco.cms.businesslogic; using umbraco.cms.presentation.Trees; using umbraco.controls.Tree; using Umbraco.Core.Services; +using Umbraco.Web.Security; using Umbraco.Web.WebServices; namespace umbraco.controls.Tree diff --git a/src/Umbraco.Web/umbraco.presentation/umbraco/controls/Tree/TreeControl.ascx.cs b/src/Umbraco.Web/umbraco.presentation/umbraco/controls/Tree/TreeControl.ascx.cs index 385c4c1843..67d82f327f 100644 --- a/src/Umbraco.Web/umbraco.presentation/umbraco/controls/Tree/TreeControl.ascx.cs +++ b/src/Umbraco.Web/umbraco.presentation/umbraco/controls/Tree/TreeControl.ascx.cs @@ -13,6 +13,7 @@ using System.Drawing; using System.Linq; using Umbraco.Core; using Umbraco.Core.Services; +using Umbraco.Web.Security; namespace umbraco.controls.Tree { From 7442c96be13759aea240ee339568fa6e65887b1f Mon Sep 17 00:00:00 2001 From: Shannon Date: Thu, 5 Apr 2018 23:15:51 +1000 Subject: [PATCH 12/14] removes unused methods --- .../Security/AuthenticationExtensions.cs | 36 ++----------------- 1 file changed, 2 insertions(+), 34 deletions(-) diff --git a/src/Umbraco.Web/Security/AuthenticationExtensions.cs b/src/Umbraco.Web/Security/AuthenticationExtensions.cs index 0eeb840496..6984eb2817 100644 --- a/src/Umbraco.Web/Security/AuthenticationExtensions.cs +++ b/src/Umbraco.Web/Security/AuthenticationExtensions.cs @@ -181,32 +181,7 @@ namespace Umbraco.Web.Security http.Items[Constants.Security.ForceReAuthFlag] = true; return true; } - - ///// - ///// Creates the umbraco authentication ticket - ///// - ///// - ///// - //public static AuthenticationTicket CreateUmbracoAuthTicket(this HttpContextBase http, UserData userdata) - //{ - // //ONLY used by BasePage.doLogin! - - // if (http == null) throw new ArgumentNullException("http"); - // if (userdata == null) throw new ArgumentNullException("userdata"); - - // var userDataString = JsonConvert.SerializeObject(userdata); - // return CreateAuthTicketAndCookie( - // http, - // userdata.Username, - // userDataString, - // //use the configuration timeout - this is the same timeout that will be used when renewing the ticket. - // GlobalSettings.TimeOutInMinutes, - // //Umbraco has always persisted it's original cookie for 1 day so we'll keep it that way - // 1440, - // UmbracoConfig.For.UmbracoSettings().Security.AuthCookieName, - // UmbracoConfig.For.UmbracoSettings().Security.AuthCookieDomain); - //} - + /// /// returns the number of seconds the user has until their auth session times out /// @@ -218,14 +193,7 @@ namespace Umbraco.Web.Security var ticket = http.GetUmbracoAuthTicket(); return ticket.GetRemainingAuthSeconds(); } - - public static double GetRemainingAuthSeconds(this IOwinContext owinCtx) - { - if (owinCtx == null) throw new ArgumentNullException(nameof(owinCtx)); - var ticket = owinCtx.GetUmbracoAuthTicket(); - return ticket.GetRemainingAuthSeconds(); - } - + /// /// returns the number of seconds the user has until their auth session times out /// From c90d6be8ab4cd54af149171221034939a74ec546 Mon Sep 17 00:00:00 2001 From: Shannon Date: Fri, 6 Apr 2018 13:51:54 +1000 Subject: [PATCH 13/14] U4-8861 Extract GlobalSettings to an interface and expose on the standard UmbracoConfig.For settings singleton including a bunch of cleanup, getting the installer and steps to be DI --- .../ConfigurationCompositionRoot.cs | 1 + src/Umbraco.Core/Composing/TypeLoader.cs | 75 +-- .../Configuration/GlobalSettings.cs | 466 ++---------------- .../Configuration/GlobalSettingsExtensions.cs | 141 ++++++ .../Configuration/IGlobalSettings.cs | 84 ++++ .../Configuration/LocalTempStorage.cs | 2 +- .../Configuration/UmbracoConfig.cs | 22 +- src/Umbraco.Core/Constants-Web.cs | 2 + src/Umbraco.Core/IO/SystemDirectories.cs | 7 +- src/Umbraco.Core/IO/SystemFiles.cs | 35 +- .../Migrations/Install/DatabaseBuilder.cs | 8 +- .../Models/Identity/BackOfficeIdentityUser.cs | 5 +- .../Models/Identity/IdentityProfile.cs | 5 +- src/Umbraco.Core/Models/Membership/User.cs | 2 +- src/Umbraco.Core/Models/UserExtensions.cs | 9 +- .../Packaging/PackageInstallation.cs | 2 +- .../Repositories/Implement/UserRepository.cs | 14 +- src/Umbraco.Core/Runtime/CoreRuntime.cs | 5 +- .../Runtime/CoreRuntimeComponent.cs | 5 +- src/Umbraco.Core/RuntimeState.cs | 7 +- .../BackOfficeCookieAuthenticationProvider.cs | 25 +- .../Security/BackOfficeSignInManager.cs | 33 +- .../Security/BackOfficeUserManager.cs | 7 +- .../Security/BackOfficeUserStore.cs | 7 +- .../Security/SessionIdValidator.cs | 13 +- .../Services/Implement/NotificationService.cs | 12 +- .../Services/Implement/UserService.cs | 6 +- src/Umbraco.Core/Sync/ApplicationUrlHelper.cs | 18 +- src/Umbraco.Core/Sync/ConfigServerAddress.cs | 8 +- .../Sync/ConfigServerRegistrar.cs | 9 +- .../Sync/DatabaseServerMessenger.cs | 11 +- src/Umbraco.Core/Umbraco.Core.csproj | 2 + src/Umbraco.Core/UriExtensions.cs | 78 +-- src/Umbraco.Tests/App.config | 2 +- .../PublishedContentCacheTests.cs | 15 +- .../Composing/ComposingTestBase.cs | 3 +- .../Composing/TypeLoaderTests.cs | 5 +- .../Configurations/GlobalSettingsTests.cs | 34 +- .../CoreThings/TryConvertToTests.cs | 2 +- src/Umbraco.Tests/CoreThings/UdiTests.cs | 5 +- .../CoreThings/UriExtensionsTests.cs | 5 +- src/Umbraco.Tests/IO/FileSystemsTests.cs | 2 +- src/Umbraco.Tests/Macros/MacroTests.cs | 2 +- .../Misc/ApplicationUrlHelperTests.cs | 84 ++-- src/Umbraco.Tests/Misc/UriUtilityTests.cs | 7 +- src/Umbraco.Tests/Models/ContentTests.cs | 2 +- src/Umbraco.Tests/Models/MacroTests.cs | 2 +- .../Packaging/PackageExtractionTests.cs | 2 +- .../Repositories/UserRepositoryTest.cs | 4 +- .../PropertyEditorValueEditorTests.cs | 2 +- .../PublishedContentMoreTests.cs | 7 +- .../PublishedContent/PublishedMediaTests.cs | 2 +- .../ContentFinderByNiceUrlAndTemplateTests.cs | 12 +- .../Routing/ContentFinderByNiceUrlTests.cs | 45 +- .../ContentFinderByNiceUrlWithDomainsTests.cs | 17 +- .../Routing/DomainsAndCulturesTests.cs | 17 +- .../Routing/NiceUrlProviderTests.cs | 62 ++- .../Routing/NiceUrlRoutesTests.cs | 53 +- .../NiceUrlsProviderWithDomainsTests.cs | 94 ++-- .../Routing/RenderRouteHandlerTests.cs | 7 +- .../Routing/UmbracoModuleTests.cs | 2 +- .../Routing/UrlsWithNestedDomains.cs | 13 +- .../Runtimes/CoreRuntimeTests.cs | 2 +- .../Scoping/ScopedNuCacheTests.cs | 10 +- src/Umbraco.Tests/Scoping/ScopedXmlTests.cs | 4 +- .../Security/BackOfficeCookieManagerTests.cs | 13 +- .../Services/PackagingServiceTests.cs | 2 +- .../Strings/CmsHelperCasingTests.cs | 4 +- .../Strings/DefaultShortStringHelperTests.cs | 48 +- .../TestHelpers/BaseUsingSqlCeSyntax.cs | 3 +- .../TestControllerActivatorBase.cs | 14 +- .../TestHelpers/SettingsForTests.cs | 139 +++--- .../TestHelpers/TestObjects-Mocks.cs | 16 +- src/Umbraco.Tests/TestHelpers/TestObjects.cs | 11 +- .../TestHelpers/TestWithDatabaseBase.cs | 34 +- src/Umbraco.Tests/Testing/UmbracoTestBase.cs | 16 +- src/Umbraco.Tests/Umbraco.Tests.csproj | 11 +- .../UmbracoExamine/ExamineBaseTest.cs | 2 +- .../Controllers/PluginControllerAreaTests.cs | 9 +- ...RenderIndexActionSelectorAttributeTests.cs | 16 +- .../Web/Mvc/SurfaceControllerTests.cs | 20 +- .../Web/Mvc/UmbracoViewPageTests.cs | 9 +- .../Web/TemplateUtilitiesTests.cs | 8 +- .../Web/WebExtensionMethodTests.cs | 15 +- src/Umbraco.Web.UI/Umbraco/umbraco.aspx.cs | 2 +- .../umbraco/Views/Default.cshtml | 3 +- src/Umbraco.Web.UI/web.Template.Debug.config | 4 +- src/Umbraco.Web.UI/web.Template.config | 2 +- src/Umbraco.Web/AppBuilderExtensions.cs | 5 +- .../BatchedDatabaseServerMessenger.cs | 5 +- .../Cache/CacheRefresherComponent.cs | 3 +- ...aseServerRegistrarAndMessengerComponent.cs | 5 +- .../InstallerCompositionRoot.cs | 42 ++ .../Editors/AuthenticationController.cs | 8 +- .../Editors/BackOfficeController.cs | 4 +- .../Editors/BackOfficeServerVariables.cs | 6 +- src/Umbraco.Web/Editors/PreviewController.cs | 8 +- .../Editors/UpdateCheckController.cs | 4 +- src/Umbraco.Web/Editors/UsersController.cs | 6 +- .../HealthCheck/Checks/Security/HttpsCheck.cs | 7 +- .../HtmlHelperBackOfficeExtensions.cs | 5 +- .../Controllers/InstallApiController.cs | 30 +- .../Install/Controllers/InstallController.cs | 13 +- src/Umbraco.Web/Install/InstallHelper.cs | 60 +-- .../Install/InstallStepCollection.cs | 40 ++ .../MajorVersion7UpgradeReport.cs | 134 ----- .../Install/InstallSteps/NewInstallStep.cs | 6 +- .../InstallSteps/SetUmbracoVersionStep.cs | 19 +- .../InstallSteps/StarterKitDownloadStep.cs | 8 +- .../InstallSteps/Version73FileCleanup.cs | 90 ---- src/Umbraco.Web/Macros/MacroRenderer.cs | 2 +- .../Models/ContentEditing/ContentTypeBasic.cs | 2 +- .../Models/Mapping/UserMapperProfile.cs | 10 +- src/Umbraco.Web/Models/Trees/TreeNode.cs | 2 +- .../Mvc/AreaRegistrationExtensions.cs | 24 +- src/Umbraco.Web/Mvc/BackOfficeArea.cs | 17 +- src/Umbraco.Web/Mvc/PluginControllerArea.cs | 27 +- .../Mvc/UmbracoAuthorizeAttribute.cs | 2 +- src/Umbraco.Web/Mvc/UmbracoController.cs | 7 + .../Mvc/UmbracoRequireHttpsAttribute.cs | 5 +- src/Umbraco.Web/Mvc/UrlHelperExtensions.cs | 6 +- .../NotificationServiceExtensions.cs | 32 +- .../PropertyEditors/RteEmbedController.cs | 3 +- .../PublishedCache/NuCache/ContentCache.cs | 7 +- .../NuCache/PublishedSnapshotService.cs | 7 +- .../PublishedContentCache.cs | 9 +- .../PublishedSnapshotService.cs | 19 +- .../XmlPublishedCache/XmlCacheComponent.cs | 6 +- .../XmlPublishedCache/XmlStore.cs | 15 +- src/Umbraco.Web/Routing/AliasUrlProvider.cs | 15 +- .../Routing/ContentFinderByProfile.cs | 67 --- src/Umbraco.Web/Routing/DefaultUrlProvider.cs | 9 +- .../Runtime/WebRuntimeComponent.cs | 38 +- .../Security/AuthenticationExtensions.cs | 3 + .../Security/Identity/AppBuilderExtensions.cs | 98 +++- .../Identity/BackOfficeCookieManager.cs | 12 +- .../Identity/ExternalSignInAutoLinkOptions.cs | 17 +- .../Identity/GetUserSecondsMiddleWare.cs | 7 +- .../PreviewAuthenticationMiddleware.cs | 7 +- .../UmbracoBackOfficeCookieAuthOptions.cs | 11 +- src/Umbraco.Web/Security/OwinExtensions.cs | 3 +- src/Umbraco.Web/Security/WebSecurity.cs | 17 +- .../Trees/LegacyTreeDataConverter.cs | 3 +- src/Umbraco.Web/UI/Pages/BasePage.cs | 2 +- .../UI/Pages/UmbracoEnsuredPage.cs | 3 +- src/Umbraco.Web/Umbraco.Web.csproj | 5 +- src/Umbraco.Web/UmbracoContext.cs | 60 ++- src/Umbraco.Web/UmbracoDefaultOwinStartup.cs | 24 +- src/Umbraco.Web/UmbracoModule.cs | 18 +- src/Umbraco.Web/UriUtility.cs | 7 +- .../CheckIfUserTicketDataIsStaleAttribute.cs | 3 +- .../SetAngularAntiForgeryTokensAttribute.cs | 4 +- .../UmbracoWebApiRequireHttpsAttribute.cs | 2 +- .../WebApi/UmbracoApiControllerBase.cs | 7 + .../WebServices/EmbedMediaService.cs | 2 +- .../UmbracoAuthorizedWebService.cs | 7 - .../WebServices/UmbracoWebService.cs | 16 +- .../umbraco/dialogs/sendToTranslation.aspx.cs | 5 +- .../umbraco/translation/xml.aspx.cs | 2 +- .../webservices/CheckForUpgrade.asmx.cs | 6 +- .../umbraco/webservices/nodeSorter.asmx.cs | 3 +- 161 files changed, 1637 insertions(+), 1608 deletions(-) create mode 100644 src/Umbraco.Core/Configuration/GlobalSettingsExtensions.cs create mode 100644 src/Umbraco.Core/Configuration/IGlobalSettings.cs create mode 100644 src/Umbraco.Web/Composing/CompositionRoots/InstallerCompositionRoot.cs create mode 100644 src/Umbraco.Web/Install/InstallStepCollection.cs delete mode 100644 src/Umbraco.Web/Install/InstallSteps/MajorVersion7UpgradeReport.cs delete mode 100644 src/Umbraco.Web/Install/InstallSteps/Version73FileCleanup.cs delete mode 100644 src/Umbraco.Web/Routing/ContentFinderByProfile.cs diff --git a/src/Umbraco.Core/Composing/CompositionRoots/ConfigurationCompositionRoot.cs b/src/Umbraco.Core/Composing/CompositionRoots/ConfigurationCompositionRoot.cs index a254c7820d..82912163b6 100644 --- a/src/Umbraco.Core/Composing/CompositionRoots/ConfigurationCompositionRoot.cs +++ b/src/Umbraco.Core/Composing/CompositionRoots/ConfigurationCompositionRoot.cs @@ -15,6 +15,7 @@ namespace Umbraco.Core.Composing.CompositionRoots container.Register(factory => factory.GetInstance().Content); container.Register(factory => factory.GetInstance().Templates); container.Register(factory => factory.GetInstance().RequestHandler); + container.Register(factory => UmbracoConfig.For.GlobalSettings()); // fixme - other sections we need to add? } diff --git a/src/Umbraco.Core/Composing/TypeLoader.cs b/src/Umbraco.Core/Composing/TypeLoader.cs index 9ca1b2fa1c..46157c1748 100644 --- a/src/Umbraco.Core/Composing/TypeLoader.cs +++ b/src/Umbraco.Core/Composing/TypeLoader.cs @@ -29,6 +29,7 @@ namespace Umbraco.Core.Composing private const string CacheKey = "umbraco-types.list"; private readonly IRuntimeCacheProvider _runtimeCache; + private readonly IGlobalSettings _globalSettings; private readonly ProfilingLogger _logger; private readonly object _typesLock = new object(); @@ -45,11 +46,13 @@ namespace Umbraco.Core.Composing /// Initializes a new instance of the class. /// /// The application runtime cache. + /// /// A profiling logger. /// Whether to detect changes using hashes. - internal TypeLoader(IRuntimeCacheProvider runtimeCache, ProfilingLogger logger, bool detectChanges = true) + internal TypeLoader(IRuntimeCacheProvider runtimeCache, IGlobalSettings globalSettings, ProfilingLogger logger, bool detectChanges = true) { _runtimeCache = runtimeCache ?? throw new ArgumentNullException(nameof(runtimeCache)); + _globalSettings = globalSettings ?? throw new ArgumentNullException(nameof(globalSettings)); _logger = logger ?? throw new ArgumentNullException(nameof(logger)); if (detectChanges) @@ -354,17 +357,17 @@ namespace Umbraco.Core.Composing } // internal for tests - internal static string GetTypesListFilePath() => GetFileBasePath() + ".list"; + internal string GetTypesListFilePath() => GetFileBasePath() + ".list"; - private static string GetTypesHashFilePath() => GetFileBasePath() + ".hash"; + private string GetTypesHashFilePath() => GetFileBasePath() + ".hash"; - private static string GetFileBasePath() + private string GetFileBasePath() { - var localTempStorage = GlobalSettings.LocalTempStorageLocation; + var localTempStorage = _globalSettings.LocalTempStorageLocation; if (_localTempStorage != localTempStorage) { string path; - switch (GlobalSettings.LocalTempStorageLocation) + switch (_globalSettings.LocalTempStorageLocation) { case LocalTempStorage.AspNetTemp: path = Path.Combine(HttpRuntime.CodegenDir, "UmbracoData", "umbraco-types"); @@ -398,38 +401,38 @@ namespace Umbraco.Core.Composing return _fileBasePath; } - private static string GetFilePath(string extension) - { - string path; - switch (GlobalSettings.LocalTempStorageLocation) - { - case LocalTempStorage.AspNetTemp: - path = Path.Combine(HttpRuntime.CodegenDir, "UmbracoData", "umbraco-types." + extension); - break; - case LocalTempStorage.EnvironmentTemp: - // include the appdomain hash is just a safety check, for example if a website is moved from worker A to worker B and then back - // to worker A again, in theory the %temp% folder should already be empty but we really want to make sure that its not - // utilizing an old path - assuming we cannot have SHA1 collisions on AppDomainAppId - var appDomainHash = HttpRuntime.AppDomainAppId.ToSHA1(); - var cachePath = Path.Combine(Environment.ExpandEnvironmentVariables("%temp%"), "UmbracoData", appDomainHash); - path = Path.Combine(cachePath, "umbraco-types." + extension); - break; - case LocalTempStorage.Default: - default: - var tempFolder = IOHelper.MapPath("~/App_Data/TEMP/TypesCache"); - path = Path.Combine(tempFolder, "umbraco-types." + NetworkHelper.FileSafeMachineName + "." + extension); - break; - } + //private string GetFilePath(string extension) + //{ + // string path; + // switch (_globalSettings.LocalTempStorageLocation) + // { + // case LocalTempStorage.AspNetTemp: + // path = Path.Combine(HttpRuntime.CodegenDir, "UmbracoData", "umbraco-types." + extension); + // break; + // case LocalTempStorage.EnvironmentTemp: + // // include the appdomain hash is just a safety check, for example if a website is moved from worker A to worker B and then back + // // to worker A again, in theory the %temp% folder should already be empty but we really want to make sure that its not + // // utilizing an old path - assuming we cannot have SHA1 collisions on AppDomainAppId + // var appDomainHash = HttpRuntime.AppDomainAppId.ToSHA1(); + // var cachePath = Path.Combine(Environment.ExpandEnvironmentVariables("%temp%"), "UmbracoData", appDomainHash); + // path = Path.Combine(cachePath, "umbraco-types." + extension); + // break; + // case LocalTempStorage.Default: + // default: + // var tempFolder = IOHelper.MapPath("~/App_Data/TEMP/TypesCache"); + // path = Path.Combine(tempFolder, "umbraco-types." + NetworkHelper.FileSafeMachineName + "." + extension); + // break; + // } - // ensure that the folder exists - var directory = Path.GetDirectoryName(path); - if (directory == null) - throw new InvalidOperationException($"Could not determine folder for file \"{path}\"."); - if (Directory.Exists(directory) == false) - Directory.CreateDirectory(directory); + // // ensure that the folder exists + // var directory = Path.GetDirectoryName(path); + // if (directory == null) + // throw new InvalidOperationException($"Could not determine folder for file \"{path}\"."); + // if (Directory.Exists(directory) == false) + // Directory.CreateDirectory(directory); - return path; - } + // return path; + //} // internal for tests internal void WriteCache() diff --git a/src/Umbraco.Core/Configuration/GlobalSettings.cs b/src/Umbraco.Core/Configuration/GlobalSettings.cs index 060ecf5d17..5ce9dd0a35 100644 --- a/src/Umbraco.Core/Configuration/GlobalSettings.cs +++ b/src/Umbraco.Core/Configuration/GlobalSettings.cs @@ -1,12 +1,10 @@ using System; -using System.Collections.Generic; using System.Configuration; using System.Linq; using System.Net.Configuration; using System.Web; using System.Web.Configuration; using System.Web.Hosting; -using System.Web.Routing; using System.Web.Security; using System.Xml; using System.Xml.Linq; @@ -18,36 +16,22 @@ using Umbraco.Core.Security; namespace Umbraco.Core.Configuration { - //NOTE: Do not expose this class ever until we cleanup all configuration including removal of static classes, etc... - // we have this two tasks logged: - // http://issues.umbraco.org/issue/U4-58 - // http://issues.umbraco.org/issue/U4-115 - - // TODO: There's a current task and branch to refactor this into interfaces and proper config: http://issues.umbraco.org/issue/U4-8861 - // PR https://github.com/umbraco/Umbraco-CMS/compare/dev-v8...temp-U4-8861?expand=1 - //TODO: Replace checking for if the app settings exist and returning an empty string, instead return the defaults! /// /// The GlobalSettings Class contains general settings information for the entire Umbraco instance based on information from web.config appsettings /// - [Obsolete("TODO: Need to move this configuration class into the proper configuration accesors for v8!")] - public class GlobalSettings + public class GlobalSettings : IGlobalSettings { #region Private static fields - private static Version _version; - private static readonly object Locker = new object(); - //make this volatile so that we can ensure thread safety with a double check lock - private static volatile string _reservedUrlsCache; - private static string _reservedPathsCache; - private static HashSet _reservedList = new HashSet(); + private static string _reservedPaths; private static string _reservedUrls; //ensure the built on (non-changeable) reserved paths are there at all times - private const string StaticReservedPaths = "~/app_plugins/,~/install/,"; - private const string StaticReservedUrls = "~/config/splashes/booting.aspx,~/config/splashes/noNodes.aspx,~/VSEnterpriseHelper.axd,"; + internal const string StaticReservedPaths = "~/app_plugins/,~/install/,"; + internal const string StaticReservedUrls = "~/config/splashes/booting.aspx,~/config/splashes/noNodes.aspx,~/VSEnterpriseHelper.axd,"; #endregion /// @@ -55,7 +39,7 @@ namespace Umbraco.Core.Configuration /// private static void ResetInternal() { - _reservedUrlsCache = null; + GlobalSettingsExtensions.Reset(); _reservedPaths = null; _reservedUrls = null; HasSmtpServer = null; @@ -69,7 +53,8 @@ namespace Umbraco.Core.Configuration { ResetInternal(); } - + + //fixme should this go on the interface or some other helper? public static bool HasSmtpServerConfigured(string appPath) { if (HasSmtpServer.HasValue) return HasSmtpServer.Value; @@ -93,15 +78,15 @@ namespace Umbraco.Core.Configuration /// Gets the reserved urls from web.config. /// /// The reserved urls. - public static string ReservedUrls + public string ReservedUrls { get - { + { if (_reservedUrls == null) { var urls = ConfigurationManager.AppSettings.ContainsKey("umbracoReservedUrls") - ? ConfigurationManager.AppSettings["umbracoReservedUrls"] - : string.Empty; + ? ConfigurationManager.AppSettings["umbracoReservedUrls"] + : string.Empty; //ensure the built on (non-changeable) reserved paths are there at all times _reservedUrls = StaticReservedUrls + urls; @@ -115,7 +100,7 @@ namespace Umbraco.Core.Configuration /// Gets the reserved paths from web.config /// /// The reserved paths. - public static string ReservedPaths + public string ReservedPaths { get { @@ -137,7 +122,6 @@ namespace Umbraco.Core.Configuration } return _reservedPaths; } - internal set { _reservedPaths = value; } } /// @@ -147,7 +131,7 @@ namespace Umbraco.Core.Configuration /// /// Defaults to ~/App_Data/umbraco.config /// - public static string ContentXmlFile + public string ContentXmlFile { get { @@ -156,26 +140,12 @@ namespace Umbraco.Core.Configuration : "~/App_Data/umbraco.config"; } } - - /// - /// Gets the path to the storage directory (/data by default). - /// - /// The storage directory. - public static string StorageDirectory - { - get - { - return ConfigurationManager.AppSettings.ContainsKey("umbracoStorageDirectory") - ? ConfigurationManager.AppSettings["umbracoStorageDirectory"] - : "~/App_Data"; - } - } - + /// /// Gets the path to umbraco's root directory (/umbraco by default). /// /// The path. - public static string Path + public string Path { get { @@ -183,56 +153,13 @@ namespace Umbraco.Core.Configuration ? IOHelper.ResolveUrl(ConfigurationManager.AppSettings["umbracoPath"]) : string.Empty; } - } - - /// - /// This returns the string of the MVC Area route. - /// - /// - /// THIS IS TEMPORARY AND SHOULD BE REMOVED WHEN WE MIGRATE/UPDATE THE CONFIG SETTINGS TO BE A REAL CONFIG SECTION - /// AND SHOULD PROBABLY BE HANDLED IN A MORE ROBUST WAY. - /// - /// This will return the MVC area that we will route all custom routes through like surface controllers, etc... - /// We will use the 'Path' (default ~/umbraco) to create it but since it cannot contain '/' and people may specify a path of ~/asdf/asdf/admin - /// we will convert the '/' to '-' and use that as the path. its a bit lame but will work. - /// - /// We also make sure that the virtual directory (SystemDirectories.Root) is stripped off first, otherwise we'd end up with something - /// like "MyVirtualDirectory-Umbraco" instead of just "Umbraco". - /// - public static string UmbracoMvcArea - { - get - { - if (Path.IsNullOrWhiteSpace()) - { - throw new InvalidOperationException("Cannot create an MVC Area path without the umbracoPath specified"); - } - var path = Path; - if (path.StartsWith(SystemDirectories.Root)) // beware of TrimStart, see U4-2518 - path = path.Substring(SystemDirectories.Root.Length); - return path.TrimStart('~').TrimStart('/').Replace('/', '-').Trim().ToLower(); - } - } - - /// - /// Gets the path to umbraco's client directory (/umbraco_client by default). - /// This is a relative path to the Umbraco Path as it always must exist beside the 'umbraco' - /// folder since the CSS paths to images depend on it. - /// - /// The path. - public static string ClientPath - { - get - { - return Path + "/../umbraco_client"; - } - } + } /// /// Gets or sets the configuration status. This will return the version number of the currently installed umbraco instance. /// /// The configuration status. - public static string ConfigurationStatus + public string ConfigurationStatus { get { @@ -245,39 +172,7 @@ namespace Umbraco.Core.Configuration SaveSetting("umbracoConfigurationStatus", value); } } - - /// - /// Gets or sets the Umbraco members membership providers' useLegacyEncoding state. This will return a boolean - /// - /// The useLegacyEncoding status. - public static bool UmbracoMembershipProviderLegacyEncoding - { - get - { - return IsConfiguredMembershipProviderUsingLegacyEncoding(Constants.Conventions.Member.UmbracoMemberProviderName); - } - set - { - SetMembershipProvidersLegacyEncoding(Constants.Conventions.Member.UmbracoMemberProviderName, value); - } - } - - /// - /// Gets or sets the Umbraco users membership providers' useLegacyEncoding state. This will return a boolean - /// - /// The useLegacyEncoding status. - public static bool UmbracoUsersMembershipProviderLegacyEncoding - { - get - { - return IsConfiguredMembershipProviderUsingLegacyEncoding(UmbracoConfig.For.UmbracoSettings().Providers.DefaultBackOfficeUserProvider); - } - set - { - SetMembershipProvidersLegacyEncoding(UmbracoConfig.For.UmbracoSettings().Providers.DefaultBackOfficeUserProvider, value); - } - } - + /// /// Saves a setting into the configuration file. /// @@ -320,64 +215,15 @@ namespace Umbraco.Core.Configuration ConfigurationManager.RefreshSection("appSettings"); } } - - private static void SetMembershipProvidersLegacyEncoding(string providerName, bool useLegacyEncoding) - { - //check if this can even be configured. - var membershipProvider = Membership.Providers[providerName] as MembershipProviderBase; - if (membershipProvider == null) - { - return; - } - if (membershipProvider.GetType().Namespace == "umbraco.providers.members") - { - //its the legacy one, this cannot be changed - return; - } - - var webConfigFilename = IOHelper.MapPath(string.Format("{0}/web.config", SystemDirectories.Root)); - var webConfigXml = XDocument.Load(webConfigFilename, LoadOptions.PreserveWhitespace); - - var membershipConfigs = webConfigXml.XPathSelectElements("configuration/system.web/membership/providers/add").ToList(); - - if (membershipConfigs.Any() == false) - return; - - var provider = membershipConfigs.SingleOrDefault(c => c.Attribute("name") != null && c.Attribute("name").Value == providerName); - - if (provider == null) - return; - - provider.SetAttributeValue("useLegacyEncoding", useLegacyEncoding); - - webConfigXml.Save(webConfigFilename, SaveOptions.DisableFormatting); - } - - private static bool IsConfiguredMembershipProviderUsingLegacyEncoding(string providerName) - { - //check if this can even be configured. - var membershipProvider = Membership.Providers[providerName] as MembershipProviderBase; - if (membershipProvider == null) - { - return false; - } - - return membershipProvider.UseLegacyEncoding; - } - - /// - /// Gets the full path to root. - /// - /// The fullpath to root. - public static string FullpathToRoot - { - get { return IOHelper.GetRootDirectorySafe(); } - } + + [Obsolete("Use IOHelper.GetRootDirectorySafe() instead")] + public static string FullPathToRoot => IOHelper.GetRootDirectorySafe(); /// /// Gets a value indicating whether umbraco is running in [debug mode]. /// /// true if [debug mode]; otherwise, false. + //fixme surely thsi doesn't belong here and it's also a web request context thing public static bool DebugMode { get @@ -403,7 +249,7 @@ namespace Umbraco.Core.Configuration /// Gets the time out in minutes. /// /// The time out in minutes. - public static int TimeOutInMinutes + public int TimeOutInMinutes { get { @@ -422,7 +268,7 @@ namespace Umbraco.Core.Configuration /// Gets a value indicating whether umbraco uses directory urls. /// /// true if umbraco uses directory urls; otherwise, false. - public static bool UseDirectoryUrls + public bool UseDirectoryUrls { get { @@ -441,7 +287,7 @@ namespace Umbraco.Core.Configuration /// Returns a string value to determine if umbraco should skip version-checking. /// /// The version check period in days (0 = never). - public static int VersionCheckPeriod + public int VersionCheckPeriod { get { @@ -455,34 +301,14 @@ namespace Umbraco.Core.Configuration } } } - - /// - /// Returns a string value to determine if umbraco should disbable xslt extensions - /// - /// "true" if version xslt extensions are disabled, otherwise, "false" - [Obsolete("This is no longer used and will be removed from the codebase in future releases")] - public static string DisableXsltExtensions - { - get - { - return ConfigurationManager.AppSettings.ContainsKey("umbracoDisableXsltExtensions") - ? ConfigurationManager.AppSettings["umbracoDisableXsltExtensions"] - : "false"; - } - } - - internal static bool ContentCacheXmlStoredInCodeGen - { - get { return LocalTempStorageLocation == LocalTempStorage.AspNetTemp; } - } - + /// /// This is the location type to store temporary files such as cache files or other localized files for a given machine /// /// /// Currently used for the xml cache file and the plugin cache files /// - internal static LocalTempStorage LocalTempStorageLocation + public LocalTempStorage LocalTempStorageLocation { get { @@ -494,21 +320,12 @@ namespace Umbraco.Core.Configuration } } - /// - /// Returns a string value to determine if umbraco should use Xhtml editing mode in the wysiwyg editor - /// - /// "true" if Xhtml mode is enable, otherwise, "false" - [Obsolete("This is no longer used and will be removed from the codebase in future releases")] - public static string EditXhtmlMode - { - get { return "true"; } - } - /// /// Gets the default UI language. /// /// The default UI language. - public static string DefaultUILanguage + // ReSharper disable once InconsistentNaming + public string DefaultUILanguage { get { @@ -518,28 +335,13 @@ namespace Umbraco.Core.Configuration } } - /// - /// Gets the profile URL. - /// - /// The profile URL. - public static string ProfileUrl - { - get - { - //the default will be 'profiler' - return ConfigurationManager.AppSettings.ContainsKey("umbracoProfileUrl") - ? ConfigurationManager.AppSettings["umbracoProfileUrl"] - : "profiler"; - } - } - /// /// Gets a value indicating whether umbraco should hide top level nodes from generated urls. /// /// /// true if umbraco hides top level nodes from urls; otherwise, false. /// - public static bool HideTopLevelNodeFromPath + public bool HideTopLevelNodeFromPath { get { @@ -554,95 +356,16 @@ namespace Umbraco.Core.Configuration } } - /// - /// Gets the current version. - /// - /// The current version. - [Obsolete("Use Umbraco.Core.Configuration.UmbracoVersion.Current instead", false)] - public static string CurrentVersion - { - get { return UmbracoVersion.SemanticVersion.ToSemanticString(); } - } - - /// - /// Gets the major version number. - /// - /// The major version number. - [Obsolete("Use Umbraco.Core.Configuration.UmbracoVersion.Current instead", false)] - public static int VersionMajor - { - get - { - return UmbracoVersion.Current.Major; - } - } - - /// - /// Gets the minor version number. - /// - /// The minor version number. - [Obsolete("Use Umbraco.Core.Configuration.UmbracoVersion.Current instead", false)] - public static int VersionMinor - { - get - { - return UmbracoVersion.Current.Minor; - } - } - - /// - /// Gets the patch version number. - /// - /// The patch version number. - [Obsolete("Use Umbraco.Core.Configuration.UmbracoVersion.Current instead", false)] - public static int VersionPatch - { - get - { - return UmbracoVersion.Current.Build; - } - } - - /// - /// Gets the version comment (like beta or RC). - /// - /// The version comment. - [Obsolete("Use Umbraco.Core.Configuration.UmbracoVersion.Current instead", false)] - public static string VersionComment - { - get - { - return Umbraco.Core.Configuration.UmbracoVersion.CurrentComment; - } - } - - - /// - /// Requests the is in umbraco application directory structure. - /// - /// The context. - /// - public static bool RequestIsInUmbracoApplication(HttpContext context) - { - return context.Request.Path.ToLower().IndexOf(IOHelper.ResolveUrl(SystemDirectories.Umbraco).ToLower()) > -1; - } - - public static bool RequestIsInUmbracoApplication(HttpContextBase context) - { - return context.Request.Path.ToLower().IndexOf(IOHelper.ResolveUrl(SystemDirectories.Umbraco).ToLower()) > -1; - } - /// /// Gets a value indicating whether umbraco should force a secure (https) connection to the backoffice. /// - /// true if [use SSL]; otherwise, false. - public static bool UseSSL + public bool UseHttps { get { try { - return bool.Parse(ConfigurationManager.AppSettings["umbracoUseSSL"]); + return bool.Parse(ConfigurationManager.AppSettings["umbracoUseHttps"]); } catch { @@ -651,131 +374,6 @@ namespace Umbraco.Core.Configuration } } - /// - /// Gets the umbraco license. - /// - /// The license. - public static string License - { - get - { - string license = - "the open source license MIT. The umbraco UI is freeware licensed under the umbraco license."; - - var versionDoc = new XmlDocument(); - var versionReader = new XmlTextReader(IOHelper.MapPath(SystemDirectories.Umbraco + "/version.xml")); - versionDoc.Load(versionReader); - versionReader.Close(); - - // check for license - try - { - string licenseUrl = - versionDoc.SelectSingleNode("/version/licensing/licenseUrl").FirstChild.Value; - string licenseValidation = - versionDoc.SelectSingleNode("/version/licensing/licenseValidation").FirstChild.Value; - string licensedTo = - versionDoc.SelectSingleNode("/version/licensing/licensedTo").FirstChild.Value; - - if (licensedTo != "" && licenseUrl != "") - { - license = "umbraco Commercial License
Registered to:
" + - licensedTo.Replace("\n", "
") + "
For use with domain:
" + - licenseUrl; - } - } - catch - { - } - - return license; - } - } - - /// - /// Determines whether the current request is reserved based on the route table and - /// whether the specified URL is reserved or is inside a reserved path. - /// - /// - /// - /// The route collection to lookup the request in - /// - public static bool IsReservedPathOrUrl(string url, HttpContextBase httpContext, RouteCollection routes) - { - if (httpContext == null) throw new ArgumentNullException("httpContext"); - if (routes == null) throw new ArgumentNullException("routes"); - - //check if the current request matches a route, if so then it is reserved. - var route = routes.GetRouteData(httpContext); - if (route != null) - return true; - - //continue with the standard ignore routine - return IsReservedPathOrUrl(url); - } - - /// - /// Determines whether the specified URL is reserved or is inside a reserved path. - /// - /// The URL to check. - /// - /// true if the specified URL is reserved; otherwise, false. - /// - public static bool IsReservedPathOrUrl(string url) - { - if (_reservedUrlsCache == null) - { - lock (Locker) - { - if (_reservedUrlsCache == null) - { - // store references to strings to determine changes - _reservedPathsCache = GlobalSettings.ReservedPaths; - _reservedUrlsCache = GlobalSettings.ReservedUrls; - - // add URLs and paths to a new list - var newReservedList = new HashSet(); - foreach (var reservedUrlTrimmed in _reservedUrlsCache - .Split(new[] {","}, StringSplitOptions.RemoveEmptyEntries) - .Select(x => x.Trim().ToLowerInvariant()) - .Where(x => x.IsNullOrWhiteSpace() == false) - .Select(reservedUrl => IOHelper.ResolveUrl(reservedUrl).Trim().EnsureStartsWith("/")) - .Where(reservedUrlTrimmed => reservedUrlTrimmed.IsNullOrWhiteSpace() == false)) - { - newReservedList.Add(reservedUrlTrimmed); - } - - foreach (var reservedPathTrimmed in _reservedPathsCache - .Split(new[] {","}, StringSplitOptions.RemoveEmptyEntries) - .Select(x => x.Trim().ToLowerInvariant()) - .Where(x => x.IsNullOrWhiteSpace() == false) - .Select(reservedPath => IOHelper.ResolveUrl(reservedPath).Trim().EnsureStartsWith("/").EnsureEndsWith("/")) - .Where(reservedPathTrimmed => reservedPathTrimmed.IsNullOrWhiteSpace() == false)) - { - newReservedList.Add(reservedPathTrimmed); - } - - // use the new list from now on - _reservedList = newReservedList; - } - } - } - - //The url should be cleaned up before checking: - // * If it doesn't contain an '.' in the path then we assume it is a path based URL, if that is the case we should add an trailing '/' because all of our reservedPaths use a trailing '/' - // * We shouldn't be comparing the query at all - var pathPart = url.Split(new[] {'?'}, StringSplitOptions.RemoveEmptyEntries)[0].ToLowerInvariant(); - if (pathPart.Contains(".") == false) - { - pathPart = pathPart.EnsureEndsWith('/'); - } - - // return true if url starts with an element of the reserved list - return _reservedList.Any(x => pathPart.InvariantStartsWith(x)); - } - - - } diff --git a/src/Umbraco.Core/Configuration/GlobalSettingsExtensions.cs b/src/Umbraco.Core/Configuration/GlobalSettingsExtensions.cs new file mode 100644 index 0000000000..1e37ae0668 --- /dev/null +++ b/src/Umbraco.Core/Configuration/GlobalSettingsExtensions.cs @@ -0,0 +1,141 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Web; +using System.Web.Routing; +using Umbraco.Core.IO; + +namespace Umbraco.Core.Configuration +{ + public static class GlobalSettingsExtensions + { + /// + /// Used in unit testing to reset all config items, this is automatically called by GlobalSettings.Reset() + /// + internal static void Reset() + { + _reservedUrlsCache = null; + _mvcArea = null; + } + + private static readonly object Locker = new object(); + //make this volatile so that we can ensure thread safety with a double check lock + private static volatile string _reservedUrlsCache; + private static string _reservedPathsCache; + private static HashSet _reservedList = new HashSet(); + private static string _mvcArea; + + /// + /// This returns the string of the MVC Area route. + /// + /// + /// This will return the MVC area that we will route all custom routes through like surface controllers, etc... + /// We will use the 'Path' (default ~/umbraco) to create it but since it cannot contain '/' and people may specify a path of ~/asdf/asdf/admin + /// we will convert the '/' to '-' and use that as the path. its a bit lame but will work. + /// + /// We also make sure that the virtual directory (SystemDirectories.Root) is stripped off first, otherwise we'd end up with something + /// like "MyVirtualDirectory-Umbraco" instead of just "Umbraco". + /// + public static string GetUmbracoMvcArea(this IGlobalSettings globalSettings) + { + if (_mvcArea != null) return _mvcArea; + + if (globalSettings.Path.IsNullOrWhiteSpace()) + { + throw new InvalidOperationException("Cannot create an MVC Area path without the umbracoPath specified"); + } + + var path = globalSettings.Path; + if (path.StartsWith(SystemDirectories.Root)) // beware of TrimStart, see U4-2518 + path = path.Substring(SystemDirectories.Root.Length); + _mvcArea = path.TrimStart('~').TrimStart('/').Replace('/', '-').Trim().ToLower(); + return _mvcArea; + } + + /// + /// Determines whether the specified URL is reserved or is inside a reserved path. + /// + /// + /// The URL to check. + /// + /// true if the specified URL is reserved; otherwise, false. + /// + internal static bool IsReservedPathOrUrl(this IGlobalSettings globalSettings, string url) + { + if (_reservedUrlsCache == null) + { + lock (Locker) + { + if (_reservedUrlsCache == null) + { + // store references to strings to determine changes + _reservedPathsCache = globalSettings.ReservedPaths; + _reservedUrlsCache = globalSettings.ReservedUrls; + + // add URLs and paths to a new list + var newReservedList = new HashSet(); + foreach (var reservedUrlTrimmed in _reservedUrlsCache + .Split(new[] {","}, StringSplitOptions.RemoveEmptyEntries) + .Select(x => x.Trim().ToLowerInvariant()) + .Where(x => x.IsNullOrWhiteSpace() == false) + .Select(reservedUrl => IOHelper.ResolveUrl(reservedUrl).Trim().EnsureStartsWith("/")) + .Where(reservedUrlTrimmed => reservedUrlTrimmed.IsNullOrWhiteSpace() == false)) + { + newReservedList.Add(reservedUrlTrimmed); + } + + foreach (var reservedPathTrimmed in _reservedPathsCache + .Split(new[] {","}, StringSplitOptions.RemoveEmptyEntries) + .Select(x => x.Trim().ToLowerInvariant()) + .Where(x => x.IsNullOrWhiteSpace() == false) + .Select(reservedPath => IOHelper.ResolveUrl(reservedPath).Trim().EnsureStartsWith("/").EnsureEndsWith("/")) + .Where(reservedPathTrimmed => reservedPathTrimmed.IsNullOrWhiteSpace() == false)) + { + newReservedList.Add(reservedPathTrimmed); + } + + // use the new list from now on + _reservedList = newReservedList; + } + } + } + + //The url should be cleaned up before checking: + // * If it doesn't contain an '.' in the path then we assume it is a path based URL, if that is the case we should add an trailing '/' because all of our reservedPaths use a trailing '/' + // * We shouldn't be comparing the query at all + var pathPart = url.Split(new[] {'?'}, StringSplitOptions.RemoveEmptyEntries)[0].ToLowerInvariant(); + if (pathPart.Contains(".") == false) + { + pathPart = pathPart.EnsureEndsWith('/'); + } + + // return true if url starts with an element of the reserved list + return _reservedList.Any(x => pathPart.InvariantStartsWith(x)); + } + + /// + /// Determines whether the current request is reserved based on the route table and + /// whether the specified URL is reserved or is inside a reserved path. + /// + /// + /// + /// + /// The route collection to lookup the request in + /// + internal static bool IsReservedPathOrUrl(this IGlobalSettings globalSettings, string url, HttpContextBase httpContext, RouteCollection routes) + { + if (httpContext == null) throw new ArgumentNullException(nameof(httpContext)); + if (routes == null) throw new ArgumentNullException(nameof(routes)); + + //check if the current request matches a route, if so then it is reserved. + var route = routes.GetRouteData(httpContext); + if (route != null) + return true; + + //continue with the standard ignore routine + return globalSettings.IsReservedPathOrUrl(url); + } + + + } +} diff --git a/src/Umbraco.Core/Configuration/IGlobalSettings.cs b/src/Umbraco.Core/Configuration/IGlobalSettings.cs new file mode 100644 index 0000000000..cf9478d30a --- /dev/null +++ b/src/Umbraco.Core/Configuration/IGlobalSettings.cs @@ -0,0 +1,84 @@ +namespace Umbraco.Core.Configuration +{ + /// + /// Contains general settings information for the entire Umbraco instance based on information from web.config appsettings + /// + public interface IGlobalSettings + { + /// + /// Gets the reserved urls from web.config. + /// + /// The reserved urls. + string ReservedUrls { get; } + + /// + /// Gets the reserved paths from web.config + /// + /// The reserved paths. + string ReservedPaths { get; } + + /// + /// Gets the name of the content XML file. + /// + /// The content XML. + /// + /// Defaults to ~/App_Data/umbraco.config + /// + string ContentXmlFile { get; } + + /// + /// Gets the path to umbraco's root directory (/umbraco by default). + /// + string Path { get; } + + /// + /// Gets or sets the configuration status. This will return the version number of the currently installed umbraco instance. + /// + string ConfigurationStatus { get; set; } + + /// + /// Gets the time out in minutes. + /// + int TimeOutInMinutes { get; } + + /// + /// Gets a value indicating whether umbraco uses directory urls. + /// + /// true if umbraco uses directory urls; otherwise, false. + bool UseDirectoryUrls { get; } + + /// + /// Gets the default UI language. + /// + /// The default UI language. + // ReSharper disable once InconsistentNaming + string DefaultUILanguage { get; } + + /// + /// Gets a value indicating whether umbraco should hide top level nodes from generated urls. + /// + /// + /// true if umbraco hides top level nodes from urls; otherwise, false. + /// + bool HideTopLevelNodeFromPath { get; } + + /// + /// Gets a value indicating whether umbraco should force a secure (https) connection to the backoffice. + /// + bool UseHttps { get; } + + /// + /// Returns a string value to determine if umbraco should skip version-checking. + /// + /// The version check period in days (0 = never). + int VersionCheckPeriod { get; } + + /// + /// This is the location type to store temporary files such as cache files or other localized files for a given machine + /// + /// + /// Used for some cache files and for specific environments such as Azure + /// + LocalTempStorage LocalTempStorageLocation { get; } + } +} diff --git a/src/Umbraco.Core/Configuration/LocalTempStorage.cs b/src/Umbraco.Core/Configuration/LocalTempStorage.cs index 1231ee7156..0013fb68e4 100644 --- a/src/Umbraco.Core/Configuration/LocalTempStorage.cs +++ b/src/Umbraco.Core/Configuration/LocalTempStorage.cs @@ -1,6 +1,6 @@ namespace Umbraco.Core.Configuration { - internal enum LocalTempStorage + public enum LocalTempStorage { Unknown = 0, Default, diff --git a/src/Umbraco.Core/Configuration/UmbracoConfig.cs b/src/Umbraco.Core/Configuration/UmbracoConfig.cs index 6daa9f6f6f..f16faab06e 100644 --- a/src/Umbraco.Core/Configuration/UmbracoConfig.cs +++ b/src/Umbraco.Core/Configuration/UmbracoConfig.cs @@ -65,17 +65,20 @@ namespace Umbraco.Core.Configuration /// /// /// - public UmbracoConfig(IUmbracoSettingsSection umbracoSettings, IDashboardSection dashboardSettings, IHealthChecks healthChecks) + /// + public UmbracoConfig(IUmbracoSettingsSection umbracoSettings, IDashboardSection dashboardSettings, IHealthChecks healthChecks, IGlobalSettings globalSettings) { SetHealthCheckSettings(healthChecks); SetUmbracoSettings(umbracoSettings); SetDashboardSettings(dashboardSettings); + SetGlobalConfig(globalSettings); } private IHealthChecks _healthChecks; private IDashboardSection _dashboardSection; private IUmbracoSettingsSection _umbracoSettings; private IGridConfig _gridConfig; + private IGlobalSettings _globalSettings; /// /// Gets the IHealthCheck config @@ -134,6 +137,23 @@ namespace Umbraco.Core.Configuration _umbracoSettings = value; } + /// + /// Only for testing + /// + /// + public void SetGlobalConfig(IGlobalSettings value) + { + _globalSettings = value; + } + + /// + /// Gets the IGlobalSettings + /// + public IGlobalSettings GlobalSettings() + { + return _globalSettings ?? (_globalSettings = new GlobalSettings()); + } + /// /// Gets the IUmbracoSettings /// diff --git a/src/Umbraco.Core/Constants-Web.cs b/src/Umbraco.Core/Constants-Web.cs index ec06b742da..a5f140ddba 100644 --- a/src/Umbraco.Core/Constants-Web.cs +++ b/src/Umbraco.Core/Constants-Web.cs @@ -21,6 +21,8 @@ namespace Umbraco.Core /// public const string PreviewCookieName = "UMB_PREVIEW"; + public const string InstallerCookieName = "umb_installId"; + /// /// The auth cookie name /// diff --git a/src/Umbraco.Core/IO/SystemDirectories.cs b/src/Umbraco.Core/IO/SystemDirectories.cs index d9f0eba841..7d3bfd3ae0 100644 --- a/src/Umbraco.Core/IO/SystemDirectories.cs +++ b/src/Umbraco.Core/IO/SystemDirectories.cs @@ -1,4 +1,5 @@ -using System.Web; +using System; +using System.Web; namespace Umbraco.Core.IO { @@ -66,9 +67,11 @@ namespace Umbraco.Core.IO if (_root != null) return _root; var appPath = HttpRuntime.AppDomainAppVirtualPath; - if (appPath == "/") appPath = string.Empty; + // ReSharper disable once ConditionIsAlwaysTrueOrFalse + if (appPath == null || appPath == "/") appPath = string.Empty; _root = appPath; + return _root; } //Only required for unit tests diff --git a/src/Umbraco.Core/IO/SystemFiles.cs b/src/Umbraco.Core/IO/SystemFiles.cs index 20b7bf6a3e..a0ca748cd6 100644 --- a/src/Umbraco.Core/IO/SystemFiles.cs +++ b/src/Umbraco.Core/IO/SystemFiles.cs @@ -18,27 +18,24 @@ namespace Umbraco.Core.IO public static string FeedProxyConfig => string.Concat(SystemDirectories.Config, "/feedProxy.config"); // fixme - kill - public static string ContentCacheXml + public static string GetContentCacheXml(IGlobalSettings globalSettings) { - get + switch (globalSettings.LocalTempStorageLocation) { - switch (GlobalSettings.LocalTempStorageLocation) - { - case LocalTempStorage.AspNetTemp: - return Path.Combine(HttpRuntime.CodegenDir, @"UmbracoData\umbraco.config"); - case LocalTempStorage.EnvironmentTemp: - var appDomainHash = HttpRuntime.AppDomainAppId.ToSHA1(); - var cachePath = Path.Combine(Environment.ExpandEnvironmentVariables("%temp%"), "UmbracoData", - //include the appdomain hash is just a safety check, for example if a website is moved from worker A to worker B and then back - // to worker A again, in theory the %temp% folder should already be empty but we really want to make sure that its not - // utilizing an old path - appDomainHash); - return Path.Combine(cachePath, "umbraco.config"); - case LocalTempStorage.Default: - return IOHelper.ReturnPath("umbracoContentXML", "~/App_Data/umbraco.config"); - default: - throw new ArgumentOutOfRangeException(); - } + case LocalTempStorage.AspNetTemp: + return Path.Combine(HttpRuntime.CodegenDir, @"UmbracoData\umbraco.config"); + case LocalTempStorage.EnvironmentTemp: + var appDomainHash = HttpRuntime.AppDomainAppId.ToSHA1(); + var cachePath = Path.Combine(Environment.ExpandEnvironmentVariables("%temp%"), "UmbracoData", + //include the appdomain hash is just a safety check, for example if a website is moved from worker A to worker B and then back + // to worker A again, in theory the %temp% folder should already be empty but we really want to make sure that its not + // utilizing an old path + appDomainHash); + return Path.Combine(cachePath, "umbraco.config"); + case LocalTempStorage.Default: + return IOHelper.ReturnPath("umbracoContentXML", "~/App_Data/umbraco.config"); + default: + throw new ArgumentOutOfRangeException(); } } } diff --git a/src/Umbraco.Core/Migrations/Install/DatabaseBuilder.cs b/src/Umbraco.Core/Migrations/Install/DatabaseBuilder.cs index a4a4097e36..a3fd35df44 100644 --- a/src/Umbraco.Core/Migrations/Install/DatabaseBuilder.cs +++ b/src/Umbraco.Core/Migrations/Install/DatabaseBuilder.cs @@ -24,6 +24,7 @@ namespace Umbraco.Core.Migrations.Install { private readonly IUmbracoDatabaseFactory _databaseFactory; private readonly IScopeProvider _scopeProvider; + private readonly IGlobalSettings _globalSettings; private readonly IRuntimeState _runtime; private readonly IMigrationBuilder _migrationBuilder; private readonly IKeyValueService _keyValueService; @@ -32,9 +33,10 @@ namespace Umbraco.Core.Migrations.Install private DatabaseSchemaResult _databaseSchemaValidationResult; - public DatabaseBuilder(IScopeProvider scopeProvider, IUmbracoDatabaseFactory databaseFactory, IRuntimeState runtime, ILogger logger, IMigrationBuilder migrationBuilder, IKeyValueService keyValueService, PostMigrationCollection postMigrations) + public DatabaseBuilder(IScopeProvider scopeProvider, IGlobalSettings globalSettings, IUmbracoDatabaseFactory databaseFactory, IRuntimeState runtime, ILogger logger, IMigrationBuilder migrationBuilder, IKeyValueService keyValueService, PostMigrationCollection postMigrations) { _scopeProvider = scopeProvider; + _globalSettings = globalSettings; _databaseFactory = databaseFactory; _runtime = runtime; _logger = logger; @@ -132,7 +134,7 @@ namespace Umbraco.Core.Migrations.Install { SaveConnectionString(EmbeddedDatabaseConnectionString, Constants.DbProviderNames.SqlCe, logger); - var path = Path.Combine(GlobalSettings.FullpathToRoot, "App_Data", "Umbraco.sdf"); + var path = Path.Combine(GlobalSettings.FullPathToRoot, "App_Data", "Umbraco.sdf"); if (File.Exists(path) == false) { // this should probably be in a "using (new SqlCeEngine)" clause but not sure @@ -488,7 +490,7 @@ namespace Umbraco.Core.Migrations.Install var installedSchemaVersion = schemaResult.DetermineInstalledVersion(); //If Configuration Status is empty and the determined version is "empty" its a new install - otherwise upgrade the existing - if (string.IsNullOrEmpty(GlobalSettings.ConfigurationStatus) && installedSchemaVersion.Equals(new Version(0, 0, 0))) + if (string.IsNullOrEmpty(_globalSettings.ConfigurationStatus) && installedSchemaVersion.Equals(new Version(0, 0, 0))) { if (_runtime.Level == RuntimeLevel.Run) throw new Exception("Umbraco is already configured!"); diff --git a/src/Umbraco.Core/Models/Identity/BackOfficeIdentityUser.cs b/src/Umbraco.Core/Models/Identity/BackOfficeIdentityUser.cs index bd4905729d..75ed8238d0 100644 --- a/src/Umbraco.Core/Models/Identity/BackOfficeIdentityUser.cs +++ b/src/Umbraco.Core/Models/Identity/BackOfficeIdentityUser.cs @@ -6,6 +6,7 @@ using System.Linq; using System.Reflection; using System.Security.Claims; using System.Threading.Tasks; +using Umbraco.Core.Configuration; using Umbraco.Core.Models.Entities; using Umbraco.Core.Models.Membership; using Umbraco.Core.Security; @@ -64,7 +65,7 @@ namespace Umbraco.Core.Models.Identity _startContentIds = new int[] { }; _groups = new IReadOnlyUserGroup[] { }; _allowedSections = new string[] { }; - _culture = Configuration.GlobalSettings.DefaultUILanguage; + _culture = UmbracoConfig.For.GlobalSettings().DefaultUILanguage; //fixme inject somehow? _groups = new IReadOnlyUserGroup[0]; _roles = new ObservableCollection>(); _roles.CollectionChanged += _roles_CollectionChanged; @@ -81,7 +82,7 @@ namespace Umbraco.Core.Models.Identity _startContentIds = new int[] { }; _groups = new IReadOnlyUserGroup[] { }; _allowedSections = new string[] { }; - _culture = Configuration.GlobalSettings.DefaultUILanguage; + _culture = UmbracoConfig.For.GlobalSettings().DefaultUILanguage; //fixme inject somehow? _groups = groups.ToArray(); _roles = new ObservableCollection>(_groups.Select(x => new IdentityUserRole { diff --git a/src/Umbraco.Core/Models/Identity/IdentityProfile.cs b/src/Umbraco.Core/Models/Identity/IdentityProfile.cs index eef2a17aa5..f44003b62a 100644 --- a/src/Umbraco.Core/Models/Identity/IdentityProfile.cs +++ b/src/Umbraco.Core/Models/Identity/IdentityProfile.cs @@ -1,6 +1,7 @@ using System; using System.Linq; using AutoMapper; +using Umbraco.Core.Configuration; using Umbraco.Core.Models.Membership; using Umbraco.Core.Security; using Umbraco.Core.Services; @@ -9,7 +10,7 @@ namespace Umbraco.Core.Models.Identity { public class IdentityProfile : Profile { - public IdentityProfile(ILocalizedTextService textService, IEntityService entityService) + public IdentityProfile(ILocalizedTextService textService, IEntityService entityService, IGlobalSettings globalSettings) { CreateMap() .BeforeMap((src, dest) => @@ -25,7 +26,7 @@ namespace Umbraco.Core.Models.Identity .ForMember(dest => dest.IsApproved, opt => opt.MapFrom(src => src.IsApproved)) .ForMember(dest => dest.UserName, opt => opt.MapFrom(src => src.Username)) .ForMember(dest => dest.PasswordHash, opt => opt.MapFrom(user => GetPasswordHash(user.RawPasswordValue))) - .ForMember(dest => dest.Culture, opt => opt.MapFrom(src => src.GetUserCulture(textService))) + .ForMember(dest => dest.Culture, opt => opt.MapFrom(src => src.GetUserCulture(textService, globalSettings))) .ForMember(dest => dest.Name, opt => opt.MapFrom(src => src.Name)) .ForMember(dest => dest.StartMediaIds, opt => opt.MapFrom(src => src.StartMediaIds)) .ForMember(dest => dest.StartContentIds, opt => opt.MapFrom(src => src.StartContentIds)) diff --git a/src/Umbraco.Core/Models/Membership/User.cs b/src/Umbraco.Core/Models/Membership/User.cs index 2dd750a353..0e3ab70e0a 100644 --- a/src/Umbraco.Core/Models/Membership/User.cs +++ b/src/Umbraco.Core/Models/Membership/User.cs @@ -27,7 +27,7 @@ namespace Umbraco.Core.Models.Membership { SessionTimeout = 60; _userGroups = new HashSet(); - _language = GlobalSettings.DefaultUILanguage; + _language = UmbracoConfig.For.GlobalSettings().DefaultUILanguage; //fixme inject somehow? _isApproved = true; _isLockedOut = false; _startContentIds = new int[] { }; diff --git a/src/Umbraco.Core/Models/UserExtensions.cs b/src/Umbraco.Core/Models/UserExtensions.cs index f66f0b4ef7..f78de43f01 100644 --- a/src/Umbraco.Core/Models/UserExtensions.cs +++ b/src/Umbraco.Core/Models/UserExtensions.cs @@ -126,15 +126,16 @@ namespace Umbraco.Core.Models /// /// /// + /// /// - public static CultureInfo GetUserCulture(this IUser user, ILocalizedTextService textService) + public static CultureInfo GetUserCulture(this IUser user, ILocalizedTextService textService, IGlobalSettings globalSettings) { if (user == null) throw new ArgumentNullException(nameof(user)); if (textService == null) throw new ArgumentNullException(nameof(textService)); - return GetUserCulture(user.Language, textService); + return GetUserCulture(user.Language, textService, globalSettings); } - internal static CultureInfo GetUserCulture(string userLanguage, ILocalizedTextService textService) + internal static CultureInfo GetUserCulture(string userLanguage, ILocalizedTextService textService, IGlobalSettings globalSettings) { try { @@ -148,7 +149,7 @@ namespace Umbraco.Core.Models catch (CultureNotFoundException) { //return the default one - return CultureInfo.GetCultureInfo(GlobalSettings.DefaultUILanguage); + return CultureInfo.GetCultureInfo(globalSettings.DefaultUILanguage); } } diff --git a/src/Umbraco.Core/Packaging/PackageInstallation.cs b/src/Umbraco.Core/Packaging/PackageInstallation.cs index 9a62fe8b9a..2e33bfbf2b 100644 --- a/src/Umbraco.Core/Packaging/PackageInstallation.cs +++ b/src/Umbraco.Core/Packaging/PackageInstallation.cs @@ -25,7 +25,7 @@ namespace Umbraco.Core.Packaging public PackageInstallation(IPackagingService packagingService, IMacroService macroService, IFileService fileService, IPackageExtraction packageExtraction) - : this(packagingService, macroService, fileService, packageExtraction, GlobalSettings.FullpathToRoot) + : this(packagingService, macroService, fileService, packageExtraction, GlobalSettings.FullPathToRoot) {} public PackageInstallation(IPackagingService packagingService, IMacroService macroService, diff --git a/src/Umbraco.Core/Persistence/Repositories/Implement/UserRepository.cs b/src/Umbraco.Core/Persistence/Repositories/Implement/UserRepository.cs index 636c9fda69..05fe456bbd 100644 --- a/src/Umbraco.Core/Persistence/Repositories/Implement/UserRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/Implement/UserRepository.cs @@ -27,29 +27,33 @@ namespace Umbraco.Core.Persistence.Repositories.Implement internal class UserRepository : NPocoRepositoryBase, IUserRepository { private readonly IMapperCollection _mapperCollection; + private readonly IGlobalSettings _globalSettings; private string _passwordConfigJson; private bool _passwordConfigInitialized; /// /// Constructor /// - /// + /// /// /// - /// + /// /// A dictionary specifying the configuration for user passwords. If this is null then no password configuration will be persisted or read. /// - public UserRepository(IScopeAccessor scopeAccessor, CacheHelper cacheHelper, ILogger logger, IMapperCollection mapperCollection) + /// + public UserRepository(IScopeAccessor scopeAccessor, CacheHelper cacheHelper, ILogger logger, IMapperCollection mapperCollection, IGlobalSettings globalSettings) : base(scopeAccessor, cacheHelper, logger) { _mapperCollection = mapperCollection; + _globalSettings = globalSettings; } // for tests - internal UserRepository(IScopeAccessor scopeAccessor, CacheHelper cacheHelper, ILogger logger, IMapperCollection mapperCollection, IDictionary passwordConfig) + internal UserRepository(IScopeAccessor scopeAccessor, CacheHelper cacheHelper, ILogger logger, IMapperCollection mapperCollection, IDictionary passwordConfig, IGlobalSettings globalSettings) : base(scopeAccessor, cacheHelper, logger) { _mapperCollection = mapperCollection; + _globalSettings = globalSettings; _passwordConfigJson = JsonConvert.SerializeObject(passwordConfig); _passwordConfigInitialized = true; } @@ -192,7 +196,7 @@ ORDER BY colName"; return false; //now detect if there's been a timeout - if (DateTime.UtcNow - found.LastValidatedUtc > TimeSpan.FromMinutes(GlobalSettings.TimeOutInMinutes)) + if (DateTime.UtcNow - found.LastValidatedUtc > TimeSpan.FromMinutes(_globalSettings.TimeOutInMinutes)) { //timeout detected, update the record ClearLoginSession(sessionId); diff --git a/src/Umbraco.Core/Runtime/CoreRuntime.cs b/src/Umbraco.Core/Runtime/CoreRuntime.cs index 731f84e20f..35ac5aff86 100644 --- a/src/Umbraco.Core/Runtime/CoreRuntime.cs +++ b/src/Umbraco.Core/Runtime/CoreRuntime.cs @@ -7,6 +7,7 @@ using LightInject; using Umbraco.Core.Cache; using Umbraco.Core.Components; using Umbraco.Core.Composing; +using Umbraco.Core.Composing.CompositionRoots; using Umbraco.Core.Configuration; using Umbraco.Core.Exceptions; using Umbraco.Core.IO; @@ -194,6 +195,8 @@ namespace Umbraco.Core.Runtime container.RegisterSingleton(); container.RegisterSingleton(); + container.RegisterFrom(); + // register caches // need the deep clone runtime cache profiver to ensure entities are cached properly, ie // are cloned in and cloned out - no request-based cache here since no web-based context, @@ -206,7 +209,7 @@ namespace Umbraco.Core.Runtime container.RegisterSingleton(f => f.GetInstance().RuntimeCache); // register the plugin manager - container.RegisterSingleton(f => new TypeLoader(f.GetInstance(), f.GetInstance())); + container.RegisterSingleton(f => new TypeLoader(f.GetInstance(), f.GetInstance(), f.GetInstance())); // register syntax providers - required by database factory container.Register("MySqlSyntaxProvider"); diff --git a/src/Umbraco.Core/Runtime/CoreRuntimeComponent.cs b/src/Umbraco.Core/Runtime/CoreRuntimeComponent.cs index 6a5a3f4dc0..eeacba2b7c 100644 --- a/src/Umbraco.Core/Runtime/CoreRuntimeComponent.cs +++ b/src/Umbraco.Core/Runtime/CoreRuntimeComponent.cs @@ -35,7 +35,6 @@ namespace Umbraco.Core.Runtime base.Compose(composition); // register from roots - composition.Container.RegisterFrom(); composition.Container.RegisterFrom(); composition.Container.RegisterFrom(); composition.Container.RegisterFrom(); @@ -78,7 +77,7 @@ namespace Umbraco.Core.Runtime composition.Container.RegisterSingleton(f => { if (UmbracoConfig.For.UmbracoSettings().DistributedCall.Enabled) - return new ConfigServerRegistrar(UmbracoConfig.For.UmbracoSettings(), f.GetInstance()); + return new ConfigServerRegistrar(f.GetInstance(), f.GetInstance(), f.GetInstance()); if ("true".InvariantEquals(ConfigurationManager.AppSettings["umbracoDisableElectionForSingleServer"])) return new SingleServerRegistrar(f.GetInstance()); return new DatabaseServerRegistrar( @@ -94,8 +93,8 @@ namespace Umbraco.Core.Runtime factory.GetInstance(), factory.GetInstance(), factory.GetInstance(), - factory.GetInstance(), factory.GetInstance(), + factory.GetInstance(), true, new DatabaseServerMessengerOptions())); composition.Container.RegisterCollectionBuilder() diff --git a/src/Umbraco.Core/RuntimeState.cs b/src/Umbraco.Core/RuntimeState.cs index d740352649..a1401e035a 100644 --- a/src/Umbraco.Core/RuntimeState.cs +++ b/src/Umbraco.Core/RuntimeState.cs @@ -103,14 +103,15 @@ namespace Umbraco.Core /// /// Ensures that the property has a value. /// + /// /// /// - internal void EnsureApplicationUrl(HttpRequestBase request = null, IUmbracoSettingsSection settings = null) + internal void EnsureApplicationUrl(IUmbracoSettingsSection settings, IGlobalSettings globalSettings, HttpRequestBase request = null) { // see U4-10626 - in some cases we want to reset the application url // (this is a simplified version of what was in 7.x) // note: should this be optional? is it expensive? - var url = request == null ? null : ApplicationUrlHelper.GetApplicationUrlFromCurrentRequest(request); + var url = request == null ? null : ApplicationUrlHelper.GetApplicationUrlFromCurrentRequest(request, globalSettings); var change = url != null && !_applicationUrls.Contains(url); if (change) { @@ -119,7 +120,7 @@ namespace Umbraco.Core } if (ApplicationUrl != null && !change) return; - ApplicationUrl = new Uri(ApplicationUrlHelper.GetApplicationUrl(_logger, request, settings)); + ApplicationUrl = new Uri(ApplicationUrlHelper.GetApplicationUrl(_logger, globalSettings, settings, request)); } private readonly ManualResetEventSlim _runLevel = new ManualResetEventSlim(false); diff --git a/src/Umbraco.Core/Security/BackOfficeCookieAuthenticationProvider.cs b/src/Umbraco.Core/Security/BackOfficeCookieAuthenticationProvider.cs index a52f720b53..4d6a4fdaeb 100644 --- a/src/Umbraco.Core/Security/BackOfficeCookieAuthenticationProvider.cs +++ b/src/Umbraco.Core/Security/BackOfficeCookieAuthenticationProvider.cs @@ -16,9 +16,16 @@ namespace Umbraco.Core.Security { public class BackOfficeCookieAuthenticationProvider : CookieAuthenticationProvider { - // fixme inject - private IUserService UserService => Current.Services.UserService; - private IRuntimeState RuntimeState => Current.RuntimeState; + private readonly IUserService _userService; + private readonly IRuntimeState _runtimeState; + private readonly IGlobalSettings _globalSettings; + + public BackOfficeCookieAuthenticationProvider(IUserService userService, IRuntimeState runtimeState, IGlobalSettings globalSettings) + { + _userService = userService; + _runtimeState = runtimeState; + _globalSettings = globalSettings; + } public override void ResponseSignIn(CookieResponseSignInContext context) { @@ -27,8 +34,8 @@ namespace Umbraco.Core.Security //generate a session id and assign it //create a session token - if we are configured and not in an upgrade state then use the db, otherwise just generate one - var session = RuntimeState.Level == RuntimeLevel.Run - ? UserService.CreateLoginSession(backOfficeIdentity.Id, context.OwinContext.GetCurrentRequestIpAddress()) + var session = _runtimeState.Level == RuntimeLevel.Run + ? _userService.CreateLoginSession(backOfficeIdentity.Id, context.OwinContext.GetCurrentRequestIpAddress()) : Guid.NewGuid(); backOfficeIdentity.SessionId = session.ToString(); @@ -46,7 +53,7 @@ namespace Umbraco.Core.Security var sessionId = claimsIdentity.FindFirstValue(Constants.Security.SessionIdClaimType); if (sessionId.IsNullOrWhiteSpace() == false && Guid.TryParse(sessionId, out var guidSession)) { - UserService.ClearLoginSession(guidSession); + _userService.ClearLoginSession(guidSession); } } @@ -96,10 +103,10 @@ namespace Umbraco.Core.Security /// /// So that we are not overloading the database this throttles it's check to every minute /// - protected virtual async Task EnsureValidSessionId(CookieValidateIdentityContext context) + protected virtual async Task EnsureValidSessionId(CookieValidateIdentityContext context) { - if (RuntimeState.Level == RuntimeLevel.Run) - await SessionIdValidator.ValidateSessionAsync(TimeSpan.FromMinutes(1), context); + if (_runtimeState.Level == RuntimeLevel.Run) + await SessionIdValidator.ValidateSessionAsync(TimeSpan.FromMinutes(1), context, _globalSettings); } diff --git a/src/Umbraco.Core/Security/BackOfficeSignInManager.cs b/src/Umbraco.Core/Security/BackOfficeSignInManager.cs index 0362ab00b8..d156871697 100644 --- a/src/Umbraco.Core/Security/BackOfficeSignInManager.cs +++ b/src/Umbraco.Core/Security/BackOfficeSignInManager.cs @@ -17,14 +17,16 @@ namespace Umbraco.Core.Security { private readonly ILogger _logger; private readonly IOwinRequest _request; + private readonly IGlobalSettings _globalSettings; - public BackOfficeSignInManager(UserManager userManager, IAuthenticationManager authenticationManager, ILogger logger, IOwinRequest request) + public BackOfficeSignInManager(UserManager userManager, IAuthenticationManager authenticationManager, ILogger logger, IGlobalSettings globalSettings, IOwinRequest request) : base(userManager, authenticationManager) { if (logger == null) throw new ArgumentNullException("logger"); if (request == null) throw new ArgumentNullException("request"); _logger = logger; _request = request; + _globalSettings = globalSettings; AuthenticationType = Constants.Security.BackOfficeAuthenticationType; } @@ -33,12 +35,13 @@ namespace Umbraco.Core.Security return user.GenerateUserIdentityAsync((BackOfficeUserManager)UserManager); } - public static BackOfficeSignInManager Create(IdentityFactoryOptions options, IOwinContext context, ILogger logger) + public static BackOfficeSignInManager Create(IdentityFactoryOptions options, IOwinContext context, IGlobalSettings globalSettings, ILogger logger) { return new BackOfficeSignInManager( context.GetBackOfficeUserManager(), context.Authentication, logger, + globalSettings, context.Request); } @@ -55,31 +58,19 @@ namespace Umbraco.Core.Security { case SignInStatus.Success: _logger.WriteCore(TraceEventType.Information, 0, - string.Format( - "User: {0} logged in from IP address {1}", - userName, - _request.RemoteIpAddress), null, null); + $"User: {userName} logged in from IP address {_request.RemoteIpAddress}", null, null); break; case SignInStatus.LockedOut: _logger.WriteCore(TraceEventType.Information, 0, - string.Format( - "Login attempt failed for username {0} from IP address {1}, the user is locked", - userName, - _request.RemoteIpAddress), null, null); + $"Login attempt failed for username {userName} from IP address {_request.RemoteIpAddress}, the user is locked", null, null); break; case SignInStatus.RequiresVerification: _logger.WriteCore(TraceEventType.Information, 0, - string.Format( - "Login attempt requires verification for username {0} from IP address {1}", - userName, - _request.RemoteIpAddress), null, null); + $"Login attempt requires verification for username {userName} from IP address {_request.RemoteIpAddress}", null, null); break; case SignInStatus.Failure: _logger.WriteCore(TraceEventType.Information, 0, - string.Format( - "Login attempt failed for username {0} from IP address {1}", - userName, - _request.RemoteIpAddress), null, null); + $"Login attempt failed for username {userName} from IP address {_request.RemoteIpAddress}", null, null); break; default: throw new ArgumentOutOfRangeException(); @@ -107,7 +98,7 @@ namespace Umbraco.Core.Security //if the user is null, create an empty one which can be used for auto-linking if (user == null) - user = BackOfficeIdentityUser.CreateNew(userName, null, GlobalSettings.DefaultUILanguage); + user = BackOfficeIdentityUser.CreateNew(userName, null, _globalSettings.DefaultUILanguage); //check the password for the user, this will allow a developer to auto-link //an account if they have specified an IBackOfficeUserPasswordChecker @@ -202,7 +193,7 @@ namespace Umbraco.Core.Security IsPersistent = isPersistent, AllowRefresh = true, IssuedUtc = nowUtc, - ExpiresUtc = nowUtc.AddMinutes(GlobalSettings.TimeOutInMinutes) + ExpiresUtc = nowUtc.AddMinutes(_globalSettings.TimeOutInMinutes) }, userIdentity, rememberBrowserIdentity); } else @@ -212,7 +203,7 @@ namespace Umbraco.Core.Security IsPersistent = isPersistent, AllowRefresh = true, IssuedUtc = nowUtc, - ExpiresUtc = nowUtc.AddMinutes(GlobalSettings.TimeOutInMinutes) + ExpiresUtc = nowUtc.AddMinutes(_globalSettings.TimeOutInMinutes) }, userIdentity); } diff --git a/src/Umbraco.Core/Security/BackOfficeUserManager.cs b/src/Umbraco.Core/Security/BackOfficeUserManager.cs index 4c651e9432..8324ec11a0 100644 --- a/src/Umbraco.Core/Security/BackOfficeUserManager.cs +++ b/src/Umbraco.Core/Security/BackOfficeUserManager.cs @@ -54,6 +54,7 @@ namespace Umbraco.Core.Security /// /// /// + /// /// public static BackOfficeUserManager Create( IdentityFactoryOptions options, @@ -62,14 +63,16 @@ namespace Umbraco.Core.Security IEntityService entityService, IExternalLoginService externalLoginService, MembershipProviderBase membershipProvider, - IContentSection contentSectionConfig) + IContentSection contentSectionConfig, + IGlobalSettings globalSettings) { if (options == null) throw new ArgumentNullException("options"); if (userService == null) throw new ArgumentNullException("userService"); if (memberTypeService == null) throw new ArgumentNullException("memberTypeService"); if (externalLoginService == null) throw new ArgumentNullException("externalLoginService"); - var manager = new BackOfficeUserManager(new BackOfficeUserStore(userService, memberTypeService, entityService, externalLoginService, membershipProvider)); + var manager = new BackOfficeUserManager( + new BackOfficeUserStore(userService, memberTypeService, entityService, externalLoginService, globalSettings, membershipProvider)); manager.InitUserManager(manager, membershipProvider, contentSectionConfig, options); return manager; } diff --git a/src/Umbraco.Core/Security/BackOfficeUserStore.cs b/src/Umbraco.Core/Security/BackOfficeUserStore.cs index dc6a939c65..2f70f32d89 100644 --- a/src/Umbraco.Core/Security/BackOfficeUserStore.cs +++ b/src/Umbraco.Core/Security/BackOfficeUserStore.cs @@ -8,6 +8,7 @@ using System.Web.Security; using AutoMapper; using Microsoft.AspNet.Identity; using Microsoft.Owin; +using Umbraco.Core.Configuration; using Umbraco.Core.Exceptions; using Umbraco.Core.Models; using Umbraco.Core.Models.Identity; @@ -38,14 +39,16 @@ namespace Umbraco.Core.Security private readonly IMemberTypeService _memberTypeService; private readonly IEntityService _entityService; private readonly IExternalLoginService _externalLoginService; + private readonly IGlobalSettings _globalSettings; private bool _disposed = false; - public BackOfficeUserStore(IUserService userService, IMemberTypeService memberTypeService, IEntityService entityService, IExternalLoginService externalLoginService, MembershipProviderBase usersMembershipProvider) + public BackOfficeUserStore(IUserService userService, IMemberTypeService memberTypeService, IEntityService entityService, IExternalLoginService externalLoginService, IGlobalSettings globalSettings, MembershipProviderBase usersMembershipProvider) { _userService = userService; _memberTypeService = memberTypeService; _entityService = entityService; _externalLoginService = externalLoginService; + _globalSettings = globalSettings; if (userService == null) throw new ArgumentNullException("userService"); if (usersMembershipProvider == null) throw new ArgumentNullException("usersMembershipProvider"); if (externalLoginService == null) throw new ArgumentNullException("externalLoginService"); @@ -88,7 +91,7 @@ namespace Umbraco.Core.Security var userEntity = new User(user.Name, user.Email, user.UserName, emptyPasswordValue) { DefaultToLiveEditing = false, - Language = user.Culture ?? Configuration.GlobalSettings.DefaultUILanguage, + Language = user.Culture ?? _globalSettings.DefaultUILanguage, StartContentIds = user.StartContentIds ?? new int[] { }, StartMediaIds = user.StartMediaIds ?? new int[] { }, IsLockedOut = user.IsLockedOut, diff --git a/src/Umbraco.Core/Security/SessionIdValidator.cs b/src/Umbraco.Core/Security/SessionIdValidator.cs index 1737baa778..f738ad9c22 100644 --- a/src/Umbraco.Core/Security/SessionIdValidator.cs +++ b/src/Umbraco.Core/Security/SessionIdValidator.cs @@ -28,12 +28,12 @@ namespace Umbraco.Core.Security { public const string CookieName = "UMB_UCONTEXT_C"; - public static async Task ValidateSessionAsync(TimeSpan validateInterval, CookieValidateIdentityContext context) + public static async Task ValidateSessionAsync(TimeSpan validateInterval, CookieValidateIdentityContext context, IGlobalSettings globalSettings) { - if (context.Request.Uri.IsBackOfficeRequest(HttpRuntime.AppDomainAppVirtualPath) == false) + if (context.Request.Uri.IsBackOfficeRequest(HttpRuntime.AppDomainAppVirtualPath, globalSettings) == false) return; - var valid = await ValidateSessionAsync(validateInterval, context.OwinContext, context.Options.CookieManager, context.Options.SystemClock, context.Properties.IssuedUtc, context.Identity); + var valid = await ValidateSessionAsync(validateInterval, context.OwinContext, context.Options.CookieManager, context.Options.SystemClock, context.Properties.IssuedUtc, context.Identity, globalSettings); if (valid == false) { @@ -48,7 +48,8 @@ namespace Umbraco.Core.Security ICookieManager cookieManager, ISystemClock systemClock, DateTimeOffset? authTicketIssueDate, - ClaimsIdentity currentIdentity) + ClaimsIdentity currentIdentity, + IGlobalSettings globalSettings) { if (owinCtx == null) throw new ArgumentNullException("owinCtx"); if (cookieManager == null) throw new ArgumentNullException("cookieManager"); @@ -107,7 +108,7 @@ namespace Umbraco.Core.Security new CookieOptions { HttpOnly = true, - Secure = GlobalSettings.UseSSL || owinCtx.Request.IsSecure, + Secure = globalSettings.UseHttps || owinCtx.Request.IsSecure, Path = "/" }); @@ -115,4 +116,4 @@ namespace Umbraco.Core.Security } } -} \ No newline at end of file +} diff --git a/src/Umbraco.Core/Services/Implement/NotificationService.cs b/src/Umbraco.Core/Services/Implement/NotificationService.cs index 0b57958724..b65218409a 100644 --- a/src/Umbraco.Core/Services/Implement/NotificationService.cs +++ b/src/Umbraco.Core/Services/Implement/NotificationService.cs @@ -25,12 +25,14 @@ namespace Umbraco.Core.Services.Implement private readonly IUserService _userService; private readonly IContentService _contentService; private readonly INotificationsRepository _notificationsRepository; + private readonly IGlobalSettings _globalSettings; private readonly ILogger _logger; public NotificationService(IScopeProvider provider, IUserService userService, IContentService contentService, ILogger logger, - INotificationsRepository notificationsRepository) + INotificationsRepository notificationsRepository, IGlobalSettings globalSettings) { _notificationsRepository = notificationsRepository; + _globalSettings = globalSettings; _uowProvider = provider ?? throw new ArgumentNullException(nameof(provider)); _userService = userService ?? throw new ArgumentNullException(nameof(userService)); _contentService = contentService ?? throw new ArgumentNullException(nameof(contentService)); @@ -425,7 +427,7 @@ namespace Umbraco.Core.Services.Implement " "); } - string protocol = GlobalSettings.UseSSL ? "https" : "http"; + string protocol = _globalSettings.UseHttps ? "https" : "http"; string[] subjectVars = { @@ -471,7 +473,7 @@ namespace Umbraco.Core.Services.Implement // nh, issue 30724. Due to hardcoded http strings in resource files, we need to check for https replacements here // adding the server name to make sure we don't replace external links - if (GlobalSettings.UseSSL && string.IsNullOrEmpty(mail.Body) == false) + if (_globalSettings.UseHttps && string.IsNullOrEmpty(mail.Body) == false) { string serverName = http.Request.ServerVariables["SERVER_NAME"]; mail.Body = mail.Body.Replace( @@ -482,9 +484,9 @@ namespace Umbraco.Core.Services.Implement return new NotificationRequest(mail, actionName, mailingUser.Name, mailingUser.Email); } - private static string ReplaceLinks(string text, HttpRequestBase request) + private string ReplaceLinks(string text, HttpRequestBase request) { - var sb = new StringBuilder(GlobalSettings.UseSSL ? "https://" : "http://"); + var sb = new StringBuilder(_globalSettings.UseHttps ? "https://" : "http://"); sb.Append(request.ServerVariables["SERVER_NAME"]); sb.Append(":"); sb.Append(request.Url.Port); diff --git a/src/Umbraco.Core/Services/Implement/UserService.cs b/src/Umbraco.Core/Services/Implement/UserService.cs index 9c5d65c6f3..4b27fb5c51 100644 --- a/src/Umbraco.Core/Services/Implement/UserService.cs +++ b/src/Umbraco.Core/Services/Implement/UserService.cs @@ -28,14 +28,16 @@ namespace Umbraco.Core.Services.Implement { private readonly IUserRepository _userRepository; private readonly IUserGroupRepository _userGroupRepository; + private readonly IGlobalSettings _globalSettings; private readonly bool _isUpgrading; public UserService(IScopeProvider provider, ILogger logger, IEventMessagesFactory eventMessagesFactory, IRuntimeState runtimeState, - IUserRepository userRepository, IUserGroupRepository userGroupRepository) + IUserRepository userRepository, IUserGroupRepository userGroupRepository, IGlobalSettings globalSettings) : base(provider, logger, eventMessagesFactory) { _userRepository = userRepository; _userGroupRepository = userGroupRepository; + _globalSettings = globalSettings; _isUpgrading = runtimeState.Level == RuntimeLevel.Install || runtimeState.Level == RuntimeLevel.Upgrade; } @@ -120,7 +122,7 @@ namespace Umbraco.Core.Services.Implement { DefaultToLiveEditing = false, Email = email, - Language = GlobalSettings.DefaultUILanguage, + Language = _globalSettings.DefaultUILanguage, Name = username, RawPasswordValue = passwordValue, Username = username, diff --git a/src/Umbraco.Core/Sync/ApplicationUrlHelper.cs b/src/Umbraco.Core/Sync/ApplicationUrlHelper.cs index 1e40f46775..691a325eaa 100644 --- a/src/Umbraco.Core/Sync/ApplicationUrlHelper.cs +++ b/src/Umbraco.Core/Sync/ApplicationUrlHelper.cs @@ -29,9 +29,9 @@ namespace Umbraco.Core.Sync // FIXME need another way to do it, eg an interface, injected! public static Func ApplicationUrlProvider { get; set; } - internal static string GetApplicationUrl(ILogger logger, HttpRequestBase request = null, IUmbracoSettingsSection settings = null) + internal static string GetApplicationUrl(ILogger logger, IGlobalSettings globalSettings, IUmbracoSettingsSection settings, HttpRequestBase request = null) { - var umbracoApplicationUrl = TryGetApplicationUrl(settings ?? UmbracoConfig.For.UmbracoSettings(), logger); + var umbracoApplicationUrl = TryGetApplicationUrl(settings, logger, globalSettings); if (umbracoApplicationUrl != null) return umbracoApplicationUrl; @@ -45,12 +45,12 @@ namespace Umbraco.Core.Sync if (request == null) return null; - umbracoApplicationUrl = GetApplicationUrlFromCurrentRequest(request); + umbracoApplicationUrl = GetApplicationUrlFromCurrentRequest(request, globalSettings); logger.Info(TypeOfApplicationUrlHelper, "ApplicationUrl: " + umbracoApplicationUrl + " (UmbracoModule request)"); return umbracoApplicationUrl; } - internal static string TryGetApplicationUrl(IUmbracoSettingsSection settings, ILogger logger) + internal static string TryGetApplicationUrl(IUmbracoSettingsSection settings, ILogger logger, IGlobalSettings globalSettings) { // try umbracoSettings:settings/web.routing/@umbracoApplicationUrl // which is assumed to: @@ -75,7 +75,7 @@ namespace Umbraco.Core.Sync url = settings.ScheduledTasks.BaseUrl; if (url.IsNullOrWhiteSpace() == false) { - var ssl = GlobalSettings.UseSSL ? "s" : ""; + var ssl = globalSettings.UseHttps ? "s" : ""; url = "http" + ssl + "://" + url; var umbracoApplicationUrl = url.TrimEnd('/'); logger.Info(TypeOfApplicationUrlHelper, "ApplicationUrl: " + umbracoApplicationUrl + " (using scheduledTasks/@baseUrl)"); @@ -100,7 +100,7 @@ namespace Umbraco.Core.Sync return null; } - public static string GetApplicationUrlFromCurrentRequest(HttpRequestBase request) + public static string GetApplicationUrlFromCurrentRequest(HttpRequestBase request, IGlobalSettings globalSettings) { // if (HTTP and SSL not required) or (HTTPS and SSL required), // use ports from request @@ -108,12 +108,12 @@ namespace Umbraco.Core.Sync // if non-standard ports used, // user may need to set umbracoApplicationUrl manually per // http://our.umbraco.org/documentation/Using-Umbraco/Config-files/umbracoSettings/#ScheduledTasks - var port = (request.IsSecureConnection == false && GlobalSettings.UseSSL == false) - || (request.IsSecureConnection && GlobalSettings.UseSSL) + var port = (request.IsSecureConnection == false && globalSettings.UseHttps == false) + || (request.IsSecureConnection && globalSettings.UseHttps) ? ":" + request.ServerVariables["SERVER_PORT"] : ""; - var useSsl = GlobalSettings.UseSSL || port == "443"; + var useSsl = globalSettings.UseHttps || port == "443"; var ssl = useSsl ? "s" : ""; // force, whatever the first request var url = "http" + ssl + "://" + request.ServerVariables["SERVER_NAME"] + port + IOHelper.ResolveUrl(SystemDirectories.Umbraco); diff --git a/src/Umbraco.Core/Sync/ConfigServerAddress.cs b/src/Umbraco.Core/Sync/ConfigServerAddress.cs index fa1cf20f8e..be00544344 100644 --- a/src/Umbraco.Core/Sync/ConfigServerAddress.cs +++ b/src/Umbraco.Core/Sync/ConfigServerAddress.cs @@ -9,17 +9,17 @@ namespace Umbraco.Core.Sync /// internal class ConfigServerAddress : IServerAddress { - public ConfigServerAddress(IServer n) + public ConfigServerAddress(IServer n, IGlobalSettings globalSettings) { var webServicesUrl = IOHelper.ResolveUrl(SystemDirectories.WebServices); - var protocol = GlobalSettings.UseSSL ? "https" : "http"; + var protocol = globalSettings.UseHttps ? "https" : "http"; if (n.ForceProtocol.IsNullOrWhiteSpace() == false) protocol = n.ForceProtocol; var domain = n.ServerAddress; if (n.ForcePortnumber.IsNullOrWhiteSpace() == false) - domain += string.Format(":{0}", n.ForcePortnumber); - ServerAddress = string.Format("{0}://{1}{2}/cacheRefresher.asmx", protocol, domain, webServicesUrl); + domain += $":{n.ForcePortnumber}"; + ServerAddress = $"{protocol}://{domain}{webServicesUrl}/cacheRefresher.asmx"; } public string ServerAddress { get; private set; } diff --git a/src/Umbraco.Core/Sync/ConfigServerRegistrar.cs b/src/Umbraco.Core/Sync/ConfigServerRegistrar.cs index 5929e307dc..83e085b324 100644 --- a/src/Umbraco.Core/Sync/ConfigServerRegistrar.cs +++ b/src/Umbraco.Core/Sync/ConfigServerRegistrar.cs @@ -1,6 +1,7 @@ using System.Collections.Generic; using System.Linq; using System.Web; +using Umbraco.Core.Configuration; using Umbraco.Core.Configuration.UmbracoSettings; using Umbraco.Core.IO; using Umbraco.Core.Logging; @@ -17,12 +18,12 @@ namespace Umbraco.Core.Sync private readonly ServerRole _serverRole; private readonly string _umbracoApplicationUrl; - public ConfigServerRegistrar(IUmbracoSettingsSection settings, ILogger logger) - : this(settings.DistributedCall, logger) + public ConfigServerRegistrar(IUmbracoSettingsSection settings, ILogger logger, IGlobalSettings globalSettings) + : this(settings.DistributedCall, logger, globalSettings) { } // for tests - internal ConfigServerRegistrar(IDistributedCallSection settings, ILogger logger) + internal ConfigServerRegistrar(IDistributedCallSection settings, ILogger logger, IGlobalSettings globalSettings) { if (settings.Enabled == false) { @@ -35,7 +36,7 @@ namespace Umbraco.Core.Sync var serversA = settings.Servers.ToArray(); _addresses = serversA - .Select(x => new ConfigServerAddress(x)) + .Select(x => new ConfigServerAddress(x, globalSettings)) .Cast() .ToList(); diff --git a/src/Umbraco.Core/Sync/DatabaseServerMessenger.cs b/src/Umbraco.Core/Sync/DatabaseServerMessenger.cs index f7d3b9a7a0..0fcb7036f7 100644 --- a/src/Umbraco.Core/Sync/DatabaseServerMessenger.cs +++ b/src/Umbraco.Core/Sync/DatabaseServerMessenger.cs @@ -35,7 +35,7 @@ namespace Umbraco.Core.Sync private readonly object _locko = new object(); private readonly ProfilingLogger _profilingLogger; private readonly ISqlContext _sqlContext; - private readonly Lazy _distCacheFilePath = new Lazy(GetDistCacheFilePath); + private readonly Lazy _distCacheFilePath; private int _lastId = -1; private DateTime _lastSync; private DateTime _lastPruned; @@ -46,18 +46,19 @@ namespace Umbraco.Core.Sync public DatabaseServerMessengerOptions Options { get; } public DatabaseServerMessenger( - IRuntimeState runtime, IScopeProvider scopeProvider, ISqlContext sqlContext, ILogger logger, ProfilingLogger proflog, + IRuntimeState runtime, IScopeProvider scopeProvider, ISqlContext sqlContext, ProfilingLogger proflog, IGlobalSettings globalSettings, bool distributedEnabled, DatabaseServerMessengerOptions options) : base(distributedEnabled) { ScopeProvider = scopeProvider ?? throw new ArgumentNullException(nameof(scopeProvider)); - Logger = logger ?? throw new ArgumentNullException(nameof(logger)); _sqlContext = sqlContext; _runtime = runtime; _profilingLogger = proflog ?? throw new ArgumentNullException(nameof(proflog)); + Logger = proflog.Logger; Options = options ?? throw new ArgumentNullException(nameof(options)); _lastPruned = _lastSync = DateTime.UtcNow; _syncIdle = new ManualResetEvent(true); + _distCacheFilePath = new Lazy(() => GetDistCacheFilePath(globalSettings)); } protected ILogger Logger { get; } @@ -522,12 +523,12 @@ namespace Umbraco.Core.Sync + "/D" + AppDomain.CurrentDomain.Id // eg 22 + "] " + Guid.NewGuid().ToString("N").ToUpper(); // make it truly unique - private static string GetDistCacheFilePath() + private string GetDistCacheFilePath(IGlobalSettings globalSettings) { var fileName = HttpRuntime.AppDomainAppId.ReplaceNonAlphanumericChars(string.Empty) + "-lastsynced.txt"; string distCacheFilePath; - switch (GlobalSettings.LocalTempStorageLocation) + switch (globalSettings.LocalTempStorageLocation) { case LocalTempStorage.AspNetTemp: distCacheFilePath = Path.Combine(HttpRuntime.CodegenDir, @"UmbracoData", fileName); diff --git a/src/Umbraco.Core/Umbraco.Core.csproj b/src/Umbraco.Core/Umbraco.Core.csproj index 7790b8a769..1d91f30097 100644 --- a/src/Umbraco.Core/Umbraco.Core.csproj +++ b/src/Umbraco.Core/Umbraco.Core.csproj @@ -208,6 +208,7 @@ + @@ -229,6 +230,7 @@ + diff --git a/src/Umbraco.Core/UriExtensions.cs b/src/Umbraco.Core/UriExtensions.cs index 88180428c4..742e71ad93 100644 --- a/src/Umbraco.Core/UriExtensions.cs +++ b/src/Umbraco.Core/UriExtensions.cs @@ -13,33 +13,34 @@ namespace Umbraco.Core /// public static class UriExtensions { - /// - /// Checks if the current uri is a back office request - /// - /// - /// - /// The current application path or VirtualPath - /// + /// + /// Checks if the current uri is a back office request + /// + /// + /// + /// The current application path or VirtualPath + /// + /// /// - /// - /// There are some special routes we need to check to properly determine this: - /// - /// If any route has an extension in the path like .aspx = back office - /// - /// These are def back office: - /// /Umbraco/RestServices = back office - /// /Umbraco/BackOffice = back office - /// If it's not any of the above, and there's no extension then we cannot determine if it's back office or front-end - /// so we can only assume that it is not back office. This will occur if people use an UmbracoApiController for the backoffice - /// but do not inherit from UmbracoAuthorizedApiController and do not use [IsBackOffice] attribute. - /// - /// These are def front-end: - /// /Umbraco/Surface = front-end - /// /Umbraco/Api = front-end - /// But if we've got this far we'll just have to assume it's front-end anyways. - /// - /// - internal static bool IsBackOfficeRequest(this Uri url, string applicationPath) + /// + /// There are some special routes we need to check to properly determine this: + /// + /// If any route has an extension in the path like .aspx = back office + /// + /// These are def back office: + /// /Umbraco/RestServices = back office + /// /Umbraco/BackOffice = back office + /// If it's not any of the above, and there's no extension then we cannot determine if it's back office or front-end + /// so we can only assume that it is not back office. This will occur if people use an UmbracoApiController for the backoffice + /// but do not inherit from UmbracoAuthorizedApiController and do not use [IsBackOffice] attribute. + /// + /// These are def front-end: + /// /Umbraco/Surface = front-end + /// /Umbraco/Api = front-end + /// But if we've got this far we'll just have to assume it's front-end anyways. + /// + /// + internal static bool IsBackOfficeRequest(this Uri url, string applicationPath, IGlobalSettings globalSettings) { applicationPath = applicationPath ?? string.Empty; @@ -48,13 +49,13 @@ namespace Umbraco.Core var urlPath = fullUrlPath.TrimStart(appPath).EnsureStartsWith('/'); //check if this is in the umbraco back office - var isUmbracoPath = urlPath.InvariantStartsWith(GlobalSettings.Path.EnsureStartsWith('/').TrimStart(appPath.EnsureStartsWith('/')).EnsureStartsWith('/')); + var isUmbracoPath = urlPath.InvariantStartsWith(globalSettings.Path.EnsureStartsWith('/').TrimStart(appPath.EnsureStartsWith('/')).EnsureStartsWith('/')); //if not, then def not back office if (isUmbracoPath == false) return false; //if its the normal /umbraco path - if (urlPath.InvariantEquals("/" + GlobalSettings.UmbracoMvcArea) - || urlPath.InvariantEquals("/" + GlobalSettings.UmbracoMvcArea + "/")) + if (urlPath.InvariantEquals("/" + globalSettings.GetUmbracoMvcArea()) + || urlPath.InvariantEquals("/" + globalSettings.GetUmbracoMvcArea() + "/")) { return true; } @@ -75,15 +76,15 @@ namespace Umbraco.Core } //check for special back office paths - if (urlPath.InvariantStartsWith("/" + GlobalSettings.UmbracoMvcArea + "/BackOffice/") - || urlPath.InvariantStartsWith("/" + GlobalSettings.UmbracoMvcArea + "/RestServices/")) + if (urlPath.InvariantStartsWith("/" + globalSettings.GetUmbracoMvcArea() + "/BackOffice/") + || urlPath.InvariantStartsWith("/" + globalSettings.GetUmbracoMvcArea() + "/RestServices/")) { return true; } //check for special front-end paths - if (urlPath.InvariantStartsWith("/" + GlobalSettings.UmbracoMvcArea + "/Surface/") - || urlPath.InvariantStartsWith("/" + GlobalSettings.UmbracoMvcArea + "/Api/")) + if (urlPath.InvariantStartsWith("/" + globalSettings.GetUmbracoMvcArea() + "/Surface/") + || urlPath.InvariantStartsWith("/" + globalSettings.GetUmbracoMvcArea() + "/Api/")) { return false; } @@ -122,13 +123,14 @@ namespace Umbraco.Core /// Checks if the uri is a request for the default back office page /// /// + /// /// - internal static bool IsDefaultBackOfficeRequest(this Uri url) + internal static bool IsDefaultBackOfficeRequest(this Uri url, IGlobalSettings globalSettings) { - if (url.AbsolutePath.InvariantEquals(GlobalSettings.Path.TrimEnd("/")) - || url.AbsolutePath.InvariantEquals(GlobalSettings.Path.EnsureEndsWith('/')) - || url.AbsolutePath.InvariantEquals(GlobalSettings.Path.EnsureEndsWith('/') + "Default") - || url.AbsolutePath.InvariantEquals(GlobalSettings.Path.EnsureEndsWith('/') + "Default/")) + if (url.AbsolutePath.InvariantEquals(globalSettings.Path.TrimEnd("/")) + || url.AbsolutePath.InvariantEquals(globalSettings.Path.EnsureEndsWith('/')) + || url.AbsolutePath.InvariantEquals(globalSettings.Path.EnsureEndsWith('/') + "Default") + || url.AbsolutePath.InvariantEquals(globalSettings.Path.EnsureEndsWith('/') + "Default/")) { return true; } diff --git a/src/Umbraco.Tests/App.config b/src/Umbraco.Tests/App.config index 58c7c9c409..e909ae8566 100644 --- a/src/Umbraco.Tests/App.config +++ b/src/Umbraco.Tests/App.config @@ -62,7 +62,7 @@ - + diff --git a/src/Umbraco.Tests/Cache/PublishedCache/PublishedContentCacheTests.cs b/src/Umbraco.Tests/Cache/PublishedCache/PublishedContentCacheTests.cs index a79f961af7..f330c126d0 100644 --- a/src/Umbraco.Tests/Cache/PublishedCache/PublishedContentCacheTests.cs +++ b/src/Umbraco.Tests/Cache/PublishedCache/PublishedContentCacheTests.cs @@ -53,16 +53,18 @@ namespace Umbraco.Tests.Cache.PublishedCache _httpContextFactory = new FakeHttpContextFactory("~/Home"); - var settings = SettingsForTests.GenerateMockSettings(); + var umbracoSettings = SettingsForTests.GenerateMockUmbracoSettings(); + var globalSettings = SettingsForTests.GenerateMockGlobalSettings(); + SettingsForTests.ConfigureSettings(umbracoSettings); + SettingsForTests.ConfigureSettings(globalSettings); - SettingsForTests.ConfigureSettings(settings); _xml = new XmlDocument(); _xml.LoadXml(GetXml()); var xmlStore = new XmlStore(() => _xml, null, null, null); var cacheProvider = new StaticCacheProvider(); var domainCache = new DomainCache(ServiceContext.DomainService); var publishedShapshot = new Umbraco.Web.PublishedCache.XmlPublishedCache.PublishedShapshot( - new PublishedContentCache(xmlStore, domainCache, cacheProvider, ContentTypesCache, null, null), + new PublishedContentCache(xmlStore, domainCache, cacheProvider, globalSettings, ContentTypesCache, null, null), new PublishedMediaCache(xmlStore, ServiceContext.MediaService, ServiceContext.UserService, cacheProvider, ContentTypesCache), new PublishedMemberCache(null, cacheProvider, Current.Services.MemberService, ContentTypesCache), domainCache); @@ -72,9 +74,10 @@ namespace Umbraco.Tests.Cache.PublishedCache _umbracoContext = new UmbracoContext( _httpContextFactory.HttpContext, publishedSnapshotService.Object, - new WebSecurity(_httpContextFactory.HttpContext, Current.Services.UserService), - settings, - Enumerable.Empty()); + new WebSecurity(_httpContextFactory.HttpContext, Current.Services.UserService, globalSettings), + umbracoSettings, + Enumerable.Empty(), + globalSettings); _cache = _umbracoContext.ContentCache; } diff --git a/src/Umbraco.Tests/Composing/ComposingTestBase.cs b/src/Umbraco.Tests/Composing/ComposingTestBase.cs index 37f4df268c..be595885e7 100644 --- a/src/Umbraco.Tests/Composing/ComposingTestBase.cs +++ b/src/Umbraco.Tests/Composing/ComposingTestBase.cs @@ -5,6 +5,7 @@ using NUnit.Framework; using Umbraco.Core.Cache; using Umbraco.Core.Composing; using Umbraco.Core.Logging; +using Umbraco.Tests.TestHelpers; namespace Umbraco.Tests.Composing { @@ -19,7 +20,7 @@ namespace Umbraco.Tests.Composing { ProfilingLogger = new ProfilingLogger(Mock.Of(), Mock.Of()); - TypeLoader = new TypeLoader(NullCacheProvider.Instance, ProfilingLogger, detectChanges: false) + TypeLoader = new TypeLoader(NullCacheProvider.Instance, SettingsForTests.GenerateMockGlobalSettings(), ProfilingLogger, detectChanges: false) { AssembliesToScan = AssembliesToScan }; diff --git a/src/Umbraco.Tests/Composing/TypeLoaderTests.cs b/src/Umbraco.Tests/Composing/TypeLoaderTests.cs index e2af507871..8965d60018 100644 --- a/src/Umbraco.Tests/Composing/TypeLoaderTests.cs +++ b/src/Umbraco.Tests/Composing/TypeLoaderTests.cs @@ -12,6 +12,7 @@ using Umbraco.Core.Composing; using Umbraco.Core.IO; using Umbraco.Core.Logging; using Umbraco.Core.PropertyEditors; +using Umbraco.Tests.TestHelpers; using Umbraco.Web; using Umbraco.Web.PropertyEditors; @@ -25,7 +26,7 @@ namespace Umbraco.Tests.Composing public void Initialize() { // this ensures it's reset - _typeLoader = new TypeLoader(NullCacheProvider.Instance, new ProfilingLogger(Mock.Of(), Mock.Of())); + _typeLoader = new TypeLoader(NullCacheProvider.Instance, SettingsForTests.GenerateMockGlobalSettings(), new ProfilingLogger(Mock.Of(), Mock.Of())); foreach (var file in Directory.GetFiles(IOHelper.MapPath("~/App_Data/TEMP/TypesCache"))) File.Delete(file); @@ -146,7 +147,7 @@ namespace Umbraco.Tests.Composing [Test] public void Detect_Legacy_Plugin_File_List() { - var filePath = TypeLoader.GetTypesListFilePath(); + var filePath = _typeLoader.GetTypesListFilePath(); var fileDir = Path.GetDirectoryName(filePath); Directory.CreateDirectory(fileDir); diff --git a/src/Umbraco.Tests/Configurations/GlobalSettingsTests.cs b/src/Umbraco.Tests/Configurations/GlobalSettingsTests.cs index 6c3d5c6eec..d50e940b1a 100644 --- a/src/Umbraco.Tests/Configurations/GlobalSettingsTests.cs +++ b/src/Umbraco.Tests/Configurations/GlobalSettingsTests.cs @@ -1,5 +1,6 @@ using System.Web.Mvc; using System.Web.Routing; +using Moq; using NUnit.Framework; using Umbraco.Core.Configuration; using Umbraco.Core.IO; @@ -10,26 +11,24 @@ namespace Umbraco.Tests.Configurations [TestFixture] public class GlobalSettingsTests : BaseWebTest { + private string _root; + public override void SetUp() { base.SetUp(); - - SettingsForTests.UmbracoPath = "~/umbraco"; + _root = SystemDirectories.Root; } public override void TearDown() { base.TearDown(); - - //ensure this is reset - SystemDirectories.Root = null; - SettingsForTests.UmbracoPath = "~/umbraco"; + SystemDirectories.Root = _root; } [Test] public void Is_Debug_Mode() { - Assert.That(Umbraco.Core.Configuration.GlobalSettings.DebugMode, Is.EqualTo(true)); + Assert.That(GlobalSettings.DebugMode, Is.EqualTo(true)); } [Ignore("fixme - ignored test")] @@ -46,9 +45,12 @@ namespace Umbraco.Tests.Configurations [TestCase("~/some-wacky/nestedPath", "/MyVirtualDir/NestedVDir/", "some-wacky-nestedpath")] public void Umbraco_Mvc_Area(string path, string rootPath, string outcome) { - SettingsForTests.UmbracoPath = path; + var globalSettingsMock = Mock.Get(TestObjects.GetGlobalSettings()); //this will modify the IGlobalSettings instance stored in the container + globalSettingsMock.Setup(x => x.Path).Returns(IOHelper.ResolveUrl(path)); + SettingsForTests.ConfigureSettings(globalSettingsMock.Object); + SystemDirectories.Root = rootPath; - Assert.AreEqual(outcome, Umbraco.Core.Configuration.GlobalSettings.UmbracoMvcArea); + Assert.AreEqual(outcome, UmbracoConfig.For.GlobalSettings().GetUmbracoMvcArea()); } [TestCase("/umbraco/umbraco.aspx")] @@ -61,7 +63,8 @@ namespace Umbraco.Tests.Configurations [TestCase("/config/splashes/booting.aspx")] public void Is_Reserved_Path_Or_Url(string url) { - Assert.IsTrue(Umbraco.Core.Configuration.GlobalSettings.IsReservedPathOrUrl(url)); + var globalSettings = TestObjects.GetGlobalSettings(); + Assert.IsTrue(globalSettings.IsReservedPathOrUrl(url)); } [TestCase("/umbraco_client/Tree/treeIcons.css")] @@ -75,7 +78,8 @@ namespace Umbraco.Tests.Configurations [TestCase("/install.aspx")] public void Is_Not_Reserved_Path_Or_Url(string url) { - Assert.IsFalse(Umbraco.Core.Configuration.GlobalSettings.IsReservedPathOrUrl(url)); + var globalSettings = TestObjects.GetGlobalSettings(); + Assert.IsFalse(globalSettings.IsReservedPathOrUrl(url)); } @@ -92,8 +96,10 @@ namespace Umbraco.Tests.Configurations public void Is_Reserved_By_Route(string url, bool shouldMatch) { //reset the app config, we only want to test routes not the hard coded paths - Umbraco.Core.Configuration.GlobalSettings.ReservedPaths = ""; - Umbraco.Core.Configuration.GlobalSettings.ReservedUrls = ""; + var globalSettingsMock = Mock.Get(TestObjects.GetGlobalSettings()); //this will modify the IGlobalSettings instance stored in the container + globalSettingsMock.Setup(x => x.ReservedPaths).Returns(""); + globalSettingsMock.Setup(x => x.ReservedUrls).Returns(""); + SettingsForTests.ConfigureSettings(globalSettingsMock.Object); var routes = new RouteCollection(); @@ -112,7 +118,7 @@ namespace Umbraco.Tests.Configurations Assert.AreEqual( shouldMatch, - Umbraco.Core.Configuration.GlobalSettings.IsReservedPathOrUrl(url, context.HttpContext, routes)); + globalSettingsMock.Object.IsReservedPathOrUrl(url, context.HttpContext, routes)); } } } diff --git a/src/Umbraco.Tests/CoreThings/TryConvertToTests.cs b/src/Umbraco.Tests/CoreThings/TryConvertToTests.cs index 39e541aa38..2e187d85a5 100644 --- a/src/Umbraco.Tests/CoreThings/TryConvertToTests.cs +++ b/src/Umbraco.Tests/CoreThings/TryConvertToTests.cs @@ -15,7 +15,7 @@ namespace Umbraco.Tests.CoreThings { base.SetUp(); - var settings = SettingsForTests.GetDefault(); + var settings = SettingsForTests.GetDefaultUmbracoSettings(); // fixme - base should do it! Container.RegisterSingleton(_ => new DefaultShortStringHelper(settings)); diff --git a/src/Umbraco.Tests/CoreThings/UdiTests.cs b/src/Umbraco.Tests/CoreThings/UdiTests.cs index 63cfcb093d..62aa56bd14 100644 --- a/src/Umbraco.Tests/CoreThings/UdiTests.cs +++ b/src/Umbraco.Tests/CoreThings/UdiTests.cs @@ -12,6 +12,7 @@ using Umbraco.Core.Composing; using Umbraco.Core.Deploy; using Umbraco.Core.Logging; using Umbraco.Core.Serialization; +using Umbraco.Tests.TestHelpers; namespace Umbraco.Tests.CoreThings { @@ -23,7 +24,9 @@ namespace Umbraco.Tests.CoreThings { // fixme - bad in a unit test - but Udi has a static ctor that wants it?! var container = new Mock(); - container.Setup(x => x.GetInstance(typeof (TypeLoader))).Returns(new TypeLoader(NullCacheProvider.Instance, new ProfilingLogger(Mock.Of(), Mock.Of()))); + var globalSettings = SettingsForTests.GenerateMockGlobalSettings(); + container.Setup(x => x.GetInstance(typeof (TypeLoader))).Returns( + new TypeLoader(NullCacheProvider.Instance, globalSettings, new ProfilingLogger(Mock.Of(), Mock.Of()))); Current.Container = container.Object; Udi.ResetUdiTypes(); diff --git a/src/Umbraco.Tests/CoreThings/UriExtensionsTests.cs b/src/Umbraco.Tests/CoreThings/UriExtensionsTests.cs index ab10be1a65..7f00bed123 100644 --- a/src/Umbraco.Tests/CoreThings/UriExtensionsTests.cs +++ b/src/Umbraco.Tests/CoreThings/UriExtensionsTests.cs @@ -2,6 +2,7 @@ using NUnit.Framework; using Umbraco.Core; using Umbraco.Core.IO; +using Umbraco.Tests.TestHelpers; namespace Umbraco.Tests.CoreThings { @@ -48,9 +49,9 @@ namespace Umbraco.Tests.CoreThings public void Is_Back_Office_Request(string input, string virtualPath, bool expected) { SystemDirectories.Root = virtualPath; - + var globalConfig = SettingsForTests.GenerateMockGlobalSettings(); var source = new Uri(input); - Assert.AreEqual(expected, source.IsBackOfficeRequest(virtualPath)); + Assert.AreEqual(expected, source.IsBackOfficeRequest(virtualPath, globalConfig)); } [TestCase("http://www.domain.com/install", true)] diff --git a/src/Umbraco.Tests/IO/FileSystemsTests.cs b/src/Umbraco.Tests/IO/FileSystemsTests.cs index ef2fa3ce72..79b1d8bf6c 100644 --- a/src/Umbraco.Tests/IO/FileSystemsTests.cs +++ b/src/Umbraco.Tests/IO/FileSystemsTests.cs @@ -23,7 +23,7 @@ namespace Umbraco.Tests.IO public void Setup() { //init the config singleton - var config = SettingsForTests.GetDefault(); + var config = SettingsForTests.GetDefaultUmbracoSettings(); SettingsForTests.ConfigureSettings(config); _container = new ServiceContainer(); diff --git a/src/Umbraco.Tests/Macros/MacroTests.cs b/src/Umbraco.Tests/Macros/MacroTests.cs index 6c5c88f6ff..e3a4db5390 100644 --- a/src/Umbraco.Tests/Macros/MacroTests.cs +++ b/src/Umbraco.Tests/Macros/MacroTests.cs @@ -26,7 +26,7 @@ namespace Umbraco.Tests.Macros new IsolatedRuntimeCache(type => new ObjectCacheRuntimeCacheProvider())); //Current.ApplicationContext = new ApplicationContext(cacheHelper, new ProfilingLogger(Mock.Of(), Mock.Of())); - UmbracoConfig.For.SetUmbracoSettings(SettingsForTests.GetDefault()); + UmbracoConfig.For.SetUmbracoSettings(SettingsForTests.GetDefaultUmbracoSettings()); } [TestCase("123", "IntProp", typeof(int))] diff --git a/src/Umbraco.Tests/Misc/ApplicationUrlHelperTests.cs b/src/Umbraco.Tests/Misc/ApplicationUrlHelperTests.cs index a20b86cc7b..bb134d7e35 100644 --- a/src/Umbraco.Tests/Misc/ApplicationUrlHelperTests.cs +++ b/src/Umbraco.Tests/Misc/ApplicationUrlHelperTests.cs @@ -7,8 +7,10 @@ using NUnit.Framework; using Umbraco.Core; using Umbraco.Core.Configuration.UmbracoSettings; using Umbraco.Core.Composing; +using Umbraco.Core.Configuration; using Umbraco.Core.Logging; using Umbraco.Core.Sync; +using Umbraco.Tests.TestHelpers; namespace Umbraco.Tests.Misc { @@ -20,9 +22,9 @@ namespace Umbraco.Tests.Misc // note: in tests, read appContext._umbracoApplicationUrl and not the property, // because reading the property does run some code, as long as the field is null. - private void Initialize(IUmbracoSettingsSection settings) + private void Initialize(IUmbracoSettingsSection settings, IGlobalSettings globalSettings) { - _registrar = new ConfigServerRegistrar(settings.DistributedCall, Mock.Of()); + _registrar = new ConfigServerRegistrar(settings.DistributedCall, Mock.Of(), globalSettings); var container = new ServiceContainer(); container.ConfigureUmbracoCore(); container.Register(_ => _registrar); @@ -51,15 +53,16 @@ namespace Umbraco.Tests.Misc && section.WebRouting == Mock.Of(wrSection => wrSection.UmbracoApplicationUrl == (string) null) && section.ScheduledTasks == Mock.Of()); + var globalConfig = Mock.Get(SettingsForTests.GenerateMockGlobalSettings()); + globalConfig.Setup(x => x.UseHttps).Returns(true); + ApplicationUrlHelper.ApplicationUrlProvider = request => "http://server1.com/umbraco"; - Initialize(settings); + Initialize(settings, globalConfig.Object); var state = new RuntimeState(Mock.Of(), new Lazy(Mock.Of), new Lazy(Mock.Of)); - ConfigurationManager.AppSettings.Set("umbracoUseSSL", "true"); // does not make a diff here - - state.EnsureApplicationUrl(settings: settings); + state.EnsureApplicationUrl(settings, globalConfig.Object); Assert.AreEqual("http://server1.com/umbraco", state.ApplicationUrl.ToString()); } @@ -74,11 +77,12 @@ namespace Umbraco.Tests.Misc && section.WebRouting == Mock.Of(wrSection => wrSection.UmbracoApplicationUrl == (string) null) && section.ScheduledTasks == Mock.Of()); - Initialize(settings); + var globalConfig = Mock.Get(SettingsForTests.GenerateMockGlobalSettings()); + globalConfig.Setup(x => x.UseHttps).Returns(true); - ConfigurationManager.AppSettings.Set("umbracoUseSSL", "true"); // does not make a diff here - - var url = ApplicationUrlHelper.TryGetApplicationUrl(settings, Mock.Of()); + Initialize(settings, globalConfig.Object); + + var url = ApplicationUrlHelper.TryGetApplicationUrl(settings, Mock.Of(), globalConfig.Object); // still NOT set Assert.IsNull(url); @@ -99,11 +103,12 @@ namespace Umbraco.Tests.Misc && section.WebRouting == Mock.Of(wrSection => wrSection.UmbracoApplicationUrl == (string)null) && section.ScheduledTasks == Mock.Of(tasksSection => tasksSection.BaseUrl == (string)null)); - Initialize(settings); + var globalConfig = Mock.Get(SettingsForTests.GenerateMockGlobalSettings()); + globalConfig.Setup(x => x.UseHttps).Returns(true); - ConfigurationManager.AppSettings.Set("umbracoUseSSL", "true"); + Initialize(settings, globalConfig.Object); - var url = ApplicationUrlHelper.TryGetApplicationUrl(settings, Mock.Of()); + var url = ApplicationUrlHelper.TryGetApplicationUrl(settings, Mock.Of(), globalConfig.Object); Assert.AreEqual("http://server1.com:80/umbraco", url); @@ -126,11 +131,12 @@ namespace Umbraco.Tests.Misc && section.WebRouting == Mock.Of(wrSection => wrSection.UmbracoApplicationUrl == (string)null) && section.ScheduledTasks == Mock.Of(tasksSection => tasksSection.BaseUrl == (string)null)); - Initialize(settings); + var globalConfig = Mock.Get(SettingsForTests.GenerateMockGlobalSettings()); + globalConfig.Setup(x => x.UseHttps).Returns(true); - ConfigurationManager.AppSettings.Set("umbracoUseSSL", "true"); + Initialize(settings, globalConfig.Object); - var url = ApplicationUrlHelper.TryGetApplicationUrl(settings, Mock.Of()); + var url = ApplicationUrlHelper.TryGetApplicationUrl(settings, Mock.Of(), globalConfig.Object); Assert.AreEqual("http://server1.com:80/umbraco", url); @@ -153,11 +159,12 @@ namespace Umbraco.Tests.Misc && section.WebRouting == Mock.Of(wrSection => wrSection.UmbracoApplicationUrl == (string)null) && section.ScheduledTasks == Mock.Of(tasksSection => tasksSection.BaseUrl == (string)null)); - Initialize(settings); + var globalConfig = Mock.Get(SettingsForTests.GenerateMockGlobalSettings()); + globalConfig.Setup(x => x.UseHttps).Returns(true); - ConfigurationManager.AppSettings.Set("umbracoUseSSL", "true"); + Initialize(settings, globalConfig.Object); - var url = ApplicationUrlHelper.TryGetApplicationUrl(settings, Mock.Of()); + var url = ApplicationUrlHelper.TryGetApplicationUrl(settings, Mock.Of(), globalConfig.Object); Assert.IsNull(url); @@ -174,8 +181,10 @@ namespace Umbraco.Tests.Misc section.DistributedCall == Mock.Of(callSection => callSection.Enabled == false && callSection.Servers == Enumerable.Empty()) && section.WebRouting == Mock.Of(wrSection => wrSection.UmbracoApplicationUrl == (string)null) && section.ScheduledTasks == Mock.Of(tasksSection => tasksSection.BaseUrl == (string)null)); - - Initialize(settings); + + var globalConfig = Mock.Get(SettingsForTests.GenerateMockGlobalSettings()); + + Initialize(settings, globalConfig.Object); var role = _registrar.GetCurrentServerRole(); Assert.AreEqual(ServerRole.Single, role); @@ -191,7 +200,9 @@ namespace Umbraco.Tests.Misc && section.WebRouting == Mock.Of(wrSection => wrSection.UmbracoApplicationUrl == (string)null) && section.ScheduledTasks == Mock.Of(tasksSection => tasksSection.BaseUrl == (string)null)); - Initialize(settings); + var globalConfig = Mock.Get(SettingsForTests.GenerateMockGlobalSettings()); + + Initialize(settings, globalConfig.Object); var role = _registrar.GetCurrentServerRole(); Assert.AreEqual(ServerRole.Unknown, role); @@ -210,7 +221,9 @@ namespace Umbraco.Tests.Misc && section.WebRouting == Mock.Of(wrSection => wrSection.UmbracoApplicationUrl == (string)null) && section.ScheduledTasks == Mock.Of(tasksSection => tasksSection.BaseUrl == (string)null)); - Initialize(settings); + var globalConfig = Mock.Get(SettingsForTests.GenerateMockGlobalSettings()); + + Initialize(settings, globalConfig.Object); var role = _registrar.GetCurrentServerRole(); Assert.AreEqual(ServerRole.Slave, role); @@ -224,11 +237,12 @@ namespace Umbraco.Tests.Misc && section.WebRouting == Mock.Of(wrSection => wrSection.UmbracoApplicationUrl == (string) null) && section.ScheduledTasks == Mock.Of(tasksSection => tasksSection.BaseUrl == "mycoolhost.com/umbraco")); - Initialize(settings); + var globalConfig = Mock.Get(SettingsForTests.GenerateMockGlobalSettings()); + globalConfig.Setup(x => x.UseHttps).Returns(false); - ConfigurationManager.AppSettings.Set("umbracoUseSSL", "false"); - - var url = ApplicationUrlHelper.TryGetApplicationUrl(settings, Mock.Of()); + Initialize(settings, globalConfig.Object); + + var url = ApplicationUrlHelper.TryGetApplicationUrl(settings, Mock.Of(), globalConfig.Object); Assert.AreEqual("http://mycoolhost.com/umbraco", url); } @@ -241,11 +255,12 @@ namespace Umbraco.Tests.Misc && section.WebRouting == Mock.Of(wrSection => wrSection.UmbracoApplicationUrl == (string) null) && section.ScheduledTasks == Mock.Of(tasksSection => tasksSection.BaseUrl == "mycoolhost.com/umbraco/")); - Initialize(settings); + var globalConfig = Mock.Get(SettingsForTests.GenerateMockGlobalSettings()); + globalConfig.Setup(x => x.UseHttps).Returns(true); - ConfigurationManager.AppSettings.Set("umbracoUseSSL", "true"); - - var url = ApplicationUrlHelper.TryGetApplicationUrl(settings, Mock.Of()); + Initialize(settings, globalConfig.Object); + + var url = ApplicationUrlHelper.TryGetApplicationUrl(settings, Mock.Of(), globalConfig.Object); Assert.AreEqual("https://mycoolhost.com/umbraco", url); } @@ -258,11 +273,12 @@ namespace Umbraco.Tests.Misc && section.WebRouting == Mock.Of(wrSection => wrSection.UmbracoApplicationUrl == "httpx://whatever.com/umbraco/") && section.ScheduledTasks == Mock.Of(tasksSection => tasksSection.BaseUrl == "mycoolhost.com/umbraco")); - Initialize(settings); + var globalConfig = Mock.Get(SettingsForTests.GenerateMockGlobalSettings()); + globalConfig.Setup(x => x.UseHttps).Returns(true); - ConfigurationManager.AppSettings.Set("umbracoUseSSL", "true"); // does not make a diff here + Initialize(settings, globalConfig.Object); - var url = ApplicationUrlHelper.TryGetApplicationUrl(settings, Mock.Of()); + var url = ApplicationUrlHelper.TryGetApplicationUrl(settings, Mock.Of(), globalConfig.Object); Assert.AreEqual("httpx://whatever.com/umbraco", url); } diff --git a/src/Umbraco.Tests/Misc/UriUtilityTests.cs b/src/Umbraco.Tests/Misc/UriUtilityTests.cs index 851060ce13..0bd9156f20 100644 --- a/src/Umbraco.Tests/Misc/UriUtilityTests.cs +++ b/src/Umbraco.Tests/Misc/UriUtilityTests.cs @@ -84,7 +84,10 @@ namespace Umbraco.Tests.Misc { ConfigurationManager.AppSettings.Set("umbracoUseDirectoryUrls", directoryUrls ? "true" : "false"); - var settings = SettingsForTests.GenerateMockSettings(); + var globalConfig = Mock.Get(SettingsForTests.GenerateMockGlobalSettings()); + globalConfig.Setup(x => x.UseDirectoryUrls).Returns(directoryUrls); + + var settings = SettingsForTests.GenerateMockUmbracoSettings(); var requestMock = Mock.Get(settings.RequestHandler); requestMock.Setup(x => x.AddTrailingSlash).Returns(trailingSlash); SettingsForTests.ConfigureSettings(settings); @@ -93,7 +96,7 @@ namespace Umbraco.Tests.Misc var expectedUri = NewUri(expectedUrl); var sourceUri = NewUri(sourceUrl); - var resultUri = UriUtility.UriFromUmbraco(sourceUri); + var resultUri = UriUtility.UriFromUmbraco(sourceUri, globalConfig.Object, settings.RequestHandler); Assert.AreEqual(expectedUri.ToString(), resultUri.ToString()); } diff --git a/src/Umbraco.Tests/Models/ContentTests.cs b/src/Umbraco.Tests/Models/ContentTests.cs index 93e3e91f6a..be22c39626 100644 --- a/src/Umbraco.Tests/Models/ContentTests.cs +++ b/src/Umbraco.Tests/Models/ContentTests.cs @@ -29,7 +29,7 @@ namespace Umbraco.Tests.Models { base.SetUp(); - var config = SettingsForTests.GetDefault(); + var config = SettingsForTests.GetDefaultUmbracoSettings(); SettingsForTests.ConfigureSettings(config); } diff --git a/src/Umbraco.Tests/Models/MacroTests.cs b/src/Umbraco.Tests/Models/MacroTests.cs index 64e485c965..052c42942b 100644 --- a/src/Umbraco.Tests/Models/MacroTests.cs +++ b/src/Umbraco.Tests/Models/MacroTests.cs @@ -13,7 +13,7 @@ namespace Umbraco.Tests.Models [SetUp] public void Init() { - var config = SettingsForTests.GetDefault(); + var config = SettingsForTests.GetDefaultUmbracoSettings(); SettingsForTests.ConfigureSettings(config); } diff --git a/src/Umbraco.Tests/Packaging/PackageExtractionTests.cs b/src/Umbraco.Tests/Packaging/PackageExtractionTests.cs index a1bdb0979d..118d57ab2a 100644 --- a/src/Umbraco.Tests/Packaging/PackageExtractionTests.cs +++ b/src/Umbraco.Tests/Packaging/PackageExtractionTests.cs @@ -14,7 +14,7 @@ namespace Umbraco.Tests.Packaging private static string GetTestPackagePath(string packageName) { const string testPackagesDirName = "Packaging\\Packages"; - string path = Path.Combine(Core.Configuration.GlobalSettings.FullpathToRoot, testPackagesDirName, packageName); + string path = Path.Combine(Core.Configuration.GlobalSettings.FullPathToRoot, testPackagesDirName, packageName); return path; } diff --git a/src/Umbraco.Tests/Persistence/Repositories/UserRepositoryTest.cs b/src/Umbraco.Tests/Persistence/Repositories/UserRepositoryTest.cs index a636e956f9..fe2c946331 100644 --- a/src/Umbraco.Tests/Persistence/Repositories/UserRepositoryTest.cs +++ b/src/Umbraco.Tests/Persistence/Repositories/UserRepositoryTest.cs @@ -49,7 +49,7 @@ namespace Umbraco.Tests.Persistence.Repositories private UserRepository CreateRepository(IScopeProvider provider) { var accessor = (IScopeAccessor) provider; - var repository = new UserRepository(accessor, CacheHelper.CreateDisabledCacheHelper(), Mock.Of(), Mock.Of()); + var repository = new UserRepository(accessor, CacheHelper.CreateDisabledCacheHelper(), Mock.Of(), Mock.Of(), TestObjects.GetGlobalSettings()); return repository; } @@ -204,7 +204,7 @@ namespace Umbraco.Tests.Persistence.Repositories var id = user.Id; - var repository2 = new UserRepository((IScopeAccessor) provider, CacheHelper.CreateDisabledCacheHelper(), Logger, Mock.Of()); + var repository2 = new UserRepository((IScopeAccessor) provider, CacheHelper.CreateDisabledCacheHelper(), Logger, Mock.Of(),TestObjects.GetGlobalSettings()); repository2.Delete(user); diff --git a/src/Umbraco.Tests/PropertyEditors/PropertyEditorValueEditorTests.cs b/src/Umbraco.Tests/PropertyEditors/PropertyEditorValueEditorTests.cs index ff2ee0aebd..acbd021319 100644 --- a/src/Umbraco.Tests/PropertyEditors/PropertyEditorValueEditorTests.cs +++ b/src/Umbraco.Tests/PropertyEditors/PropertyEditorValueEditorTests.cs @@ -25,7 +25,7 @@ namespace Umbraco.Tests.PropertyEditors var container = new ServiceContainer(); container.ConfigureUmbracoCore(); container.Register(_ - => new DefaultShortStringHelper(new DefaultShortStringHelperConfig().WithDefault(SettingsForTests.GetDefault()))); + => new DefaultShortStringHelper(new DefaultShortStringHelperConfig().WithDefault(SettingsForTests.GetDefaultUmbracoSettings()))); } [TearDown] diff --git a/src/Umbraco.Tests/PublishedContent/PublishedContentMoreTests.cs b/src/Umbraco.Tests/PublishedContent/PublishedContentMoreTests.cs index 5d4e0e1691..2713229a5e 100644 --- a/src/Umbraco.Tests/PublishedContent/PublishedContentMoreTests.cs +++ b/src/Umbraco.Tests/PublishedContent/PublishedContentMoreTests.cs @@ -65,13 +65,16 @@ namespace Umbraco.Tests.PublishedContent var publishedSnapshotService = new Mock(); publishedSnapshotService.Setup(x => x.CreatePublishedSnapshot(It.IsAny())).Returns(publishedSnapshot); + var globalSettings = TestObjects.GetGlobalSettings(); + var httpContext = GetHttpContextFactory("http://umbraco.local/", routeData).HttpContext; var umbracoContext = new UmbracoContext( httpContext, publishedSnapshotService.Object, - new WebSecurity(httpContext, Current.Services.UserService), + new WebSecurity(httpContext, Current.Services.UserService, globalSettings), TestObjects.GetUmbracoSettings(), - Enumerable.Empty()); + Enumerable.Empty(), + globalSettings); return umbracoContext; } diff --git a/src/Umbraco.Tests/PublishedContent/PublishedMediaTests.cs b/src/Umbraco.Tests/PublishedContent/PublishedMediaTests.cs index f53f761060..adfc9f535a 100644 --- a/src/Umbraco.Tests/PublishedContent/PublishedMediaTests.cs +++ b/src/Umbraco.Tests/PublishedContent/PublishedMediaTests.cs @@ -439,7 +439,7 @@ namespace Umbraco.Tests.PublishedContent [Test] public void Convert_From_Standard_Xml() { - var config = SettingsForTests.GenerateMockSettings(); + var config = SettingsForTests.GenerateMockUmbracoSettings(); SettingsForTests.ConfigureSettings(config); diff --git a/src/Umbraco.Tests/Routing/ContentFinderByNiceUrlAndTemplateTests.cs b/src/Umbraco.Tests/Routing/ContentFinderByNiceUrlAndTemplateTests.cs index 713a8e68d6..c58899d4d1 100644 --- a/src/Umbraco.Tests/Routing/ContentFinderByNiceUrlAndTemplateTests.cs +++ b/src/Umbraco.Tests/Routing/ContentFinderByNiceUrlAndTemplateTests.cs @@ -1,4 +1,5 @@ -using NUnit.Framework; +using Moq; +using NUnit.Framework; using Umbraco.Tests.TestHelpers; using Umbraco.Web.Routing; using Umbraco.Core.Models; @@ -26,15 +27,18 @@ namespace Umbraco.Tests.Routing [TestCase("/home/Sub1.aspx/blah")] public void Match_Document_By_Url_With_Template(string urlAsString) { + + var globalSettings = Mock.Get(TestObjects.GetGlobalSettings()); //this will modify the IGlobalSettings instance stored in the container + globalSettings.Setup(x => x.HideTopLevelNodeFromPath).Returns(false); + SettingsForTests.ConfigureSettings(globalSettings.Object); + var template1 = CreateTemplate("test"); var template2 = CreateTemplate("blah"); - var umbracoContext = GetUmbracoContext(urlAsString, template1.Id); + var umbracoContext = GetUmbracoContext(urlAsString, template1.Id, globalSettings:globalSettings.Object); var publishedRouter = CreatePublishedRouter(); var frequest = publishedRouter.CreateRequest(umbracoContext); var lookup = new ContentFinderByNiceUrlAndTemplate(Logger); - SettingsForTests.HideTopLevelNodeFromPath = false; - var result = lookup.TryFindContent(frequest); Assert.IsTrue(result); diff --git a/src/Umbraco.Tests/Routing/ContentFinderByNiceUrlTests.cs b/src/Umbraco.Tests/Routing/ContentFinderByNiceUrlTests.cs index fe8fbcf8f7..66f5cc722a 100644 --- a/src/Umbraco.Tests/Routing/ContentFinderByNiceUrlTests.cs +++ b/src/Umbraco.Tests/Routing/ContentFinderByNiceUrlTests.cs @@ -1,6 +1,8 @@ using System; using System.Globalization; +using Moq; using NUnit.Framework; +using Umbraco.Core.Configuration; using Umbraco.Core.Models; using Umbraco.Tests.TestHelpers; using Umbraco.Tests.Testing; @@ -25,13 +27,16 @@ namespace Umbraco.Tests.Routing [TestCase("/test-page", 1172)] public void Match_Document_By_Url_Hide_Top_Level(string urlString, int expectedId) { - var umbracoContext = GetUmbracoContext(urlString); + var globalSettingsMock = Mock.Get(TestObjects.GetGlobalSettings()); //this will modify the IGlobalSettings instance stored in the container + globalSettingsMock.Setup(x => x.HideTopLevelNodeFromPath).Returns(true); + SettingsForTests.ConfigureSettings(globalSettingsMock.Object); + + var umbracoContext = GetUmbracoContext(urlString, globalSettings:globalSettingsMock.Object); var publishedRouter = CreatePublishedRouter(); var frequest = publishedRouter.CreateRequest(umbracoContext); var lookup = new ContentFinderByNiceUrl(Logger); - SettingsForTests.HideTopLevelNodeFromPath = true; - Assert.IsTrue(Core.Configuration.GlobalSettings.HideTopLevelNodeFromPath); + Assert.IsTrue(UmbracoConfig.For.GlobalSettings().HideTopLevelNodeFromPath); // fixme debugging - going further down, the routes cache is NOT empty?! if (urlString == "/home/sub1") @@ -58,13 +63,16 @@ namespace Umbraco.Tests.Routing [TestCase("/home/Sub1.aspx", 1173)] public void Match_Document_By_Url(string urlString, int expectedId) { - var umbracoContext = GetUmbracoContext(urlString); + var globalSettingsMock = Mock.Get(TestObjects.GetGlobalSettings()); //this will modify the IGlobalSettings instance stored in the container + globalSettingsMock.Setup(x => x.HideTopLevelNodeFromPath).Returns(false); + SettingsForTests.ConfigureSettings(globalSettingsMock.Object); + + var umbracoContext = GetUmbracoContext(urlString, globalSettings:globalSettingsMock.Object); var publishedRouter = CreatePublishedRouter(); var frequest = publishedRouter.CreateRequest(umbracoContext); var lookup = new ContentFinderByNiceUrl(Logger); - SettingsForTests.HideTopLevelNodeFromPath = false; - Assert.IsFalse(Core.Configuration.GlobalSettings.HideTopLevelNodeFromPath); + Assert.IsFalse(UmbracoConfig.For.GlobalSettings().HideTopLevelNodeFromPath); var result = lookup.TryFindContent(frequest); @@ -81,12 +89,15 @@ namespace Umbraco.Tests.Routing [TestCase("/home/sub1/custom-sub-4-with-æøå", 1180)] public void Match_Document_By_Url_With_Special_Characters(string urlString, int expectedId) { - var umbracoContext = GetUmbracoContext(urlString); + var globalSettingsMock = Mock.Get(TestObjects.GetGlobalSettings()); //this will modify the IGlobalSettings instance stored in the container + globalSettingsMock.Setup(x => x.HideTopLevelNodeFromPath).Returns(false); + SettingsForTests.ConfigureSettings(globalSettingsMock.Object); + + var umbracoContext = GetUmbracoContext(urlString, globalSettings:globalSettingsMock.Object); var publishedRouter = CreatePublishedRouter(); var frequest = publishedRouter.CreateRequest(umbracoContext); var lookup = new ContentFinderByNiceUrl(Logger); - SettingsForTests.HideTopLevelNodeFromPath = false; - + var result = lookup.TryFindContent(frequest); Assert.IsTrue(result); @@ -106,12 +117,15 @@ namespace Umbraco.Tests.Routing [TestCase("/home/sub1/custom-sub-4-with-æøå", 1180)] public void Match_Document_By_Url_With_Special_Characters_Using_Hostname(string urlString, int expectedId) { - var umbracoContext = GetUmbracoContext(urlString); + var globalSettingsMock = Mock.Get(TestObjects.GetGlobalSettings()); //this will modify the IGlobalSettings instance stored in the container + globalSettingsMock.Setup(x => x.HideTopLevelNodeFromPath).Returns(false); + SettingsForTests.ConfigureSettings(globalSettingsMock.Object); + + var umbracoContext = GetUmbracoContext(urlString, globalSettings:globalSettingsMock.Object); var publishedRouter = CreatePublishedRouter(); var frequest = publishedRouter.CreateRequest(umbracoContext); frequest.Domain = new DomainAndUri(new Domain(1, "mysite", -1, CultureInfo.CurrentCulture, false), new Uri("http://mysite/")); var lookup = new ContentFinderByNiceUrl(Logger); - SettingsForTests.HideTopLevelNodeFromPath = false; var result = lookup.TryFindContent(frequest); @@ -133,13 +147,16 @@ namespace Umbraco.Tests.Routing [TestCase("/æøå/home/sub1/custom-sub-4-with-æøå", 1180)] public void Match_Document_By_Url_With_Special_Characters_In_Hostname(string urlString, int expectedId) { - var umbracoContext = GetUmbracoContext(urlString); + var globalSettingsMock = Mock.Get(TestObjects.GetGlobalSettings()); //this will modify the IGlobalSettings instance stored in the container + globalSettingsMock.Setup(x => x.HideTopLevelNodeFromPath).Returns(false); + SettingsForTests.ConfigureSettings(globalSettingsMock.Object); + + var umbracoContext = GetUmbracoContext(urlString, globalSettings:globalSettingsMock.Object); var publishedRouter = CreatePublishedRouter(); var frequest = publishedRouter.CreateRequest(umbracoContext); frequest.Domain = new DomainAndUri(new Domain(1, "mysite/æøå", -1, CultureInfo.CurrentCulture, false), new Uri("http://mysite/æøå")); var lookup = new ContentFinderByNiceUrl(Logger); - SettingsForTests.HideTopLevelNodeFromPath = false; - + var result = lookup.TryFindContent(frequest); Assert.IsTrue(result); diff --git a/src/Umbraco.Tests/Routing/ContentFinderByNiceUrlWithDomainsTests.cs b/src/Umbraco.Tests/Routing/ContentFinderByNiceUrlWithDomainsTests.cs index e05fed11dc..396697001d 100644 --- a/src/Umbraco.Tests/Routing/ContentFinderByNiceUrlWithDomainsTests.cs +++ b/src/Umbraco.Tests/Routing/ContentFinderByNiceUrlWithDomainsTests.cs @@ -1,4 +1,5 @@ -using NUnit.Framework; +using Moq; +using NUnit.Framework; using Umbraco.Core.Models; using Umbraco.Tests.TestHelpers; using Umbraco.Web.Routing; @@ -123,9 +124,11 @@ namespace Umbraco.Tests.Routing { SetDomains3(); - SettingsForTests.HideTopLevelNodeFromPath = true; - - var umbracoContext = GetUmbracoContext(url); + var globalSettingsMock = Mock.Get(TestObjects.GetGlobalSettings()); //this will modify the IGlobalSettings instance stored in the container + globalSettingsMock.Setup(x => x.HideTopLevelNodeFromPath).Returns(true); + SettingsForTests.ConfigureSettings(globalSettingsMock.Object); + + var umbracoContext = GetUmbracoContext(url, globalSettings:globalSettingsMock.Object); var publishedRouter = CreatePublishedRouter(Container); var frequest = publishedRouter.CreateRequest(umbracoContext); @@ -164,9 +167,11 @@ namespace Umbraco.Tests.Routing // defaults depend on test environment expectedCulture = expectedCulture ?? System.Threading.Thread.CurrentThread.CurrentUICulture.Name; - SettingsForTests.HideTopLevelNodeFromPath = true; + var globalSettingsMock = Mock.Get(TestObjects.GetGlobalSettings()); //this will modify the IGlobalSettings instance stored in the container + globalSettingsMock.Setup(x => x.HideTopLevelNodeFromPath).Returns(true); + SettingsForTests.ConfigureSettings(globalSettingsMock.Object); - var umbracoContext = GetUmbracoContext(url); + var umbracoContext = GetUmbracoContext(url, globalSettings:globalSettingsMock.Object); var publishedRouter = CreatePublishedRouter(Container); var frequest = publishedRouter.CreateRequest(umbracoContext); diff --git a/src/Umbraco.Tests/Routing/DomainsAndCulturesTests.cs b/src/Umbraco.Tests/Routing/DomainsAndCulturesTests.cs index e67248cdfa..b1d024cc8f 100644 --- a/src/Umbraco.Tests/Routing/DomainsAndCulturesTests.cs +++ b/src/Umbraco.Tests/Routing/DomainsAndCulturesTests.cs @@ -1,4 +1,5 @@ using System; +using Moq; using NUnit.Framework; using Umbraco.Core.Models; using Umbraco.Tests.TestHelpers; @@ -263,7 +264,11 @@ namespace Umbraco.Tests.Routing { SetDomains1(); - var umbracoContext = GetUmbracoContext(inputUrl); + var globalSettings = Mock.Get(TestObjects.GetGlobalSettings()); //this will modify the IGlobalSettings instance stored in the container + globalSettings.Setup(x => x.HideTopLevelNodeFromPath).Returns(false); + SettingsForTests.ConfigureSettings(globalSettings.Object); + + var umbracoContext = GetUmbracoContext(inputUrl, globalSettings:globalSettings.Object); var publishedRouter = CreatePublishedRouter(Container); var frequest = publishedRouter.CreateRequest(umbracoContext); @@ -271,8 +276,7 @@ namespace Umbraco.Tests.Routing publishedRouter.FindDomain(frequest); Assert.AreEqual(expectedCulture, frequest.Culture.Name); - - SettingsForTests.HideTopLevelNodeFromPath = false; + var finder = new ContentFinderByNiceUrl(Logger); var result = finder.TryFindContent(frequest); @@ -310,7 +314,11 @@ namespace Umbraco.Tests.Routing // defaults depend on test environment expectedCulture = expectedCulture ?? System.Threading.Thread.CurrentThread.CurrentUICulture.Name; - var umbracoContext = GetUmbracoContext(inputUrl); + var globalSettings = Mock.Get(TestObjects.GetGlobalSettings()); //this will modify the IGlobalSettings instance stored in the container + globalSettings.Setup(x => x.HideTopLevelNodeFromPath).Returns(false); + SettingsForTests.ConfigureSettings(globalSettings.Object); + + var umbracoContext = GetUmbracoContext(inputUrl, globalSettings:globalSettings.Object); var publishedRouter = CreatePublishedRouter(Container); var frequest = publishedRouter.CreateRequest(umbracoContext); @@ -318,7 +326,6 @@ namespace Umbraco.Tests.Routing publishedRouter.FindDomain(frequest); // find document - SettingsForTests.HideTopLevelNodeFromPath = false; var finder = new ContentFinderByNiceUrl(Logger); var result = finder.TryFindContent(frequest); diff --git a/src/Umbraco.Tests/Routing/NiceUrlProviderTests.cs b/src/Umbraco.Tests/Routing/NiceUrlProviderTests.cs index 0898392484..246a9beb8a 100644 --- a/src/Umbraco.Tests/Routing/NiceUrlProviderTests.cs +++ b/src/Umbraco.Tests/Routing/NiceUrlProviderTests.cs @@ -27,7 +27,7 @@ namespace Umbraco.Tests.Routing base.SetUp(); //generate new mock settings and assign so we can configure in individual tests - _umbracoSettings = SettingsForTests.GenerateMockSettings(); + _umbracoSettings = SettingsForTests.GenerateMockUmbracoSettings(); SettingsForTests.ConfigureSettings(_umbracoSettings); } @@ -38,10 +38,16 @@ namespace Umbraco.Tests.Routing [Test] public void Ensure_Cache_Is_Correct() { - var umbracoContext = GetUmbracoContext("/test", 1111, urlProviders: new [] { new DefaultUrlProvider(_umbracoSettings.RequestHandler, Logger) }); - SettingsForTests.UseDirectoryUrls = true; - SettingsForTests.HideTopLevelNodeFromPath = false; + var globalSettings = Mock.Get(TestObjects.GetGlobalSettings()); //this will modify the IGlobalSettings instance stored in the container + globalSettings.Setup(x => x.UseDirectoryUrls).Returns(true); + globalSettings.Setup(x => x.HideTopLevelNodeFromPath).Returns(false); + SettingsForTests.ConfigureSettings(globalSettings.Object); + var umbracoContext = GetUmbracoContext("/test", 1111, urlProviders: new [] + { + new DefaultUrlProvider(_umbracoSettings.RequestHandler, Logger, globalSettings.Object) + }, globalSettings:globalSettings.Object); + var requestHandlerMock = Mock.Get(_umbracoSettings.RequestHandler); requestHandlerMock.Setup(x => x.AddTrailingSlash).Returns(false);// (cached routes have none) @@ -95,10 +101,16 @@ namespace Umbraco.Tests.Routing [TestCase(1172, "/test-page/")] public void Get_Nice_Url_Not_Hiding_Top_Level(int nodeId, string niceUrlMatch) { - var umbracoContext = GetUmbracoContext("/test", 1111, urlProviders: new[] { new DefaultUrlProvider(_umbracoSettings.RequestHandler, Logger) }); + var globalSettings = Mock.Get(TestObjects.GetGlobalSettings()); //this will modify the IGlobalSettings instance stored in the container + globalSettings.Setup(x => x.UseDirectoryUrls).Returns(true); + globalSettings.Setup(x => x.HideTopLevelNodeFromPath).Returns(false); + SettingsForTests.ConfigureSettings(globalSettings.Object); + + var umbracoContext = GetUmbracoContext("/test", 1111, urlProviders: new[] + { + new DefaultUrlProvider(_umbracoSettings.RequestHandler, Logger, globalSettings.Object) + }, globalSettings:globalSettings.Object); - SettingsForTests.UseDirectoryUrls = true; - SettingsForTests.HideTopLevelNodeFromPath = false; var requestMock = Mock.Get(_umbracoSettings.RequestHandler); requestMock.Setup(x => x.UseDomainPrefixes).Returns(false); @@ -119,10 +131,16 @@ namespace Umbraco.Tests.Routing [TestCase(1172, "/test-page/")] // not hidden because not first root public void Get_Nice_Url_Hiding_Top_Level(int nodeId, string niceUrlMatch) { - var umbracoContext = GetUmbracoContext("/test", 1111, urlProviders: new[] { new DefaultUrlProvider(_umbracoSettings.RequestHandler, Logger) }); + var globalSettings = Mock.Get(TestObjects.GetGlobalSettings()); //this will modify the IGlobalSettings instance stored in the container + globalSettings.Setup(x => x.UseDirectoryUrls).Returns(true); + globalSettings.Setup(x => x.HideTopLevelNodeFromPath).Returns(true); + SettingsForTests.ConfigureSettings(globalSettings.Object); + + var umbracoContext = GetUmbracoContext("/test", 1111, urlProviders: new[] + { + new DefaultUrlProvider(_umbracoSettings.RequestHandler, Logger, globalSettings.Object) + }, globalSettings:globalSettings.Object); - SettingsForTests.UseDirectoryUrls = true; - SettingsForTests.HideTopLevelNodeFromPath = true; var requestMock = Mock.Get(_umbracoSettings.RequestHandler); requestMock.Setup(x => x.UseDomainPrefixes).Returns(false); @@ -133,12 +151,19 @@ namespace Umbraco.Tests.Routing [Test] public void Get_Nice_Url_Relative_Or_Absolute() { - SettingsForTests.UseDirectoryUrls = true; - SettingsForTests.HideTopLevelNodeFromPath = false; + var globalSettings = Mock.Get(TestObjects.GetGlobalSettings()); //this will modify the IGlobalSettings instance stored in the container + globalSettings.Setup(x => x.UseDirectoryUrls).Returns(true); + globalSettings.Setup(x => x.HideTopLevelNodeFromPath).Returns(false); + SettingsForTests.ConfigureSettings(globalSettings.Object); + + var requestMock = Mock.Get(_umbracoSettings.RequestHandler); requestMock.Setup(x => x.UseDomainPrefixes).Returns(false); - var umbracoContext = GetUmbracoContext("http://example.com/test", 1111, umbracoSettings: _umbracoSettings, urlProviders: new[] { new DefaultUrlProvider(_umbracoSettings.RequestHandler, Logger) }); + var umbracoContext = GetUmbracoContext("http://example.com/test", 1111, umbracoSettings: _umbracoSettings, urlProviders: new[] + { + new DefaultUrlProvider(_umbracoSettings.RequestHandler, Logger, globalSettings.Object) + }, globalSettings:globalSettings.Object); Assert.AreEqual("/home/sub1/custom-sub-1/", umbracoContext.UrlProvider.GetUrl(1177)); @@ -153,10 +178,15 @@ namespace Umbraco.Tests.Routing [Test] public void Get_Nice_Url_Unpublished() { - var umbracoContext = GetUmbracoContext("http://example.com/test", 1111, urlProviders: new[] { new DefaultUrlProvider(_umbracoSettings.RequestHandler, Logger) }); + var globalSettings = Mock.Get(TestObjects.GetGlobalSettings()); //this will modify the IGlobalSettings instance stored in the container + globalSettings.Setup(x => x.UseDirectoryUrls).Returns(true); + globalSettings.Setup(x => x.HideTopLevelNodeFromPath).Returns(false); + SettingsForTests.ConfigureSettings(globalSettings.Object); - SettingsForTests.UseDirectoryUrls = true; - SettingsForTests.HideTopLevelNodeFromPath = false; + var umbracoContext = GetUmbracoContext("http://example.com/test", 1111, urlProviders: new[] + { + new DefaultUrlProvider(_umbracoSettings.RequestHandler, Logger, globalSettings.Object) + }, globalSettings:globalSettings.Object); //mock the Umbraco settings that we need var requestMock = Mock.Get(_umbracoSettings.RequestHandler); diff --git a/src/Umbraco.Tests/Routing/NiceUrlRoutesTests.cs b/src/Umbraco.Tests/Routing/NiceUrlRoutesTests.cs index 7d45a0e85b..2c44a26117 100644 --- a/src/Umbraco.Tests/Routing/NiceUrlRoutesTests.cs +++ b/src/Umbraco.Tests/Routing/NiceUrlRoutesTests.cs @@ -1,4 +1,5 @@ using System; +using Moq; using NUnit.Framework; using Umbraco.Core.Models; using Umbraco.Tests.TestHelpers; @@ -192,12 +193,14 @@ DetermineRouteById(id): [TestCase(2006, false, "/x/b/e")] public void GetRouteByIdNoHide(int id, bool hide, string expected) { - var umbracoContext = GetUmbracoContext("/test", 0); + var globalSettings = Mock.Get(TestObjects.GetGlobalSettings()); //this will modify the IGlobalSettings instance stored in the container + globalSettings.Setup(x => x.HideTopLevelNodeFromPath).Returns(hide); + SettingsForTests.ConfigureSettings(globalSettings.Object); + + var umbracoContext = GetUmbracoContext("/test", 0, globalSettings: globalSettings.Object); var cache = umbracoContext.ContentCache as PublishedContentCache; if (cache == null) throw new Exception("Unsupported IPublishedContentCache, only the Xml one is supported."); - SettingsForTests.HideTopLevelNodeFromPath = hide; - var route = cache.GetRouteById(false, id); Assert.AreEqual(expected, route); } @@ -215,12 +218,14 @@ DetermineRouteById(id): [TestCase(2006, true, "/b/e")] // risky! public void GetRouteByIdHide(int id, bool hide, string expected) { - var umbracoContext = GetUmbracoContext("/test", 0); + var globalSettings = Mock.Get(TestObjects.GetGlobalSettings()); //this will modify the IGlobalSettings instance stored in the container + globalSettings.Setup(x => x.HideTopLevelNodeFromPath).Returns(hide); + SettingsForTests.ConfigureSettings(globalSettings.Object); + + var umbracoContext = GetUmbracoContext("/test", 0, globalSettings: globalSettings.Object); var cache = umbracoContext.ContentCache as PublishedContentCache; if (cache == null) throw new Exception("Unsupported IPublishedContentCache, only the Xml one is supported."); - SettingsForTests.HideTopLevelNodeFromPath = hide; - var route = cache.GetRouteById(false, id); Assert.AreEqual(expected, route); } @@ -228,12 +233,14 @@ DetermineRouteById(id): [Test] public void GetRouteByIdCache() { - var umbracoContext = GetUmbracoContext("/test", 0); + var globalSettings = Mock.Get(TestObjects.GetGlobalSettings()); //this will modify the IGlobalSettings instance stored in the container + globalSettings.Setup(x => x.HideTopLevelNodeFromPath).Returns(false); + SettingsForTests.ConfigureSettings(globalSettings.Object); + + var umbracoContext = GetUmbracoContext("/test", 0, globalSettings:globalSettings.Object); var cache = umbracoContext.ContentCache as PublishedContentCache; if (cache == null) throw new Exception("Unsupported IPublishedContentCache, only the Xml one is supported."); - - SettingsForTests.HideTopLevelNodeFromPath = false; - + var route = cache.GetRouteById(false, 1000); Assert.AreEqual("/a", route); @@ -258,12 +265,14 @@ DetermineRouteById(id): [TestCase("/x", false, 2000)] public void GetByRouteNoHide(string route, bool hide, int expected) { - var umbracoContext = GetUmbracoContext("/test", 0); + var globalSettings = Mock.Get(TestObjects.GetGlobalSettings()); //this will modify the IGlobalSettings instance stored in the container + globalSettings.Setup(x => x.HideTopLevelNodeFromPath).Returns(hide); + SettingsForTests.ConfigureSettings(globalSettings.Object); + + var umbracoContext = GetUmbracoContext("/test", 0, globalSettings:globalSettings.Object); var cache = umbracoContext.ContentCache as PublishedContentCache; if (cache == null) throw new Exception("Unsupported IPublishedContentCache, only the Xml one is supported."); - SettingsForTests.HideTopLevelNodeFromPath = hide; - const bool preview = false; // make sure we don't cache - but HOW? should be some sort of switch?! var content = cache.GetByRoute(preview, route); if (expected < 0) @@ -288,12 +297,14 @@ DetermineRouteById(id): [TestCase("/b/c", true, 1002)] // (hence the 2005 collision) public void GetByRouteHide(string route, bool hide, int expected) { - var umbracoContext = GetUmbracoContext("/test", 0); + var globalSettings = Mock.Get(TestObjects.GetGlobalSettings()); //this will modify the IGlobalSettings instance stored in the container + globalSettings.Setup(x => x.HideTopLevelNodeFromPath).Returns(hide); + SettingsForTests.ConfigureSettings(globalSettings.Object); + + var umbracoContext = GetUmbracoContext("/test", 0, globalSettings:globalSettings.Object); var cache = umbracoContext.ContentCache as PublishedContentCache; if (cache == null) throw new Exception("Unsupported IPublishedContentCache, only the Xml one is supported."); - SettingsForTests.HideTopLevelNodeFromPath = hide; - const bool preview = false; // make sure we don't cache - but HOW? should be some sort of switch?! var content = cache.GetByRoute(preview, route); if (expected < 0) @@ -310,12 +321,14 @@ DetermineRouteById(id): [Test] public void GetByRouteCache() { - var umbracoContext = GetUmbracoContext("/test", 0); + var globalSettings = Mock.Get(TestObjects.GetGlobalSettings()); //this will modify the IGlobalSettings instance stored in the container + globalSettings.Setup(x => x.HideTopLevelNodeFromPath).Returns(false); + SettingsForTests.ConfigureSettings(globalSettings.Object); + + var umbracoContext = GetUmbracoContext("/test", 0, globalSettings:globalSettings.Object); var cache = umbracoContext.ContentCache as PublishedContentCache; if (cache == null) throw new Exception("Unsupported IPublishedContentCache, only the Xml one is supported."); - - SettingsForTests.HideTopLevelNodeFromPath = false; - + var content = cache.GetByRoute(false, "/a/b/c"); Assert.IsNotNull(content); Assert.AreEqual(1002, content.Id); diff --git a/src/Umbraco.Tests/Routing/NiceUrlsProviderWithDomainsTests.cs b/src/Umbraco.Tests/Routing/NiceUrlsProviderWithDomainsTests.cs index 349d1011e4..fa223420f2 100644 --- a/src/Umbraco.Tests/Routing/NiceUrlsProviderWithDomainsTests.cs +++ b/src/Umbraco.Tests/Routing/NiceUrlsProviderWithDomainsTests.cs @@ -173,15 +173,20 @@ namespace Umbraco.Tests.Routing [TestCase(10011, "https://domain1.com", false, "/1001-1/")] public void Get_Nice_Url_SimpleDomain(int nodeId, string currentUrl, bool absolute, string expected) { - var settings = SettingsForTests.GenerateMockSettings(); + var settings = SettingsForTests.GenerateMockUmbracoSettings(); var request = Mock.Get(settings.RequestHandler); request.Setup(x => x.UseDomainPrefixes).Returns(false); - var umbracoContext = GetUmbracoContext("/test", 1111, umbracoSettings: settings, urlProviders: new[] { new DefaultUrlProvider(settings.RequestHandler, Logger) }); - - SettingsForTests.UseDirectoryUrls = true; - SettingsForTests.HideTopLevelNodeFromPath = false; // ignored w/domains + var globalSettings = Mock.Get(TestObjects.GetGlobalSettings()); //this will modify the IGlobalSettings instance stored in the container + globalSettings.Setup(x => x.UseDirectoryUrls).Returns(true); + globalSettings.Setup(x => x.HideTopLevelNodeFromPath).Returns(false); // ignored w/domains + SettingsForTests.ConfigureSettings(globalSettings.Object); + var umbracoContext = GetUmbracoContext("/test", 1111, umbracoSettings: settings, urlProviders: new[] + { + new DefaultUrlProvider(settings.RequestHandler, Logger, globalSettings.Object) + }, globalSettings:globalSettings.Object); + SetDomains1(); var currentUri = new Uri(currentUrl); @@ -204,14 +209,19 @@ namespace Umbraco.Tests.Routing [TestCase(10011, "https://domain1.com", false, "http://domain1.com/foo/1001-1/")] public void Get_Nice_Url_SimpleWithSchemeAndPath(int nodeId, string currentUrl, bool absolute, string expected) { - var settings = SettingsForTests.GenerateMockSettings(); + var settings = SettingsForTests.GenerateMockUmbracoSettings(); var request = Mock.Get(settings.RequestHandler); request.Setup(x => x.UseDomainPrefixes).Returns(false); - var umbracoContext = GetUmbracoContext("/test", 1111, umbracoSettings: settings, urlProviders: new[] { new DefaultUrlProvider(settings.RequestHandler, Logger) }); + var globalSettings = Mock.Get(TestObjects.GetGlobalSettings()); //this will modify the IGlobalSettings instance stored in the container + globalSettings.Setup(x => x.UseDirectoryUrls).Returns(true); + globalSettings.Setup(x => x.HideTopLevelNodeFromPath).Returns(false); // ignored w/domains + SettingsForTests.ConfigureSettings(globalSettings.Object); - SettingsForTests.UseDirectoryUrls = true; - SettingsForTests.HideTopLevelNodeFromPath = false; // ignored w/domains + var umbracoContext = GetUmbracoContext("/test", 1111, umbracoSettings: settings, urlProviders: new[] + { + new DefaultUrlProvider(settings.RequestHandler, Logger, globalSettings.Object) + }, globalSettings:globalSettings.Object); SetDomains2(); @@ -227,14 +237,19 @@ namespace Umbraco.Tests.Routing [TestCase(1002, "http://domain1.com", false, "/1002/")] public void Get_Nice_Url_DeepDomain(int nodeId, string currentUrl, bool absolute, string expected) { - var settings = SettingsForTests.GenerateMockSettings(); + var settings = SettingsForTests.GenerateMockUmbracoSettings(); var request = Mock.Get(settings.RequestHandler); request.Setup(x => x.UseDomainPrefixes).Returns(false); - var umbracoContext = GetUmbracoContext("/test", 1111, umbracoSettings: settings, urlProviders: new[] { new DefaultUrlProvider(settings.RequestHandler, Logger) }); + var globalSettings = Mock.Get(TestObjects.GetGlobalSettings()); //this will modify the IGlobalSettings instance stored in the container + globalSettings.Setup(x => x.UseDirectoryUrls).Returns(true); + globalSettings.Setup(x => x.HideTopLevelNodeFromPath).Returns(false); // ignored w/domains + SettingsForTests.ConfigureSettings(globalSettings.Object); - SettingsForTests.UseDirectoryUrls = true; - SettingsForTests.HideTopLevelNodeFromPath = false; // ignored w/domains + var umbracoContext = GetUmbracoContext("/test", 1111, umbracoSettings: settings, urlProviders: new[] + { + new DefaultUrlProvider(settings.RequestHandler, Logger, globalSettings.Object) + }, globalSettings:globalSettings.Object); SetDomains3(); @@ -256,14 +271,19 @@ namespace Umbraco.Tests.Routing [TestCase(100321, "http://domain3.com", false, "/fr/1003-2-1/")] public void Get_Nice_Url_NestedDomains(int nodeId, string currentUrl, bool absolute, string expected) { - var settings = SettingsForTests.GenerateMockSettings(); + var settings = SettingsForTests.GenerateMockUmbracoSettings(); var request = Mock.Get(settings.RequestHandler); request.Setup(x => x.UseDomainPrefixes).Returns(false); - var umbracoContext = GetUmbracoContext("/test", 1111, umbracoSettings: settings, urlProviders: new[] { new DefaultUrlProvider(settings.RequestHandler, Logger) }); + var globalSettings = Mock.Get(TestObjects.GetGlobalSettings()); //this will modify the IGlobalSettings instance stored in the container + globalSettings.Setup(x => x.UseDirectoryUrls).Returns(true); + globalSettings.Setup(x => x.HideTopLevelNodeFromPath).Returns(false); // ignored w/domains + SettingsForTests.ConfigureSettings(globalSettings.Object); - SettingsForTests.UseDirectoryUrls = true; - SettingsForTests.HideTopLevelNodeFromPath = false; // ignored w/domains + var umbracoContext = GetUmbracoContext("/test", 1111, umbracoSettings: settings, urlProviders: new[] + { + new DefaultUrlProvider(settings.RequestHandler, Logger, globalSettings.Object) + }, globalSettings:globalSettings.Object); SetDomains4(); @@ -275,14 +295,19 @@ namespace Umbraco.Tests.Routing [Test] public void Get_Nice_Url_DomainsAndCache() { - var settings = SettingsForTests.GenerateMockSettings(); + var settings = SettingsForTests.GenerateMockUmbracoSettings(); var request = Mock.Get(settings.RequestHandler); request.Setup(x => x.UseDomainPrefixes).Returns(false); - var umbracoContext = GetUmbracoContext("/test", 1111, umbracoSettings: settings, urlProviders: new[] { new DefaultUrlProvider(settings.RequestHandler, Logger) }); + var globalSettings = Mock.Get(TestObjects.GetGlobalSettings()); //this will modify the IGlobalSettings instance stored in the container + globalSettings.Setup(x => x.UseDirectoryUrls).Returns(true); + globalSettings.Setup(x => x.HideTopLevelNodeFromPath).Returns(false); // ignored w/domains + SettingsForTests.ConfigureSettings(globalSettings.Object); - SettingsForTests.UseDirectoryUrls = true; - SettingsForTests.HideTopLevelNodeFromPath = false; // ignored w/domains + var umbracoContext = GetUmbracoContext("/test", 1111, umbracoSettings: settings, urlProviders: new[] + { + new DefaultUrlProvider(settings.RequestHandler, Logger, globalSettings.Object) + }, globalSettings:globalSettings.Object); SetDomains4(); @@ -337,14 +362,19 @@ namespace Umbraco.Tests.Routing [Test] public void Get_Nice_Url_Relative_Or_Absolute() { - var settings = SettingsForTests.GenerateMockSettings(); + var settings = SettingsForTests.GenerateMockUmbracoSettings(); var requestMock = Mock.Get(settings.RequestHandler); requestMock.Setup(x => x.UseDomainPrefixes).Returns(false); - var umbracoContext = GetUmbracoContext("http://domain1.com/test", 1111, umbracoSettings: settings, urlProviders: new[] { new DefaultUrlProvider(settings.RequestHandler, Logger) }); + var globalSettings = Mock.Get(TestObjects.GetGlobalSettings()); //this will modify the IGlobalSettings instance stored in the container + globalSettings.Setup(x => x.UseDirectoryUrls).Returns(true); + globalSettings.Setup(x => x.HideTopLevelNodeFromPath).Returns(false); // ignored w/domains + SettingsForTests.ConfigureSettings(globalSettings.Object); - SettingsForTests.UseDirectoryUrls = true; - SettingsForTests.HideTopLevelNodeFromPath = false; + var umbracoContext = GetUmbracoContext("http://domain1.com/test", 1111, umbracoSettings: settings, urlProviders: new[] + { + new DefaultUrlProvider(settings.RequestHandler, Logger, globalSettings.Object) + }, globalSettings:globalSettings.Object); SetDomains4(); @@ -366,11 +396,17 @@ namespace Umbraco.Tests.Routing [Test] public void Get_Nice_Url_Alternate() { - var settings = SettingsForTests.GenerateMockSettings(); - var umbracoContext = GetUmbracoContext("http://domain1.com/en/test", 1111, umbracoSettings: settings, urlProviders: new[] { new DefaultUrlProvider(settings.RequestHandler, Logger) }); + var settings = SettingsForTests.GenerateMockUmbracoSettings(); - SettingsForTests.UseDirectoryUrls = true; - SettingsForTests.HideTopLevelNodeFromPath = false; + var globalSettings = Mock.Get(TestObjects.GetGlobalSettings()); //this will modify the IGlobalSettings instance stored in the container + globalSettings.Setup(x => x.UseDirectoryUrls).Returns(true); + globalSettings.Setup(x => x.HideTopLevelNodeFromPath).Returns(false); // ignored w/domains + SettingsForTests.ConfigureSettings(globalSettings.Object); + + var umbracoContext = GetUmbracoContext("http://domain1.com/en/test", 1111, umbracoSettings: settings, urlProviders: new[] + { + new DefaultUrlProvider(settings.RequestHandler, Logger, globalSettings.Object) + }, globalSettings:globalSettings.Object); SetDomains5(); diff --git a/src/Umbraco.Tests/Routing/RenderRouteHandlerTests.cs b/src/Umbraco.Tests/Routing/RenderRouteHandlerTests.cs index 08d0cbadbe..d0b3622127 100644 --- a/src/Umbraco.Tests/Routing/RenderRouteHandlerTests.cs +++ b/src/Umbraco.Tests/Routing/RenderRouteHandlerTests.cs @@ -31,10 +31,9 @@ namespace Umbraco.Tests.Routing { base.SetUp(); - SettingsForTests.UmbracoPath = "~/umbraco"; - WebRuntimeComponent.CreateRoutes( - new TestUmbracoContextAccessor(), + new TestUmbracoContextAccessor(), + TestObjects.GetGlobalSettings(), new SurfaceControllerTypeCollection(Enumerable.Empty()), new UmbracoApiControllerTypeCollection(Enumerable.Empty())); } @@ -71,7 +70,7 @@ namespace Umbraco.Tests.Routing var umbracoApiControllerTypes = new UmbracoApiControllerTypeCollection(Current.TypeLoader.GetUmbracoApiControllers()); Container.RegisterInstance(umbracoApiControllerTypes); - Container.RegisterSingleton(_ => new DefaultShortStringHelper(SettingsForTests.GetDefault())); + Container.RegisterSingleton(_ => new DefaultShortStringHelper(SettingsForTests.GetDefaultUmbracoSettings())); } public override void TearDown() diff --git a/src/Umbraco.Tests/Routing/UmbracoModuleTests.cs b/src/Umbraco.Tests/Routing/UmbracoModuleTests.cs index 44c4b5c561..23a0773f71 100644 --- a/src/Umbraco.Tests/Routing/UmbracoModuleTests.cs +++ b/src/Umbraco.Tests/Routing/UmbracoModuleTests.cs @@ -31,8 +31,8 @@ namespace Umbraco.Tests.Routing var runtime = new RuntimeState(_module.Logger, new Lazy(), new Lazy()); _module.Runtime = runtime; runtime.Level = RuntimeLevel.Run; + _module.GlobalSettings = TestObjects.GetGlobalSettings(); - SettingsForTests.ConfigurationStatus = UmbracoVersion.SemanticVersion.ToSemanticString(); //SettingsForTests.ReservedPaths = "~/umbraco,~/install/"; //SettingsForTests.ReservedUrls = "~/config/splashes/booting.aspx,~/install/default.aspx,~/config/splashes/noNodes.aspx,~/VSEnterpriseHelper.axd"; diff --git a/src/Umbraco.Tests/Routing/UrlsWithNestedDomains.cs b/src/Umbraco.Tests/Routing/UrlsWithNestedDomains.cs index 857f91f0c9..41a7bf730d 100644 --- a/src/Umbraco.Tests/Routing/UrlsWithNestedDomains.cs +++ b/src/Umbraco.Tests/Routing/UrlsWithNestedDomains.cs @@ -28,10 +28,12 @@ namespace Umbraco.Tests.Routing [Test] public void DoNotPolluteCache() { - SettingsForTests.UseDirectoryUrls = true; - SettingsForTests.HideTopLevelNodeFromPath = false; // ignored w/domains + var globalSettings = Mock.Get(TestObjects.GetGlobalSettings()); //this will modify the IGlobalSettings instance stored in the container + globalSettings.Setup(x => x.UseDirectoryUrls).Returns(true); + globalSettings.Setup(x => x.HideTopLevelNodeFromPath).Returns(false); + SettingsForTests.ConfigureSettings(globalSettings.Object); - var settings = SettingsForTests.GenerateMockSettings(); + var settings = SettingsForTests.GenerateMockUmbracoSettings(); var request = Mock.Get(settings.RequestHandler); request.Setup(x => x.UseDomainPrefixes).Returns(true); @@ -40,7 +42,10 @@ namespace Umbraco.Tests.Routing const string url = "http://domain1.com/1001-1/1001-1-1"; // get the nice url for 100111 - var umbracoContext = GetUmbracoContext(url, 9999, umbracoSettings: settings, urlProviders: new [] { new DefaultUrlProvider(settings.RequestHandler, Logger) }); + var umbracoContext = GetUmbracoContext(url, 9999, umbracoSettings: settings, urlProviders: new [] + { + new DefaultUrlProvider(settings.RequestHandler, Logger, globalSettings.Object) + }, globalSettings:globalSettings.Object); Assert.AreEqual("http://domain2.com/1001-1-1/", umbracoContext.UrlProvider.GetUrl(100111, true)); // check that the proper route has been cached diff --git a/src/Umbraco.Tests/Runtimes/CoreRuntimeTests.cs b/src/Umbraco.Tests/Runtimes/CoreRuntimeTests.cs index 3288800bac..770dead600 100644 --- a/src/Umbraco.Tests/Runtimes/CoreRuntimeTests.cs +++ b/src/Umbraco.Tests/Runtimes/CoreRuntimeTests.cs @@ -163,7 +163,7 @@ namespace Umbraco.Tests.Runtimes { base.Compose(composition); - composition.Container.Register(factory => SettingsForTests.GetDefault()); + composition.Container.Register(factory => SettingsForTests.GetDefaultUmbracoSettings()); composition.Container.RegisterSingleton(); Composed = true; diff --git a/src/Umbraco.Tests/Scoping/ScopedNuCacheTests.cs b/src/Umbraco.Tests/Scoping/ScopedNuCacheTests.cs index 474f15d29b..585a943416 100644 --- a/src/Umbraco.Tests/Scoping/ScopedNuCacheTests.cs +++ b/src/Umbraco.Tests/Scoping/ScopedNuCacheTests.cs @@ -8,6 +8,7 @@ using NUnit.Framework; using Umbraco.Core; using Umbraco.Core.Cache; using Umbraco.Core.Composing; +using Umbraco.Core.Configuration; using Umbraco.Core.Configuration.UmbracoSettings; using Umbraco.Core.Events; using Umbraco.Core.Models; @@ -89,7 +90,7 @@ namespace Umbraco.Tests.Scoping publishedSnapshotAccessor, Logger, ScopeProvider, - documentRepository, mediaRepository, memberRepository); + documentRepository, mediaRepository, memberRepository, Container.GetInstance()); } protected UmbracoContext GetUmbracoContextNu(string url, int templateId = 1234, RouteData routeData = null, bool setSingleton = false, IUmbracoSettingsSection umbracoSettings = null, IEnumerable urlProviders = null) @@ -102,9 +103,10 @@ namespace Umbraco.Tests.Scoping var umbracoContext = new UmbracoContext( httpContext, service, - new WebSecurity(httpContext, Current.Services.UserService), - umbracoSettings ?? SettingsForTests.GetDefault(), - urlProviders ?? Enumerable.Empty()); + new WebSecurity(httpContext, Current.Services.UserService, TestObjects.GetGlobalSettings()), + umbracoSettings ?? SettingsForTests.GetDefaultUmbracoSettings(), + urlProviders ?? Enumerable.Empty(), + TestObjects.GetGlobalSettings()); if (setSingleton) Umbraco.Web.Composing.Current.UmbracoContextAccessor.UmbracoContext = umbracoContext; diff --git a/src/Umbraco.Tests/Scoping/ScopedXmlTests.cs b/src/Umbraco.Tests/Scoping/ScopedXmlTests.cs index 6ee0fd1290..258056f198 100644 --- a/src/Umbraco.Tests/Scoping/ScopedXmlTests.cs +++ b/src/Umbraco.Tests/Scoping/ScopedXmlTests.cs @@ -79,7 +79,7 @@ namespace Umbraco.Tests.Scoping Assert.AreSame(XmlStore, ((PublishedContentCache) umbracoContext.ContentCache).XmlStore); // settings - var settings = SettingsForTests.GenerateMockSettings(); + var settings = SettingsForTests.GenerateMockUmbracoSettings(); var contentMock = Mock.Get(settings.Content); contentMock.Setup(x => x.XmlCacheEnabled).Returns(false); SettingsForTests.ConfigureSettings(settings); @@ -201,7 +201,7 @@ namespace Umbraco.Tests.Scoping Assert.AreSame(XmlStore, ((PublishedContentCache)umbracoContext.ContentCache).XmlStore); // settings - var settings = SettingsForTests.GenerateMockSettings(); + var settings = SettingsForTests.GenerateMockUmbracoSettings(); var contentMock = Mock.Get(settings.Content); contentMock.Setup(x => x.XmlCacheEnabled).Returns(false); SettingsForTests.ConfigureSettings(settings); diff --git a/src/Umbraco.Tests/Security/BackOfficeCookieManagerTests.cs b/src/Umbraco.Tests/Security/BackOfficeCookieManagerTests.cs index 19bacce0ad..1b182024c3 100644 --- a/src/Umbraco.Tests/Security/BackOfficeCookieManagerTests.cs +++ b/src/Umbraco.Tests/Security/BackOfficeCookieManagerTests.cs @@ -29,11 +29,12 @@ namespace Umbraco.Tests.Security var umbracoContext = new UmbracoContext( Mock.Of(), Mock.Of(), - new WebSecurity(Mock.Of(), Current.Services.UserService), - TestObjects.GetUmbracoSettings(), new List()); + new WebSecurity(Mock.Of(), Current.Services.UserService, TestObjects.GetGlobalSettings()), + TestObjects.GetUmbracoSettings(), new List(),TestObjects.GetGlobalSettings()); var runtime = Mock.Of(x => x.Level == RuntimeLevel.Install); - var mgr = new BackOfficeCookieManager(Mock.Of(accessor => accessor.UmbracoContext == umbracoContext), runtime); + var mgr = new BackOfficeCookieManager( + Mock.Of(accessor => accessor.UmbracoContext == umbracoContext), runtime, TestObjects.GetGlobalSettings()); var result = mgr.ShouldAuthenticateRequest(Mock.Of(), new Uri("http://localhost/umbraco")); @@ -46,11 +47,11 @@ namespace Umbraco.Tests.Security var umbCtx = new UmbracoContext( Mock.Of(), Mock.Of(), - new WebSecurity(Mock.Of(), Current.Services.UserService), - TestObjects.GetUmbracoSettings(), new List()); + new WebSecurity(Mock.Of(), Current.Services.UserService, TestObjects.GetGlobalSettings()), + TestObjects.GetUmbracoSettings(), new List(), TestObjects.GetGlobalSettings()); var runtime = Mock.Of(x => x.Level == RuntimeLevel.Run); - var mgr = new BackOfficeCookieManager(Mock.Of(accessor => accessor.UmbracoContext == umbCtx), runtime); + var mgr = new BackOfficeCookieManager(Mock.Of(accessor => accessor.UmbracoContext == umbCtx), runtime, TestObjects.GetGlobalSettings()); var request = new Mock(); request.Setup(owinRequest => owinRequest.Uri).Returns(new Uri("http://localhost/umbraco")); diff --git a/src/Umbraco.Tests/Services/PackagingServiceTests.cs b/src/Umbraco.Tests/Services/PackagingServiceTests.cs index 474f8cd2a1..17c065338d 100644 --- a/src/Umbraco.Tests/Services/PackagingServiceTests.cs +++ b/src/Umbraco.Tests/Services/PackagingServiceTests.cs @@ -76,7 +76,7 @@ namespace Umbraco.Tests.Services private static string GetTestPackagePath(string packageName) { const string testPackagesDirName = "Packaging\\Packages"; - string path = Path.Combine(Core.Configuration.GlobalSettings.FullpathToRoot, testPackagesDirName, packageName); + string path = Path.Combine(Core.Configuration.GlobalSettings.FullPathToRoot, testPackagesDirName, packageName); return path; } diff --git a/src/Umbraco.Tests/Strings/CmsHelperCasingTests.cs b/src/Umbraco.Tests/Strings/CmsHelperCasingTests.cs index b133632eda..0fb0dee68c 100644 --- a/src/Umbraco.Tests/Strings/CmsHelperCasingTests.cs +++ b/src/Umbraco.Tests/Strings/CmsHelperCasingTests.cs @@ -13,7 +13,7 @@ namespace Umbraco.Tests.Strings public void Setup() { //set default config - var config = SettingsForTests.GetDefault(); + var config = SettingsForTests.GetDefaultUmbracoSettings(); SettingsForTests.ConfigureSettings(config); } @@ -39,7 +39,7 @@ namespace Umbraco.Tests.Strings [TestCase("WhoIsNumber6InTheVillage", "Who Is Number6 In The Village")] // issue is fixed public void CompatibleDefaultReplacement(string input, string expected) { - var helper = new DefaultShortStringHelper(SettingsForTests.GetDefault()); + var helper = new DefaultShortStringHelper(SettingsForTests.GetDefaultUmbracoSettings()); var output = input.Length < 2 ? input : helper.SplitPascalCasing(input, ' ').ToFirstUpperInvariant(); Assert.AreEqual(expected, output); } diff --git a/src/Umbraco.Tests/Strings/DefaultShortStringHelperTests.cs b/src/Umbraco.Tests/Strings/DefaultShortStringHelperTests.cs index 67baab695c..19cac22287 100644 --- a/src/Umbraco.Tests/Strings/DefaultShortStringHelperTests.cs +++ b/src/Umbraco.Tests/Strings/DefaultShortStringHelperTests.cs @@ -28,7 +28,7 @@ namespace Umbraco.Tests.Strings // NOTE pre-filters runs _before_ Recode takes place // so there still may be utf8 chars even though you want ascii - _helper = new DefaultShortStringHelper(new DefaultShortStringHelperConfig().WithDefault(SettingsForTests.GetDefault()) + _helper = new DefaultShortStringHelper(new DefaultShortStringHelperConfig().WithDefault(SettingsForTests.GetDefaultUmbracoSettings()) .WithConfig(CleanStringType.FileName, new DefaultShortStringHelperConfig.Config { //PreFilter = ClearFileChars, // done in IsTerm @@ -96,7 +96,7 @@ namespace Umbraco.Tests.Strings [Test] public void U4_4056() { - var settings = SettingsForTests.GenerateMockSettings(); + var settings = SettingsForTests.GenerateMockUmbracoSettings(); var contentMock = Mock.Get(settings.RequestHandler); contentMock.Setup(x => x.CharCollection).Returns(Enumerable.Empty()); contentMock.Setup(x => x.ConvertUrlsToAscii).Returns(false); @@ -121,7 +121,7 @@ namespace Umbraco.Tests.Strings [Test] public void U4_4056_TryAscii() { - var settings = SettingsForTests.GenerateMockSettings(); + var settings = SettingsForTests.GenerateMockUmbracoSettings(); var contentMock = Mock.Get(settings.RequestHandler); contentMock.Setup(x => x.CharCollection).Returns(Enumerable.Empty()); contentMock.Setup(x => x.ConvertUrlsToAscii).Returns(false); @@ -148,7 +148,7 @@ namespace Umbraco.Tests.Strings [Test] public void CleanStringUnderscoreInTerm() { - var helper = new DefaultShortStringHelper(new DefaultShortStringHelperConfig().WithDefault(SettingsForTests.GetDefault()) + var helper = new DefaultShortStringHelper(new DefaultShortStringHelperConfig().WithDefault(SettingsForTests.GetDefaultUmbracoSettings()) .WithConfig(CleanStringType.Alias, new DefaultShortStringHelperConfig.Config { // underscore is accepted within terms @@ -158,7 +158,7 @@ namespace Umbraco.Tests.Strings })); Assert.AreEqual("foo_bar*nil", helper.CleanString("foo_bar nil", CleanStringType.Alias)); - helper = new DefaultShortStringHelper(new DefaultShortStringHelperConfig().WithDefault(SettingsForTests.GetDefault()) + helper = new DefaultShortStringHelper(new DefaultShortStringHelperConfig().WithDefault(SettingsForTests.GetDefaultUmbracoSettings()) .WithConfig(CleanStringType.Alias, new DefaultShortStringHelperConfig.Config { // underscore is not accepted within terms @@ -172,7 +172,7 @@ namespace Umbraco.Tests.Strings [Test] public void CleanStringLeadingChars() { - var helper = new DefaultShortStringHelper(new DefaultShortStringHelperConfig().WithDefault(SettingsForTests.GetDefault()) + var helper = new DefaultShortStringHelper(new DefaultShortStringHelperConfig().WithDefault(SettingsForTests.GetDefaultUmbracoSettings()) .WithConfig(CleanStringType.Alias, new DefaultShortStringHelperConfig.Config { // letters and digits are valid leading chars @@ -182,7 +182,7 @@ namespace Umbraco.Tests.Strings })); Assert.AreEqual("0123foo*bar*543*nil*321", helper.CleanString("0123foo_bar 543 nil 321", CleanStringType.Alias)); - helper = new DefaultShortStringHelper(new DefaultShortStringHelperConfig().WithDefault(SettingsForTests.GetDefault()) + helper = new DefaultShortStringHelper(new DefaultShortStringHelperConfig().WithDefault(SettingsForTests.GetDefaultUmbracoSettings()) .WithConfig(CleanStringType.Alias, new DefaultShortStringHelperConfig.Config { // only letters are valid leading chars @@ -193,14 +193,14 @@ namespace Umbraco.Tests.Strings Assert.AreEqual("foo*bar*543*nil*321", helper.CleanString("0123foo_bar 543 nil 321", CleanStringType.Alias)); Assert.AreEqual("foo*bar*543*nil*321", helper.CleanString("0123 foo_bar 543 nil 321", CleanStringType.Alias)); - helper = new DefaultShortStringHelper(new DefaultShortStringHelperConfig().WithDefault(SettingsForTests.GetDefault())); + helper = new DefaultShortStringHelper(new DefaultShortStringHelperConfig().WithDefault(SettingsForTests.GetDefaultUmbracoSettings())); Assert.AreEqual("child2", helper.CleanStringForSafeAlias("1child2")); } [Test] public void CleanStringTermOnUpper() { - var helper = new DefaultShortStringHelper(new DefaultShortStringHelperConfig().WithDefault(SettingsForTests.GetDefault()) + var helper = new DefaultShortStringHelper(new DefaultShortStringHelperConfig().WithDefault(SettingsForTests.GetDefaultUmbracoSettings()) .WithConfig(CleanStringType.Alias, new DefaultShortStringHelperConfig.Config { StringType = CleanStringType.Utf8 | CleanStringType.Unchanged, @@ -210,7 +210,7 @@ namespace Umbraco.Tests.Strings })); Assert.AreEqual("foo*Bar", helper.CleanString("fooBar", CleanStringType.Alias)); - helper = new DefaultShortStringHelper(new DefaultShortStringHelperConfig().WithDefault(SettingsForTests.GetDefault()) + helper = new DefaultShortStringHelper(new DefaultShortStringHelperConfig().WithDefault(SettingsForTests.GetDefaultUmbracoSettings()) .WithConfig(CleanStringType.Alias, new DefaultShortStringHelperConfig.Config { StringType = CleanStringType.Utf8 | CleanStringType.Unchanged, @@ -224,7 +224,7 @@ namespace Umbraco.Tests.Strings [Test] public void CleanStringAcronymOnNonUpper() { - var helper = new DefaultShortStringHelper(new DefaultShortStringHelperConfig().WithDefault(SettingsForTests.GetDefault()) + var helper = new DefaultShortStringHelper(new DefaultShortStringHelperConfig().WithDefault(SettingsForTests.GetDefaultUmbracoSettings()) .WithConfig(CleanStringType.Alias, new DefaultShortStringHelperConfig.Config { StringType = CleanStringType.Utf8 | CleanStringType.Unchanged, @@ -237,7 +237,7 @@ namespace Umbraco.Tests.Strings Assert.AreEqual("foo*BAnil", helper.CleanString("foo BAnil", CleanStringType.Alias)); Assert.AreEqual("foo*Bnil", helper.CleanString("foo Bnil", CleanStringType.Alias)); - helper = new DefaultShortStringHelper(new DefaultShortStringHelperConfig().WithDefault(SettingsForTests.GetDefault()) + helper = new DefaultShortStringHelper(new DefaultShortStringHelperConfig().WithDefault(SettingsForTests.GetDefaultUmbracoSettings()) .WithConfig(CleanStringType.Alias, new DefaultShortStringHelperConfig.Config { StringType = CleanStringType.Utf8 | CleanStringType.Unchanged, @@ -254,7 +254,7 @@ namespace Umbraco.Tests.Strings [Test] public void CleanStringGreedyAcronyms() { - var helper = new DefaultShortStringHelper(new DefaultShortStringHelperConfig().WithDefault(SettingsForTests.GetDefault()) + var helper = new DefaultShortStringHelper(new DefaultShortStringHelperConfig().WithDefault(SettingsForTests.GetDefaultUmbracoSettings()) .WithConfig(CleanStringType.Alias, new DefaultShortStringHelperConfig.Config { StringType = CleanStringType.Utf8 | CleanStringType.Unchanged, @@ -267,7 +267,7 @@ namespace Umbraco.Tests.Strings Assert.AreEqual("foo*BA*nil", helper.CleanString("foo BAnil", CleanStringType.Alias)); Assert.AreEqual("foo*Bnil", helper.CleanString("foo Bnil", CleanStringType.Alias)); - helper = new DefaultShortStringHelper(new DefaultShortStringHelperConfig().WithDefault(SettingsForTests.GetDefault()) + helper = new DefaultShortStringHelper(new DefaultShortStringHelperConfig().WithDefault(SettingsForTests.GetDefaultUmbracoSettings()) .WithConfig(CleanStringType.Alias, new DefaultShortStringHelperConfig.Config { StringType = CleanStringType.Utf8 | CleanStringType.Unchanged, @@ -284,7 +284,7 @@ namespace Umbraco.Tests.Strings [Test] public void CleanStringWhiteSpace() { - var helper = new DefaultShortStringHelper(new DefaultShortStringHelperConfig().WithDefault(SettingsForTests.GetDefault()) + var helper = new DefaultShortStringHelper(new DefaultShortStringHelperConfig().WithDefault(SettingsForTests.GetDefaultUmbracoSettings()) .WithConfig(CleanStringType.Alias, new DefaultShortStringHelperConfig.Config { StringType = CleanStringType.Utf8 | CleanStringType.Unchanged, @@ -297,7 +297,7 @@ namespace Umbraco.Tests.Strings [Test] public void CleanStringSeparator() { - var helper = new DefaultShortStringHelper(new DefaultShortStringHelperConfig().WithDefault(SettingsForTests.GetDefault()) + var helper = new DefaultShortStringHelper(new DefaultShortStringHelperConfig().WithDefault(SettingsForTests.GetDefaultUmbracoSettings()) .WithConfig(CleanStringType.Alias, new DefaultShortStringHelperConfig.Config { StringType = CleanStringType.Utf8 | CleanStringType.Unchanged, @@ -305,7 +305,7 @@ namespace Umbraco.Tests.Strings })); Assert.AreEqual("foo*bar", helper.CleanString("foo bar", CleanStringType.Alias)); - helper = new DefaultShortStringHelper(new DefaultShortStringHelperConfig().WithDefault(SettingsForTests.GetDefault()) + helper = new DefaultShortStringHelper(new DefaultShortStringHelperConfig().WithDefault(SettingsForTests.GetDefaultUmbracoSettings()) .WithConfig(CleanStringType.Alias, new DefaultShortStringHelperConfig.Config { StringType = CleanStringType.Utf8 | CleanStringType.Unchanged, @@ -313,14 +313,14 @@ namespace Umbraco.Tests.Strings })); Assert.AreEqual("foo bar", helper.CleanString("foo bar", CleanStringType.Alias)); - helper = new DefaultShortStringHelper(new DefaultShortStringHelperConfig().WithDefault(SettingsForTests.GetDefault()) + helper = new DefaultShortStringHelper(new DefaultShortStringHelperConfig().WithDefault(SettingsForTests.GetDefaultUmbracoSettings()) .WithConfig(CleanStringType.Alias, new DefaultShortStringHelperConfig.Config { StringType = CleanStringType.Utf8 | CleanStringType.Unchanged })); Assert.AreEqual("foobar", helper.CleanString("foo bar", CleanStringType.Alias)); - helper = new DefaultShortStringHelper(new DefaultShortStringHelperConfig().WithDefault(SettingsForTests.GetDefault()) + helper = new DefaultShortStringHelper(new DefaultShortStringHelperConfig().WithDefault(SettingsForTests.GetDefaultUmbracoSettings()) .WithConfig(CleanStringType.Alias, new DefaultShortStringHelperConfig.Config { StringType = CleanStringType.Utf8 | CleanStringType.Unchanged, @@ -332,7 +332,7 @@ namespace Umbraco.Tests.Strings [Test] public void CleanStringSymbols() { - var helper = new DefaultShortStringHelper(new DefaultShortStringHelperConfig().WithDefault(SettingsForTests.GetDefault()) + var helper = new DefaultShortStringHelper(new DefaultShortStringHelperConfig().WithDefault(SettingsForTests.GetDefaultUmbracoSettings()) .WithConfig(CleanStringType.Alias, new DefaultShortStringHelperConfig.Config { StringType = CleanStringType.Utf8 | CleanStringType.Unchanged, @@ -386,7 +386,7 @@ namespace Umbraco.Tests.Strings [Test] public void CleanStringEncoding() { - var helper = new DefaultShortStringHelper(new DefaultShortStringHelperConfig().WithDefault(SettingsForTests.GetDefault()) + var helper = new DefaultShortStringHelper(new DefaultShortStringHelperConfig().WithDefault(SettingsForTests.GetDefaultUmbracoSettings()) .WithConfig(CleanStringType.Alias, new DefaultShortStringHelperConfig.Config { StringType = CleanStringType.Utf8 | CleanStringType.Unchanged, @@ -395,7 +395,7 @@ namespace Umbraco.Tests.Strings Assert.AreEqual("中文测试", helper.CleanString("中文测试", CleanStringType.Alias)); Assert.AreEqual("léger*中文测试*ZÔRG", helper.CleanString("léger 中文测试 ZÔRG", CleanStringType.Alias)); - helper = new DefaultShortStringHelper(new DefaultShortStringHelperConfig().WithDefault(SettingsForTests.GetDefault()) + helper = new DefaultShortStringHelper(new DefaultShortStringHelperConfig().WithDefault(SettingsForTests.GetDefaultUmbracoSettings()) .WithConfig(CleanStringType.Alias, new DefaultShortStringHelperConfig.Config { StringType = CleanStringType.Ascii | CleanStringType.Unchanged, @@ -408,7 +408,7 @@ namespace Umbraco.Tests.Strings [Test] public void CleanStringDefaultConfig() { - var settings = SettingsForTests.GenerateMockSettings(); + var settings = SettingsForTests.GenerateMockUmbracoSettings(); var contentMock = Mock.Get(settings.RequestHandler); contentMock.Setup(x => x.CharCollection).Returns(Enumerable.Empty()); contentMock.Setup(x => x.ConvertUrlsToAscii).Returns(false); @@ -434,7 +434,7 @@ namespace Umbraco.Tests.Strings [Test] public void CleanStringCasing() { - var helper = new DefaultShortStringHelper(new DefaultShortStringHelperConfig().WithDefault(SettingsForTests.GetDefault()) + var helper = new DefaultShortStringHelper(new DefaultShortStringHelperConfig().WithDefault(SettingsForTests.GetDefaultUmbracoSettings()) .WithConfig(CleanStringType.Alias, new DefaultShortStringHelperConfig.Config { StringType = CleanStringType.Utf8 | CleanStringType.Unchanged, diff --git a/src/Umbraco.Tests/TestHelpers/BaseUsingSqlCeSyntax.cs b/src/Umbraco.Tests/TestHelpers/BaseUsingSqlCeSyntax.cs index 38899170cd..e28e3f7c29 100644 --- a/src/Umbraco.Tests/TestHelpers/BaseUsingSqlCeSyntax.cs +++ b/src/Umbraco.Tests/TestHelpers/BaseUsingSqlCeSyntax.cs @@ -41,7 +41,8 @@ namespace Umbraco.Tests.TestHelpers container.RegisterSingleton(factory => Mock.Of()); var logger = new ProfilingLogger(Mock.Of(), Mock.Of()); - var pluginManager = new TypeLoader(NullCacheProvider.Instance, + var pluginManager = new TypeLoader(NullCacheProvider.Instance, + SettingsForTests.GenerateMockGlobalSettings(), logger, false); container.RegisterInstance(pluginManager); diff --git a/src/Umbraco.Tests/TestHelpers/ControllerTesting/TestControllerActivatorBase.cs b/src/Umbraco.Tests/TestHelpers/ControllerTesting/TestControllerActivatorBase.cs index d5213cbcda..0b3e5d6efd 100644 --- a/src/Umbraco.Tests/TestHelpers/ControllerTesting/TestControllerActivatorBase.cs +++ b/src/Umbraco.Tests/TestHelpers/ControllerTesting/TestControllerActivatorBase.cs @@ -68,8 +68,7 @@ namespace Umbraco.Tests.TestHelpers.ControllerTesting localizedTextService:Mock.Of(), sectionService:Mock.Of()); - //ensure the configuration matches the current version for tests - SettingsForTests.ConfigurationStatus = UmbracoVersion.SemanticVersion.ToSemanticString(); + var globalSettings = SettingsForTests.GenerateMockGlobalSettings(); // fixme v8? ////new app context @@ -85,19 +84,25 @@ namespace Umbraco.Tests.TestHelpers.ControllerTesting // new ProfilingLogger(Mock.Of(), Mock.Of()), // true); + var httpContextItems = new Dictionary + { + //add the special owin environment to the httpcontext items, this is how the GetOwinContext works + ["owin.Environment"] = new Dictionary() + }; + //httpcontext with an auth'd user var httpContext = Mock.Of( http => http.User == owinContext.Authentication.User //ensure the request exists with a cookies collection && http.Request == Mock.Of(r => r.Cookies == new HttpCookieCollection()) //ensure the request exists with an items collection - && http.Items == Mock.Of()); + && http.Items == httpContextItems); //chuck it into the props since this is what MS does when hosted and it's needed there request.Properties["MS_HttpContext"] = httpContext; var backofficeIdentity = (UmbracoBackOfficeIdentity) owinContext.Authentication.User.Identity; - var webSecurity = new Mock(null, null); + var webSecurity = new Mock(null, null, globalSettings); //mock CurrentUser var groups = new List(); @@ -142,6 +147,7 @@ namespace Umbraco.Tests.TestHelpers.ControllerTesting webSecurity.Object, Mock.Of(section => section.WebRouting == Mock.Of(routingSection => routingSection.UrlProviderMode == UrlProviderMode.Auto.ToString())), Enumerable.Empty(), + globalSettings, true); //replace it var urlHelper = new Mock(); diff --git a/src/Umbraco.Tests/TestHelpers/SettingsForTests.cs b/src/Umbraco.Tests/TestHelpers/SettingsForTests.cs index 7c75003378..5d47c82dff 100644 --- a/src/Umbraco.Tests/TestHelpers/SettingsForTests.cs +++ b/src/Umbraco.Tests/TestHelpers/SettingsForTests.cs @@ -5,11 +5,17 @@ using Moq; using Umbraco.Core; using Umbraco.Core.Configuration; using Umbraco.Core.Configuration.UmbracoSettings; +using Umbraco.Core.IO; namespace Umbraco.Tests.TestHelpers { public class SettingsForTests { + public static void ConfigureSettings(IGlobalSettings settings) + { + UmbracoConfig.For.SetGlobalConfig(settings); + } + // umbracoSettings /// @@ -21,11 +27,28 @@ namespace Umbraco.Tests.TestHelpers UmbracoConfig.For.SetUmbracoSettings(settings); } + public static IGlobalSettings GenerateMockGlobalSettings() + { + var config = Mock.Of( + settings => + settings.ConfigurationStatus == UmbracoVersion.SemanticVersion.ToSemanticString() && + settings.UseHttps == false && + settings.HideTopLevelNodeFromPath == false && + settings.Path == IOHelper.ResolveUrl("~/umbraco") && + settings.UseDirectoryUrls == true && + settings.TimeOutInMinutes == 20 && + settings.DefaultUILanguage == "en" && + settings.LocalTempStorageLocation == LocalTempStorage.Default && + settings.ReservedPaths == (GlobalSettings.StaticReservedPaths + "~/umbraco") && + settings.ReservedUrls == GlobalSettings.StaticReservedUrls); + return config; + } + /// /// Returns generated settings which can be stubbed to return whatever values necessary /// /// - public static IUmbracoSettingsSection GenerateMockSettings() + public static IUmbracoSettingsSection GenerateMockUmbracoSettings() { var settings = new Mock(); @@ -68,103 +91,83 @@ namespace Umbraco.Tests.TestHelpers return settings.Object; } - // from appSettings + //// from appSettings - private static readonly IDictionary SavedAppSettings = new Dictionary(); + //private static readonly IDictionary SavedAppSettings = new Dictionary(); - static void SaveSetting(string key) - { - SavedAppSettings[key] = ConfigurationManager.AppSettings[key]; - } + //static void SaveSetting(string key) + //{ + // SavedAppSettings[key] = ConfigurationManager.AppSettings[key]; + //} - static void SaveSettings() - { - SaveSetting("umbracoHideTopLevelNodeFromPath"); - SaveSetting("umbracoUseDirectoryUrls"); - SaveSetting("umbracoPath"); - SaveSetting("umbracoReservedPaths"); - SaveSetting("umbracoReservedUrls"); - SaveSetting("umbracoConfigurationStatus"); - } + //static void SaveSettings() + //{ + // SaveSetting("umbracoHideTopLevelNodeFromPath"); + // SaveSetting("umbracoUseDirectoryUrls"); + // SaveSetting("umbracoPath"); + // SaveSetting("umbracoReservedPaths"); + // SaveSetting("umbracoReservedUrls"); + // SaveSetting("umbracoConfigurationStatus"); + //} - public static bool HideTopLevelNodeFromPath - { - get { return GlobalSettings.HideTopLevelNodeFromPath; } - set { ConfigurationManager.AppSettings.Set("umbracoHideTopLevelNodeFromPath", value ? "true" : "false"); } - } - - public static bool UseDirectoryUrls - { - get { return GlobalSettings.UseDirectoryUrls; } - set { ConfigurationManager.AppSettings.Set("umbracoUseDirectoryUrls", value ? "true" : "false"); } - } - - public static string UmbracoPath - { - get { return GlobalSettings.Path; } - set { ConfigurationManager.AppSettings.Set("umbracoPath", value); } - } - - public static string ReservedPaths - { - get { return GlobalSettings.ReservedPaths; } - set { GlobalSettings.ReservedPaths = value; } - } - - public static string ReservedUrls - { - get { return GlobalSettings.ReservedUrls; } - set { GlobalSettings.ReservedUrls = value; } - } - - public static string ConfigurationStatus - { - get { return GlobalSettings.ConfigurationStatus; } - set { ConfigurationManager.AppSettings.Set("umbracoConfigurationStatus", value); } - } + // reset & defaults - static SettingsForTests() - { - SaveSettings(); - } + //static SettingsForTests() + //{ + // //SaveSettings(); + //} public static void Reset() { - ResetUmbracoSettings(); + ResetSettings(); GlobalSettings.Reset(); - foreach (var kvp in SavedAppSettings) - ConfigurationManager.AppSettings.Set(kvp.Key, kvp.Value); + //foreach (var kvp in SavedAppSettings) + // ConfigurationManager.AppSettings.Set(kvp.Key, kvp.Value); - // set some defaults that are wrong in the config file?! - // this is annoying, really - HideTopLevelNodeFromPath = false; + //// set some defaults that are wrong in the config file?! + //// this is annoying, really + //HideTopLevelNodeFromPath = false; } /// /// This sets all settings back to default settings /// - private static void ResetUmbracoSettings() + private static void ResetSettings() { - ConfigureSettings(GetDefault()); + _defaultGlobalSettings = null; + ConfigureSettings(GetDefaultUmbracoSettings()); + ConfigureSettings(GetDefaultGlobalSettings()); } - private static IUmbracoSettingsSection _defaultSettings; + private static IUmbracoSettingsSection _defaultUmbracoSettings; + private static IGlobalSettings _defaultGlobalSettings; - internal static IUmbracoSettingsSection GetDefault() + internal static IGlobalSettings GetDefaultGlobalSettings() { - if (_defaultSettings == null) + if (_defaultGlobalSettings == null) { + _defaultGlobalSettings = GenerateMockGlobalSettings(); + } + return _defaultGlobalSettings; + } + + internal static IUmbracoSettingsSection GetDefaultUmbracoSettings() + { + if (_defaultUmbracoSettings == null) + { + //TODO: Just make this mocks instead of reading from the config + var config = new FileInfo(TestHelper.MapPathForTest("~/Configurations/UmbracoSettings/web.config")); var fileMap = new ExeConfigurationFileMap { ExeConfigFilename = config.FullName }; var configuration = ConfigurationManager.OpenMappedExeConfiguration(fileMap, ConfigurationUserLevel.None); - _defaultSettings = configuration.GetSection("umbracoConfiguration/defaultSettings") as UmbracoSettingsSection; + _defaultUmbracoSettings = configuration.GetSection("umbracoConfiguration/defaultSettings") as UmbracoSettingsSection; } - return _defaultSettings; + return _defaultUmbracoSettings; } } } diff --git a/src/Umbraco.Tests/TestHelpers/TestObjects-Mocks.cs b/src/Umbraco.Tests/TestHelpers/TestObjects-Mocks.cs index 6ee99ef582..50cb115eae 100644 --- a/src/Umbraco.Tests/TestHelpers/TestObjects-Mocks.cs +++ b/src/Umbraco.Tests/TestHelpers/TestObjects-Mocks.cs @@ -7,6 +7,7 @@ using System.Web; using LightInject; using Moq; using Umbraco.Core; +using Umbraco.Core.Configuration; using Umbraco.Core.Configuration.UmbracoSettings; using Umbraco.Core.Events; using Umbraco.Core.Logging; @@ -112,16 +113,20 @@ namespace Umbraco.Tests.TestHelpers publishedSnapshotServiceMock.Setup(x => x.CreatePublishedSnapshot(It.IsAny())).Returns(publishedSnapshot); var publishedSnapshotService = publishedSnapshotServiceMock.Object; - var webSecurity = new Mock(null, null).Object; - var settings = GetUmbracoSettings(); + var umbracoSettings = GetUmbracoSettings(); + var globalSettings = GetGlobalSettings(); + var webSecurity = new Mock(null, null, globalSettings).Object; var urlProviders = Enumerable.Empty(); if (accessor == null) accessor = new TestUmbracoContextAccessor(); - return UmbracoContext.EnsureContext(accessor, httpContext, publishedSnapshotService, webSecurity, settings, urlProviders, true); + return UmbracoContext.EnsureContext(accessor, httpContext, publishedSnapshotService, webSecurity, umbracoSettings, urlProviders, globalSettings, true); } public IUmbracoSettingsSection GetUmbracoSettings() { + //fixme Why not use the SettingsForTest.GenerateMock ... ? + //fixme Shouldn't we use the default ones so they are the same instance for each test? + var umbracoSettingsMock = new Mock(); var webRoutingSectionMock = new Mock(); webRoutingSectionMock.Setup(x => x.UrlProviderMode).Returns(UrlProviderMode.Auto.ToString()); @@ -129,6 +134,11 @@ namespace Umbraco.Tests.TestHelpers return umbracoSettingsMock.Object; } + public IGlobalSettings GetGlobalSettings() + { + return SettingsForTests.GetDefaultGlobalSettings(); + } + #region Inner classes private class MockDbConnection : DbConnection diff --git a/src/Umbraco.Tests/TestHelpers/TestObjects.cs b/src/Umbraco.Tests/TestHelpers/TestObjects.cs index d29ba5e41e..b0676f2eb9 100644 --- a/src/Umbraco.Tests/TestHelpers/TestObjects.cs +++ b/src/Umbraco.Tests/TestHelpers/TestObjects.cs @@ -9,6 +9,7 @@ using NPoco; using Umbraco.Core; using Umbraco.Core.Cache; using Umbraco.Core.Composing; +using Umbraco.Core.Configuration; using Umbraco.Core.Events; using Umbraco.Core.IO; using Umbraco.Core.Logging; @@ -89,13 +90,14 @@ namespace Umbraco.Tests.TestHelpers /// /// Gets a ServiceContext. /// - /// A repository factory. - /// A database unit of work provider. + /// /// A cache. /// A logger. + /// /// An event messages factory. /// Some url segment providers. /// A container. + /// /// A ServiceContext. /// Should be used sparingly for integration tests only - for unit tests /// just mock the services to be passed to the ctor of the ServiceContext. @@ -103,6 +105,7 @@ namespace Umbraco.Tests.TestHelpers IScopeProvider scopeProvider, IScopeAccessor scopeAccessor, CacheHelper cache, ILogger logger, + IGlobalSettings globalSettings, IEventMessagesFactory eventMessagesFactory, IEnumerable urlSegmentProviders, IServiceFactory container = null) @@ -156,10 +159,10 @@ namespace Umbraco.Tests.TestHelpers var runtimeState = Mock.Of(); var idkMap = new IdkMap(scopeProvider); - var userService = GetLazyService(container, c => new UserService(scopeProvider, logger, eventMessagesFactory, runtimeState, GetRepo(c), GetRepo(c))); + var userService = GetLazyService(container, c => new UserService(scopeProvider, logger, eventMessagesFactory, runtimeState, GetRepo(c), GetRepo(c),globalSettings)); var dataTypeService = GetLazyService(container, c => new DataTypeService(scopeProvider, logger, eventMessagesFactory, GetRepo(c), GetRepo(c), GetRepo(c), GetRepo(c), GetRepo(c))); var contentService = GetLazyService(container, c => new ContentService(scopeProvider, logger, eventMessagesFactory, mediaFileSystem, GetRepo(c), GetRepo(c), GetRepo(c), GetRepo(c), GetRepo(c))); - var notificationService = GetLazyService(container, c => new NotificationService(scopeProvider, userService.Value, contentService.Value, logger, GetRepo(c))); + var notificationService = GetLazyService(container, c => new NotificationService(scopeProvider, userService.Value, contentService.Value, logger, GetRepo(c),globalSettings)); var serverRegistrationService = GetLazyService(container, c => new ServerRegistrationService(scopeProvider, logger, eventMessagesFactory, GetRepo(c))); var memberGroupService = GetLazyService(container, c => new MemberGroupService(scopeProvider, logger, eventMessagesFactory, GetRepo(c))); var memberService = GetLazyService(container, c => new MemberService(scopeProvider, logger, eventMessagesFactory, memberGroupService.Value, mediaFileSystem, GetRepo(c), GetRepo(c), GetRepo(c), GetRepo(c))); diff --git a/src/Umbraco.Tests/TestHelpers/TestWithDatabaseBase.cs b/src/Umbraco.Tests/TestHelpers/TestWithDatabaseBase.cs index 83042c4897..9a2828fd9f 100644 --- a/src/Umbraco.Tests/TestHelpers/TestWithDatabaseBase.cs +++ b/src/Umbraco.Tests/TestHelpers/TestWithDatabaseBase.cs @@ -134,7 +134,9 @@ namespace Umbraco.Tests.TestHelpers } // ensure the configuration matches the current version for tests - SettingsForTests.ConfigurationStatus = UmbracoVersion.Current.ToString(3); + var globalSettingsMock = Mock.Get(TestObjects.GetGlobalSettings()); //this will modify the IGlobalSettings instance stored in the container + globalSettingsMock.Setup(x => x.ConfigurationStatus).Returns(UmbracoVersion.Current.ToString(3)); + SettingsForTests.ConfigureSettings(globalSettingsMock.Object); using (ProfilingLogger.TraceDuration("Initialize database.")) { @@ -247,22 +249,25 @@ namespace Umbraco.Tests.TestHelpers var cache = NullCacheProvider.Instance; ContentTypesCache = new PublishedContentTypeCache( - Current.Services.ContentTypeService, - Current.Services.MediaTypeService, - Current.Services.MemberTypeService, + Container.GetInstance(), + Container.GetInstance(), + Container.GetInstance(), Container.GetInstance(), - Current.Logger); + Logger); // testing=true so XmlStore will not use the file nor the database var publishedSnapshotAccessor = new UmbracoContextPublishedSnapshotAccessor(Umbraco.Web.Composing.Current.UmbracoContextAccessor); var service = new PublishedSnapshotService( - Current.Services, + ServiceContext, Container.GetInstance(), - (ScopeProvider) Current.ScopeProvider, + ScopeProvider, cache, publishedSnapshotAccessor, - Current.Container.GetInstance(), Current.Container.GetInstance(), Current.Container.GetInstance(), - Current.Logger, ContentTypesCache, null, true, Options.PublishedRepositoryEvents); + Container.GetInstance(), Container.GetInstance(), Container.GetInstance(), + Logger, + Container.GetInstance(), + ContentTypesCache, + null, true, Options.PublishedRepositoryEvents); // initialize PublishedCacheService content with an Xml source service.XmlStore.GetXmlDocument = () => @@ -331,14 +336,14 @@ namespace Umbraco.Tests.TestHelpers } catch (Exception ex) { - Core.Composing.Current.Logger.Error("Could not remove the old database file", ex); + Logger.Error("Could not remove the old database file", ex); // swallow this exception - that's because a sub class might require further teardown logic onFail?.Invoke(ex); } } - protected UmbracoContext GetUmbracoContext(string url, int templateId = 1234, RouteData routeData = null, bool setSingleton = false, IUmbracoSettingsSection umbracoSettings = null, IEnumerable urlProviders = null) + protected UmbracoContext GetUmbracoContext(string url, int templateId = 1234, RouteData routeData = null, bool setSingleton = false, IUmbracoSettingsSection umbracoSettings = null, IEnumerable urlProviders = null, IGlobalSettings globalSettings = null) { // ensure we have a PublishedCachesService var service = PublishedSnapshotService as PublishedSnapshotService; @@ -358,9 +363,10 @@ namespace Umbraco.Tests.TestHelpers var umbracoContext = new UmbracoContext( httpContext, service, - new WebSecurity(httpContext, Core.Composing.Current.Services.UserService), - umbracoSettings ?? SettingsForTests.GetDefault(), - urlProviders ?? Enumerable.Empty()); + new WebSecurity(httpContext, Container.GetInstance(), Container.GetInstance()), + umbracoSettings ?? Container.GetInstance(), + urlProviders ?? Enumerable.Empty(), + globalSettings ?? Container.GetInstance()); if (setSingleton) Umbraco.Web.Composing.Current.UmbracoContextAccessor.UmbracoContext = umbracoContext; diff --git a/src/Umbraco.Tests/Testing/UmbracoTestBase.cs b/src/Umbraco.Tests/Testing/UmbracoTestBase.cs index b5c10fa4a3..003ba9ff4d 100644 --- a/src/Umbraco.Tests/Testing/UmbracoTestBase.cs +++ b/src/Umbraco.Tests/Testing/UmbracoTestBase.cs @@ -12,6 +12,7 @@ using Umbraco.Core.Cache; using Umbraco.Core.Components; using Umbraco.Core.Composing; using Umbraco.Core.Composing.CompositionRoots; +using Umbraco.Core.Configuration; using Umbraco.Core.Events; using Umbraco.Core.IO; using Umbraco.Core.Logging; @@ -225,7 +226,7 @@ namespace Umbraco.Tests.Testing private static TypeLoader CreateCommonPluginManager(IServiceFactory f) { - return new TypeLoader(f.GetInstance().RuntimeCache, f.GetInstance(), false) + return new TypeLoader(f.GetInstance().RuntimeCache, f.GetInstance(), f.GetInstance(), false) { AssembliesToScan = new[] { @@ -249,15 +250,20 @@ namespace Umbraco.Tests.Testing { if (withApplication == false) return; - var settings = SettingsForTests.GetDefault(); + var umbracoSettings = SettingsForTests.GetDefaultUmbracoSettings(); + var globalSettings = SettingsForTests.GetDefaultGlobalSettings(); + //apply these globally + SettingsForTests.ConfigureSettings(umbracoSettings); + SettingsForTests.ConfigureSettings(globalSettings); // default Datalayer/Repositories/SQL/Database/etc... Container.RegisterFrom(); // register basic stuff that might need to be there for some container resolvers to work - Container.RegisterSingleton(factory => SettingsForTests.GetDefault()); - Container.RegisterSingleton(factory => settings.Content); - Container.RegisterSingleton(factory => settings.Templates); + Container.RegisterSingleton(factory => umbracoSettings); + Container.RegisterSingleton(factory => globalSettings); + Container.RegisterSingleton(factory => umbracoSettings.Content); + Container.RegisterSingleton(factory => umbracoSettings.Templates); Container.Register(factory => new MediaFileSystem(Mock.Of())); Container.RegisterSingleton(factory => ExamineManager.Instance); diff --git a/src/Umbraco.Tests/Umbraco.Tests.csproj b/src/Umbraco.Tests/Umbraco.Tests.csproj index 017df4450d..90455f910e 100644 --- a/src/Umbraco.Tests/Umbraco.Tests.csproj +++ b/src/Umbraco.Tests/Umbraco.Tests.csproj @@ -607,7 +607,16 @@ $(NuGetPackageFolders.Split(';')[0]) + + + + + + + + + @@ -616,5 +625,5 @@ - + \ No newline at end of file diff --git a/src/Umbraco.Tests/UmbracoExamine/ExamineBaseTest.cs b/src/Umbraco.Tests/UmbracoExamine/ExamineBaseTest.cs index 5f55ed2bd0..4016510f40 100644 --- a/src/Umbraco.Tests/UmbracoExamine/ExamineBaseTest.cs +++ b/src/Umbraco.Tests/UmbracoExamine/ExamineBaseTest.cs @@ -32,7 +32,7 @@ namespace Umbraco.Tests.UmbracoExamine { base.Compose(); - Container.RegisterSingleton(_ => new DefaultShortStringHelper(SettingsForTests.GetDefault())); + Container.RegisterSingleton(_ => new DefaultShortStringHelper(SettingsForTests.GetDefaultUmbracoSettings())); } } } diff --git a/src/Umbraco.Tests/Web/Controllers/PluginControllerAreaTests.cs b/src/Umbraco.Tests/Web/Controllers/PluginControllerAreaTests.cs index f42a02efe4..669c607aea 100644 --- a/src/Umbraco.Tests/Web/Controllers/PluginControllerAreaTests.cs +++ b/src/Umbraco.Tests/Web/Controllers/PluginControllerAreaTests.cs @@ -14,7 +14,8 @@ namespace Umbraco.Tests.Web.Controllers public void Ensure_Same_Area1() { Assert.Throws(() => - new PluginControllerArea(new PluginControllerMetadata[] + new PluginControllerArea(TestObjects.GetGlobalSettings(), + new PluginControllerMetadata[] { PluginController.GetMetadata(typeof(Plugin1Controller)), PluginController.GetMetadata(typeof(Plugin2Controller)), @@ -26,7 +27,8 @@ namespace Umbraco.Tests.Web.Controllers public void Ensure_Same_Area3() { Assert.Throws(() => - new PluginControllerArea(new PluginControllerMetadata[] + new PluginControllerArea(TestObjects.GetGlobalSettings(), + new PluginControllerMetadata[] { PluginController.GetMetadata(typeof(Plugin1Controller)), PluginController.GetMetadata(typeof(Plugin2Controller)), @@ -37,7 +39,8 @@ namespace Umbraco.Tests.Web.Controllers [Test] public void Ensure_Same_Area2() { - var area = new PluginControllerArea(new PluginControllerMetadata[] + var area = new PluginControllerArea(TestObjects.GetGlobalSettings(), + new PluginControllerMetadata[] { PluginController.GetMetadata(typeof(Plugin1Controller)), PluginController.GetMetadata(typeof(Plugin2Controller)) diff --git a/src/Umbraco.Tests/Web/Mvc/RenderIndexActionSelectorAttributeTests.cs b/src/Umbraco.Tests/Web/Mvc/RenderIndexActionSelectorAttributeTests.cs index 2afeb3ffba..1a61882949 100644 --- a/src/Umbraco.Tests/Web/Mvc/RenderIndexActionSelectorAttributeTests.cs +++ b/src/Umbraco.Tests/Web/Mvc/RenderIndexActionSelectorAttributeTests.cs @@ -58,6 +58,7 @@ namespace Umbraco.Tests.Web.Mvc [Test] public void Matches_Default_Index() { + var globalSettings = TestObjects.GetGlobalSettings(); var attr = new RenderIndexActionSelectorAttribute(); var req = new RequestContext(); //var appCtx = new ApplicationContext( @@ -67,9 +68,10 @@ namespace Umbraco.Tests.Web.Mvc Current.UmbracoContextAccessor, Mock.Of(), Mock.Of(), - new Mock(null, null).Object, + new Mock(null, null, globalSettings).Object, TestObjects.GetUmbracoSettings(), Enumerable.Empty(), + globalSettings, true); var ctrl = new MatchesDefaultIndexController { UmbracoContext = umbCtx }; var controllerCtx = new ControllerContext(req, ctrl); @@ -82,15 +84,17 @@ namespace Umbraco.Tests.Web.Mvc [Test] public void Matches_Overriden_Index() { + var globalSettings = TestObjects.GetGlobalSettings(); var attr = new RenderIndexActionSelectorAttribute(); var req = new RequestContext(); var umbCtx = UmbracoContext.EnsureContext( Current.UmbracoContextAccessor, Mock.Of(), Mock.Of(), - new Mock(null, null).Object, + new Mock(null, null, globalSettings).Object, TestObjects.GetUmbracoSettings(), Enumerable.Empty(), + globalSettings, true); var ctrl = new MatchesOverriddenIndexController { UmbracoContext = umbCtx }; var controllerCtx = new ControllerContext(req, ctrl); @@ -103,15 +107,17 @@ namespace Umbraco.Tests.Web.Mvc [Test] public void Matches_Custom_Index() { + var globalSettings = TestObjects.GetGlobalSettings(); var attr = new RenderIndexActionSelectorAttribute(); var req = new RequestContext(); var umbCtx = UmbracoContext.EnsureContext( Current.UmbracoContextAccessor, Mock.Of(), Mock.Of(), - new Mock(null, null).Object, + new Mock(null, null, globalSettings).Object, TestObjects.GetUmbracoSettings(), Enumerable.Empty(), + globalSettings, true); var ctrl = new MatchesCustomIndexController { UmbracoContext = umbCtx }; var controllerCtx = new ControllerContext(req, ctrl); @@ -124,15 +130,17 @@ namespace Umbraco.Tests.Web.Mvc [Test] public void Matches_Async_Index_Same_Signature() { + var globalSettings = TestObjects.GetGlobalSettings(); var attr = new RenderIndexActionSelectorAttribute(); var req = new RequestContext(); var umbCtx = UmbracoContext.EnsureContext( Current.UmbracoContextAccessor, Mock.Of(), Mock.Of(), - new Mock(null, null).Object, + new Mock(null, null, globalSettings).Object, TestObjects.GetUmbracoSettings(), Enumerable.Empty(), + globalSettings, true); var ctrl = new MatchesAsyncIndexController { UmbracoContext = umbCtx }; var controllerCtx = new ControllerContext(req, ctrl); diff --git a/src/Umbraco.Tests/Web/Mvc/SurfaceControllerTests.cs b/src/Umbraco.Tests/Web/Mvc/SurfaceControllerTests.cs index ea33f5d81e..d9a12751c0 100644 --- a/src/Umbraco.Tests/Web/Mvc/SurfaceControllerTests.cs +++ b/src/Umbraco.Tests/Web/Mvc/SurfaceControllerTests.cs @@ -36,13 +36,15 @@ namespace Umbraco.Tests.Web.Mvc [Test] public void Can_Construct_And_Get_Result() { + var globalSettings = TestObjects.GetGlobalSettings(); var umbracoContext = UmbracoContext.EnsureContext( Current.UmbracoContextAccessor, new Mock().Object, Mock.Of(), - new Mock(null, null).Object, + new Mock(null, null, globalSettings).Object, TestObjects.GetUmbracoSettings(), Enumerable.Empty(), + globalSettings, true); var ctrl = new TestSurfaceController { UmbracoContext = umbracoContext }; @@ -55,13 +57,15 @@ namespace Umbraco.Tests.Web.Mvc [Test] public void Umbraco_Context_Not_Null() { + var globalSettings = TestObjects.GetGlobalSettings(); var umbCtx = UmbracoContext.EnsureContext( Current.UmbracoContextAccessor, new Mock().Object, Mock.Of(), - new Mock(null, null).Object, + new Mock(null, null, globalSettings).Object, TestObjects.GetUmbracoSettings(), Enumerable.Empty(), + globalSettings, true); var ctrl = new TestSurfaceController { UmbracoContext = umbCtx }; @@ -72,13 +76,15 @@ namespace Umbraco.Tests.Web.Mvc [Test] public void Umbraco_Helper_Not_Null() { + var globalSettings = TestObjects.GetGlobalSettings(); var umbracoContext = UmbracoContext.EnsureContext( Current.UmbracoContextAccessor, new Mock().Object, Mock.Of(), - new Mock(null, null).Object, + new Mock(null, null, globalSettings).Object, TestObjects.GetUmbracoSettings(), Enumerable.Empty(), + globalSettings, true); var controller = new TestSurfaceController { UmbracoContext = umbracoContext }; @@ -95,14 +101,16 @@ namespace Umbraco.Tests.Web.Mvc publishedSnapshot.Setup(x => x.Members).Returns(Mock.Of()); var publishedSnapshotService = new Mock(); publishedSnapshotService.Setup(x => x.CreatePublishedSnapshot(It.IsAny())).Returns(publishedSnapshot.Object); + var globalSettings = TestObjects.GetGlobalSettings(); var umbracoContext = UmbracoContext.EnsureContext( Current.UmbracoContextAccessor, new Mock().Object, publishedSnapshotService.Object, - new Mock(null, null).Object, + new Mock(null, null, globalSettings).Object, Mock.Of(section => section.WebRouting == Mock.Of(routingSection => routingSection.UrlProviderMode == "AutoLegacy")), Enumerable.Empty(), + globalSettings, true); var helper = new UmbracoHelper( @@ -130,14 +138,16 @@ namespace Umbraco.Tests.Web.Mvc public void Mock_Current_Page() { var webRoutingSettings = Mock.Of(section => section.UrlProviderMode == "AutoLegacy"); + var globalSettings = TestObjects.GetGlobalSettings(); var umbracoContext = UmbracoContext.EnsureContext( Current.UmbracoContextAccessor, new Mock().Object, Mock.Of(), - new Mock(null, null).Object, + new Mock(null, null, globalSettings).Object, Mock.Of(section => section.WebRouting == webRoutingSettings), Enumerable.Empty(), + globalSettings, true); var content = Mock.Of(publishedContent => publishedContent.Id == 12345); diff --git a/src/Umbraco.Tests/Web/Mvc/UmbracoViewPageTests.cs b/src/Umbraco.Tests/Web/Mvc/UmbracoViewPageTests.cs index f010cc6958..053a1f7c5d 100644 --- a/src/Umbraco.Tests/Web/Mvc/UmbracoViewPageTests.cs +++ b/src/Umbraco.Tests/Web/Mvc/UmbracoViewPageTests.cs @@ -388,7 +388,7 @@ namespace Umbraco.Tests.Web.Mvc ViewContext GetViewContext() { - var settings = SettingsForTests.GetDefault(); + var settings = SettingsForTests.GetDefaultUmbracoSettings(); var logger = Mock.Of(); var umbracoContext = GetUmbracoContext( logger, settings, @@ -425,16 +425,17 @@ namespace Umbraco.Tests.Web.Mvc var factory = Mock.Of(); _service = new PublishedSnapshotService(svcCtx, factory, scopeProvider, cache, Enumerable.Empty(), null, null, null, null, - Current.Logger, null, true, false); // no events + Current.Logger, TestObjects.GetGlobalSettings(), null, true, false); // no events var http = GetHttpContextFactory(url, routeData).HttpContext; var ctx = new UmbracoContext( GetHttpContextFactory(url, routeData).HttpContext, _service, - new WebSecurity(http, Current.Services.UserService), + new WebSecurity(http, Current.Services.UserService, TestObjects.GetGlobalSettings()), TestObjects.GetUmbracoSettings(), - Enumerable.Empty()); + Enumerable.Empty(), + TestObjects.GetGlobalSettings()); //if (setSingleton) //{ diff --git a/src/Umbraco.Tests/Web/TemplateUtilitiesTests.cs b/src/Umbraco.Tests/Web/TemplateUtilitiesTests.cs index 5e33aec072..8b52ce1893 100644 --- a/src/Umbraco.Tests/Web/TemplateUtilitiesTests.cs +++ b/src/Umbraco.Tests/Web/TemplateUtilitiesTests.cs @@ -36,7 +36,8 @@ namespace Umbraco.Tests.Web // fixme - bad in a unit test - but Udi has a static ctor that wants it?! var container = new Mock(); - container.Setup(x => x.GetInstance(typeof(TypeLoader))).Returns(new TypeLoader(NullCacheProvider.Instance, new ProfilingLogger(Mock.Of(), Mock.Of()))); + container.Setup(x => x.GetInstance(typeof(TypeLoader))).Returns( + new TypeLoader(NullCacheProvider.Instance, SettingsForTests.GenerateMockGlobalSettings(), new ProfilingLogger(Mock.Of(), Mock.Of()))); container.Setup(x => x.GetInstance(typeof (ServiceContext))).Returns(serviceContext); Current.Container = container.Object; @@ -77,15 +78,18 @@ namespace Umbraco.Tests.Web return "/my-test-url"; }); + var globalSettings = SettingsForTests.GenerateMockGlobalSettings(); + using (var umbCtx = UmbracoContext.EnsureContext( Umbraco.Web.Composing.Current.UmbracoContextAccessor, Mock.Of(), Mock.Of(), - new Mock(null, null).Object, + new Mock(null, null, globalSettings).Object, //setup a quick mock of the WebRouting section Mock.Of(section => section.WebRouting == Mock.Of(routingSection => routingSection.UrlProviderMode == "AutoLegacy")), //pass in the custom url provider new[]{ testUrlProvider.Object }, + globalSettings, true)) { var output = TemplateUtilities.ParseInternalLinks(input, umbCtx.UrlProvider); diff --git a/src/Umbraco.Tests/Web/WebExtensionMethodTests.cs b/src/Umbraco.Tests/Web/WebExtensionMethodTests.cs index 7b53d624a0..86339c309f 100644 --- a/src/Umbraco.Tests/Web/WebExtensionMethodTests.cs +++ b/src/Umbraco.Tests/Web/WebExtensionMethodTests.cs @@ -26,9 +26,10 @@ namespace Umbraco.Tests.Web var umbCtx = new UmbracoContext( Mock.Of(), Mock.Of(), - new WebSecurity(Mock.Of(), Current.Services.UserService), + new WebSecurity(Mock.Of(), Current.Services.UserService, TestObjects.GetGlobalSettings()), TestObjects.GetUmbracoSettings(), - new List()); + new List(), + TestObjects.GetGlobalSettings()); var r1 = new RouteData(); r1.DataTokens.Add(Core.Constants.Web.UmbracoContextDataToken, umbCtx); @@ -42,9 +43,10 @@ namespace Umbraco.Tests.Web var umbCtx = new UmbracoContext( Mock.Of(), Mock.Of(), - new WebSecurity(Mock.Of(), Current.Services.UserService), + new WebSecurity(Mock.Of(), Current.Services.UserService, TestObjects.GetGlobalSettings()), TestObjects.GetUmbracoSettings(), - new List()); + new List(), + TestObjects.GetGlobalSettings()); var r1 = new RouteData(); r1.DataTokens.Add(Core.Constants.Web.UmbracoContextDataToken, umbCtx); @@ -68,9 +70,10 @@ namespace Umbraco.Tests.Web var umbCtx = new UmbracoContext( Mock.Of(), Mock.Of(), - new WebSecurity(Mock.Of(), Current.Services.UserService), + new WebSecurity(Mock.Of(), Current.Services.UserService, TestObjects.GetGlobalSettings()), TestObjects.GetUmbracoSettings(), - new List()); + new List(), + TestObjects.GetGlobalSettings()); var httpContext = Mock.Of(); diff --git a/src/Umbraco.Web.UI/Umbraco/umbraco.aspx.cs b/src/Umbraco.Web.UI/Umbraco/umbraco.aspx.cs index a148ac6e05..7f9f6b3019 100644 --- a/src/Umbraco.Web.UI/Umbraco/umbraco.aspx.cs +++ b/src/Umbraco.Web.UI/Umbraco/umbraco.aspx.cs @@ -13,7 +13,7 @@ namespace Umbraco.Web.UI.Umbraco protected void Page_Load(object sender, EventArgs e) { Response.Status = "301 Moved Permanently"; - Response.AddHeader("Location", GlobalSettings.Path); + Response.AddHeader("Location", UmbracoConfig.For.GlobalSettings().Path); } } } diff --git a/src/Umbraco.Web.UI/umbraco/Views/Default.cshtml b/src/Umbraco.Web.UI/umbraco/Views/Default.cshtml index 22e4c90962..7387072247 100644 --- a/src/Umbraco.Web.UI/umbraco/Views/Default.cshtml +++ b/src/Umbraco.Web.UI/umbraco/Views/Default.cshtml @@ -11,6 +11,7 @@ @using Umbraco.Web @using Umbraco.Web.Editors @using umbraco +@using Umbraco.Core.Configuration @inherits System.Web.Mvc.WebViewPage @@ -94,7 +95,7 @@ view="ysodOverlay.view"> - @Html.BareMinimumServerVariablesScript(Url, Url.Action("ExternalLogin", "BackOffice", new { area = ViewBag.UmbracoPath }), Model.Features) + @Html.BareMinimumServerVariablesScript(Url, Url.Action("ExternalLogin", "BackOffice", new { area = ViewBag.UmbracoPath }), Model.Features, UmbracoConfig.For.GlobalSettings())