From 616b549eb70220408fd8e6e9c2365bd5b42f0ba0 Mon Sep 17 00:00:00 2001 From: Adam Rauch Date: Tue, 3 Mar 2026 17:13:50 -0800 Subject: [PATCH 1/3] Allow assigning "See Audit Log Events" role in folders & projects (#7460) --- .../api/audit/query/DefaultAuditTypeTable.java | 9 +-------- .../security/roles/CanSeeAuditLogFolderRole.java | 16 ++++++++++++++++ .../api/security/roles/CanSeeAuditLogRole.java | 11 ++++++++++- .../labkey/api/security/roles/RoleManager.java | 1 + 4 files changed, 28 insertions(+), 9 deletions(-) create mode 100644 api/src/org/labkey/api/security/roles/CanSeeAuditLogFolderRole.java diff --git a/api/src/org/labkey/api/audit/query/DefaultAuditTypeTable.java b/api/src/org/labkey/api/audit/query/DefaultAuditTypeTable.java index 4a1647ae863..dae043f66f0 100644 --- a/api/src/org/labkey/api/audit/query/DefaultAuditTypeTable.java +++ b/api/src/org/labkey/api/audit/query/DefaultAuditTypeTable.java @@ -34,14 +34,9 @@ import org.labkey.api.query.QueryUpdateService; import org.labkey.api.query.UserSchema; import org.labkey.api.query.column.BuiltInColumnTypes; -import org.labkey.api.security.SecurityManager; -import org.labkey.api.security.User; import org.labkey.api.security.UserPrincipal; import org.labkey.api.security.permissions.Permission; import org.labkey.api.security.permissions.ReadPermission; -import org.labkey.api.security.roles.CanSeeAuditLogRole; -import org.labkey.api.security.roles.Role; -import org.labkey.api.security.roles.RoleManager; import java.util.ArrayList; import java.util.List; @@ -119,9 +114,7 @@ protected void initColumns() @Override protected SimpleFilter.FilterClause getContainerFilterClause(ContainerFilter filter, FieldKey fieldKey) { - User user = (null == getUserSchema()) ? null : getUserSchema().getUser(); - Set roles = SecurityManager.canSeeAuditLog(user) ? RoleManager.roleSet(CanSeeAuditLogRole.class) : null; - return filter.createFilterClause(getSchema(), fieldKey, CanSeeAuditLogPermission.class, roles); + return filter.createFilterClause(getSchema(), fieldKey, CanSeeAuditLogPermission.class, Set.of()); } // Subclasses may override this to provide customizations to the column diff --git a/api/src/org/labkey/api/security/roles/CanSeeAuditLogFolderRole.java b/api/src/org/labkey/api/security/roles/CanSeeAuditLogFolderRole.java new file mode 100644 index 00000000000..9ebd470280c --- /dev/null +++ b/api/src/org/labkey/api/security/roles/CanSeeAuditLogFolderRole.java @@ -0,0 +1,16 @@ +package org.labkey.api.security.roles; + +import org.labkey.api.audit.permissions.CanSeeAuditLogPermission; + +/** + * See {@link CanSeeAuditLogRole} for the site role version + */ +public class CanSeeAuditLogFolderRole extends AbstractRole +{ + protected CanSeeAuditLogFolderRole() + { + super("See Audit Log Events", "Allows non-administrators to view audit log events. " + CanSeeAuditLogRole.FINAL_WARNING_LINE, + CanSeeAuditLogPermission.class + ); + } +} diff --git a/api/src/org/labkey/api/security/roles/CanSeeAuditLogRole.java b/api/src/org/labkey/api/security/roles/CanSeeAuditLogRole.java index 3a0bddf8fb6..f033329e500 100644 --- a/api/src/org/labkey/api/security/roles/CanSeeAuditLogRole.java +++ b/api/src/org/labkey/api/security/roles/CanSeeAuditLogRole.java @@ -18,11 +18,20 @@ import org.labkey.api.audit.permissions.CanSeeAuditLogPermission; import org.labkey.api.security.permissions.SeeUserDetailsPermission; +/** + * See {@link CanSeeAuditLogFolderRole}, the project/folder version of this role + */ public class CanSeeAuditLogRole extends AbstractRootContainerRole { + static final String FINAL_WARNING_LINE = "This role should be used with caution since the audit log may " + + "contain sensitive or protected information. For example, dataset or list imports where detailed logging " + + "was turned on."; + public CanSeeAuditLogRole() { - super("See Audit Log Events", "Allows non-administrators to view audit log events", + super("See Audit Log Events", "Allows non-administrators to view audit log events in the " + + "root, every project, and every folder on this site. This level of visibility is not generally recommended. " + + "For more granular control, assign this role at the folder level instead. " + FINAL_WARNING_LINE, CanSeeAuditLogPermission.class, SeeUserDetailsPermission.class ); diff --git a/api/src/org/labkey/api/security/roles/RoleManager.java b/api/src/org/labkey/api/security/roles/RoleManager.java index d656e5592d9..8ba6de628b1 100644 --- a/api/src/org/labkey/api/security/roles/RoleManager.java +++ b/api/src/org/labkey/api/security/roles/RoleManager.java @@ -134,6 +134,7 @@ private int getPermLevel(Role r) registerRole(new SubmitterRole()); registerRole(new NoPermissionsRole()); registerRole(new OwnerRole()); + registerRole(new CanSeeAuditLogFolderRole()); } public static void addAdminRoleListener(AdminRoleListener listener) From 3b281f7f731359abc6dd59f718a8ba2baf8251da Mon Sep 17 00:00:00 2001 From: Adam Rauch Date: Wed, 4 Mar 2026 17:53:37 -0800 Subject: [PATCH 2/3] Fix GetTransactionRowIdsAction --- audit/src/org/labkey/audit/AuditController.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/audit/src/org/labkey/audit/AuditController.java b/audit/src/org/labkey/audit/AuditController.java index e44599c0749..acd22a9e9b5 100644 --- a/audit/src/org/labkey/audit/AuditController.java +++ b/audit/src/org/labkey/audit/AuditController.java @@ -383,11 +383,12 @@ public void validateForm(AuditTransactionForm form, Errors errors) public Object execute(AuditTransactionForm form, BindException errors) { List rowIds; - ContainerFilter cf = ContainerFilter.getContainerFilterByName(form.getContainerFilter(), getContainer(), getUser()); + User elevatedUser = ElevatedUser.ensureCanSeeAuditLogRole(getContainer(), getUser()); + ContainerFilter cf = ContainerFilter.getContainerFilterByName(form.getContainerFilter(), getContainer(), elevatedUser); if (form.isSampleType()) - rowIds = AuditLogImpl.get().getTransactionSampleIds(form.getTransactionAuditId(), ElevatedUser.ensureCanSeeAuditLogRole(getContainer(), getUser()), getContainer(), cf); + rowIds = AuditLogImpl.get().getTransactionSampleIds(form.getTransactionAuditId(), elevatedUser, getContainer(), cf); else - rowIds = AuditLogImpl.get().getTransactionSourceIds(form.getTransactionAuditId(), ElevatedUser.ensureCanSeeAuditLogRole(getContainer(), getUser()), getContainer(), cf); + rowIds = AuditLogImpl.get().getTransactionSourceIds(form.getTransactionAuditId(), elevatedUser, getContainer(), cf); ApiSimpleResponse response = new ApiSimpleResponse(); response.put("success", true); From 625a4923f9fb0a3c3c7fbcc48b3233837bbe2b26 Mon Sep 17 00:00:00 2001 From: Adam Rauch Date: Thu, 5 Mar 2026 11:03:12 -0800 Subject: [PATCH 3/3] Restore funky code --- .../api/audit/query/DefaultAuditTypeTable.java | 14 +++++++++++++- api/src/org/labkey/api/data/ContainerFilter.java | 4 ++-- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/api/src/org/labkey/api/audit/query/DefaultAuditTypeTable.java b/api/src/org/labkey/api/audit/query/DefaultAuditTypeTable.java index dae043f66f0..3f3b0af48a2 100644 --- a/api/src/org/labkey/api/audit/query/DefaultAuditTypeTable.java +++ b/api/src/org/labkey/api/audit/query/DefaultAuditTypeTable.java @@ -34,9 +34,14 @@ import org.labkey.api.query.QueryUpdateService; import org.labkey.api.query.UserSchema; import org.labkey.api.query.column.BuiltInColumnTypes; +import org.labkey.api.security.SecurityManager; +import org.labkey.api.security.User; import org.labkey.api.security.UserPrincipal; import org.labkey.api.security.permissions.Permission; import org.labkey.api.security.permissions.ReadPermission; +import org.labkey.api.security.roles.CanSeeAuditLogRole; +import org.labkey.api.security.roles.Role; +import org.labkey.api.security.roles.RoleManager; import java.util.ArrayList; import java.util.List; @@ -114,7 +119,14 @@ protected void initColumns() @Override protected SimpleFilter.FilterClause getContainerFilterClause(ContainerFilter filter, FieldKey fieldKey) { - return filter.createFilterClause(getSchema(), fieldKey, CanSeeAuditLogPermission.class, Set.of()); + // TODO: Setting a contextual role on the container filter clause should not be necessary; the user passed + // (separately) to the ContainerFilter should have the appropriate permission. However, some app actions + // (GetTransactionRowIdsAction, maybe GetLocationHistoryAction, etc.) have been relying on this behavior. Clean + // this up soon, but not for 26.3. Note that this is the only code path that passes contextual roles into + // createFilterClause(), so we could eliminate that option during clean up. + User user = (null == getUserSchema()) ? null : getUserSchema().getUser(); + Set roles = SecurityManager.canSeeAuditLog(user) ? RoleManager.roleSet(CanSeeAuditLogRole.class) : null; + return filter.createFilterClause(getSchema(), fieldKey, CanSeeAuditLogPermission.class, roles); } // Subclasses may override this to provide customizations to the column diff --git a/api/src/org/labkey/api/data/ContainerFilter.java b/api/src/org/labkey/api/data/ContainerFilter.java index 4576d8ec25a..fb495327f14 100644 --- a/api/src/org/labkey/api/data/ContainerFilter.java +++ b/api/src/org/labkey/api/data/ContainerFilter.java @@ -169,9 +169,9 @@ public SimpleFilter.FilterClause createFilterClause(DbSchema schema, FieldKey co } /** Create a FilterClause that restricts based on the containers that meet the filter and user that meets the permission*/ - public SimpleFilter.FilterClause createFilterClause(DbSchema schema, FieldKey containerFilterColumn, Class permission, Set roles) + public SimpleFilter.FilterClause createFilterClause(DbSchema schema, FieldKey containerFilterColumn, Class permission, Set contextualRoles) { - return new ContainerClause(schema, containerFilterColumn, this, permission, roles); + return new ContainerClause(schema, containerFilterColumn, this, permission, contextualRoles); }