Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Issue 50569: Add ability for users to supply descriptions with API keys #2083

Merged
merged 3 commits into from
Oct 7, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions pull_request_template.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
<!-- Rationale describing why this pull request is needed, what behavior it's adding/changing/removing, etc. (replace this comment) -->

#### Related Pull Requests
* <!-- list of links to related pull requests (replace this comment) -->
- <!-- list of links to related pull requests (replace this comment) -->

#### Changes
* <!-- list of descriptions of changes that are worth noting (replace this comment) -->
- <!-- list of descriptions of changes that are worth noting (replace this comment) -->
119 changes: 119 additions & 0 deletions src/org/labkey/test/credentials/ApiKeyDialog.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
package org.labkey.test.credentials;

import org.labkey.test.Locator;
import org.labkey.test.components.bootstrap.ModalDialog;
import org.labkey.test.components.html.Input;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;

import java.awt.*;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.UnsupportedFlavorException;
import java.io.IOException;

public class ApiKeyDialog extends ModalDialog
{
public static final String API_KEY_TITLE = "API Key";
public static final String SESSION_KEY_TITLE = "Session Key";

private final String _title;

public ApiKeyDialog(WebDriver driver, String title)
{
super(new ModalDialogFinder(driver).withTitle(title));
_title = title;
}

public ApiKeyDialog generateApiKey()
{
elementCache().generateApiKeyButton.click();
return new ApiKeyDialog(getDriver(), _title);
}

public ApiKeyDialog copyKey()
{
elementCache().copyKeyButton.click();
return this;
}

public String getClipboardContent() throws IOException, UnsupportedFlavorException
{
return (String) Toolkit.getDefaultToolkit().getSystemClipboard()
.getData(DataFlavor.stringFlavor);
}

public boolean isCopyButtonDisplayed()
{
return elementCache().copyKeyButton.isDisplayed();
}

public boolean isCopyButtonEnabled()
{
return elementCache().copyKeyButton.isEnabled();
}

public boolean isGenerateButtonEnabled()
{
return elementCache().generateApiKeyButton.isEnabled();
}

public boolean isGenerateButtonDisplayed()
{
return elementCache().generateApiKeyButton.isDisplayed();
}

public boolean isInputFieldEnabled()
{
return elementCache().inputField.getComponentElement().isEnabled();
}

public boolean isInputFieldDisplayed()
{
return elementCache().inputField.getComponentElement().isDisplayed();
}

public boolean isDescriptionFieldDisplayed() { return elementCache().descriptionInput.getComponentElement().isDisplayed(); }

public void clickDone()
{
elementCache().doneButton.click();
}

public ApiKeyDialog setDescription(String description)
{
elementCache().descriptionInput.getComponentElement().sendKeys(description);
return this;
}

public String getDescription()
{
return elementCache().descriptionDisplay.getText();
}

public String getInputFieldValue()
{
return elementCache().inputField.getValue();
}

@Override
protected ApiKeyDialog.ElementCache newElementCache()
{
return new ApiKeyDialog.ElementCache();
}

@Override
protected ApiKeyDialog.ElementCache elementCache()
{
return (ApiKeyDialog.ElementCache) super.elementCache();
}

protected class ElementCache extends ModalDialog.ElementCache
{
Input descriptionInput = Input.Input(Locator.tagWithId("input", "keyDescription"), getDriver()).refindWhenNeeded(this);
WebElement descriptionDisplay = Locator.tagWithClassContaining("div", "api-key__description").refindWhenNeeded(this);
WebElement generateApiKeyButton = Locator.tagWithText("button", "Generate API Key").findWhenNeeded(this);
Input inputField = Input.Input(Locator.tagWithClass("input", "api-key__input"), getDriver()).findWhenNeeded(this);
WebElement copyKeyButton = Locator.tagWithName("button", "copy_apikey_token").findWhenNeeded(this);
WebElement doneButton = Locator.tagWithText("button", "Done").findWhenNeeded(this);
}
}
33 changes: 23 additions & 10 deletions src/org/labkey/test/tests/ApiKeyTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
package org.labkey.test.tests;

import org.apache.hc.core5.http.HttpStatus;
import org.jetbrains.annotations.Nullable;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.experimental.categories.Category;
Expand All @@ -40,6 +41,7 @@
import org.labkey.test.categories.Daily;
import org.labkey.test.components.bootstrap.ModalDialog;
import org.labkey.test.components.ui.grids.QueryGrid;
import org.labkey.test.credentials.ApiKeyDialog;
import org.labkey.test.pages.core.admin.CustomizeSitePage;
import org.labkey.test.util.Maps;
import org.labkey.test.util.TestUser;
Expand Down Expand Up @@ -178,11 +180,13 @@ public void testNonAdminUser() throws IOException

log("Log in as non-admin user.");
signIn(EDITOR_USER.getEmail(), EDITOR_USER.getPassword());
String apiKey = generateAPIKey();
String keyDescription = "Key for editing";
String apiKey = generateAPIKey(keyDescription);
verifyValidAPIKey(apiKey);

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);
Expand All @@ -199,15 +203,15 @@ public void testStandardApiKey() throws IOException
.setApiKeyExpiration(CustomizeSitePage.KeyExpirationOptions.ONE_WEEK)
.save();

String apiKey = generateAPIKey(_generatedApiKeys);
String apiKey = generateAPIKeyAndRecord(_generatedApiKeys);
log("Verify active API key via api authentication");
verifyValidAPIKey(apiKey);
log("Verify active API key via basic authentication");
verifyValidAPIKey(apiKey, true);

log("Generate two other keys for use in testing deletion.");
generateAPIKey();
generateAPIKey();
generateAPIKey(null);
generateAPIKey(null);
QueryGrid grid = new QueryGrid.QueryGridFinder(getDriver()).waitFor();
int beforeDeleteCount = grid.getRecordCount();
grid = deleteAPIKeyViaUI();
Expand Down Expand Up @@ -244,7 +248,7 @@ public void testApiKeysImpersonation() throws IOException
.setAllowSessionKeys(true)
.save();
List<Map<String, Object>> _generatedApiKeys = new ArrayList<>();
generateAPIKey(_generatedApiKeys);
generateAPIKeyAndRecord(_generatedApiKeys);
goToProjectHome();
impersonate(EDITOR_USER.getEmail());
goToExternalToolPage();
Expand Down Expand Up @@ -371,21 +375,30 @@ private String generateSessionKey()
goToExternalToolPage();
waitForText("API keys are used to authorize");
clickButton("Generate Session Key", 0);
ApiKeyDialog dialog = new ApiKeyDialog(this.getDriver(), ApiKeyDialog.SESSION_KEY_TITLE);
waitForFormElementToNotEqual(Locator.inputByNameContaining("session_token"), "");
return Locator.inputByNameContaining("session_token").findElement(getDriver()).getAttribute("value");
String key = Locator.inputByNameContaining("session_token").findElement(getDriver()).getAttribute("value");
dialog.clickDone();
return key;
}

private String generateAPIKey()
private String generateAPIKey(@Nullable String description)
{
goToExternalToolPage();
clickButton("Generate API Key", 0);
ApiKeyDialog dialog = new ApiKeyDialog(this.getDriver(), ApiKeyDialog.API_KEY_TITLE);
if (description != null)
dialog.setDescription(description);
dialog = dialog.generateApiKey();
waitForFormElementToNotEqual(Locator.inputByNameContaining("apikey_token"), "");
return Locator.inputByNameContaining("apikey_token").findElement(getDriver()).getAttribute("value");
String key = Locator.inputByNameContaining("apikey_token").findElement(getDriver()).getAttribute("value");
dialog.clickDone();
return key;
}

private String generateAPIKey(List<Map<String, Object>> _generatedApiKeys) throws IOException
private String generateAPIKeyAndRecord(List<Map<String, Object>> _generatedApiKeys) throws IOException
{
String apiKey = generateAPIKey();
String apiKey = generateAPIKey(null);
// get record
_generatedApiKeys.add(getLastAPIKeyRecord());
return apiKey;
Expand Down