From 475f7e6c3b8a71234151db2265a53885b710f616 Mon Sep 17 00:00:00 2001 From: Sebastiaan Janssen Date: Thu, 4 Mar 2021 09:40:23 +0100 Subject: [PATCH 1/5] Bump version to 8.12.0 --- src/SolutionInfo.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/SolutionInfo.cs b/src/SolutionInfo.cs index cab7b9a12b..c064920d34 100644 --- a/src/SolutionInfo.cs +++ b/src/SolutionInfo.cs @@ -19,4 +19,4 @@ using System.Resources; // these are FYI and changed automatically [assembly: AssemblyFileVersion("8.12.0")] -[assembly: AssemblyInformationalVersion("8.12.0-rc")] +[assembly: AssemblyInformationalVersion("8.12.0")] From af658100486d54fcbe9a404759cf0054af091eb4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niels=20Lyngs=C3=B8?= Date: Mon, 8 Mar 2021 09:44:33 +0100 Subject: [PATCH 2/5] no need to prevent or stop propagation on this. (#9933) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Niels Lyngsø --- .../directives/components/upload/umbfileupload.directive.js | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/components/upload/umbfileupload.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/components/upload/umbfileupload.directive.js index 3581aed9e0..60882a372f 100644 --- a/src/Umbraco.Web.UI.Client/src/common/directives/components/upload/umbfileupload.directive.js +++ b/src/Umbraco.Web.UI.Client/src/common/directives/components/upload/umbfileupload.directive.js @@ -20,11 +20,7 @@ function umbFileUpload() { el.val(''); }); - el.on('drag dragstart dragend dragover dragenter dragleave drop', function (e) { - e.preventDefault(); - e.stopPropagation(); - }) - .on('dragover dragenter', function () { + el.on('dragover dragenter', function () { scope.$emit("isDragover", { value: true }); }) .on('dragleave dragend drop', function () { From cef1a73a2e97243f695b4ee9a8ab4d7cd6e3328a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niels=20Lyngs=C3=B8?= Date: Mon, 8 Mar 2021 09:44:33 +0100 Subject: [PATCH 3/5] no need to prevent or stop propagation on this. (#9933) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Niels Lyngsø (cherry picked from commit af658100486d54fcbe9a404759cf0054af091eb4) --- .../directives/components/upload/umbfileupload.directive.js | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/components/upload/umbfileupload.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/components/upload/umbfileupload.directive.js index 3581aed9e0..60882a372f 100644 --- a/src/Umbraco.Web.UI.Client/src/common/directives/components/upload/umbfileupload.directive.js +++ b/src/Umbraco.Web.UI.Client/src/common/directives/components/upload/umbfileupload.directive.js @@ -20,11 +20,7 @@ function umbFileUpload() { el.val(''); }); - el.on('drag dragstart dragend dragover dragenter dragleave drop', function (e) { - e.preventDefault(); - e.stopPropagation(); - }) - .on('dragover dragenter', function () { + el.on('dragover dragenter', function () { scope.$emit("isDragover", { value: true }); }) .on('dragleave dragend drop', function () { From fc447bb1013b71a2edd7dd031652afea0033db9a Mon Sep 17 00:00:00 2001 From: Lars-Erik Aabech Date: Mon, 8 Mar 2021 12:23:03 +0100 Subject: [PATCH 4/5] Should allow grid editors to use hash based settings (#9837) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Should allow grid editors to use hash based settings * Swap to using vm in grid config controller, as well as showing button when there's map settings * Included keys for styles in empty state check for grid settings * converted the code into more AngularJS performant code * Remove rogue change to grid.editors.config * use watchCollection instead Co-authored-by: Niels Lyngsø (cherry picked from commit 008827f785df3a6ce1c150ceebb9fc826fc0d739) --- .../grid/dialogs/config.controller.js | 20 ++++++++++++++++++- .../propertyeditors/grid/dialogs/config.html | 8 ++++---- 2 files changed, 23 insertions(+), 5 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/grid/dialogs/config.controller.js b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/grid/dialogs/config.controller.js index 30c89d5f2e..7330d69b2f 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/grid/dialogs/config.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/grid/dialogs/config.controller.js @@ -16,7 +16,25 @@ function ConfigController($scope) { $scope.model.close(); } } - + + vm.showEmptyState = false; + vm.showConfig = false; + vm.showStyles = false; + + $scope.$watchCollection('model.config', onWatch); + $scope.$watchCollection('model.styles', onWatch); + + function onWatch() { + + vm.showConfig = $scope.model.config && + ($scope.model.config.length > 0 || Object.keys($scope.model.config).length > 0); + vm.showStyles = $scope.model.styles && + ($scope.model.styles.length > 0 || Object.keys($scope.model.styles).length > 0); + + vm.showEmptyState = vm.showConfig === false && vm.showStyles === false; + + } + } angular.module("umbraco").controller("Umbraco.PropertyEditors.GridPrevalueEditor.ConfigController", ConfigController); diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/grid/dialogs/config.html b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/grid/dialogs/config.html index a7cabd1636..88585b76fa 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/grid/dialogs/config.html +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/grid/dialogs/config.html @@ -13,11 +13,11 @@ - + No further configuration available - +
@@ -29,7 +29,7 @@ - +
@@ -52,7 +52,7 @@ shortcut="esc" action="vm.close()"> - Date: Mon, 8 Mar 2021 13:26:52 +0100 Subject: [PATCH 5/5] User manager related updates (#9935) * Only allow not-admins to assign groups they have themselves * Only admins is allowed to change password of other admins * Fixed issue with deep clone of UserGroup. The Allowed sections was not cloned. This resulted in the allowed sections of the object stored in cache was updated, everytime we changed the allowed sections on an object cloned from the cache. Even if we did not save it. * Only Admins are allowed to add sections to a user group, that they don't have access to themselves * Align backend code with UI. User managers that is are not admin, can only assign the same groups new users, that they have themselves. * Make existingGroupAliases and empty array when creating a new user Co-authored-by: Mole --- .../Models/Membership/UserGroup.cs | 18 ++++- src/Umbraco.Tests/Models/UserGroupTests.cs | 80 +++++++++++++++++++ src/Umbraco.Tests/Umbraco.Tests.csproj | 1 + .../UserEditorAuthorizationHelperTests.cs | 31 +++++++ src/Umbraco.Web.UI.Client/package-lock.json | 40 +++++----- .../UserGroupEditorAuthorizationHelper.cs | 11 +-- .../Filters/UserGroupValidateAttribute.cs | 6 +- src/Umbraco.Web/Editors/PasswordChanger.cs | 8 +- .../Editors/UserEditorAuthorizationHelper.cs | 14 +++- .../Editors/UserGroupsController.cs | 6 +- 10 files changed, 177 insertions(+), 38 deletions(-) create mode 100644 src/Umbraco.Tests/Models/UserGroupTests.cs diff --git a/src/Umbraco.Core/Models/Membership/UserGroup.cs b/src/Umbraco.Core/Models/Membership/UserGroup.cs index 31421f990d..eb797d6621 100644 --- a/src/Umbraco.Core/Models/Membership/UserGroup.cs +++ b/src/Umbraco.Core/Models/Membership/UserGroup.cs @@ -19,7 +19,7 @@ namespace Umbraco.Core.Models.Membership private string _icon; private string _name; private IEnumerable _permissions; - private readonly List _sectionCollection; + private List _sectionCollection; //Custom comparer for enumerable private static readonly DelegateEqualityComparer> StringEnumerableComparer = @@ -101,7 +101,10 @@ namespace Umbraco.Core.Models.Membership set => SetPropertyValueAndDetectChanges(value, ref _permissions, nameof(Permissions), StringEnumerableComparer); } - public IEnumerable AllowedSections => _sectionCollection; + public IEnumerable AllowedSections + { + get => _sectionCollection; + } public void RemoveAllowedSection(string sectionAlias) { @@ -121,5 +124,16 @@ namespace Umbraco.Core.Models.Membership } public int UserCount { get; } + + protected override void PerformDeepClone(object clone) + { + + base.PerformDeepClone(clone); + + var clonedEntity = (UserGroup)clone; + + //manually clone the start node props + clonedEntity._sectionCollection = new List(_sectionCollection); + } } } diff --git a/src/Umbraco.Tests/Models/UserGroupTests.cs b/src/Umbraco.Tests/Models/UserGroupTests.cs new file mode 100644 index 0000000000..3cd1bfcb5d --- /dev/null +++ b/src/Umbraco.Tests/Models/UserGroupTests.cs @@ -0,0 +1,80 @@ +using System; +using System.Diagnostics; +using System.Linq; +using NUnit.Framework; +using Umbraco.Core.Composing; +using Umbraco.Core.Models.Membership; +using Umbraco.Core.Serialization; +using Umbraco.Tests.TestHelpers; + +namespace Umbraco.Tests.Models +{ + [TestFixture] + public class UserGroupTests + { + [SetUp] + public void Setup() + { + Current.Reset(); + Current.UnlockConfigs(); + Current.Configs.Add(SettingsForTests.GetDefaultGlobalSettings); + Current.Configs.Add(SettingsForTests.GetDefaultUmbracoSettings); + } + + [Test] + + public void Can_Deep_Clone() + { + var item = Build(); + + var clone = (UserGroup)item.DeepClone(); + + Assert.AreNotSame(clone, item); + Assert.AreEqual(clone, item); + + Assert.AreEqual(clone.AllowedSections.Count(), item.AllowedSections.Count()); + Assert.AreNotSame(clone.AllowedSections, item.AllowedSections); + + //Verify normal properties with reflection + var allProps = clone.GetType().GetProperties(); + foreach (var propertyInfo in allProps) + { + Assert.AreEqual(propertyInfo.GetValue(clone, null), propertyInfo.GetValue(item, null)); + } + } + + [Test] + public void Can_Serialize_Without_Error() + { + var ss = new SerializationService(new JsonNetSerializer()); + + var item = Build(); + + var result = ss.ToStream(item); + var json = result.ResultStream.ToJsonString(); + Debug.Print(json); + } + + private UserGroup Build() + { + var item = new UserGroup() + { + Id = 3, + Key = Guid.NewGuid(), + UpdateDate = DateTime.Now, + CreateDate = DateTime.Now, + Name = "Test", + Alias = "alias", + Icon = "icon", + Permissions = new []{"a", "b", "c"}, + DeleteDate = null, + StartContentId = null, + StartMediaId = null, + }; + item.AddAllowedSection("A"); + item.AddAllowedSection("B"); + + return item; + } + } +} diff --git a/src/Umbraco.Tests/Umbraco.Tests.csproj b/src/Umbraco.Tests/Umbraco.Tests.csproj index f86098997a..27fcebd41d 100644 --- a/src/Umbraco.Tests/Umbraco.Tests.csproj +++ b/src/Umbraco.Tests/Umbraco.Tests.csproj @@ -145,6 +145,7 @@ + diff --git a/src/Umbraco.Tests/Web/Controllers/UserEditorAuthorizationHelperTests.cs b/src/Umbraco.Tests/Web/Controllers/UserEditorAuthorizationHelperTests.cs index 4478b59085..f531bf4e09 100644 --- a/src/Umbraco.Tests/Web/Controllers/UserEditorAuthorizationHelperTests.cs +++ b/src/Umbraco.Tests/Web/Controllers/UserEditorAuthorizationHelperTests.cs @@ -116,6 +116,37 @@ namespace Umbraco.Tests.Web.Controllers Assert.IsTrue(result.Success); } + [Test] + [TestCase(Constants.Security.AdminGroupAlias, Constants.Security.AdminGroupAlias, ExpectedResult = true)] + [TestCase(Constants.Security.AdminGroupAlias, "SomethingElse", ExpectedResult = true)] + [TestCase(Constants.Security.EditorGroupAlias, Constants.Security.AdminGroupAlias, ExpectedResult = false)] + [TestCase(Constants.Security.EditorGroupAlias, "SomethingElse", ExpectedResult = false)] + [TestCase(Constants.Security.EditorGroupAlias, Constants.Security.EditorGroupAlias, ExpectedResult = true)] + public bool Can_only_add_user_groups_you_are_part_of_yourself_unless_you_are_admin(string groupAlias, string groupToAdd) + { + var currentUser = Mock.Of(user => user.Groups == new[] + { + new ReadOnlyUserGroup(1, "CurrentUser", "icon-user", null, null, groupAlias, new string[0], new string[0]) + }); + IUser savingUser = null; // This means it is a new created user + + var contentService = new Mock(); + var mediaService = new Mock(); + var userService = new Mock(); + var entityService = new Mock(); + + var authHelper = new UserEditorAuthorizationHelper( + contentService.Object, + mediaService.Object, + userService.Object, + entityService.Object, + AppCaches.Disabled); + + var result = authHelper.IsAuthorized(currentUser, savingUser, new int[0], new int[0], new[] { groupToAdd }); + + return result.Success; + } + [Test] public void Can_Add_Another_Content_Start_Node_On_User_With_Access() { diff --git a/src/Umbraco.Web.UI.Client/package-lock.json b/src/Umbraco.Web.UI.Client/package-lock.json index 1b28cfb029..4245cf3b23 100644 --- a/src/Umbraco.Web.UI.Client/package-lock.json +++ b/src/Umbraco.Web.UI.Client/package-lock.json @@ -2681,7 +2681,7 @@ "cli-color": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/cli-color/-/cli-color-1.4.0.tgz", - "integrity": "sha1-fRBzj0hSaCT4/n2lGFfLD1cv4B8=", + "integrity": "sha512-xu6RvQqqrWEo6MPR1eixqGPywhYBHRs653F9jfXB2Hx4jdM/3WxiNE1vppRmxtMIfl16SFYTpYlrnqH/HsK/2w==", "dev": true, "requires": { "ansi-regex": "^2.1.1", @@ -2915,7 +2915,7 @@ "color": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/color/-/color-3.0.0.tgz", - "integrity": "sha1-2SC0Mo1TSjrIKV1o971LpsQnvpo=", + "integrity": "sha512-jCpd5+s0s0t7p3pHQKpnJ0TpQKKdleP71LWcA0aqiljpiuAkOSUFN/dyH8ZwF0hRmFlrIuRhufds1QyEP9EB+w==", "dev": true, "requires": { "color-convert": "^1.9.1", @@ -3813,7 +3813,7 @@ "diagnostics": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/diagnostics/-/diagnostics-1.1.1.tgz", - "integrity": "sha1-yrasM99wydmnJ0kK5DrJladpsio=", + "integrity": "sha512-8wn1PmdunLJ9Tqbx+Fx/ZEuHfJf4NKSN2ZBj7SJC/OWRWha843+WsTjqMe1B5E3p28jqBlp+mJ2fPVxPyNgYKQ==", "dev": true, "requires": { "colorspace": "1.1.x", @@ -3908,7 +3908,7 @@ "domhandler": { "version": "2.4.2", "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-2.4.2.tgz", - "integrity": "sha1-iAUJfpM9ZehVRvcm1g9euItE+AM=", + "integrity": "sha512-JiK04h0Ht5u/80fdLMCEmV4zkNh2BcoMFBmZ/91WtYZ8qVXSKjiw7fXMgFPnHcSZgOo3XdinHvmnDUeMf5R4wA==", "dev": true, "requires": { "domelementtype": "1" @@ -4177,7 +4177,7 @@ "debug": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", - "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "integrity": "sha1-W7WgZyYotkFJVmuhaBnmFRjGcmE=", "dev": true, "requires": { "ms": "2.0.0" @@ -4219,7 +4219,7 @@ "env-variable": { "version": "0.0.5", "resolved": "https://registry.npmjs.org/env-variable/-/env-variable-0.0.5.tgz", - "integrity": "sha1-kT3YML7xHpagOcA41BMGBOujf4g=", + "integrity": "sha512-zoB603vQReOFvTg5xMl9I1P2PnHsHQQKTEowsKKD7nseUfJq6UWzK+4YtlWUO1nhiQUxe6XMkk+JleSZD1NZFA==", "dev": true }, "errno": { @@ -4354,7 +4354,7 @@ "source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha1-dHIq8y6WFOnCh6jQu95IteLxomM=", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "dev": true, "optional": true } @@ -7236,7 +7236,7 @@ "readable-stream": { "version": "2.3.6", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", - "integrity": "sha1-sRwn2IuP8fvgcGQ8+UsMea4bCq8=", + "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", "dev": true, "requires": { "core-util-is": "~1.0.0", @@ -7251,7 +7251,7 @@ "string_decoder": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha1-nPFhG6YmhdcDCunkujQUnDrwP8g=", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "dev": true, "requires": { "safe-buffer": "~5.1.0" @@ -8466,7 +8466,7 @@ "source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha1-dHIq8y6WFOnCh6jQu95IteLxomM=", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "dev": true }, "to-regex-range": { @@ -8533,7 +8533,7 @@ "kuler": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/kuler/-/kuler-1.0.1.tgz", - "integrity": "sha1-73x4TzbJ+24W3TFQ0VJneysCKKY=", + "integrity": "sha512-J9nVUucG1p/skKul6DU3PUZrhs0LPulNaeUOox0IyXDi8S4CztTHs1gQphhuZmzXG7VOQSf6NJfKuzteQLv9gQ==", "dev": true, "requires": { "colornames": "^1.1.1" @@ -9105,7 +9105,7 @@ "memoizee": { "version": "0.4.14", "resolved": "https://registry.npmjs.org/memoizee/-/memoizee-0.4.14.tgz", - "integrity": "sha1-B6APIEaZ+alcLZ53IYJxx81hDVc=", + "integrity": "sha512-/SWFvWegAIYAO4NQMpcX+gcra0yEZu4OntmUdrBaWrJncxOqAziGFlHxc7yjKVK2uu3lpPW27P27wkR82wA8mg==", "dev": true, "requires": { "d": "1", @@ -9232,7 +9232,7 @@ "minimize": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/minimize/-/minimize-2.2.0.tgz", - "integrity": "sha1-ixZ28wBR2FmNdDZGvRJpCwdNpMM=", + "integrity": "sha512-IxR2XMbw9pXCxApkdD9BTcH2U4XlXhbeySUrv71rmMS9XDA8BVXEsIuFu24LtwCfBgfbL7Fuh8/ZzkO5DaTLlQ==", "dev": true, "requires": { "argh": "^0.1.4", @@ -9257,7 +9257,7 @@ "is-extendable": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha1-p0cPnkJnM9gb2B4RVSZOOjUHyrQ=", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", "dev": true, "requires": { "is-plain-object": "^2.0.4" @@ -9435,9 +9435,9 @@ "dev": true }, "nouislider": { - "version": "14.6.2", - "resolved": "https://registry.npmjs.org/nouislider/-/nouislider-14.6.2.tgz", - "integrity": "sha512-/lJeqJBghNAZS3P2VYrHzm1RM6YJPvvC/1wNpGaHBRX+05wpzUDafrW/ohAYp4kjKhRH8+BJ0vkorCHiMmgTMQ==" + "version": "14.6.3", + "resolved": "https://registry.npmjs.org/nouislider/-/nouislider-14.6.3.tgz", + "integrity": "sha512-/3tAqsWY2JYW9vd7bC14bFRA1P9A+pRHOtKmoMsyfnB0fQcd1UFx2pdY1Ey5wAUzTnXTesmYaEo/ecLVETijIQ==" }, "now-and-later": { "version": "2.0.1", @@ -14764,7 +14764,7 @@ "debug": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", - "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "integrity": "sha1-W7WgZyYotkFJVmuhaBnmFRjGcmE=", "dev": true, "requires": { "ms": "2.0.0" @@ -15356,7 +15356,7 @@ "text-hex": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/text-hex/-/text-hex-1.0.0.tgz", - "integrity": "sha1-adycGxdEbueakr9biEu0uRJ1BvU=", + "integrity": "sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg==", "dev": true }, "text-table": { @@ -15448,7 +15448,7 @@ "timers-ext": { "version": "0.1.7", "resolved": "https://registry.npmjs.org/timers-ext/-/timers-ext-0.1.7.tgz", - "integrity": "sha1-b1ethXjgej+5+R2Th9ZWR1VeJcY=", + "integrity": "sha512-b85NUNzTSdodShTIbky6ZF02e8STtVVfD+fu4aXXShEELpozH+bCpJLYMPZbsABN2wDH7fJpqIoXxJpzbf0NqQ==", "dev": true, "requires": { "es5-ext": "~0.10.46", diff --git a/src/Umbraco.Web/Editors/Filters/UserGroupEditorAuthorizationHelper.cs b/src/Umbraco.Web/Editors/Filters/UserGroupEditorAuthorizationHelper.cs index ea403758d0..ad3dae5e06 100644 --- a/src/Umbraco.Web/Editors/Filters/UserGroupEditorAuthorizationHelper.cs +++ b/src/Umbraco.Web/Editors/Filters/UserGroupEditorAuthorizationHelper.cs @@ -76,18 +76,15 @@ namespace Umbraco.Web.Editors.Filters /// /// Authorize that the user is not adding a section to the group that they don't have access to /// - /// - /// - /// - /// - public Attempt AuthorizeSectionChanges(IUser currentUser, - IEnumerable currentAllowedSections, + public Attempt AuthorizeSectionChanges( + IUser currentUser, + IEnumerable existingSections, IEnumerable proposedAllowedSections) { if (currentUser.IsAdmin()) return Attempt.Succeed(); - var sectionsAdded = currentAllowedSections.Except(proposedAllowedSections).ToArray(); + var sectionsAdded = proposedAllowedSections.Except(existingSections).ToArray(); var sectionAccessMissing = sectionsAdded.Except(currentUser.AllowedSections).ToArray(); return sectionAccessMissing.Length > 0 ? Attempt.Fail("Current user doesn't have access to add these sections " + string.Join(", ", sectionAccessMissing)) diff --git a/src/Umbraco.Web/Editors/Filters/UserGroupValidateAttribute.cs b/src/Umbraco.Web/Editors/Filters/UserGroupValidateAttribute.cs index 78cd8e6a4d..a2647d2ee9 100644 --- a/src/Umbraco.Web/Editors/Filters/UserGroupValidateAttribute.cs +++ b/src/Umbraco.Web/Editors/Filters/UserGroupValidateAttribute.cs @@ -58,13 +58,9 @@ namespace Umbraco.Web.Editors.Filters return; } - //map the model to the persisted instance - Mapper.Map(userGroupSave, persisted); break; case ContentSaveAction.SaveNew: - //create the persisted model from mapping the saved model - persisted = Mapper.Map(userGroupSave); - ((UserGroup)persisted).ResetIdentity(); + persisted = new UserGroup(); break; default: actionContext.Response = actionContext.Request.CreateErrorResponse(HttpStatusCode.NotFound, new ArgumentOutOfRangeException()); diff --git a/src/Umbraco.Web/Editors/PasswordChanger.cs b/src/Umbraco.Web/Editors/PasswordChanger.cs index 2698a68b40..404ce27e39 100644 --- a/src/Umbraco.Web/Editors/PasswordChanger.cs +++ b/src/Umbraco.Web/Editors/PasswordChanger.cs @@ -1,5 +1,6 @@ using System; using System.ComponentModel.DataAnnotations; +using System.Linq; using System.Threading.Tasks; using System.Web; using System.Web.Http.ModelBinding; @@ -84,6 +85,11 @@ namespace Umbraco.Web.Editors return Attempt.Fail(new PasswordChangedModel { ChangeError = new ValidationResult("The current user is not authorized", new[] { "resetPassword" }) }); } + if (!currentUser.IsAdmin() && savingUser.IsAdmin()) + { + return Attempt.Fail(new PasswordChangedModel { ChangeError = new ValidationResult("The current user cannot change the password for the specified user", new[] { "resetPassword" }) }); + } + //ok, we should be able to reset it var resetToken = await userMgr.GeneratePasswordResetTokenAsync(savingUser.Id); var newPass = passwordModel.NewPassword.IsNullOrWhiteSpace() @@ -246,7 +252,7 @@ namespace Umbraco.Web.Editors return Attempt.Fail(new PasswordChangedModel { ChangeError = new ValidationResult("Cannot set an empty password", new[] { "value" }) }); } - //without being able to retrieve the original password, + //without being able to retrieve the original password, //we cannot arbitrarily change the password without knowing the old one and no old password was supplied - need to return an error if (passwordModel.OldPassword.IsNullOrWhiteSpace() && membershipProvider.EnablePasswordRetrieval == false) { diff --git a/src/Umbraco.Web/Editors/UserEditorAuthorizationHelper.cs b/src/Umbraco.Web/Editors/UserEditorAuthorizationHelper.cs index f666b6d5a3..bd031c0527 100644 --- a/src/Umbraco.Web/Editors/UserEditorAuthorizationHelper.cs +++ b/src/Umbraco.Web/Editors/UserEditorAuthorizationHelper.cs @@ -78,6 +78,18 @@ namespace Umbraco.Web.Editors if (userGroupAliases != null) { var savingGroupAliases = userGroupAliases.ToArray(); + var existingGroupAliases = savingUser == null + ? new string[0] + : savingUser.Groups.Select(x => x.Alias).ToArray(); + + var addedGroupAliases = savingGroupAliases.Except(existingGroupAliases); + + // As we know the current user is not admin, it is only allowed to use groups that the user do have themselves. + var savingGroupAliasesNotAllowed = addedGroupAliases.Except(currentUser.Groups.Select(x=>x.Alias)).ToArray(); + if (savingGroupAliasesNotAllowed.Any()) + { + return Attempt.Fail("Cannot assign the group(s) '" + string.Join(", ", savingGroupAliasesNotAllowed) + "', the current user is not part of them or admin"); + } //only validate any groups that have changed. //a non-admin user can remove groups and add groups that they have access to @@ -93,9 +105,7 @@ namespace Umbraco.Web.Editors if (userGroupsChanged) { // d) A user cannot assign a group to another user that they do not belong to - var currentUserGroups = currentUser.Groups.Select(x => x.Alias).ToArray(); - foreach (var group in newGroups) { if (currentUserGroups.Contains(group) == false) diff --git a/src/Umbraco.Web/Editors/UserGroupsController.cs b/src/Umbraco.Web/Editors/UserGroupsController.cs index 77f7a305af..c8620b35fe 100644 --- a/src/Umbraco.Web/Editors/UserGroupsController.cs +++ b/src/Umbraco.Web/Editors/UserGroupsController.cs @@ -39,7 +39,8 @@ namespace Umbraco.Web.Editors throw new HttpResponseException(Request.CreateResponse(HttpStatusCode.Unauthorized, isAuthorized.Result)); //if sections were added we need to check that the current user has access to that section - isAuthorized = authHelper.AuthorizeSectionChanges(Security.CurrentUser, + isAuthorized = authHelper.AuthorizeSectionChanges( + Security.CurrentUser, userGroupSave.PersistedUserGroup.AllowedSections, userGroupSave.Sections); if (isAuthorized == false) @@ -57,6 +58,9 @@ namespace Umbraco.Web.Editors //need to ensure current user is in a group if not an admin to avoid a 401 EnsureNonAdminUserIsInSavedUserGroup(userGroupSave); + //map the model to the persisted instance + Mapper.Map(userGroupSave, userGroupSave.PersistedUserGroup); + //save the group Services.UserService.Save(userGroupSave.PersistedUserGroup, userGroupSave.Users.ToArray());