diff --git a/api/src/org/labkey/api/action/PermissionCheckableAction.java b/api/src/org/labkey/api/action/PermissionCheckableAction.java index 5795a2e2693..984aa69a8a4 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 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; @@ -148,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); @@ -159,18 +164,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 +223,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 +240,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; }