From 29c0dd8e8d31886445099f0ca6306a525224ce67 Mon Sep 17 00:00:00 2001 From: labkey-nicka Date: Mon, 15 Dec 2025 08:29:59 -0800 Subject: [PATCH 1/3] Add debug logging --- .../api/action/PermissionCheckableAction.java | 15 ++++++++++++++- api/src/org/labkey/api/data/Container.java | 13 +++++++++++-- 2 files changed, 25 insertions(+), 3 deletions(-) diff --git a/api/src/org/labkey/api/action/PermissionCheckableAction.java b/api/src/org/labkey/api/action/PermissionCheckableAction.java index 5795a2e2693..9ea8e01c952 100644 --- a/api/src/org/labkey/api/action/PermissionCheckableAction.java +++ b/api/src/org/labkey/api/action/PermissionCheckableAction.java @@ -16,6 +16,7 @@ package org.labkey.api.action; import jakarta.servlet.http.HttpServletResponse; +import org.apache.logging.log4j.Logger; import org.jetbrains.annotations.Nullable; import org.labkey.api.data.Container; import org.labkey.api.module.IgnoresForbiddenProjectCheck; @@ -39,6 +40,7 @@ import org.labkey.api.security.roles.RoleManager; import org.labkey.api.util.ConfigurationException; import org.labkey.api.util.HttpUtil; +import org.labkey.api.util.logging.LogHelper; import org.labkey.api.view.BadRequestException; import org.labkey.api.view.NotFoundException; import org.labkey.api.view.RedirectException; @@ -55,6 +57,7 @@ public abstract class PermissionCheckableAction implements Controller, PermissionCheckable, HasViewContext { + private static final Logger LOG = LogHelper.getLogger(PermissionCheckableAction.class, "Permission checks "); private static final HttpUtil.Method[] arrayGetPost = new HttpUtil.Method[] {Method.GET, Method.POST}; private ViewContext _context = null; UnauthorizedException.Type _unauthorizedType = UnauthorizedException.Type.redirectToLogin; @@ -159,18 +162,22 @@ private void _checkActionPermissions(Set contextualRoles) throws Unauthori methodsAllowed = methodsAllowedAnnotation.value(); if (Arrays.stream(methodsAllowed).noneMatch(s -> s.equals(method))) { - throw new BadRequestException("Method Not Allowed: " + method, null, HttpServletResponse.SC_METHOD_NOT_ALLOWED); + String msg = "Method Not Allowed: " + method; + LOG.debug(msg); + throw new BadRequestException(msg, null, HttpServletResponse.SC_METHOD_NOT_ALLOWED); } boolean requiresSiteAdmin = actionClass.isAnnotationPresent(RequiresSiteAdmin.class); if (requiresSiteAdmin && !user.hasSiteAdminPermission()) { + LOG.debug(actionClass.getName() + ": action requires site admin permissions"); throw new UnauthorizedException(); } boolean requiresLogin = actionClass.isAnnotationPresent(RequiresLogin.class); if (requiresLogin && user.isGuest()) { + LOG.debug(actionClass.getName() + ": action requires login (non-guest)"); throw new UnauthorizedException(); } @@ -214,7 +221,10 @@ private void _checkActionPermissions(Set contextualRoles) throws Unauthori // Must have all permissions in permissionsRequired if (!SecurityManager.hasAllPermissions(this.getClass().getName()+"_checkActionPermissions", c, user, permissionsRequired, contextualRoles)) + { + LOG.debug(actionClass.getName() + ": action requires all permissions: " + permissionsRequired); throw new UnauthorizedException(); + } CSRF.Method csrfCheck = actionClass.isAnnotationPresent(CSRF.class) ? actionClass.getAnnotation(CSRF.class).value() : CSRF.Method.POST; csrfCheck.validate(context); @@ -228,7 +238,10 @@ private void _checkActionPermissions(Set contextualRoles) throws Unauthori Collections.addAll(permissionsAnyOf, requiresAnyOf.value()); if (!SecurityManager.hasAnyPermissions(this.getClass().getName() + "_checkActionPermissions", c, user, permissionsAnyOf, contextualRoles)) + { + LOG.debug(actionClass.getName() + ": action requires any permissions: " + permissionsAnyOf); throw new UnauthorizedException(); + } } boolean requiresNoPermission = actionClass.isAnnotationPresent(RequiresNoPermission.class); diff --git a/api/src/org/labkey/api/data/Container.java b/api/src/org/labkey/api/data/Container.java index c55c45cd561..d8922b085fc 100644 --- a/api/src/org/labkey/api/data/Container.java +++ b/api/src/org/labkey/api/data/Container.java @@ -41,6 +41,7 @@ import org.labkey.api.query.QueryService; import org.labkey.api.security.HasPermission; import org.labkey.api.security.SecurableResource; +import org.labkey.api.security.SecurityLogger; import org.labkey.api.security.SecurityManager; import org.labkey.api.security.SecurityPolicy; import org.labkey.api.security.SecurityPolicyManager; @@ -549,7 +550,11 @@ private boolean handleForbiddenProject(User user, Set contextualRoles, boo if (null != impersonationProject && !impersonationProject.equals(currentProject)) { if (shouldThrow) - throw new ForbiddenProjectException("You are not allowed to access this folder while impersonating within a different project."); + { + String msg = "You are not allowed to access this folder while impersonating within a different project."; + SecurityLogger.log(msg, user, null, null); + throw new ForbiddenProjectException(msg); + } return true; } @@ -562,7 +567,11 @@ private boolean handleForbiddenProject(User user, Set contextualRoles, boo if (lockState.isLocked() && ContainerManager.LOCKED_PROJECT_HANDLER.isForbidden(currentProject, user, contextualRoles, lockState)) { if (shouldThrow) - throw new ForbiddenProjectException("You are not allowed to access this folder; it is " + lockState.getDescription() + "."); + { + String msg = "You are not allowed to access this folder; it is " + lockState.getDescription() + "."; + SecurityLogger.log(msg, user, null, null); + throw new ForbiddenProjectException(msg); + } return true; } From 9a9932338190ffdef88d9871014473eba38e3aaa Mon Sep 17 00:00:00 2001 From: labkey-nicka Date: Mon, 15 Dec 2025 08:30:40 -0800 Subject: [PATCH 2/3] Finish description --- api/src/org/labkey/api/action/PermissionCheckableAction.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/src/org/labkey/api/action/PermissionCheckableAction.java b/api/src/org/labkey/api/action/PermissionCheckableAction.java index 9ea8e01c952..db615b00bee 100644 --- a/api/src/org/labkey/api/action/PermissionCheckableAction.java +++ b/api/src/org/labkey/api/action/PermissionCheckableAction.java @@ -57,7 +57,7 @@ public abstract class PermissionCheckableAction implements Controller, PermissionCheckable, HasViewContext { - private static final Logger LOG = LogHelper.getLogger(PermissionCheckableAction.class, "Permission checks "); + private static final Logger LOG = LogHelper.getLogger(PermissionCheckableAction.class, "Permission checks for actions"); private static final HttpUtil.Method[] arrayGetPost = new HttpUtil.Method[] {Method.GET, Method.POST}; private ViewContext _context = null; UnauthorizedException.Type _unauthorizedType = UnauthorizedException.Type.redirectToLogin; From 5c1310e8d73b5fb45e82d5066ea1121c61b760ca Mon Sep 17 00:00:00 2001 From: labkey-nicka Date: Mon, 15 Dec 2025 14:33:40 -0800 Subject: [PATCH 3/3] Log user --- api/src/org/labkey/api/action/PermissionCheckableAction.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/api/src/org/labkey/api/action/PermissionCheckableAction.java b/api/src/org/labkey/api/action/PermissionCheckableAction.java index db615b00bee..984aa69a8a4 100644 --- a/api/src/org/labkey/api/action/PermissionCheckableAction.java +++ b/api/src/org/labkey/api/action/PermissionCheckableAction.java @@ -151,6 +151,8 @@ private void _checkActionPermissions(Set contextualRoles) throws Unauthori Container c = context.getContainer(); User user = context.getUser(); Class actionClass = getClass(); + if (LOG.isDebugEnabled()) + LOG.debug(actionClass.getName() + ": checking permissions for user " + (user == null ? "" : user.getName() + " (impersonated=" + user.isImpersonated() + ")")); if (!actionClass.isAnnotationPresent(IgnoresForbiddenProjectCheck.class)) c.throwIfForbiddenProject(user);