Skip to content
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,4 @@ seleniumVersion=4.45.0

mockserverNettyVersion=5.15.0

labkeySchemasTestVersion=26.3-SNAPSHOT
labkeySchemasTestVersion=26.7-SNAPSHOT
69 changes: 68 additions & 1 deletion src/org/labkey/test/tests/UserDetailsPermissionTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,10 @@
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.experimental.categories.Category;
import org.labkey.api.security.permissions.Permission;
import org.labkey.api.security.permissions.ReadPermission;
import org.labkey.remoteapi.CommandException;
import org.labkey.remoteapi.CommandResponse;
import org.labkey.remoteapi.Connection;
import org.labkey.remoteapi.SimpleGetCommand;
import org.labkey.test.BaseWebDriverTest;
Expand All @@ -29,22 +32,30 @@
import org.labkey.test.components.DomainDesignerPage;
import org.labkey.test.components.domain.DomainFormPanel;
import org.labkey.test.pages.query.ExecuteQueryPage;
import org.labkey.test.pages.user.ShowUsersPage;
import org.labkey.test.pages.user.UpdateUserDetailsPage;
import org.labkey.test.params.FieldDefinition;
import org.labkey.test.util.ApiPermissionsHelper;
import org.labkey.test.util.DataRegionTable;
import org.labkey.test.util.DataRegionTable.DataRegionFinder;
import org.labkey.test.util.LogMethod;
import org.labkey.test.util.PasswordUtil;
import org.labkey.test.util.PortalHelper;

import java.io.IOException;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

import static org.hamcrest.CoreMatchers.allOf;
import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.CoreMatchers.not;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.labkey.test.util.PermissionsHelper.PROJECT_ADMIN_ROLE;
import static org.labkey.test.util.PermissionsHelper.READER_ROLE;
import static org.labkey.test.util.PermissionsHelper.SITE_ADMIN_ROLE;

Expand All @@ -57,6 +68,8 @@ public class UserDetailsPermissionTest extends BaseWebDriverTest
private static final String USER_INFO_VIEWER = "user_info_viewer@usertable.test";
private static final String IMPERSONATED_USER = "impersonated_user@usertable.test";
private static final String CHECKED_USER = "checked_user@usertable.test";
private static final String PROJECT_ADMIN = "project_admin@usertable.test";
private static final String NON_MEMBER = "non_member@usertable.test";
private static final String EMAIL_TEST_LIST = "My Users";
private static final String CUSTOM_USER_COLUMN = "UserTablePermTest";
private static final String HIDDEN_COL_VIEW = "hiddenColView";
Expand All @@ -73,7 +86,7 @@ protected void doCleanup(boolean afterTest) throws TestTimeoutException
{
super.doCleanup(afterTest);

_userHelper.deleteUsers(false, USER_INFO_VIEWER, IMPERSONATED_USER, CHECKED_USER, ADMIN_USER);
_userHelper.deleteUsers(false, USER_INFO_VIEWER, IMPERSONATED_USER, CHECKED_USER, ADMIN_USER, PROJECT_ADMIN, NON_MEMBER);
}

@Override
Expand Down Expand Up @@ -116,6 +129,14 @@ private void doSetup()
apiPermissionsHelper.setPermissions(TEST_GROUP, READER_ROLE);
apiPermissionsHelper.setSiteRoleUserPermissions(USER_INFO_VIEWER, "See User and Group Details");

// A project administrator (no site-wide User Management permission) is used to verify that user details
// render from the Project Users page.
_userHelper.createUser(PROJECT_ADMIN, true, true);
new ApiPermissionsHelper("/" + getProjectName()).setUserPermissions(PROJECT_ADMIN, PROJECT_ADMIN_ROLE);

// A user with no role in the project (no read access) that should never appear on the Project Users page.
_userHelper.createUser(NON_MEMBER, true, true);

impersonate(ADMIN_USER);
{
UpdateUserDetailsPage page = goToMyAccount().clickEdit();
Expand Down Expand Up @@ -208,6 +229,52 @@ public void testUserVisibilityViaContactsWebPart()
assertTextPresent(CHECKED_USER, ADMIN_USER, HIDDEN_STRING, TEST_GROUP);
}

@Test
public void testProjectUsers() throws Exception
{
// The list of project users will be all users with read access to the folder.
Set<String> projectUsers = getUsersWithAccess(getProjectName(), ReadPermission.class);
assertFalse("A user with no project role must not have read access",
projectUsers.contains(NON_MEMBER));

// Both a site administrator and a project administrator should see the project's users and be able to open
// the details view for every one of them.
for (String admin : List.of(ADMIN_USER, PROJECT_ADMIN))
{
impersonate(admin);
goToProjectHome();

log("Verify the Project Users page, impersonating " + admin);
ShowUsersPage projectUsersPage = goToProjectUsers();
assertEquals("Project Users page displaying the wrong set of users.",
projectUsers, new HashSet<>(projectUsersPage.getUsersTable().getColumnDataAsText("Email")));

log("Verify " + admin + " can view the details page of every project user");
for (String userEmail : projectUsers)
{
DataRegionTable usersTable = goToProjectUsers().getUsersTable();
clickAndWait(usersTable.detailsLink(usersTable.getRowIndexStrict("Email", userEmail)));
assertTextPresent(userEmail, _userHelper.getDisplayNameForEmail(userEmail));
}

stopImpersonating();
}
}

/**
* Returns the set of user emails who have permission to the folder
*/
private Set<String> getUsersWithAccess(String folderPath, Class<? extends Permission> perm) throws IOException, CommandException
{
SimpleGetCommand command = new SimpleGetCommand("user", "getUsersWithPermissions");
command.setParameters(Map.of("permissions", perm.getName()));
CommandResponse response = command.execute(createDefaultConnection(), folderPath);
List<Map<String, Object>> users = response.getProperty("users");

return users.stream().
map(m -> (String) m.get("email")).collect(Collectors.toSet());
}

@Test
public void testUserVisibilityAutoCompleteApi() throws Exception
{
Expand Down
2 changes: 1 addition & 1 deletion src/org/labkey/test/tests/UserPermissionsTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -272,7 +272,7 @@ public void testAuditLogForGroupUpdates()

log("Remove user from group and verify logs");
goToProjectHome();
permissionsHelper.removeUserFromGroup(GAMMA_SUBMITTER_GROUP_NAME, GAMMA_SUBMITTER_USER);
permissionsHelper.removeUserFromGroup(GAMMA_SUBMITTER_GROUP_NAME, GAMMA_SUBMITTER_USER, getProjectName());
verifyAuditLog("User: " + GAMMA_SUBMITTER_USER + " was deleted from Group: " + GAMMA_SUBMITTER_GROUP_NAME);
}

Expand Down
10 changes: 5 additions & 5 deletions src/org/labkey/test/tests/list/ListTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -907,7 +907,7 @@ public void testAuditDetailRejectsRowIdFromOtherList() throws Exception
.setText(NAME_FIELD + "\n" + LIST_Y_ROW_VALUE)
.submit();
DataRegionTable yTable = new DataRegionTable("query", getDriver());
yTable.clickEditRow(yTable.getRowIndex(LIST_Y_ROW_VALUE));
yTable.clickEditRow(yTable.getRowIndex(NAME_FIELD, LIST_Y_ROW_VALUE));
setFormElement(Locator.name("quf_" + NAME_FIELD), LIST_Y_ROW_EDITED);
clickButton("Submit");

Expand Down Expand Up @@ -938,13 +938,13 @@ public void testAuditDetailRejectsRowIdFromOtherList() throws Exception

private int lookupListId(Connection cn, String listName) throws Exception
{
SelectRowsCommand cmd = new SelectRowsCommand("exp", "Lists");
cmd.setColumns(List.of("RowId", "Name"));
SelectRowsCommand cmd = new SelectRowsCommand("ListManager", "ListManager");
cmd.setColumns(List.of("ListId", "Name"));
cmd.addFilter(new Filter("Name", listName, Filter.Operator.EQUAL));
SelectRowsResponse rs = cmd.execute(cn, getProjectName());
if (rs.getRows().isEmpty())
throw new AssertionError("No exp.Lists row for " + listName);
return ((Number) rs.getRows().get(0).get("RowId")).intValue();
throw new AssertionError("No ListManager row for " + listName);
return ((Number) rs.getRows().get(0).get("ListId")).intValue();
}

private int lookupListAuditRowId(Connection cn, String listName) throws Exception
Expand Down
10 changes: 5 additions & 5 deletions src/org/labkey/test/util/ApiPermissionsHelper.java
Original file line number Diff line number Diff line change
Expand Up @@ -672,12 +672,12 @@ private List<String> getGroupNames(String project)
}

@Override
public void removeUserFromGroup(String groupName, String userName)
public void removeUserFromGroup(String groupName, String userName, String projectPath)
{
Integer groupId = getGroupId(groupName);
if (groupId == null)
throw new IllegalArgumentException("Attempting to remove members from non-existent site group: " + groupName);
removeMembersFromGroup(groupId, userName);
removeMembersFromGroup(groupId, projectPath, userName);
}

@Override
Expand All @@ -686,10 +686,10 @@ public void removeUserFromSiteGroup(String groupName, String userName)
Integer groupId = getSiteGroupId(groupName);
if (groupId == null)
throw new IllegalArgumentException("Attempting to remove members from non-existent group: " + groupName);
removeMembersFromGroup(groupId, userName);
removeMembersFromGroup(groupId, "/", userName);
}

private void removeMembersFromGroup(Integer groupId, String... members)
private void removeMembersFromGroup(Integer groupId, String projectPath, String... members)
{
BulkUpdateGroupCommand command = new BulkUpdateGroupCommand(groupId);
command.setCreateGroup(false);
Expand All @@ -699,7 +699,7 @@ private void removeMembersFromGroup(Integer groupId, String... members)
try
{
Connection connection = getConnection();
command.execute(connection, "/");
command.execute(connection, projectPath);
}
catch (IOException | CommandException e)
{
Expand Down
2 changes: 1 addition & 1 deletion src/org/labkey/test/util/PermissionsHelper.java
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,7 @@ public void deleteGroup(String groupName)
@LogMethod(quiet = true)
public abstract void deleteGroup(@LoggedParam String groupName, boolean failIfNotFound);

public abstract void removeUserFromGroup(String groupName, String userName);
public abstract void removeUserFromGroup(String groupName, String userName, String projectName);
public abstract void removeUserFromSiteGroup(String groupName, String userName);

public abstract boolean doesGroupExist(String groupName, String projectName);
Expand Down
4 changes: 2 additions & 2 deletions src/org/labkey/test/util/UIPermissionsHelper.java
Original file line number Diff line number Diff line change
Expand Up @@ -316,11 +316,11 @@ public void deleteGroup(@LoggedParam String groupName, boolean failIfNotFound)
@Override
public void removeUserFromSiteGroup(String groupName, String userEmail)
{
removeUserFromGroup(groupName, userEmail);
removeUserFromGroup(groupName, userEmail, "/");
}

@Override
public void removeUserFromGroup(String groupName, String userEmail)
public void removeUserFromGroup(String groupName, String userEmail, String projectPath)
{
if (!_driver.isTextPresent("Group " + groupName))
selectGroup(groupName);
Expand Down
Loading