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

Us-1682183 preparation for deprecating authentication via username & password #112

Merged
merged 3 commits into from
Jun 26, 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
7 changes: 2 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@ Both steps are also exposed in the pipeline job as `lrcRunTest` and `lrcGenTrend

### System configuration
- Navigate to **Manage Jenkins** → **System Configuration** → **Configure System** → **LoadRunner Cloud** and then configure the following settings:
- **Username** and **Password**
- If you use [API Access keys](https://admhelp.microfocus.com/lrc/en/Latest/Content/Storm/Admin-APIAccess.htm), select the **Use OAuth token** checkbox, then input the **Client ID** and **Client Secret**.
- **Client ID** and **Client Secret**
Refer to [API access keys](https://admhelp.microfocus.com/lrc/en/Latest/Content/Storm/Admin-APIAccess.htm) for details. You can still input **Username** and **Password** in the fields (depends on the feature toggle in your tenant). However, it's recommended to use API access keys.
- **URL**, default: "https://loadrunner-cloud.saas.microfocus.com"
- **Tenant ID**, for example: 123456789
- **Proxy** settings (optional). If you need to use a proxy to access LoadRunner Cloud, select **Connect LoadRunner Cloud via proxy** checkbox, then configure the following fields.
Expand All @@ -45,10 +45,7 @@ Both steps are also exposed in the pipeline job as `lrcRunTest` and `lrcGenTrend
unclassified:
lrcRunTest:
tenantId: "<TENANT ID>"
username: "<USERNAME>"
password: "<PASSWORD>"
url: "https://loadrunner-cloud.saas.microfocus.com"
useOAuth: false
clientId: "<CLIENT ID>"
clientSecret: "<CLIENT SECRET>"
useProxy: false
Expand Down
Binary file modified images/system_config.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@
<url>https://github.com/${gitHubRepo}</url>
</scm>
<properties>
<revision>5.0.5-</revision>
<revision>5.1.0-</revision>
<changelist>-SNAPSHOT</changelist>

<!-- Baseline Jenkins version you use to build the plugin. Users must have this version or newer to run. -->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,25 +33,25 @@
// #endregion

public ProxyConfiguration(final String host, final int port, final String username, final String password) {
if (host == null || host.length() == 0) {
if (host == null || host.isEmpty()) {
throw new IllegalArgumentException("host must not be empty.");
}
if (port <= 0 || port > MAX_PORT_RANGE) {
throw new IllegalArgumentException("port must be an integer between 0 to 65525");
}

this.host = host;
this.port = port;

if (username != null && password != null && username.length() > 0 && password.length() > 0) {
if (username != null && password != null && !username.isEmpty() && !password.isEmpty()) {

Check warning on line 46 in src/main/java/com/microfocus/lrc/core/entity/ProxyConfiguration.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Not covered lines

Lines 36-46 are not covered by tests
this.username = username;
this.password = Secret.fromString(password);
}
}

public ProxyConfiguration(final String host, final String port, final String username, final String password)
throws IllegalArgumentException {
if (host == null || host.length() == 0) {
if (host == null || host.isEmpty()) {

Check warning on line 54 in src/main/java/com/microfocus/lrc/core/entity/ProxyConfiguration.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Partially covered line

Line 54 is only partially covered, 3 branches are missing
throw new IllegalArgumentException("host must not be empty.");
}
int portNum;
Expand All @@ -67,7 +67,7 @@
this.host = host;
this.port = portNum;

if (username != null && password != null && username.length() > 0 && password.length() > 0) {
if (username != null && password != null && !username.isEmpty() && !password.isEmpty()) {

Check warning on line 70 in src/main/java/com/microfocus/lrc/core/entity/ProxyConfiguration.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Not covered line

Line 70 is not covered by tests
this.username = username;
this.password = Secret.fromString(password);
}
Expand Down
124 changes: 35 additions & 89 deletions src/main/java/com/microfocus/lrc/jenkins/TestRunBuilder.java
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@

static Map<String, String> readStringConfigFromEnvVars(final Run<?, ?> run, final Launcher launcher) {
Map<String, String> map = new HashMap<>();
for (StringOptionInEnvVars key : StringOptionInEnvVars.values()) {
for (StringOptionInEnvVars key : StringOptionInEnvVars.getEntries()) {
String value = EnvVarsUtil.getEnvVar(run, launcher, key.name());
if (StringUtils.isNotBlank(value)) {
map.put(key.name(), value.trim());
Expand Down Expand Up @@ -333,7 +333,7 @@

private Map<String, String> readBoolConfigFromEnvVars(final Run<?, ?> run, final Launcher launcher) {
Map<String, String> map = new HashMap<>();
for (BooleanOptionInEnvVars key : BooleanOptionInEnvVars.values()) {
for (BooleanOptionInEnvVars key : BooleanOptionInEnvVars.getEntries()) {
String value = EnvVarsUtil.getEnvVar(run, launcher, key.name());
if (StringUtils.isNotBlank(value) && !value.equals("0")
&& !value.equalsIgnoreCase("false") && !value.equalsIgnoreCase("no")) {
Expand Down Expand Up @@ -452,22 +452,21 @@

public DescriptorImpl() {
load();

if (Boolean.FALSE.equals(this.useOAuth) && !StringUtils.isBlank(this.username)) {

Check warning on line 456 in src/main/java/com/microfocus/lrc/jenkins/TestRunBuilder.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Partially covered line

Line 456 is only partially covered, 3 branches are missing
this.clientId = this.username;
this.clientSecret = this.password;

Check warning on line 458 in src/main/java/com/microfocus/lrc/jenkins/TestRunBuilder.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Not covered lines

Lines 457-458 are not covered by tests
}

this.useOAuth = true; // always use fields: 'clientId' and 'clientSecret'
}

public String getUser() {
if (Boolean.TRUE.equals(this.useOAuth)) {
return this.clientId;
} else {
return this.username;
}
return this.clientId;
}

public String getPswd() {
if (Boolean.TRUE.equals(this.useOAuth)) {
return (this.clientSecret != null) ? this.clientSecret.getPlainText() : "";
} else {
return (this.password != null) ? this.password.getPlainText() : "";
}
return (this.clientSecret != null) ? this.clientSecret.getPlainText() : "";
}

@Override
Expand Down Expand Up @@ -515,9 +514,8 @@
public boolean configure(final StaplerRequest req, final JSONObject formData) throws FormException {
// set all properties from formData
// validate all properties, throw FormException if invalid
this.username = this.getStringConfig(formData, Constants.USERNAME);
this.password = this.getPasswordConfig(formData, Constants.PASSWORD);
this.url = StringUtils.stripEnd(this.getStringConfig(formData, Constants.URL), "/");
this.tenantId = this.getStringConfig(formData, Constants.TENANTID);

this.useProxy = this.getBooleanConfig(formData, "useProxy");
this.proxyHost = this.getStringConfig(formData, "proxyHost");
Expand All @@ -533,10 +531,12 @@

this.proxyPassword = this.getPasswordConfig(formData, "proxyPassword");

this.useOAuth = this.getBooleanConfig(formData, Constants.USE_OAUTH);
this.clientId = this.getStringConfig(formData, Constants.CLIENT_ID);
this.clientSecret = this.getPasswordConfig(formData, Constants.CLIENT_SECRET);
this.tenantId = this.getStringConfig(formData, Constants.TENANTID);
this.useOAuth = true;

this.username = "";
this.password = null;

save();
return super.configure(req, formData);
Expand All @@ -545,7 +545,7 @@
@POST
public FormValidation doCheckUrl(@QueryParameter final String value) {
String errorMsg = "Please input a valid URL";
if (value == null || value.trim().length() == 0) {
if (value == null || value.trim().isEmpty()) {

Check warning on line 548 in src/main/java/com/microfocus/lrc/jenkins/TestRunBuilder.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Partially covered line

Line 548 is only partially covered, 2 branches are missing
return FormValidation.error(errorMsg);
}

Expand All @@ -558,8 +558,8 @@

@POST
public FormValidation doCheckTenantId(@QueryParameter final String value) {
if (value == null || value.trim().length() == 0) {
return FormValidation.error("Please input a Tenant ID");
if (value == null || value.trim().isEmpty()) {

Check warning on line 561 in src/main/java/com/microfocus/lrc/jenkins/TestRunBuilder.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Partially covered line

Line 561 is only partially covered, 2 branches are missing
return FormValidation.error("Please input tenant id");
}

return FormValidation.ok();
Expand All @@ -568,265 +568,211 @@
@SuppressWarnings("checkstyle:HiddenField")
@POST
public FormValidation doCheckUsername(
@QueryParameter final String value,
@QueryParameter final String useOAuth
@QueryParameter final String value
) {
if (Boolean.parseBoolean(useOAuth)) {
return FormValidation.ok();
}

if (value == null || value.trim().length() == 0) {
return FormValidation.error("Please input a Username");
if (value == null || value.trim().isEmpty()) {
return FormValidation.error("Please input client id or username");
}

return FormValidation.ok();
}

@SuppressWarnings("checkstyle:HiddenField")
@POST
public FormValidation doCheckPassword(
@QueryParameter final String value,
final @QueryParameter String useOAuth
@QueryParameter final String value
) {
if (Boolean.parseBoolean(useOAuth)) {
return FormValidation.ok();
}

if (value == null || value.trim().length() == 0) {
return FormValidation.error("Please input a Password");
}

return FormValidation.ok();
}

@SuppressWarnings("checkstyle:HiddenField")
@POST
public FormValidation doCheckClientId(
@QueryParameter final String value,
@QueryParameter final String useOAuth
) {
if (!Boolean.parseBoolean(useOAuth)) {
return FormValidation.ok();
}

if (!ApiClient.isOAuthClientId(value.trim())) {
return FormValidation.error("Please input a valid Client ID");
}

return FormValidation.ok();
}

@SuppressWarnings("checkstyle:HiddenField")
@POST
public FormValidation doCheckClientSecret(
@QueryParameter final String value,
@QueryParameter final String useOAuth
) {
if (!Boolean.parseBoolean(useOAuth)) {
return FormValidation.ok();
}

if (value == null || value.trim().length() == 0) {
return FormValidation.error("Please input a valid Client Secret");
if (value == null || value.trim().isEmpty()) {
return FormValidation.error("Please input client secret or password");
}

return FormValidation.ok();
}

@SuppressWarnings("checkstyle:HiddenField")
@POST
public FormValidation doCheckProxyHost(
@QueryParameter final String value,
@QueryParameter final String useProxy
) {
if (!Boolean.parseBoolean(useProxy)) {
return FormValidation.ok();
}

if (value == null || value.trim().length() == 0) {
return FormValidation.error("Please input a Host");
if (value == null || value.trim().isEmpty()) {
return FormValidation.error("Please input a valid proxy host");
}

return FormValidation.ok();
}

@SuppressWarnings({"checkstyle:HiddenField", "checkstyle:MagicNumber"})
@POST
public FormValidation doCheckProxyPort(
@QueryParameter final String value,
@QueryParameter final String useProxy
) {
if (!Boolean.parseBoolean(useProxy)) {
return FormValidation.ok();
}

if (value == null || value.trim().length() == 0) {
if (value == null || value.trim().isEmpty()) {
return FormValidation.ok();
}

if (!StringUtils.isNumeric(value)) {
return FormValidation.error("Please input a valid port number.");
return FormValidation.error("Please input a valid port number");
}

int portVal = Integer.parseInt(value);

if (portVal < 0 || portVal > 65535) {
return FormValidation.error("Please input a valid port number.");
return FormValidation.error("Please input a valid port number");
}

return FormValidation.ok();
}

@POST
public FormValidation doCheckProjectID(@QueryParameter final String value) {
if (value == null || value.trim().length() == 0) {
return FormValidation.error("Please input a Project ID");
if (value == null || value.trim().isEmpty()) {
return FormValidation.error("Please input project id");
}

if (!value.matches("^\\d+$")) {
return FormValidation.error("Invalid Project ID");
return FormValidation.error("Invalid project id");
}
return FormValidation.ok();
}

//#region getter/setter
public String getUrl() {
return url;
}

public void setUrl(final String url) {
this.url = url;
}

public String getTenantId() {
return tenantId;
}

public void setTenantId(final String tenantId) {
this.tenantId = tenantId;
}

public String getClientId() {
return clientId;
}

public void setClientId(final String clientId) {
this.clientId = clientId;
}

public Secret getClientSecret() {
return clientSecret;
}

public void setClientSecret(final Secret clientSecret) {
this.clientSecret = clientSecret;
}

public void setClientSecret(final String clientSecret) {
this.clientSecret = Secret.fromString(clientSecret);
}

public Boolean getUseProxy() {
return useProxy;
}

public void setUseProxy(final Boolean useProxy) {
this.useProxy = useProxy;
}

public String getProxyHost() {
return proxyHost;
}

public void setProxyHost(final String proxyHost) {
this.proxyHost = proxyHost;
}

public String getProxyPort() {
return proxyPort;
}

public void setProxyPort(final String proxyPort) {
this.proxyPort = proxyPort;
}

public String getProxyUsername() {
return proxyUsername;
}

public void setProxyUsername(final String proxyUsername) {
this.proxyUsername = proxyUsername;
}

public Secret getProxyPassword() {
return proxyPassword;
}

public void setProxyPassword(final Secret proxyPassword) {
this.proxyPassword = proxyPassword;
}

public String getUsername() {
return username;
}

public void setUsername(final String username) {
this.username = username;
}

public Secret getPassword() {
return password;
}

public void setPassword(final Secret password) {
this.password = password;
}

public Boolean getUseOAuth() {
return useOAuth;
}

public void setUseOAuth(final Boolean useOAuth) {
this.useOAuth = useOAuth;
}

//#endregion

@SuppressWarnings({"java:S107", "checkstyle:ParameterNumber", "checkstyle:HiddenField"})
@POST
public FormValidation doTestConnection(
@QueryParameter("username") final String username,
@QueryParameter("password") final Secret password,
@QueryParameter("url") final String url,
@QueryParameter("proxyHost") final String proxyHost,
@QueryParameter("proxyPort") final String proxyPort,
@QueryParameter("proxyUsername") final String proxyUsername,
@QueryParameter("proxyPassword") final Secret proxyPassword,
@QueryParameter("clientId") final String clientId,
@QueryParameter("clientSecret") final Secret clientSecret,
@QueryParameter("tenantId") final String tenantId,
@QueryParameter("useOAuth") final String useOAuth,
@QueryParameter("useProxy") final String useProxy
) {
Jenkins.get().checkPermission(Jenkins.ADMINISTER);

if (!Utils.isValidLRCUrl(url)) {
return FormValidation.error("Invalid parameter: URL");
}

if (!Utils.isValidLRCTenant(tenantId)) {
return FormValidation.error("Invalid parameter: Tenant ID");
}

boolean useOAuthFlag = Boolean.parseBoolean(useOAuth);
String user = useOAuthFlag ? clientId : username;
String pswd;

if (useOAuthFlag) {
pswd = (clientSecret != null) ? clientSecret.getPlainText() : "";
} else {
pswd = (password != null) ? password.getPlainText() : "";
}
String user = clientId;
String pswd = (clientSecret != null) ? clientSecret.getPlainText() : "";

Check warning on line 775 in src/main/java/com/microfocus/lrc/jenkins/TestRunBuilder.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Not covered lines

Lines 573-775 are not covered by tests

ServerConfiguration config = new ServerConfiguration(
url,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,10 @@
so it should be straightforward to find them.
-->
<f:section title="LoadRunner Cloud">
<f:entry title="Username" field="username">
<f:entry title="Client ID" field="clientId">
<f:textbox />
</f:entry>
<f:entry title="Password" field="password">
<f:entry title="Client Secret" field="clientSecret">
<f:password />
</f:entry>
<f:entry title="URL" field="url">
Expand All @@ -39,16 +39,6 @@
<f:entry title="Tenant ID" field="tenantId">
<f:textbox clazz="required" />
</f:entry>
<f:block>
<f:optionalBlock checked="${descriptor.useOAuth}" name="useOAuth" field="useOAuth" inline="true" title="Use OAuth token">
<f:entry title="Client ID" field="clientId" description="If it's set, jobs will use client id and client secret.">
<f:textbox />
</f:entry>
<f:entry title="Client Secret" field="clientSecret">
<f:password />
</f:entry>
</f:optionalBlock>
</f:block>
<f:block>
<f:optionalBlock checked="${descriptor.useProxy}" name="useProxy" field="useProxy" inline="true" title="Connect LoadRunner Cloud via proxy">
<f:entry title="Proxy Host" field="proxyHost" description="If a valid proxy setting is specified here, all other proxy settings will be ignored while connecting LoadRunner Cloud.">
Expand All @@ -68,7 +58,7 @@

<f:validateButton title="Test Connection" progress="Testing..."
method="testConnection"
with="username,password,url,useProxy,proxyHost,proxyPort,proxyUsername,proxyPassword,useOAuth,clientId,clientSecret,tenantId"
with="url,useProxy,proxyHost,proxyPort,proxyUsername,proxyPassword,clientId,clientSecret,tenantId"
/>

</f:section>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<div>
Your client id or username to login LoadRunner Cloud
</div>
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<div>
Your client secret or password to login LoadRunner Cloud
</div>

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
<div>
Test ID. Navigate to the General page of target load test in LoadRunner Cloud to see the ID.
Test ID. Navigate to "Test settings" page of target load test in LoadRunner Cloud to see the ID.
</div>
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
<div>
LoadRunner Cloud URL, for example: https://loadrunner-cloud.saas.microfocus.com
LoadRunner Cloud URL. For example: https://loadrunner-cloud.saas.microfocus.com
</div>

This file was deleted.

Loading