From 030c97ef26c23dfa9d763be4925a9c75f0d83dd6 Mon Sep 17 00:00:00 2001 From: Stephan Date: Fri, 2 Mar 2018 15:48:21 +0100 Subject: [PATCH] Super user is not a Zero --- src/Umbraco.Core/Attempt.cs | 10 +++++++ src/Umbraco.Core/AttemptOfTResult.cs | 21 ++++++++----- src/Umbraco.Core/Constants-Security.cs | 4 +++ .../Migrations/Install/DatabaseDataCreator.cs | 2 +- .../Migrations/Upgrade/UmbracoPlan.cs | 6 ++-- .../Migrations/Upgrade/V_8_0_0/SuperZero.cs | 28 +++++++++++++++++ .../Models/Entities/EntityBase.cs | 4 +++ src/Umbraco.Core/Models/UserExtensions.cs | 15 +++++++--- .../Security/BackOfficeUserStore.cs | 2 +- src/Umbraco.Core/Umbraco.Core.csproj | 1 + .../Editors/AuthenticationController.cs | 2 +- src/Umbraco.Web/Editors/ContentController.cs | 12 ++++---- .../Editors/CurrentUserController.cs | 4 +-- src/Umbraco.Web/Editors/MediaController.cs | 2 +- .../Editors/PackageInstallController.cs | 8 ++--- src/Umbraco.Web/Editors/SectionController.cs | 2 +- src/Umbraco.Web/Editors/UsersController.cs | 9 +++--- .../InstallSteps/StarterKitDownloadStep.cs | 2 +- src/Umbraco.Web/Security/WebSecurity.cs | 27 +++-------------- .../Trees/ContentTreeControllerBase.cs | 3 +- .../Trees/UserPermissionsTreeController.cs | 2 +- src/Umbraco.Web/Trees/UsersTreeController.cs | 30 +++++++++---------- 22 files changed, 119 insertions(+), 77 deletions(-) create mode 100644 src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/SuperZero.cs diff --git a/src/Umbraco.Core/Attempt.cs b/src/Umbraco.Core/Attempt.cs index 24063c6fbe..f1b6d2e636 100644 --- a/src/Umbraco.Core/Attempt.cs +++ b/src/Umbraco.Core/Attempt.cs @@ -35,6 +35,16 @@ namespace Umbraco.Core return Attempt.Succeed(status, result); } + /// + /// Creates a failed attempt. + /// + /// The type of the attempted operation result. + /// The failed attempt. + public static Attempt Fail() + { + return Attempt.Fail(); + } + /// /// Creates a failed attempt with a result. /// diff --git a/src/Umbraco.Core/AttemptOfTResult.cs b/src/Umbraco.Core/AttemptOfTResult.cs index 9afa74b3f3..55b1ea0a1e 100644 --- a/src/Umbraco.Core/AttemptOfTResult.cs +++ b/src/Umbraco.Core/AttemptOfTResult.cs @@ -9,6 +9,14 @@ namespace Umbraco.Core [Serializable] public struct Attempt { + // private - use Succeed() or Fail() methods to create attempts + private Attempt(bool success, TResult result, Exception exception) + { + Success = success; + Result = result; + Exception = exception; + } + /// /// Gets a value indicating whether this was successful. /// @@ -24,17 +32,14 @@ namespace Umbraco.Core /// public TResult Result { get; } + /// + /// Gets the attempt result, if successful, else a default value. + /// + public TResult ResultOr(TResult value) => Success ? Result : value; + // optimize, use a singleton failed attempt private static readonly Attempt Failed = new Attempt(false, default(TResult), null); - // private - use Succeed() or Fail() methods to create attempts - private Attempt(bool success, TResult result, Exception exception) - { - Success = success; - Result = result; - Exception = exception; - } - /// /// Creates a successful attempt. /// diff --git a/src/Umbraco.Core/Constants-Security.cs b/src/Umbraco.Core/Constants-Security.cs index e308a09ad8..2e9de0d8a4 100644 --- a/src/Umbraco.Core/Constants-Security.cs +++ b/src/Umbraco.Core/Constants-Security.cs @@ -7,6 +7,10 @@ namespace Umbraco.Core { public static class Security { + /// + /// Gets the identifier of the 'super' user. + /// + public const int SuperId = -1; public const string AdminGroupAlias = "admin"; public const string TranslatorGroupAlias = "translator"; diff --git a/src/Umbraco.Core/Migrations/Install/DatabaseDataCreator.cs b/src/Umbraco.Core/Migrations/Install/DatabaseDataCreator.cs index 41aef6b7bd..66f07b121b 100644 --- a/src/Umbraco.Core/Migrations/Install/DatabaseDataCreator.cs +++ b/src/Umbraco.Core/Migrations/Install/DatabaseDataCreator.cs @@ -140,7 +140,7 @@ namespace Umbraco.Core.Migrations.Install private void CreateUserData() { - _database.Insert(Constants.DatabaseSchema.Tables.User, "id", false, new UserDto { Id = 0, Disabled = false, NoConsole = false, UserName = "Administrator", Login = "admin", Password = "default", Email = "", UserLanguage = "en-US", CreateDate = DateTime.Now, UpdateDate = DateTime.Now }); + _database.Insert(Constants.DatabaseSchema.Tables.User, "id", false, new UserDto { Id = Constants.Security.SuperId, Disabled = false, NoConsole = false, UserName = "Administrator", Login = "admin", Password = "default", Email = "", UserLanguage = "en-US", CreateDate = DateTime.Now, UpdateDate = DateTime.Now }); } private void CreateUserGroupData() diff --git a/src/Umbraco.Core/Migrations/Upgrade/UmbracoPlan.cs b/src/Umbraco.Core/Migrations/Upgrade/UmbracoPlan.cs index 5a4450a0ee..21ce08de20 100644 --- a/src/Umbraco.Core/Migrations/Upgrade/UmbracoPlan.cs +++ b/src/Umbraco.Core/Migrations/Upgrade/UmbracoPlan.cs @@ -40,7 +40,7 @@ namespace Umbraco.Core.Migrations.Upgrade throw new InvalidOperationException("Could not get current version from web.config umbracoConfigurationStatus appSetting."); // must be at least 7.8.0 - fixme adjust when releasing - if (currentVersion < new SemVersion(7, 8)) + if (currentVersion < new SemVersion(7, 8)) throw new InvalidOperationException($"Version {currentVersion} cannot be upgraded to {UmbracoVersion.SemanticVersion}."); // cannot go back in time @@ -85,7 +85,8 @@ namespace Umbraco.Core.Migrations.Upgrade .Chain("{FB0A5429-587E-4BD0-8A67-20F0E7E62FF7}") .Chain("{F0C42457-6A3B-4912-A7EA-F27ED85A2092}") .Chain("{8640C9E4-A1C0-4C59-99BB-609B4E604981}") - .Chain("{139F26D7-7E08-48E3-81D9-E50A21A72F67}"); + .Chain("{DD1B99AF-8106-4E00-BAC7-A43003EA07F8}") + .Chain("{CC1B1201-1328-443C-954A-E0BBB8CCC1B5}"); // 7.8.1 = same as 7.8.0 From("{init-7.8.1}") @@ -155,6 +156,7 @@ namespace Umbraco.Core.Migrations.Upgrade Chain("{E3388F73-89FA-45FE-A539-C7FACC8D63DD}"); Chain("{82C4BA1D-7720-46B1-BBD7-07F3F73800E6}"); Chain("{139F26D7-7E08-48E3-81D9-E50A21A72F67}"); + Chain("{CC1B1201-1328-443C-954A-E0BBB8CCC1B5}"); } } } diff --git a/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/SuperZero.cs b/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/SuperZero.cs new file mode 100644 index 0000000000..fc85a70c6a --- /dev/null +++ b/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/SuperZero.cs @@ -0,0 +1,28 @@ +namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0 +{ + public class SuperZero : MigrationBase + { + public SuperZero(IMigrationContext context) + : base(context) + { } + + public override void Migrate() + { + var exists = Database.Fetch("select id from umbracoUser where id=-1;").Count > 0; + if (exists) return; + + Database.Execute("set identity_insert umbracoUser on;"); + Database.Execute("update umbracoUser set userLogin = userLogin + '__' where userId=0"); + Database.Execute(@" + insert into umbracoUser select -1, + userDisabled, userNoConsole, userName, substring(userLogin, 1, len(userLogin) - 2), userPassword, passwordConfig, + userEmail, userLanguage, securityStampToken, failedLoginAttempts, lastLockoutDate, + lastPasswordChangeDate, lastLoginDate, emailConfirmedDate, invitedDate, + createDate, updateDate, avatar + from umbracoUser where id=0;"); + Database.Execute("update umbracoUser2UserGroup set userId=-1 where userId=0;"); + Database.Execute("delete from umbracoUser where id=0;"); + Database.Execute("set identity_insert umbracoUser off;"); + } + } +} diff --git a/src/Umbraco.Core/Models/Entities/EntityBase.cs b/src/Umbraco.Core/Models/Entities/EntityBase.cs index ab57d57ab6..4d0c2f74d9 100644 --- a/src/Umbraco.Core/Models/Entities/EntityBase.cs +++ b/src/Umbraco.Core/Models/Entities/EntityBase.cs @@ -38,6 +38,10 @@ namespace Umbraco.Core.Models.Entities set { SetPropertyValueAndDetectChanges(value, ref _id, Ps.Value.IdSelector); + + // fixme - this is a problem w/ user 'admin' having ID 'zero' + // in v7 _hasIdentity becomes true soon as an ID is set, which is... weird + // we should NOT have 'admin' have ID 'zero' _hasIdentity = value != 0; } } diff --git a/src/Umbraco.Core/Models/UserExtensions.cs b/src/Umbraco.Core/Models/UserExtensions.cs index e7035caf10..44335b2f74 100644 --- a/src/Umbraco.Core/Models/UserExtensions.cs +++ b/src/Umbraco.Core/Models/UserExtensions.cs @@ -26,14 +26,21 @@ namespace Umbraco.Core.Models } /// - /// Determines whether this user is an admin. + /// Determines whether this user is the 'super' user. + /// + public static bool IsSuper(this IUser user) + { + if (user == null) throw new ArgumentNullException(nameof(user)); + return user.Id == Constants.Security.SuperId; + } + + /// + /// Determines whether this user belongs to the administrators group. /// - /// - /// true if this user is admin; otherwise, false. - /// public static bool IsAdmin(this IUser user) { if (user == null) throw new ArgumentNullException(nameof(user)); + // fixme should super always be admin? return user.Groups != null && user.Groups.Any(x => x.Alias == Constants.Security.AdminGroupAlias); } diff --git a/src/Umbraco.Core/Security/BackOfficeUserStore.cs b/src/Umbraco.Core/Security/BackOfficeUserStore.cs index 1935aa91c3..e5500e689c 100644 --- a/src/Umbraco.Core/Security/BackOfficeUserStore.cs +++ b/src/Umbraco.Core/Security/BackOfficeUserStore.cs @@ -99,7 +99,7 @@ namespace Umbraco.Core.Security _userService.Save(userEntity); - if (userEntity.Id == 0) throw new DataException("Could not create the user, check logs for details"); + if (!userEntity.HasIdentity) throw new DataException("Could not create the user, check logs for details"); //re-assign id user.Id = userEntity.Id; diff --git a/src/Umbraco.Core/Umbraco.Core.csproj b/src/Umbraco.Core/Umbraco.Core.csproj index 9a6ffdbe33..e1f4a31be3 100644 --- a/src/Umbraco.Core/Umbraco.Core.csproj +++ b/src/Umbraco.Core/Umbraco.Core.csproj @@ -315,6 +315,7 @@ + diff --git a/src/Umbraco.Web/Editors/AuthenticationController.cs b/src/Umbraco.Web/Editors/AuthenticationController.cs index 4ec8e5f10b..10ec705b74 100644 --- a/src/Umbraco.Web/Editors/AuthenticationController.cs +++ b/src/Umbraco.Web/Editors/AuthenticationController.cs @@ -202,7 +202,7 @@ namespace Umbraco.Web.Editors [ValidateAngularAntiForgeryToken] public async Task> GetCurrentUserLinkedLogins() { - var identityUser = await UserManager.FindByIdAsync(UmbracoContext.Security.GetUserId()); + var identityUser = await UserManager.FindByIdAsync(UmbracoContext.Security.GetUserId().ResultOr(0)); return identityUser.Logins.ToDictionary(x => x.LoginProvider, x => x.ProviderKey); } diff --git a/src/Umbraco.Web/Editors/ContentController.cs b/src/Umbraco.Web/Editors/ContentController.cs index d54a4e6bdf..c7569aa4eb 100644 --- a/src/Umbraco.Web/Editors/ContentController.cs +++ b/src/Umbraco.Web/Editors/ContentController.cs @@ -294,7 +294,7 @@ namespace Umbraco.Web.Editors throw new HttpResponseException(HttpStatusCode.NotFound); } - var emptyContent = Services.ContentService.Create("", parentId, contentType.Alias, Security.GetUserId()); + var emptyContent = Services.ContentService.Create("", parentId, contentType.Alias, Security.GetUserId().ResultOr(0)); var mapped = Mapper.Map(emptyContent); //remove this tab if it exists: umbContainerView @@ -472,9 +472,9 @@ namespace Umbraco.Web.Editors EnsureUniqueName(name, content, "name"); - var blueprint = Services.ContentService.CreateContentFromBlueprint(content, name, Security.GetUserId()); + var blueprint = Services.ContentService.CreateContentFromBlueprint(content, name, Security.GetUserId().ResultOr(0)); - Services.ContentService.SaveBlueprint(blueprint, Security.GetUserId()); + Services.ContentService.SaveBlueprint(blueprint, Security.GetUserId().ResultOr(0)); var notificationModel = new SimpleNotificationModel(); notificationModel.AddSuccessNotification( @@ -669,7 +669,7 @@ namespace Umbraco.Web.Editors } foundContent.PublishValues(); // fixme variants? - var publishResult = Services.ContentService.SaveAndPublish(foundContent, Security.GetUserId()); + var publishResult = Services.ContentService.SaveAndPublish(foundContent, Security.GetUserId().ResultOr(0)); if (publishResult.Success == false) { var notificationModel = new SimpleNotificationModel(); @@ -722,7 +722,7 @@ namespace Umbraco.Web.Editors //if the current item is in the recycle bin if (foundContent.Trashed == false) { - var moveResult = Services.ContentService.MoveToRecycleBin(foundContent, Security.GetUserId()); + var moveResult = Services.ContentService.MoveToRecycleBin(foundContent, Security.GetUserId().ResultOr(0)); if (moveResult.Success == false) { //returning an object of INotificationModel will ensure that any pending @@ -732,7 +732,7 @@ namespace Umbraco.Web.Editors } else { - var deleteResult = Services.ContentService.Delete(foundContent, Security.GetUserId()); + var deleteResult = Services.ContentService.Delete(foundContent, Security.GetUserId().ResultOr(0)); if (deleteResult.Success == false) { //returning an object of INotificationModel will ensure that any pending diff --git a/src/Umbraco.Web/Editors/CurrentUserController.cs b/src/Umbraco.Web/Editors/CurrentUserController.cs index c59aac8280..0642699b13 100644 --- a/src/Umbraco.Web/Editors/CurrentUserController.cs +++ b/src/Umbraco.Web/Editors/CurrentUserController.cs @@ -34,7 +34,7 @@ namespace Umbraco.Web.Editors [OverrideAuthorization] public async Task PostSetInvitedUserPassword([FromBody]string newPassword) { - var result = await UserManager.AddPasswordAsync(Security.GetUserId(), newPassword); + var result = await UserManager.AddPasswordAsync(Security.GetUserId().ResultOr(0), newPassword); if (result.Succeeded == false) { @@ -67,7 +67,7 @@ namespace Umbraco.Web.Editors public async Task PostSetAvatar() { //borrow the logic from the user controller - return await UsersController.PostSetAvatarInternal(Request, Services.UserService, Current.ApplicationCache.StaticCache, Security.GetUserId()); + return await UsersController.PostSetAvatarInternal(Request, Services.UserService, Current.ApplicationCache.StaticCache, Security.GetUserId().ResultOr(0)); } /// diff --git a/src/Umbraco.Web/Editors/MediaController.cs b/src/Umbraco.Web/Editors/MediaController.cs index 6b26404937..e77b5497b2 100644 --- a/src/Umbraco.Web/Editors/MediaController.cs +++ b/src/Umbraco.Web/Editors/MediaController.cs @@ -76,7 +76,7 @@ namespace Umbraco.Web.Editors throw new HttpResponseException(HttpStatusCode.NotFound); } - var emptyContent = Services.MediaService.CreateMedia("", parentId, contentType.Alias, Security.GetUserId()); + var emptyContent = Services.MediaService.CreateMedia("", parentId, contentType.Alias, Security.GetUserId().ResultOr(0)); var mapped = Mapper.Map(emptyContent); //remove this tab if it exists: umbContainerView diff --git a/src/Umbraco.Web/Editors/PackageInstallController.cs b/src/Umbraco.Web/Editors/PackageInstallController.cs index 6466017394..46e35f511d 100644 --- a/src/Umbraco.Web/Editors/PackageInstallController.cs +++ b/src/Umbraco.Web/Editors/PackageInstallController.cs @@ -71,7 +71,7 @@ namespace Umbraco.Web.Editors .Where(x => x.Data.Name == pack.Data.Name && x.Data.Id != pack.Data.Id)) { //remove from teh xml - installed.Delete(Security.GetUserId()); + installed.Delete(Security.GetUserId().ResultOr(0)); } } catch (Exception e) @@ -109,7 +109,7 @@ namespace Umbraco.Web.Editors if (found != null) { removedTemplates.Add(found); - Services.FileService.DeleteTemplate(found.Alias, Security.GetUserId()); + Services.FileService.DeleteTemplate(found.Alias, Security.GetUserId().ResultOr(0)); } pack.Data.Templates.Remove(nId.ToString()); } @@ -236,7 +236,7 @@ namespace Umbraco.Web.Editors pack.Data.Files.Remove(file); } pack.Save(); - pack.Delete(Security.GetUserId()); + pack.Delete(Security.GetUserId().ResultOr(0)); // create a summary of what was actually removed, for PackagingService.UninstalledPackage var summary = new UninstallationSummary @@ -474,7 +474,7 @@ namespace Umbraco.Web.Editors string path = Path.Combine("packages", packageGuid + ".umb"); if (File.Exists(IOHelper.MapPath(Path.Combine(SystemDirectories.Data, path))) == false) { - path = Services.PackagingService.FetchPackageFile(Guid.Parse(packageGuid), UmbracoVersion.Current, Security.GetUserId()); + path = Services.PackagingService.FetchPackageFile(Guid.Parse(packageGuid), UmbracoVersion.Current, Security.GetUserId().ResultOr(0)); } var model = new LocalPackageInstallModel diff --git a/src/Umbraco.Web/Editors/SectionController.cs b/src/Umbraco.Web/Editors/SectionController.cs index d77f923c9a..4ee1efc8ae 100644 --- a/src/Umbraco.Web/Editors/SectionController.cs +++ b/src/Umbraco.Web/Editors/SectionController.cs @@ -19,7 +19,7 @@ namespace Umbraco.Web.Editors public IEnumerable
GetSections() { - var sections = Services.SectionService.GetAllowedSections(Security.GetUserId()); + var sections = Services.SectionService.GetAllowedSections(Security.GetUserId().ResultOr(0)); var sectionModels = sections.Select(Mapper.Map).ToArray(); diff --git a/src/Umbraco.Web/Editors/UsersController.cs b/src/Umbraco.Web/Editors/UsersController.cs index 1b26889e4a..1b4a515bce 100644 --- a/src/Umbraco.Web/Editors/UsersController.cs +++ b/src/Umbraco.Web/Editors/UsersController.cs @@ -204,10 +204,10 @@ namespace Umbraco.Web.Editors var filterQuery = Current.SqlContext.Query(); //if the current user is not the administrator, then don't include this in the results. - var isAdminUser = Security.CurrentUser.Id == 0; - if (isAdminUser == false) + if (Security.CurrentUser.IsSuper() == false) { - filterQuery.Where(x => x.Id != 0); + // only super can see super + filterQuery.Where(x => x.Id != Constants.Security.SuperId); } if (filter.IsNullOrWhiteSpace() == false) @@ -580,7 +580,8 @@ namespace Umbraco.Web.Editors /// public HttpResponseMessage PostDisableUsers([FromUri]int[] userIds) { - if (userIds.Contains(Security.GetUserId())) + var tryGetCurrentUserId = Security.GetUserId(); + if (tryGetCurrentUserId && userIds.Contains(tryGetCurrentUserId.Result)) { throw new HttpResponseException( Request.CreateNotificationValidationErrorResponse("The current user cannot disable itself")); diff --git a/src/Umbraco.Web/Install/InstallSteps/StarterKitDownloadStep.cs b/src/Umbraco.Web/Install/InstallSteps/StarterKitDownloadStep.cs index 3b08b6be74..f65160e5e2 100644 --- a/src/Umbraco.Web/Install/InstallSteps/StarterKitDownloadStep.cs +++ b/src/Umbraco.Web/Install/InstallSteps/StarterKitDownloadStep.cs @@ -63,7 +63,7 @@ namespace Umbraco.Web.Install.InstallSteps var installer = new Installer(); //Go get the package file from the package repo - var packageFile = Current.Services.PackagingService.FetchPackageFile(kitGuid, UmbracoVersion.Current, _security.GetUserId()); + var packageFile = Current.Services.PackagingService.FetchPackageFile(kitGuid, UmbracoVersion.Current, _security.GetUserId().ResultOr(0)); var tempFile = installer.Import(packageFile); installer.LoadConfig(tempFile); diff --git a/src/Umbraco.Web/Security/WebSecurity.cs b/src/Umbraco.Web/Security/WebSecurity.cs index b640e4cb69..d8d001bab9 100644 --- a/src/Umbraco.Web/Security/WebSecurity.cs +++ b/src/Umbraco.Web/Security/WebSecurity.cs @@ -71,11 +71,7 @@ namespace Umbraco.Web.Security if (_currentUser == null) { var id = GetUserId(); - if (id == -1) - { - return null; - } - _currentUser = _userService.GetUserById(id); + return id ? _userService.GetUserById(id.Result) : null; } return _currentUser; @@ -202,27 +198,14 @@ namespace Umbraco.Web.Security return CurrentUser.AllowedSections.Any(uApp => uApp.InvariantEquals(app)); } - /// - /// Gets the user id. - /// - /// This is not used - /// - [Obsolete("This method is no longer used, use the GetUserId() method without parameters instead")] - public int GetUserId(string umbracoUserContextId) - { - return GetUserId(); - } - /// /// Gets the currnet user's id. /// /// - public virtual int GetUserId() + public virtual Attempt GetUserId() { var identity = _httpContext.GetCurrentIdentity(false); - if (identity == null) - return -1; - return Convert.ToInt32(identity.Id); + return identity == null ? Attempt.Fail() : Attempt.Succeed(Convert.ToInt32(identity.Id)); } /// @@ -232,9 +215,7 @@ namespace Umbraco.Web.Security public virtual string GetSessionId() { var identity = _httpContext.GetCurrentIdentity(false); - if (identity == null) - return null; - return identity.SessionId; + return identity?.SessionId; } /// diff --git a/src/Umbraco.Web/Trees/ContentTreeControllerBase.cs b/src/Umbraco.Web/Trees/ContentTreeControllerBase.cs index 4eac7e803d..a4e62551fe 100644 --- a/src/Umbraco.Web/Trees/ContentTreeControllerBase.cs +++ b/src/Umbraco.Web/Trees/ContentTreeControllerBase.cs @@ -352,7 +352,8 @@ namespace Umbraco.Web.Trees .ToList(); // A user is allowed to delete their own stuff - if (dd.CreatorId == Security.GetUserId() && actions.Contains(ActionDelete.Instance) == false) + var tryGetCurrentUserId = Security.GetUserId(); + if (tryGetCurrentUserId && dd.CreatorId == tryGetCurrentUserId.Result && actions.Contains(ActionDelete.Instance) == false) actions.Add(ActionDelete.Instance); return actions.Select(x => new MenuItem(x)); diff --git a/src/Umbraco.Web/Trees/UserPermissionsTreeController.cs b/src/Umbraco.Web/Trees/UserPermissionsTreeController.cs index 26b500d540..26caa6ac2f 100644 --- a/src/Umbraco.Web/Trees/UserPermissionsTreeController.cs +++ b/src/Umbraco.Web/Trees/UserPermissionsTreeController.cs @@ -23,7 +23,7 @@ namespace Umbraco.Web.Trees long totalUsers; nodes.AddRange( Services.UserService.GetAll(0, int.MaxValue, out totalUsers) - .Where(x => x.Id > 0 && x.IsApproved) + .Where(x => x.Id != Constants.Security.SuperId && x.IsApproved) .Select(x => CreateTreeNode(x.Id.ToString(), id, queryStrings, diff --git a/src/Umbraco.Web/Trees/UsersTreeController.cs b/src/Umbraco.Web/Trees/UsersTreeController.cs index 45436aa661..2fe08e25fb 100644 --- a/src/Umbraco.Web/Trees/UsersTreeController.cs +++ b/src/Umbraco.Web/Trees/UsersTreeController.cs @@ -26,19 +26,25 @@ namespace Umbraco.Web.Trees { var nodes = new TreeNodeCollection(); - long totalusers; - var users = new List(Services.UserService.GetAll(0, int.MaxValue, out totalusers)); - + var users = new List(Services.UserService.GetAll(0, int.MaxValue, out _)); var currentUser = UmbracoContext.Current.Security.CurrentUser; - var currentUserIsAdmin = currentUser.IsAdmin(); + var hideDisabledUsers = UmbracoConfig.For.UmbracoSettings().Security.HideDisabledUsersInBackoffice; foreach (var user in users.OrderBy(x => x.IsApproved == false)) { - if (UmbracoConfig.For.UmbracoSettings().Security.HideDisabledUsersInBackoffice && - (UmbracoConfig.For.UmbracoSettings().Security.HideDisabledUsersInBackoffice == false || - user.IsApproved == false)) - { + // hide disabled user + if (user.IsApproved == false && hideDisabledUsers) continue; + + if (user.IsSuper()) + { + // only super can see super + if (!currentUser.IsSuper()) continue; + } + else if (user.IsAdmin()) + { + // only admins can see admins + if (!currentUser.IsAdmin()) continue; } var node = CreateTreeNode( @@ -51,14 +57,6 @@ namespace Umbraco.Web.Trees "/" + queryStrings.GetValue("application") + "/framed/" + Uri.EscapeDataString("users/EditUser.aspx?id=" + user.Id)); - if (user.Id == 0) - { - if (currentUser.Id != 0) - continue; - } - else if (currentUserIsAdmin == false && user.IsAdmin()) - continue; - if (user.IsApproved == false) node.CssClasses.Add("not-published");