diff --git a/src/org/labkey/test/pages/user/UserDetailsPage.java b/src/org/labkey/test/pages/user/UserDetailsPage.java index 72c9ecf386..3a6cd52bde 100644 --- a/src/org/labkey/test/pages/user/UserDetailsPage.java +++ b/src/org/labkey/test/pages/user/UserDetailsPage.java @@ -3,7 +3,9 @@ import org.labkey.test.Locator; import org.labkey.test.WebDriverWrapper; import org.labkey.test.WebTestHelper; +import org.labkey.test.components.core.login.SetPasswordForm; import org.labkey.test.pages.LabKeyPage; +import org.labkey.test.util.PasswordUtil; import org.openqa.selenium.WebDriver; import org.openqa.selenium.WebElement; @@ -34,6 +36,15 @@ public ClonePermissionsPage clickClonePermission() return new ClonePermissionsPage(getDriver()); } + public SetPasswordForm clickChangePassword() + { + if (PasswordUtil.getUsername().equals(getCurrentUser())) + throw new IllegalArgumentException("Don't change the primary site admin user's password"); + + clickAndWait(elementCache().changePwdButton); + return new SetPasswordForm(getDriver()); + } + @Override protected ElementCache newElementCache() { @@ -44,5 +55,6 @@ protected class ElementCache extends LabKeyPage.ElementCache { WebElement editButton = Locator.lkButton("Edit").findWhenNeeded(this); WebElement cloneButton = Locator.lkButton("Clone Permissions").findWhenNeeded(this); + WebElement changePwdButton = Locator.lkButton("Change Password").findWhenNeeded(this); } } diff --git a/src/org/labkey/test/tests/ApiKeyTest.java b/src/org/labkey/test/tests/ApiKeyTest.java index 05bfc89380..f778dee9c0 100644 --- a/src/org/labkey/test/tests/ApiKeyTest.java +++ b/src/org/labkey/test/tests/ApiKeyTest.java @@ -75,7 +75,7 @@ public class ApiKeyTest extends BaseWebDriverTest @BeforeClass public static void setupProject() { - ApiKeyTest init = (ApiKeyTest) getCurrentTest(); + ApiKeyTest init = getCurrentTest(); init.doSetup(); } @@ -107,74 +107,21 @@ public void testSessionKey() throws IOException String apiKey = generateSessionKey(); - verifyValidAPIKey(apiKey); + verifyValidAPIKey(createApiKeyConnection(apiKey, false)); log("Verify session key remains valid if key generation is turned off"); goToAdminConsole() .clickSiteSettings() .setAllowSessionKeys(false) .save(); - verifyValidAPIKey(apiKey); + verifyValidAPIKey(createApiKeyConnection(apiKey, false)); signOut(); log("Verify that logging out invalidates session keys"); - verifyInvalidAPIKey(apiKey, null); + verifyInvalidAPIKey(createApiKeyConnection(apiKey, false), false); simpleSignIn(); log("Verify that session keys remain invalid after logging back in"); - verifyInvalidAPIKey(apiKey, null); - } - - private void verifyValidAPIKey(String apiKey) throws IOException - { - verifyValidAPIKey(apiKey, false, null); - } - - private Connection verifyValidAPIKey(String apiKey, boolean basicAuth, @Nullable Connection connection) throws IOException - { - Connection cn; - if (connection == null) - cn = new Connection(WebTestHelper.getBaseURL(), basicAuth ? new BasicAuthCredentialsProvider(API_USERNAME, apiKey) - : new ApiKeyCredentialsProvider(apiKey)); - else - cn = connection; - try - { - GetSchemasCommand cmd = new GetSchemasCommand(); - GetSchemasResponse resp = cmd.execute(cn, getProjectName()); - List schemaNames = resp.getSchemaNames().stream().map(String::toLowerCase).collect(Collectors.toList()); - Set missingSchemas = new HashSet<>(Arrays.asList("pipeline", "lists", "core")); - missingSchemas.removeAll(schemaNames); - assertTrue("Some expected schemas missing. Schemas missing: " + missingSchemas, missingSchemas.isEmpty()); - } - catch (CommandException e) - { - throw new RuntimeException("Response: " + e.getStatusCode(), e); - } - return cn; - } - - private void verifyInvalidAPIKey(String apiKey, @Nullable Connection connection) throws IOException - { - boolean isSessionKey = !apiKey.startsWith(API_USERNAME); - Connection cn; - if (connection == null) - cn = new Connection(WebTestHelper.getBaseURL(), new ApiKeyCredentialsProvider(apiKey)); - else - cn = connection; - try - { - GetSchemasCommand cmd = new GetSchemasCommand(); - cmd.execute(cn, getProjectName()); - if (isSessionKey) - fail("Session key didn't invalidate after logout"); - else - fail("API key should no longer be valid"); - } - catch (CommandException e) - { - assertEquals("Wrong response for invalid " + (isSessionKey ? "session" : "API") + " key", HttpStatus.SC_UNAUTHORIZED, e.getStatusCode()); - log("Success: command failed as expected."); - } + verifyInvalidAPIKey(createApiKeyConnection(apiKey, false), false); } @Test @@ -192,14 +139,14 @@ public void testNonAdminUser() throws IOException signIn(EDITOR_USER.getEmail(), EDITOR_USER.getPassword()); String keyDescription = "Key for editing"; String apiKey = generateAPIKey(keyDescription); - verifyValidAPIKey(apiKey); + verifyValidAPIKey(createApiKeyConnection(apiKey, false)); QueryGrid grid = new QueryGrid.QueryGridFinder(getDriver()).waitFor(); int beforeDeleteCount = grid.getRecordCount(); assertFalse("Row with description not found", grid.getRowMap("Description", keyDescription).isEmpty()); grid = deleteAPIKeyViaUI(); assertEquals("Number of keys after UI deletion not as expected", beforeDeleteCount - 1, grid.getRecordCount()); - verifyInvalidAPIKey(apiKey, null); + verifyInvalidAPIKey(createApiKeyConnection(apiKey, false), false); } @Test @@ -215,9 +162,9 @@ public void testStandardApiKey() throws IOException String apiKey = generateAPIKeyAndRecord(_generatedApiKeys); log("Verify active API key via api authentication"); - verifyValidAPIKey(apiKey); + verifyValidAPIKey(createApiKeyConnection(apiKey, false)); log("Verify active API key via basic authentication"); - verifyValidAPIKey(apiKey, true, null); + verifyValidAPIKey(createApiKeyConnection(apiKey, true)); log("Generate two other keys for use in testing deletion."); generateAPIKey(null); @@ -232,7 +179,7 @@ public void testStandardApiKey() throws IOException .clickSiteSettings() .setAllowApiKeys(false) .save(); - verifyValidAPIKey(apiKey); + verifyValidAPIKey(createApiKeyConnection(apiKey, false)); log("Verify key deletion via UI with disabled api key generation works."); grid = deleteAPIKeyViaUI(); @@ -242,7 +189,7 @@ public void testStandardApiKey() throws IOException log("Verify revoked/deleted api key"); deleteAPIKeys(_generatedApiKeys); - verifyInvalidAPIKey(apiKey, null); + verifyInvalidAPIKey(createApiKeyConnection(apiKey, false), false); } /* @@ -261,16 +208,17 @@ public void testSessionInvalidatesAfterAPIKeyChange() throws IOException .save(); String apiKey1 = generateAPIKeyAndRecord(_generatedApiKeys); - Connection cn = verifyValidAPIKey(apiKey1, false, null); + Connection cn = createApiKeyConnection(apiKey1, false); + verifyValidAPIKey(cn); log("Deleting the apikey"); deleteAPIKeys(_generatedApiKeys); log("Verifying the session associated with deleted apikey is invalid"); - verifyInvalidAPIKey(apiKey1, cn); +// verifyInvalidAPIKey(cn, false); log("Verifying that new connection cannot be created after apikey is deleted"); - verifyInvalidAPIKey(apiKey1, null); + verifyInvalidAPIKey(createApiKeyConnection(apiKey1, false), false); log("Generating the apikey which expires in ten seconds"); goToAdminConsole() @@ -279,17 +227,17 @@ public void testSessionInvalidatesAfterAPIKeyChange() throws IOException .setApiKeyExpiration(CustomizeSitePage.KeyExpirationOptions.TEN_SECONDS) .save(); - log("Verify apikey generation fails"); + log("Verify apikey expiration"); goToExternalToolPage(); String apikey2 = ApiKeyPanel.panelFinder(getDriver()).find().generateApiKey(); - log("Verify valid apikey cannot be created before expiring"); - verifyValidAPIKey(apikey2, false, null); + log("Verify apikey can be used before expiring"); + verifyValidAPIKey(createApiKeyConnection(apikey2, false)); sleep(10000); // Wait for apikey to expire - log("Verify apikey cannot be created after the timer is expired"); - verifyInvalidAPIKey(apikey2, null); + log("Verify apikey cannot be used after it has expired"); + verifyInvalidAPIKey(createApiKeyConnection(apikey2, false), false); } @Test @@ -392,6 +340,47 @@ public void testSessionKeyDisabled() throws IOException } } + private void verifyValidAPIKey(Connection connection) throws IOException + { + try + { + GetSchemasCommand cmd = new GetSchemasCommand(); + GetSchemasResponse resp = cmd.execute(connection, getProjectName()); + List schemaNames = resp.getSchemaNames().stream().map(String::toLowerCase).collect(Collectors.toList()); + Set missingSchemas = new HashSet<>(Arrays.asList("pipeline", "lists", "core")); + missingSchemas.removeAll(schemaNames); + assertTrue("Some expected schemas missing. Schemas missing: " + missingSchemas, missingSchemas.isEmpty()); + } + catch (CommandException e) + { + throw new RuntimeException("Response: " + e.getStatusCode(), e); + } + } + + private Connection createApiKeyConnection(String apiKey, boolean basicAuth) + { + return new Connection(WebTestHelper.getBaseURL(), basicAuth ? new BasicAuthCredentialsProvider(API_USERNAME, apiKey) + : new ApiKeyCredentialsProvider(apiKey)); + } + + private void verifyInvalidAPIKey(Connection connection, boolean isSessionKey) throws IOException + { + try + { + GetSchemasCommand cmd = new GetSchemasCommand(); + cmd.execute(connection, getProjectName()); + if (isSessionKey) + fail("Session key didn't invalidate after logout"); + else + fail("API key should no longer be valid"); + } + catch (CommandException e) + { + assertEquals("Wrong response for invalid " + (isSessionKey ? "session" : "API") + " key", HttpStatus.SC_UNAUTHORIZED, e.getStatusCode()); + log("Success: command failed as expected."); + } + } + private void verifyAPIKeysTablePresence(boolean isAdmin) { beginAt(new URLBuilder("query", "begin", getProjectName()).setFragment("sbh-ssp-core").buildURL()); diff --git a/src/org/labkey/test/tests/InvalidateSessionTest.java b/src/org/labkey/test/tests/InvalidateSessionTest.java index 826f723dda..da15af2632 100644 --- a/src/org/labkey/test/tests/InvalidateSessionTest.java +++ b/src/org/labkey/test/tests/InvalidateSessionTest.java @@ -1,6 +1,7 @@ package org.labkey.test.tests; import org.apache.hc.core5.http.HttpStatus; +import org.jetbrains.annotations.Nullable; import org.junit.Assert; import org.junit.BeforeClass; import org.junit.Test; @@ -11,7 +12,6 @@ import org.labkey.remoteapi.query.SelectRowsResponse; import org.labkey.test.BaseWebDriverTest; import org.labkey.test.categories.Daily; -import org.labkey.test.components.core.login.SetPasswordForm; import org.labkey.test.util.ApiPermissionsHelper; import org.labkey.test.util.PasswordUtil; import org.labkey.test.util.PermissionsHelper; @@ -20,9 +20,9 @@ import java.io.IOException; import java.util.Arrays; import java.util.List; -import java.util.Set; import static org.junit.Assert.fail; +import static org.labkey.test.WebTestHelper.getCookies; @Category({Daily.class}) public class InvalidateSessionTest extends BaseWebDriverTest @@ -36,20 +36,24 @@ public static void setupProject() init.doSetup(); } + @Override + protected @Nullable String getProjectName() + { + return null; + } + @Override protected void doCleanup(boolean afterTest) { - _containerHelper.deleteProject(getProjectName(), afterTest); _userHelper.deleteUsers(afterTest, USER); } private void doSetup() { - _containerHelper.createProject(getProjectName(), null); _userHelper.createUser(USER); ApiPermissionsHelper permissionsHelper = new ApiPermissionsHelper(this); - permissionsHelper.addMemberToRole(USER, "Editor", PermissionsHelper.MemberType.user); + permissionsHelper.addMemberToRole(USER, "Folder Administrator", PermissionsHelper.MemberType.user); setInitialPassword(USER); } @@ -66,7 +70,7 @@ public void testSessionInvalidatesAfterPasswordChange() throws IOException SelectRowsCommand selectCmd = new SelectRowsCommand("auditLog", "UserAuditEvent"); try { - response = selectCmd.execute(cn, getProjectName()); + response = selectCmd.execute(cn, "Home"); Assert.assertEquals("Did not establish the database connection before the password change", 200, response.getStatusCode()); } @@ -77,7 +81,8 @@ public void testSessionInvalidatesAfterPasswordChange() throws IOException log("Changing the user password"); String newPassword = PasswordUtil.getPassword() + "&*&*"; - goToChangePassword().setOldPassword(PasswordUtil.getPassword()) + goToMyAccount().clickChangePassword() + .setOldPassword(PasswordUtil.getPassword()) .setPassword1(newPassword) .setPassword2(newPassword) .clickSubmit(); @@ -101,10 +106,8 @@ public void testSessionInvalidatesAfterPasswordChange() throws IOException @Test public void testCookieAndSessionFromLogout() throws IOException { - goToProjectHome(); - log("Capture the cookie after login"); - Set beforeCookie = getDriver().manage().getCookies(); + Cookie beforeCookie = getCookies(getCurrentUser()).get(Connection.JSESSIONID); log("Establish the connection"); Connection cn = createDefaultConnection(); @@ -136,26 +139,10 @@ public void testCookieAndSessionFromLogout() throws IOException } log("Capture the cookie after logout"); - Set afterCookie = getDriver().manage().getCookies(); + Cookie afterCookie = getCookies(getCurrentUser()).get(Connection.JSESSIONID); Assert.assertFalse("Before and after log out cookie should be different", beforeCookie.equals(afterCookie)); } - private SetPasswordForm goToChangePassword() - { - if (PasswordUtil.getUsername().equals(getCurrentUser())) - throw new IllegalArgumentException("Don't change the primary site admin user's password"); - - goToMyAccount(); - clickButton("Change Password"); - return new SetPasswordForm(getDriver()); - } - - @Override - protected String getProjectName() - { - return "InvalidateSessionTest Project"; - } - @Override public List getAssociatedModules() { diff --git a/src/org/labkey/test/tests/core/login/PasswordTest.java b/src/org/labkey/test/tests/core/login/PasswordTest.java index b3c55d2362..f72d2e7149 100644 --- a/src/org/labkey/test/tests/core/login/PasswordTest.java +++ b/src/org/labkey/test/tests/core/login/PasswordTest.java @@ -138,7 +138,7 @@ public void testStrongPassword() assertSignedInNotImpersonating(); impersonate(USER); - SetPasswordForm changePasswordForm = goToChangePassword(); + SetPasswordForm changePasswordForm = goToMyAccount().clickChangePassword(); log("Verify strength gauge for 'ChangePasswordAction'"); changePasswordForm.verifyPasswordStrengthGauge(USER, displayName); @@ -183,7 +183,7 @@ public void testReusePassword() assertTextNotPresent("Choose a new password."); } // fail, used 9 passwords ago. - goToChangePassword() + goToMyAccount().clickChangePassword() .setOldPassword(currentPassword) .setNewPassword(VERY_STRONG_PASSWORD + 1) .clickSubmitExpectingError("Your password must not match a recently used password."); @@ -357,19 +357,9 @@ protected String setInitialPassword(int userId, String password) @LogMethod (quiet = true) protected void changePassword(String oldPassword, @LoggedParam String password) { - goToChangePassword() + goToMyAccount().clickChangePassword() .setOldPassword(oldPassword) .setNewPassword(password) .clickSubmit(); } - - private SetPasswordForm goToChangePassword() - { - if (PasswordUtil.getUsername().equals(getCurrentUser())) - throw new IllegalArgumentException("Don't change the primary site admin user's password"); - - goToMyAccount(); - clickButton("Change Password"); - return new SetPasswordForm(getDriver()); - } }