From ba411f20b60a0a56816659e5ba2ff0f71d062ca4 Mon Sep 17 00:00:00 2001 From: Adam Rauch Date: Thu, 26 Feb 2026 10:48:33 -0800 Subject: [PATCH 1/2] ImpersonationContext -> PermissionsContext rename/repackage --- .../org/labkey/api/security/ClonedUser.java | 5 +- .../DisallowPrivilegedRolesContext.java | 8 +- .../org/labkey/api/security/ElevatedUser.java | 8 +- .../org/labkey/api/security/LimitedUser.java | 6 +- ...ext.java => NormalPermissionsContext.java} | 237 +++++++++--------- ...onContext.java => PermissionsContext.java} | 184 +++++++------- ...t.java => ReadOnlyPermissionsContext.java} | 6 +- .../labkey/api/security/SecurityManager.java | 8 +- api/src/org/labkey/api/security/User.java | 22 +- ...xt.java => WrappedPermissionsContext.java} | 14 +- .../AbstractImpersonationContext.java | 5 +- .../GroupImpersonationContextFactory.java | 5 +- .../ImpersonationContextFactory.java | 5 +- .../RoleImpersonationContextFactory.java | 5 +- .../UserImpersonationContextFactory.java | 5 +- .../org/labkey/api/view/NavTreeManager.java | 2 +- .../org/labkey/api/view/PopupUserView.java | 6 +- .../api/assay/dilution/DilutionAssayRun.java | 15 +- .../labkey/core/admin/AdminController.java | 14 +- .../labkey/core/login/LoginController.java | 4 +- .../org/labkey/core/user/UserController.java | 10 +- .../core/view/template/bootstrap/header.jsp | 7 +- 22 files changed, 284 insertions(+), 297 deletions(-) rename api/src/org/labkey/api/security/{impersonation => }/DisallowPrivilegedRolesContext.java (79%) rename api/src/org/labkey/api/security/{impersonation/NotImpersonatingContext.java => NormalPermissionsContext.java} (81%) rename api/src/org/labkey/api/security/{impersonation/ImpersonationContext.java => PermissionsContext.java} (85%) rename api/src/org/labkey/api/security/{impersonation/ReadOnlyImpersonatingContext.java => ReadOnlyPermissionsContext.java} (80%) rename api/src/org/labkey/api/security/{impersonation/WrappedImpersonationContext.java => WrappedPermissionsContext.java} (83%) diff --git a/api/src/org/labkey/api/security/ClonedUser.java b/api/src/org/labkey/api/security/ClonedUser.java index ab2b4e6a07a..8168073f41b 100644 --- a/api/src/org/labkey/api/security/ClonedUser.java +++ b/api/src/org/labkey/api/security/ClonedUser.java @@ -1,6 +1,5 @@ package org.labkey.api.security; -import org.labkey.api.security.impersonation.ImpersonationContext; import org.labkey.api.security.roles.Role; import org.labkey.api.security.roles.RoleManager; @@ -14,13 +13,13 @@ public abstract class ClonedUser extends User { - protected ClonedUser(User user, ImpersonationContext ctx) + protected ClonedUser(User user, PermissionsContext ctx) { this(user.getEmail(), user.getUserId(), user.getFriendlyName(), user.getFirstName(), user.getLastName(), user.isActive(), user.getLastLogin(), user.getPhone(), user.getLastActivity(), ctx); } protected ClonedUser(String email, int userId, String displayName, String firstName, String lastName, boolean active, - Date lastLogin, String phone, Date lastActivity, ImpersonationContext ctx) + Date lastLogin, String phone, Date lastActivity, PermissionsContext ctx) { super(email, userId); setDisplayName(displayName); diff --git a/api/src/org/labkey/api/security/impersonation/DisallowPrivilegedRolesContext.java b/api/src/org/labkey/api/security/DisallowPrivilegedRolesContext.java similarity index 79% rename from api/src/org/labkey/api/security/impersonation/DisallowPrivilegedRolesContext.java rename to api/src/org/labkey/api/security/DisallowPrivilegedRolesContext.java index c1c3a9e4f25..3a024257870 100644 --- a/api/src/org/labkey/api/security/impersonation/DisallowPrivilegedRolesContext.java +++ b/api/src/org/labkey/api/security/DisallowPrivilegedRolesContext.java @@ -13,19 +13,17 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.labkey.api.security.impersonation; +package org.labkey.api.security; /* - A "not impersonating" context that filters out privileged site roles (i.e., Site Admin, Platform Developer) + A context that filters out privileged site roles (i.e., Site Admin, Platform Developer) */ -import org.labkey.api.security.SecurableResource; -import org.labkey.api.security.User; import org.labkey.api.security.roles.Role; import java.util.stream.Stream; -public class DisallowPrivilegedRolesContext extends NotImpersonatingContext +public class DisallowPrivilegedRolesContext extends NormalPermissionsContext { private static final DisallowPrivilegedRolesContext INSTANCE = new DisallowPrivilegedRolesContext(); diff --git a/api/src/org/labkey/api/security/ElevatedUser.java b/api/src/org/labkey/api/security/ElevatedUser.java index 128cafef712..13676a5bba0 100644 --- a/api/src/org/labkey/api/security/ElevatedUser.java +++ b/api/src/org/labkey/api/security/ElevatedUser.java @@ -2,8 +2,6 @@ import org.labkey.api.audit.permissions.CanSeeAuditLogPermission; import org.labkey.api.data.Container; -import org.labkey.api.security.impersonation.ImpersonationContext; -import org.labkey.api.security.impersonation.WrappedImpersonationContext; import org.labkey.api.security.permissions.Permission; import org.labkey.api.security.roles.CanSeeAuditLogRole; import org.labkey.api.security.roles.Role; @@ -24,10 +22,10 @@ public class ElevatedUser extends ClonedUser { private ElevatedUser(User user, Set rolesToAdd) { - super(user, new WrappedImpersonationContext(user.getImpersonationContext(), rolesToAdd)); + super(user, new WrappedPermissionsContext(user.getPermissionsContext(), rolesToAdd)); } - private ElevatedUser(User user, ImpersonationContext ctx) + private ElevatedUser(User user, PermissionsContext ctx) { super(user, ctx); } @@ -52,7 +50,7 @@ public static ElevatedUser getElevatedUser(User user, Collection _roles; @@ -99,7 +97,7 @@ private LimitedUser( @JsonProperty("_lastLogin") Date lastLogin, @JsonProperty("_phone") String phone, @JsonProperty("_lastActivity") Date lastActivity, - @JsonProperty("_impersonationContext") ImpersonationContext ctx + @JsonProperty("_impersonationContext") PermissionsContext ctx ) { super(name, userId, displayName, firstName, lastName, active, lastLogin, phone, lastActivity, ctx); diff --git a/api/src/org/labkey/api/security/impersonation/NotImpersonatingContext.java b/api/src/org/labkey/api/security/NormalPermissionsContext.java similarity index 81% rename from api/src/org/labkey/api/security/impersonation/NotImpersonatingContext.java rename to api/src/org/labkey/api/security/NormalPermissionsContext.java index 5024f2e7724..c5e7dc59115 100644 --- a/api/src/org/labkey/api/security/impersonation/NotImpersonatingContext.java +++ b/api/src/org/labkey/api/security/NormalPermissionsContext.java @@ -1,119 +1,118 @@ -/* - * Copyright (c) 2011-2019 LabKey Corporation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.labkey.api.security.impersonation; - -import org.jetbrains.annotations.Nullable; -import org.labkey.api.data.Container; -import org.labkey.api.module.ModuleLoader; -import org.labkey.api.security.GroupManager; -import org.labkey.api.security.LoginUrls; -import org.labkey.api.security.PrincipalArray; -import org.labkey.api.security.User; -import org.labkey.api.security.permissions.AdminPermission; -import org.labkey.api.security.permissions.CanImpersonatePrivilegedSiteRolesPermission; -import org.labkey.api.util.PageFlowUtil; -import org.labkey.api.view.ActionURL; -import org.labkey.api.view.NavTree; - -/** - * Used when a user is not impersonating another user, group, or role. That is, they are logged in normally, and - * operating as themselves. - */ -public class NotImpersonatingContext implements ImpersonationContext -{ - private static final NotImpersonatingContext INSTANCE = new NotImpersonatingContext(); - - public static NotImpersonatingContext get() - { - return INSTANCE; - } - - protected NotImpersonatingContext() - { - } - - @Override - public boolean isImpersonating() - { - return false; - } - - @Override - public @Nullable Container getImpersonationProject() - { - return null; - } - - @Override - public User getAdminUser() - { - return null; - } - - @Override - public String getCacheKey() - { - return ""; - } - - @Override - public ActionURL getReturnUrl() - { - return null; - } - - @Override - public ImpersonationContextFactory getFactory() - { - return null; - } - - @Override - public PrincipalArray getGroups(User user) - { - return GroupManager.getAllGroupsForPrincipal(user); - } - - @Override - public void addMenu(NavTree menu, Container c, User user, ActionURL currentURL) - { - if (ModuleLoader.getInstance().isStartupComplete()) - { - @Nullable Container project = c.getProject(); - - // Must be site or project admin (folder admins can't impersonate) - if (user.hasRootAdminPermission() || (null != project && project.hasPermission(user, AdminPermission.class))) - { - NavTree impersonateMenu = new NavTree("Impersonate"); - UserImpersonationContextFactory.addMenu(impersonateMenu); - GroupImpersonationContextFactory.addMenu(impersonateMenu); - RoleImpersonationContextFactory.addMenu(impersonateMenu); - menu.addChild(impersonateMenu); - } - // Or Impersonating Troubleshooter to impersonate site roles only - else if (null == project && user.hasRootPermission(CanImpersonatePrivilegedSiteRolesPermission.class)) - { - NavTree impersonateMenu = new NavTree("Impersonate"); - RoleImpersonationContextFactory.addMenu(impersonateMenu); - menu.addChild(impersonateMenu); - } - } - - NavTree signOut = new NavTree("Sign Out", PageFlowUtil.urlProvider(LoginUrls.class).getLogoutURL(c)); - signOut.usePost(); - menu.addChild(signOut); - } -} +/* + * Copyright (c) 2011-2019 LabKey Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.labkey.api.security; + +import org.jetbrains.annotations.Nullable; +import org.labkey.api.data.Container; +import org.labkey.api.module.ModuleLoader; +import org.labkey.api.security.impersonation.GroupImpersonationContextFactory; +import org.labkey.api.security.impersonation.ImpersonationContextFactory; +import org.labkey.api.security.impersonation.RoleImpersonationContextFactory; +import org.labkey.api.security.impersonation.UserImpersonationContextFactory; +import org.labkey.api.security.permissions.AdminPermission; +import org.labkey.api.security.permissions.CanImpersonatePrivilegedSiteRolesPermission; +import org.labkey.api.util.PageFlowUtil; +import org.labkey.api.view.ActionURL; +import org.labkey.api.view.NavTree; + +/** + * Used when a user is logged in normally and operating as themselves, not impersonating another user, group, or role. + */ +public class NormalPermissionsContext implements PermissionsContext +{ + private static final NormalPermissionsContext INSTANCE = new NormalPermissionsContext(); + + public static NormalPermissionsContext get() + { + return INSTANCE; + } + + protected NormalPermissionsContext() + { + } + + @Override + public boolean isImpersonating() + { + return false; + } + + @Override + public @Nullable Container getImpersonationProject() + { + return null; + } + + @Override + public User getAdminUser() + { + return null; + } + + @Override + public String getCacheKey() + { + return ""; + } + + @Override + public ActionURL getReturnUrl() + { + return null; + } + + @Override + public ImpersonationContextFactory getFactory() + { + return null; + } + + @Override + public PrincipalArray getGroups(User user) + { + return GroupManager.getAllGroupsForPrincipal(user); + } + + @Override + public void addMenu(NavTree menu, Container c, User user, ActionURL currentURL) + { + if (ModuleLoader.getInstance().isStartupComplete()) + { + @Nullable Container project = c.getProject(); + + // Must be site or project admin (folder admins can't impersonate) + if (user.hasRootAdminPermission() || (null != project && project.hasPermission(user, AdminPermission.class))) + { + NavTree impersonateMenu = new NavTree("Impersonate"); + UserImpersonationContextFactory.addMenu(impersonateMenu); + GroupImpersonationContextFactory.addMenu(impersonateMenu); + RoleImpersonationContextFactory.addMenu(impersonateMenu); + menu.addChild(impersonateMenu); + } + // Or Impersonating Troubleshooter to impersonate site roles only + else if (null == project && user.hasRootPermission(CanImpersonatePrivilegedSiteRolesPermission.class)) + { + NavTree impersonateMenu = new NavTree("Impersonate"); + RoleImpersonationContextFactory.addMenu(impersonateMenu); + menu.addChild(impersonateMenu); + } + } + + NavTree signOut = new NavTree("Sign Out", PageFlowUtil.urlProvider(LoginUrls.class).getLogoutURL(c)); + signOut.usePost(); + menu.addChild(signOut); + } +} diff --git a/api/src/org/labkey/api/security/impersonation/ImpersonationContext.java b/api/src/org/labkey/api/security/PermissionsContext.java similarity index 85% rename from api/src/org/labkey/api/security/impersonation/ImpersonationContext.java rename to api/src/org/labkey/api/security/PermissionsContext.java index 4eea6bf01eb..16672fd7081 100644 --- a/api/src/org/labkey/api/security/impersonation/ImpersonationContext.java +++ b/api/src/org/labkey/api/security/PermissionsContext.java @@ -1,94 +1,90 @@ -/* - * Copyright (c) 2011-2018 LabKey Corporation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.labkey.api.security.impersonation; - -import com.google.common.collect.Streams; -import org.jetbrains.annotations.Nullable; -import org.labkey.api.data.Container; -import org.labkey.api.data.ContainerManager; -import org.labkey.api.security.PrincipalArray; -import org.labkey.api.security.SecurableResource; -import org.labkey.api.security.SecurityPolicy; -import org.labkey.api.security.SecurityPolicyManager; -import org.labkey.api.security.User; -import org.labkey.api.security.permissions.Permission; -import org.labkey.api.security.roles.AbstractRootContainerRole; -import org.labkey.api.security.roles.Role; -import org.labkey.api.view.ActionURL; -import org.labkey.api.view.NavTree; - -import java.io.Serializable; -import java.util.stream.Stream; - -/** - * Context that describes the way in which a user is operating within the system. They may be logged in normally, - * or they may be impersonating a specific user or a group, depending on the implementation. - */ -public interface ImpersonationContext extends Serializable -{ - /** @return whether the user is impersonating some user, group, or role, or working as their normal self */ - boolean isImpersonating(); - /** @return if non-null, the container to which the impersonation should be restricted */ - @Nullable Container getImpersonationProject(); - /** @return the user who is actually performing the operation, not the user that they might be impersonating */ - User getAdminUser(); - String getCacheKey(); // Caching permission-related state is very tricky with impersonation; context provides a cache key suffix that captures the current impersonation state - /** @return the URL to which the user should be returned when impersonation is over */ - ActionURL getReturnUrl(); - PrincipalArray getGroups(User user); - - /** - * @return The roles assigned to this user in the provided resource's policy as well as the root. The roles may be - * modified and/or filtered by the impersonation context. Note: The returned stream may duplicate some roles; if a - * distinct stream of roles is required, callers should invoke {@code distinct()} or collect to a set. - */ - default Stream getAssignedRoles(User user, SecurableResource resource) - { - // Collect the site roles first. By default, they are applicable everywhere. - PrincipalArray groups = getGroups(user); - Container root = ContainerManager.getRoot(); - SecurityPolicy rootPolicy = root.getPolicy(); - Stream ret = rootPolicy.getRoles(groups) - .filter(role -> { - if (!role.isApplicable(rootPolicy, root)) - throw new IllegalStateException("Root role " + role.getName() + " is not applicable"); - if (!(role instanceof AbstractRootContainerRole siteRole)) - throw new IllegalStateException("Root roles should all be AbstractRootContainerRole"); - - return siteRole.isAvailableEverywhere() || resource.equals(root); - }); - - if (!resource.equals(root)) - { - // Add the roles assigned in the project or folder - SecurityPolicy policy = SecurityPolicyManager.getPolicy(resource); - ret = Streams.concat(ret, policy.getRoles(groups)); - } - - return ret; - } - - ImpersonationContextFactory getFactory(); - - /** Responsible for adding menu items to allow the user to initiate, adjust, or stop impersonating, based on the current state */ - void addMenu(NavTree menu, Container c, User user, ActionURL currentURL); - - // restrict the permissions this user is allowed - default Stream> filterPermissions(Stream> perms) - { - return perms; - } -} +/* + * Copyright (c) 2011-2018 LabKey Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.labkey.api.security; + +import com.google.common.collect.Streams; +import org.jetbrains.annotations.Nullable; +import org.labkey.api.data.Container; +import org.labkey.api.data.ContainerManager; +import org.labkey.api.security.impersonation.ImpersonationContextFactory; +import org.labkey.api.security.permissions.Permission; +import org.labkey.api.security.roles.AbstractRootContainerRole; +import org.labkey.api.security.roles.Role; +import org.labkey.api.view.ActionURL; +import org.labkey.api.view.NavTree; + +import java.io.Serializable; +import java.util.stream.Stream; + +/** + * Context that conveys the current permissions for this user. They may be logged in normally, or they may be + * impersonating a specific user, group, or role, or some other specialized situation. + */ +public interface PermissionsContext extends Serializable +{ + /** @return whether the user is impersonating some user, group, or role, or working as their normal self */ + boolean isImpersonating(); + /** @return if non-null, the container to which the impersonation should be restricted */ + @Nullable Container getImpersonationProject(); + /** @return the user who is actually performing the operation, not the user that they might be impersonating */ + User getAdminUser(); + String getCacheKey(); // Caching permission-related state is very tricky with impersonation; context provides a cache key suffix that captures the current impersonation state + /** @return the URL to which the user should be returned when impersonation is over */ + ActionURL getReturnUrl(); + PrincipalArray getGroups(User user); + + /** + * @return The roles assigned to this user in the provided resource's policy as well as the root. The roles may be + * modified and/or filtered by the impersonation context. Note: The returned stream may duplicate some roles; if a + * distinct stream of roles is required, callers should invoke {@code distinct()} or collect to a set. + */ + default Stream getAssignedRoles(User user, SecurableResource resource) + { + // Collect the site roles first. By default, they are applicable everywhere. + PrincipalArray groups = getGroups(user); + Container root = ContainerManager.getRoot(); + SecurityPolicy rootPolicy = root.getPolicy(); + Stream ret = rootPolicy.getRoles(groups) + .filter(role -> { + if (!role.isApplicable(rootPolicy, root)) + throw new IllegalStateException("Root role " + role.getName() + " is not applicable"); + if (!(role instanceof AbstractRootContainerRole siteRole)) + throw new IllegalStateException("Root roles should all be AbstractRootContainerRole"); + + return siteRole.isAvailableEverywhere() || resource.equals(root); + }); + + if (!resource.equals(root)) + { + // Add the roles assigned in the project or folder + SecurityPolicy policy = SecurityPolicyManager.getPolicy(resource); + ret = Streams.concat(ret, policy.getRoles(groups)); + } + + return ret; + } + + ImpersonationContextFactory getFactory(); + + /** Responsible for adding menu items to allow the user to initiate, adjust, or stop impersonating, based on the current state */ + void addMenu(NavTree menu, Container c, User user, ActionURL currentURL); + + // restrict the permissions this user is allowed + default Stream> filterPermissions(Stream> perms) + { + return perms; + } +} diff --git a/api/src/org/labkey/api/security/impersonation/ReadOnlyImpersonatingContext.java b/api/src/org/labkey/api/security/ReadOnlyPermissionsContext.java similarity index 80% rename from api/src/org/labkey/api/security/impersonation/ReadOnlyImpersonatingContext.java rename to api/src/org/labkey/api/security/ReadOnlyPermissionsContext.java index 60bc4d1fcdb..9c52b658a7b 100644 --- a/api/src/org/labkey/api/security/impersonation/ReadOnlyImpersonatingContext.java +++ b/api/src/org/labkey/api/security/ReadOnlyPermissionsContext.java @@ -1,8 +1,6 @@ -package org.labkey.api.security.impersonation; +package org.labkey.api.security; import org.labkey.api.data.Container; -import org.labkey.api.security.SecurableResource; -import org.labkey.api.security.User; import org.labkey.api.security.permissions.AllowedForReadOnlyUser; import org.labkey.api.security.permissions.Permission; import org.labkey.api.security.roles.Role; @@ -11,7 +9,7 @@ import java.util.stream.Stream; -public class ReadOnlyImpersonatingContext extends NotImpersonatingContext +public class ReadOnlyPermissionsContext extends NormalPermissionsContext { @Override public Stream> filterPermissions(Stream> perms) diff --git a/api/src/org/labkey/api/security/SecurityManager.java b/api/src/org/labkey/api/security/SecurityManager.java index 607ce340b85..9eb00cbfa75 100644 --- a/api/src/org/labkey/api/security/SecurityManager.java +++ b/api/src/org/labkey/api/security/SecurityManager.java @@ -67,10 +67,8 @@ import org.labkey.api.security.AuthenticationProvider.AuthenticationResponse; import org.labkey.api.security.AuthenticationProvider.ResetPasswordProvider; import org.labkey.api.security.ValidEmail.InvalidEmailException; -import org.labkey.api.security.impersonation.DisallowPrivilegedRolesContext; import org.labkey.api.security.impersonation.GroupImpersonationContextFactory; import org.labkey.api.security.impersonation.ImpersonationContextFactory; -import org.labkey.api.security.impersonation.ReadOnlyImpersonatingContext; import org.labkey.api.security.impersonation.RoleImpersonationContextFactory; import org.labkey.api.security.impersonation.UserImpersonationContextFactory; import org.labkey.api.security.permissions.AbstractPermission; @@ -606,7 +604,7 @@ public static Pair attemptAuthentication(HttpServletRe // If impersonating, stop so it gets logged if (sessionUser.isImpersonated()) { - stopImpersonating(request, sessionUser.getImpersonationContext().getFactory()); + stopImpersonating(request, sessionUser.getPermissionsContext().getFactory()); sessionUser = sessionUser.getImpersonatingUser(); // Need to log out the admin } @@ -3096,7 +3094,7 @@ public static Set> getPermissionsWithoutCheckingForb Stream> permissions = roles.flatMap(role -> role.getPermissions().stream()); if (principal instanceof User user) - permissions = user.getImpersonationContext().filterPermissions(permissions); + permissions = user.getPermissionsContext().filterPermissions(permissions); return permissions.collect(Collectors.toSet()); } @@ -3438,7 +3436,7 @@ public void testReadOnlyImpersonate() throws InvalidEmailException, UserManageme final User testUser = TestContext.get().getUser(); // this user is subsetted to only permit read permissions (see AllowedForReadOnlyUser) User user = addUser(new ValidEmail("impersonate@test.net"), null, false).getUser(); - user.setImpersonationContext(new ReadOnlyImpersonatingContext()); + user.setImpersonationContext(new ReadOnlyPermissionsContext()); Container testFolder = null; diff --git a/api/src/org/labkey/api/security/User.java b/api/src/org/labkey/api/security/User.java index 0722e272cdb..2d28b8263d2 100644 --- a/api/src/org/labkey/api/security/User.java +++ b/api/src/org/labkey/api/security/User.java @@ -29,8 +29,6 @@ import org.labkey.api.data.ContainerManager; import org.labkey.api.data.PHI; import org.labkey.api.data.Transient; -import org.labkey.api.security.impersonation.ImpersonationContext; -import org.labkey.api.security.impersonation.NotImpersonatingContext; import org.labkey.api.security.permissions.AdminPermission; import org.labkey.api.security.permissions.AnalystPermission; import org.labkey.api.security.permissions.ApplicationAdminPermission; @@ -85,7 +83,7 @@ public class User extends UserPrincipal implements Serializable, Cloneable, JSON private ActionURL _avatarUrl; private boolean _system = false; - private ImpersonationContext _impersonationContext = NotImpersonatingContext.get(); + private PermissionsContext _permissionsContext = NormalPermissionsContext.get(); public static final User guest = new GuestUser("guest", "guest"); @@ -241,7 +239,7 @@ public String getAutocompleteName(@Nullable Container c, @Nullable User currentU public PrincipalArray getGroups() { if (_groups == null) - _groups = _impersonationContext.getGroups(this); + _groups = _permissionsContext.getGroups(this); return _groups; } @@ -351,7 +349,7 @@ public boolean isInGroup(int group) @Override public Stream getAssignedRoles(SecurableResource resource) { - return _impersonationContext.getAssignedRoles(this, resource); + return _permissionsContext.getAssignedRoles(this, resource); } public JSONObject getUserProps() @@ -404,30 +402,30 @@ public void setLastActivity(Date lastActivity) _lastActivity = lastActivity; } - void setImpersonationContext(ImpersonationContext impersonationContext) + void setImpersonationContext(PermissionsContext permissionsContext) { - _impersonationContext = impersonationContext; + _permissionsContext = permissionsContext; } - public @NotNull ImpersonationContext getImpersonationContext() + public @NotNull PermissionsContext getPermissionsContext() { - return _impersonationContext; + return _permissionsContext; } public boolean isImpersonated() { - return _impersonationContext.isImpersonating(); + return _permissionsContext.isImpersonating(); } // @NotNull when isImpersonated() is true... returns the admin user, with all normal roles & groups public User getImpersonatingUser() { - return _impersonationContext.getAdminUser(); + return _permissionsContext.getAdminUser(); } public @Nullable Container getImpersonationProject() { - return _impersonationContext.getImpersonationProject(); + return _permissionsContext.getImpersonationProject(); } @Override diff --git a/api/src/org/labkey/api/security/impersonation/WrappedImpersonationContext.java b/api/src/org/labkey/api/security/WrappedPermissionsContext.java similarity index 83% rename from api/src/org/labkey/api/security/impersonation/WrappedImpersonationContext.java rename to api/src/org/labkey/api/security/WrappedPermissionsContext.java index 993fdb58d16..4aa41ae0c12 100644 --- a/api/src/org/labkey/api/security/impersonation/WrappedImpersonationContext.java +++ b/api/src/org/labkey/api/security/WrappedPermissionsContext.java @@ -13,14 +13,12 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.labkey.api.security.impersonation; +package org.labkey.api.security; import com.google.common.collect.Streams; import org.jetbrains.annotations.Nullable; import org.labkey.api.data.Container; -import org.labkey.api.security.PrincipalArray; -import org.labkey.api.security.SecurableResource; -import org.labkey.api.security.User; +import org.labkey.api.security.impersonation.ImpersonationContextFactory; import org.labkey.api.security.permissions.Permission; import org.labkey.api.security.roles.Role; import org.labkey.api.view.ActionURL; @@ -32,18 +30,18 @@ /** * Do not use this class directly; use ElevatedUser instead. */ -public class WrappedImpersonationContext implements ImpersonationContext +public class WrappedPermissionsContext implements PermissionsContext { - private final ImpersonationContext _delegate; + private final PermissionsContext _delegate; private final Set _additionalRoles; - public WrappedImpersonationContext(ImpersonationContext delegate, Set additionalRoles) + public WrappedPermissionsContext(PermissionsContext delegate, Set additionalRoles) { _delegate = delegate; _additionalRoles = additionalRoles; } - public WrappedImpersonationContext(ImpersonationContext delegate, Role additionalRole) + public WrappedPermissionsContext(PermissionsContext delegate, Role additionalRole) { this(delegate, Set.of(additionalRole)); } diff --git a/api/src/org/labkey/api/security/impersonation/AbstractImpersonationContext.java b/api/src/org/labkey/api/security/impersonation/AbstractImpersonationContext.java index 02b1db2f56f..e3ea1abbf15 100644 --- a/api/src/org/labkey/api/security/impersonation/AbstractImpersonationContext.java +++ b/api/src/org/labkey/api/security/impersonation/AbstractImpersonationContext.java @@ -19,6 +19,7 @@ import org.jetbrains.annotations.Nullable; import org.labkey.api.data.Container; import org.labkey.api.security.LoginUrls; +import org.labkey.api.security.PermissionsContext; import org.labkey.api.security.User; import org.labkey.api.security.permissions.CanImpersonatePrivilegedSiteRolesPermission; import org.labkey.api.security.roles.Role; @@ -28,7 +29,7 @@ import java.util.stream.Stream; -public abstract class AbstractImpersonationContext implements ImpersonationContext +public abstract class AbstractImpersonationContext implements PermissionsContext { private final User _adminUser; private final @Nullable Container _project; @@ -71,7 +72,7 @@ public final ActionURL getReturnUrl() @Override public void addMenu(NavTree menu, Container c, User user, ActionURL currentURL) { - ActionURL url = PageFlowUtil.urlProvider(LoginUrls.class).getStopImpersonatingURL(c, user.getImpersonationContext().getReturnUrl()); + ActionURL url = PageFlowUtil.urlProvider(LoginUrls.class).getStopImpersonatingURL(c, user.getPermissionsContext().getReturnUrl()); NavTree stop = new NavTree("Stop Impersonating", url).usePost(); menu.addChild(stop); } diff --git a/api/src/org/labkey/api/security/impersonation/GroupImpersonationContextFactory.java b/api/src/org/labkey/api/security/impersonation/GroupImpersonationContextFactory.java index 75f7f0dd08b..8580ae943dd 100644 --- a/api/src/org/labkey/api/security/impersonation/GroupImpersonationContextFactory.java +++ b/api/src/org/labkey/api/security/impersonation/GroupImpersonationContextFactory.java @@ -25,6 +25,7 @@ import org.labkey.api.data.ContainerManager; import org.labkey.api.security.Group; import org.labkey.api.security.GroupMembershipCache; +import org.labkey.api.security.PermissionsContext; import org.labkey.api.security.PrincipalArray; import org.labkey.api.security.SecurableResource; import org.labkey.api.security.SecurityManager; @@ -76,7 +77,7 @@ public GroupImpersonationContextFactory(@Nullable Container project, User adminU } @Override - public ImpersonationContext getImpersonationContext() + public PermissionsContext getImpersonationContext() { Container project = (null != _projectId ? ContainerManager.getForId(_projectId) : null); Group group = SecurityManager.getGroup(_groupId); @@ -152,7 +153,7 @@ private static boolean canImpersonateGroup(@Nullable Container project, User use return false; } - static void addMenu(NavTree menu) + public static void addMenu(NavTree menu) { NavTree groupMenu = new NavTree("Group"); groupMenu.setScript("LABKEY.Security.Impersonation.showImpersonateGroup();"); diff --git a/api/src/org/labkey/api/security/impersonation/ImpersonationContextFactory.java b/api/src/org/labkey/api/security/impersonation/ImpersonationContextFactory.java index f9b66dd6b20..26151b84aa9 100644 --- a/api/src/org/labkey/api/security/impersonation/ImpersonationContextFactory.java +++ b/api/src/org/labkey/api/security/impersonation/ImpersonationContextFactory.java @@ -15,17 +15,18 @@ */ package org.labkey.api.security.impersonation; +import jakarta.servlet.http.HttpServletRequest; +import org.labkey.api.security.PermissionsContext; import org.labkey.api.security.User; import org.labkey.api.view.ViewContext; -import jakarta.servlet.http.HttpServletRequest; import java.io.Serializable; // We store implementations of this interface in session and construct ImpersonationContexts at each request. This // protects us somewhat from user, container, etc. objects getting out-of-date. public interface ImpersonationContextFactory extends Serializable { - ImpersonationContext getImpersonationContext(); + PermissionsContext getImpersonationContext(); void startImpersonating(ViewContext context); void stopImpersonating(HttpServletRequest request); User getAdminUser(); diff --git a/api/src/org/labkey/api/security/impersonation/RoleImpersonationContextFactory.java b/api/src/org/labkey/api/security/impersonation/RoleImpersonationContextFactory.java index b9626f13abb..a273596b4d4 100644 --- a/api/src/org/labkey/api/security/impersonation/RoleImpersonationContextFactory.java +++ b/api/src/org/labkey/api/security/impersonation/RoleImpersonationContextFactory.java @@ -23,6 +23,7 @@ import org.labkey.api.audit.AuditLogService; import org.labkey.api.data.Container; import org.labkey.api.data.ContainerManager; +import org.labkey.api.security.PermissionsContext; import org.labkey.api.security.PrincipalArray; import org.labkey.api.security.RoleSet; import org.labkey.api.security.SecurableResource; @@ -102,7 +103,7 @@ public RoleImpersonationContextFactory(@Nullable Container project, User adminUs } @Override - public ImpersonationContext getImpersonationContext() + public PermissionsContext getImpersonationContext() { Container project = (null != _projectId ? ContainerManager.getForId(_projectId) : null); @@ -170,7 +171,7 @@ public void stopImpersonating(HttpServletRequest request) AuditLogService.get().addEvent(adminUser, event); } - static void addMenu(NavTree menu) + public static void addMenu(NavTree menu) { addMenu(menu, "Roles"); } diff --git a/api/src/org/labkey/api/security/impersonation/UserImpersonationContextFactory.java b/api/src/org/labkey/api/security/impersonation/UserImpersonationContextFactory.java index 1a1142b7228..8976ed4d42c 100644 --- a/api/src/org/labkey/api/security/impersonation/UserImpersonationContextFactory.java +++ b/api/src/org/labkey/api/security/impersonation/UserImpersonationContextFactory.java @@ -24,6 +24,7 @@ import org.labkey.api.data.Container; import org.labkey.api.data.ContainerManager; import org.labkey.api.security.GroupManager; +import org.labkey.api.security.PermissionsContext; import org.labkey.api.security.PrincipalArray; import org.labkey.api.security.SecurableResource; import org.labkey.api.security.SecurityManager; @@ -81,7 +82,7 @@ public User getAdminUser() } @Override - public ImpersonationContext getImpersonationContext() + public PermissionsContext getImpersonationContext() { Container project = (null != _projectId ? ContainerManager.getForId(_projectId) : null); @@ -135,7 +136,7 @@ public void stopImpersonating(HttpServletRequest request) } } - static void addMenu(NavTree menu) + public static void addMenu(NavTree menu) { NavTree userMenu = new NavTree("User"); userMenu.setScript("LABKEY.Security.Impersonation.showImpersonateUser();"); diff --git a/api/src/org/labkey/api/view/NavTreeManager.java b/api/src/org/labkey/api/view/NavTreeManager.java index 7f10643ee0d..3c2e193a261 100644 --- a/api/src/org/labkey/api/view/NavTreeManager.java +++ b/api/src/org/labkey/api/view/NavTreeManager.java @@ -163,7 +163,7 @@ private static String getCacheKey(String navTreeId, @Nullable User user) if (null != user) { // Caching permission-related state is tricky with impersonation, so involve the impersonation context - key = navTreeId + "/user=" + user.getUserId() + user.getImpersonationContext().getCacheKey(); + key = navTreeId + "/user=" + user.getUserId() + user.getPermissionsContext().getCacheKey(); } else { diff --git a/api/src/org/labkey/api/view/PopupUserView.java b/api/src/org/labkey/api/view/PopupUserView.java index 88a0b30322a..36cf221e051 100644 --- a/api/src/org/labkey/api/view/PopupUserView.java +++ b/api/src/org/labkey/api/view/PopupUserView.java @@ -17,7 +17,7 @@ import org.labkey.api.data.Container; import org.labkey.api.module.ModuleLoader; -import org.labkey.api.security.impersonation.ImpersonationContext; +import org.labkey.api.security.PermissionsContext; import org.labkey.api.security.SecurityUrls; import org.labkey.api.security.User; import org.labkey.api.security.UserUrls; @@ -66,8 +66,8 @@ public static NavTree createNavTree(ViewContext context, PageConfig pageConfig) } // Delegate impersonate, stop impersonating, adjust impersonation, and sign out menu items to the current ImpersonationContext - ImpersonationContext impersonationContext = user.getImpersonationContext(); - impersonationContext.addMenu(tree, c, user, currentURL); + PermissionsContext permissionsContext = user.getPermissionsContext(); + permissionsContext.addMenu(tree, c, user, currentURL); tree.addSeparator(); diff --git a/assay/api-src/org/labkey/api/assay/dilution/DilutionAssayRun.java b/assay/api-src/org/labkey/api/assay/dilution/DilutionAssayRun.java index e96d90abdbc..4703c9ce7af 100644 --- a/assay/api-src/org/labkey/api/assay/dilution/DilutionAssayRun.java +++ b/assay/api-src/org/labkey/api/assay/dilution/DilutionAssayRun.java @@ -47,9 +47,9 @@ import org.labkey.api.query.FieldKey; import org.labkey.api.query.QueryService; import org.labkey.api.security.ElevatedUser; +import org.labkey.api.security.PermissionsContext; import org.labkey.api.security.User; import org.labkey.api.security.UserManager; -import org.labkey.api.security.impersonation.ImpersonationContext; import org.labkey.api.view.NotFoundException; import org.labkey.api.view.ViewContext; @@ -83,7 +83,7 @@ public abstract class DilutionAssayRun extends Luc5Assay // Objects of this class are cached (held by NAbRunWrapper), so we don't want to hold onto a User object. The // passed in user might have elevated permissions, so stash the impersonation context along with the user ID. private final int _userId; - private final ImpersonationContext _impersonationContext; + private final PermissionsContext _permissionsContext; private final Map _fieldKeys; public DilutionAssayRun(DilutionAssayProvider provider, ExpRun run, @@ -92,7 +92,7 @@ public DilutionAssayRun(DilutionAssayProvider provider, ExpRun run, super(run.getRowId(), cutoffs, renderCurveFitType); _run = run; _userId = user.getUserId(); - _impersonationContext = user instanceof ElevatedUser eu ? eu.getImpersonationContext() : null; + _permissionsContext = user instanceof ElevatedUser eu ? eu.getPermissionsContext() : null; _protocol = run.getProtocol(); _provider = provider; _fieldKeys = getFieldKeys(user); @@ -116,7 +116,7 @@ public DilutionAssayRun(DilutionAssayProvider provider, ExpRun run, protected User getUser() { User user = UserManager.getUser(_userId); - return _impersonationContext != null ? ElevatedUser.getElevatedUser(user, _impersonationContext) : user; + return _permissionsContext != null ? ElevatedUser.getElevatedUser(user, _permissionsContext) : user; } public DilutionAssayProvider getProvider() @@ -295,7 +295,7 @@ protected Map getSampleProperties(ExpData outp // We need sample key without Virus for sample properties Map sampleProperties = samplePropertiesMap.get(getSampleKey(summary)); Map dataProperties = new TreeMap<>(new PropertyDescriptorComparator()); - String sampleKeyWithVirus = getSampleKeyForResultPoperties(summary, virusTable); + String sampleKeyWithVirus = getSampleKeyForResultProperties(summary, virusTable); String dataRowLsid = getDataHandler().getDataRowLSID(outputData, summary.getFirstWellGroup().getName()).toString(); mgr.getDataPropertiesFromRunData(resultTable, dataRowLsid, _run.getContainer(), propertyDescriptors, dataProperties); dilutionResultPropertiesMap.put(sampleKeyWithVirus, new DilutionResultProperties(dataProperties, @@ -553,7 +553,7 @@ protected String getWellGroupName(ExpMaterial material) List groups = getWellGroups(material); // All current NAb assay types don't mix well groups for a single sample- there may be muliple // instances of the same well group on different plates, but they'll all have the same name. - return groups != null ? groups.get(0).getName() : null; + return groups != null ? groups.getFirst().getName() : null; } /** @@ -572,7 +572,7 @@ protected String getSampleKey(DilutionSummary summary) return summary.getFirstWellGroup().getName(); } - protected String getSampleKeyForResultPoperties(DilutionSummary summary, @Nullable TableInfo virusTable) + protected String getSampleKeyForResultProperties(DilutionSummary summary, @Nullable TableInfo virusTable) { return null != virusTable ? summary.getFirstWellGroup().getName() : getSampleKey(summary); } @@ -584,5 +584,4 @@ public void updateRenderAssayBean(RenderAssayBean bean) if (!bean.isGraphsPerRowSet()) bean.setGraphsPerRow(NabGraph.DEFAULT_GRAPHS_PER_ROW); } - } diff --git a/core/src/org/labkey/core/admin/AdminController.java b/core/src/org/labkey/core/admin/AdminController.java index aa0688f7789..2f892250a6f 100644 --- a/core/src/org/labkey/core/admin/AdminController.java +++ b/core/src/org/labkey/core/admin/AdminController.java @@ -198,6 +198,7 @@ import org.labkey.api.security.IgnoresTermsOfUse; import org.labkey.api.security.LoginUrls; import org.labkey.api.security.MutableSecurityPolicy; +import org.labkey.api.security.PermissionsContext; import org.labkey.api.security.RequiresLogin; import org.labkey.api.security.RequiresNoPermission; import org.labkey.api.security.RequiresPermission; @@ -212,7 +213,6 @@ import org.labkey.api.security.UserPrincipal; import org.labkey.api.security.ValidEmail; import org.labkey.api.security.impersonation.GroupImpersonationContextFactory; -import org.labkey.api.security.impersonation.ImpersonationContext; import org.labkey.api.security.impersonation.RoleImpersonationContextFactory; import org.labkey.api.security.impersonation.UserImpersonationContextFactory; import org.labkey.api.security.permissions.AbstractActionPermissionTest; @@ -12321,9 +12321,9 @@ public static class SerializationTest extends PipelineJob.TestSerialization { static class TestJob extends PipelineJob { - ImpersonationContext _impersonationContext; - ImpersonationContext _impersonationContext1; - ImpersonationContext _impersonationContext2; + PermissionsContext _permissionsContext; + PermissionsContext _permissionsContext1; + PermissionsContext _permissionsContext2; @Override public URLHelper getStatusHref() @@ -12349,13 +12349,13 @@ public void testSerialization() RoleImpersonationContextFactory factory = new RoleImpersonationContextFactory( viewContext.getContainer(), viewContext.getUser(), Collections.singleton(RoleManager.getRole(SharedViewEditorRole.class)), Collections.emptySet(), null); - job._impersonationContext = factory.getImpersonationContext(); + job._permissionsContext = factory.getImpersonationContext(); try { UserImpersonationContextFactory factory1 = new UserImpersonationContextFactory(viewContext.getContainer(), viewContext.getUser(), UserManager.getGuestUser(), null); - job._impersonationContext1 = factory1.getImpersonationContext(); + job._permissionsContext1 = factory1.getImpersonationContext(); } catch (Exception e) { @@ -12364,7 +12364,7 @@ public void testSerialization() GroupImpersonationContextFactory factory2 = new GroupImpersonationContextFactory(viewContext.getContainer(), viewContext.getUser(), GroupManager.getGroup(ContainerManager.getRoot(), "Users", GroupEnumType.SITE), null); - job._impersonationContext2 = factory2.getImpersonationContext(); + job._permissionsContext2 = factory2.getImpersonationContext(); testSerialize(job, LOG); } } diff --git a/core/src/org/labkey/core/login/LoginController.java b/core/src/org/labkey/core/login/LoginController.java index b47c07af6a7..d9f0349a3bf 100644 --- a/core/src/org/labkey/core/login/LoginController.java +++ b/core/src/org/labkey/core/login/LoginController.java @@ -1456,7 +1456,7 @@ public void validateCommand(ReturnUrlForm form, Errors errors) @Override public boolean handlePost(ReturnUrlForm form, BindException errors) throws Exception { - SecurityManager.stopImpersonating(getViewContext().getRequest(), getUser().getImpersonationContext().getFactory()); + SecurityManager.stopImpersonating(getViewContext().getRequest(), getUser().getPermissionsContext().getFactory()); return true; } @@ -1485,7 +1485,7 @@ public void validateForm(Object o, Errors errors) @Override public Object execute(Object o, BindException errors) throws Exception { - SecurityManager.stopImpersonating(getViewContext().getRequest(), getUser().getImpersonationContext().getFactory()); + SecurityManager.stopImpersonating(getViewContext().getRequest(), getUser().getPermissionsContext().getFactory()); return new ApiSimpleResponse("success", true); } diff --git a/core/src/org/labkey/core/user/UserController.java b/core/src/org/labkey/core/user/UserController.java index b936f108410..fdf3d452105 100644 --- a/core/src/org/labkey/core/user/UserController.java +++ b/core/src/org/labkey/core/user/UserController.java @@ -82,6 +82,7 @@ import org.labkey.api.security.LoginManager; import org.labkey.api.security.LoginUrls; import org.labkey.api.security.MemberType; +import org.labkey.api.security.PermissionsContext; import org.labkey.api.security.RequiresAllOf; import org.labkey.api.security.RequiresLogin; import org.labkey.api.security.RequiresNoPermission; @@ -96,7 +97,6 @@ import org.labkey.api.security.ValidEmail; import org.labkey.api.security.ValidEmail.InvalidEmailException; import org.labkey.api.security.impersonation.GroupImpersonationContextFactory; -import org.labkey.api.security.impersonation.ImpersonationContext; import org.labkey.api.security.impersonation.RoleImpersonationContextFactory; import org.labkey.api.security.impersonation.UnauthorizedImpersonationException; import org.labkey.api.security.impersonation.UserImpersonationContextFactory; @@ -2998,7 +2998,7 @@ public class GetImpersonationRolesAction extends MutatingApiAction @Override public ApiResponse execute(Object object, BindException errors) { - ImpersonationContext context = authorizeImpersonateRoles(); + PermissionsContext context = authorizeImpersonateRoles(); Set impersonationRoles = context.isImpersonating() ? context.getAssignedRoles(getUser(), getContainer()).collect(Collectors.toSet()) : Collections.emptySet(); User user = context.isImpersonating() ? context.getAdminUser() : getUser(); @@ -3021,10 +3021,10 @@ public ApiResponse execute(Object object, BindException errors) } - private ImpersonationContext authorizeImpersonateRoles() + private PermissionsContext authorizeImpersonateRoles() { User user = getUser(); - ImpersonationContext context = user.getImpersonationContext(); + PermissionsContext context = user.getPermissionsContext(); if (context.isImpersonating()) user = context.getAdminUser(); @@ -3063,7 +3063,7 @@ public class ImpersonateRolesAction extends ImpersonateApiAction currentImpersonationRoles = context.isImpersonating() ? context.getAssignedRoles(getUser(), getContainer()).collect(Collectors.toSet()) : Collections.emptySet(); String[] roleNames = form.getRoleNames(); diff --git a/core/src/org/labkey/core/view/template/bootstrap/header.jsp b/core/src/org/labkey/core/view/template/bootstrap/header.jsp index a5d95b301f5..ccfef28d953 100644 --- a/core/src/org/labkey/core/view/template/bootstrap/header.jsp +++ b/core/src/org/labkey/core/view/template/bootstrap/header.jsp @@ -15,6 +15,7 @@ * limitations under the License. */ %> +<%@ page import="jakarta.servlet.http.HttpSession" %> <%@ page import="org.labkey.api.admin.CoreUrls" %> <%@ page import="org.labkey.api.data.Container" %> <%@ page import="org.labkey.api.module.ModuleLoader" %> @@ -44,13 +45,15 @@ <%@ page import="org.labkey.api.view.ViewContext" %> <%@ page import="org.labkey.api.view.template.ClientDependencies" %> <%@ page import="org.labkey.api.view.template.PageConfig" %> -<%@ page import="org.labkey.core.view.template.bootstrap.Header" %> <%@ page import="static org.labkey.api.view.template.WarningService.SESSION_WARNINGS_BANNER_KEY" %> <%@ page import="static org.labkey.api.util.DOM.IMG" %> <%@ page import="static org.labkey.api.util.DOM.Attribute.src" %> <%@ page import="static org.labkey.api.util.DOM.Attribute.alt" %> <%@ page import="static org.labkey.api.util.DOM.A" %> <%@ page import="static org.labkey.api.util.DOM.Attribute.href" %> +<%@ page import="org.labkey.core.view.template.bootstrap.Header" %> +<%@ page import="java.lang.Override" %> +<%@ page import="java.lang.String" %> <%@ taglib prefix="labkey" uri="http://www.labkey.org/taglib" %> <%@ page extends="org.labkey.api.jsp.JspBase" %> <%! @@ -275,7 +278,7 @@ if (user != null && user.isImpersonated()) { - ActionURL stopUrl = urlProvider(LoginUrls.class).getStopImpersonatingURL(c, user.getImpersonationContext().getReturnUrl()); + ActionURL stopUrl = urlProvider(LoginUrls.class).getStopImpersonatingURL(c, user.getPermissionsContext().getReturnUrl()); %>
  • <%=simpleLink("Stop impersonating", stopUrl).addClass("btn btn-primary").usePost()%> From 326dc3484139361728c3413782c5f4de239378ed Mon Sep 17 00:00:00 2001 From: Adam Rauch Date: Thu, 26 Feb 2026 11:21:03 -0800 Subject: [PATCH 2/2] Update comments and funny imports --- api/src/org/labkey/api/view/NavTreeManager.java | 2 +- core/src/org/labkey/core/view/template/bootstrap/header.jsp | 5 +---- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/api/src/org/labkey/api/view/NavTreeManager.java b/api/src/org/labkey/api/view/NavTreeManager.java index 3c2e193a261..ce0bc026d4e 100644 --- a/api/src/org/labkey/api/view/NavTreeManager.java +++ b/api/src/org/labkey/api/view/NavTreeManager.java @@ -162,7 +162,7 @@ private static String getCacheKey(String navTreeId, @Nullable User user) String key; if (null != user) { - // Caching permission-related state is tricky with impersonation, so involve the impersonation context + // Caching permission-related state is tricky with impersonation, so involve the permissions context key = navTreeId + "/user=" + user.getUserId() + user.getPermissionsContext().getCacheKey(); } else diff --git a/core/src/org/labkey/core/view/template/bootstrap/header.jsp b/core/src/org/labkey/core/view/template/bootstrap/header.jsp index ccfef28d953..fe51447f65d 100644 --- a/core/src/org/labkey/core/view/template/bootstrap/header.jsp +++ b/core/src/org/labkey/core/view/template/bootstrap/header.jsp @@ -15,7 +15,6 @@ * limitations under the License. */ %> -<%@ page import="jakarta.servlet.http.HttpSession" %> <%@ page import="org.labkey.api.admin.CoreUrls" %> <%@ page import="org.labkey.api.data.Container" %> <%@ page import="org.labkey.api.module.ModuleLoader" %> @@ -45,15 +44,13 @@ <%@ page import="org.labkey.api.view.ViewContext" %> <%@ page import="org.labkey.api.view.template.ClientDependencies" %> <%@ page import="org.labkey.api.view.template.PageConfig" %> +<%@ page import="org.labkey.core.view.template.bootstrap.Header" %> <%@ page import="static org.labkey.api.view.template.WarningService.SESSION_WARNINGS_BANNER_KEY" %> <%@ page import="static org.labkey.api.util.DOM.IMG" %> <%@ page import="static org.labkey.api.util.DOM.Attribute.src" %> <%@ page import="static org.labkey.api.util.DOM.Attribute.alt" %> <%@ page import="static org.labkey.api.util.DOM.A" %> <%@ page import="static org.labkey.api.util.DOM.Attribute.href" %> -<%@ page import="org.labkey.core.view.template.bootstrap.Header" %> -<%@ page import="java.lang.Override" %> -<%@ page import="java.lang.String" %> <%@ taglib prefix="labkey" uri="http://www.labkey.org/taglib" %> <%@ page extends="org.labkey.api.jsp.JspBase" %> <%!