diff --git a/api/src/org/labkey/api/audit/query/DefaultAuditTypeTable.java b/api/src/org/labkey/api/audit/query/DefaultAuditTypeTable.java index 4a1647ae863..3f3b0af48a2 100644 --- a/api/src/org/labkey/api/audit/query/DefaultAuditTypeTable.java +++ b/api/src/org/labkey/api/audit/query/DefaultAuditTypeTable.java @@ -119,6 +119,11 @@ protected void initColumns() @Override protected SimpleFilter.FilterClause getContainerFilterClause(ContainerFilter filter, FieldKey fieldKey) { + // 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); 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); } 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) 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);