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

Use credentials plugin for the developer API key, instead of storing in plain text #36

Draft
wants to merge 8 commits into
base: master
Choose a base branch
from
Draft
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
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -261,6 +261,7 @@ via [@tupilabs](https://twitter.com/tupilabs)
### Release 4.0 (????-??-??)

1. [JENKINS-64023](https://issues.jenkins-ci.org/browse/JENKINS-64023) - org.apache.commons.jelly.JellyTagException: jar:file:/var/lib/jenkins/plugins/testlink/WEB-INF/lib/testlink.jar!/hudson/plugins/testlink/TestLinkResult/index.jelly:6:57: No page found 'sidepanel.jelly' for class hudson.plugins.testlink.TestLinkResult
2. Added Credentials Plugin, and Plain Credentials Plugin as dependency, storing devKey in a string credential now, instead of using plain text

### Release 3.16 (2019-02-07)

Expand Down
32 changes: 15 additions & 17 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<parent>
<groupId>org.jenkins-ci.plugins</groupId>
<artifactId>plugin</artifactId>
<version>3.0</version>
<version>4.12</version>
<relativePath />
</parent>

Expand All @@ -25,10 +25,12 @@

<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<jenkins.version>2.60.3</jenkins.version>
<jenkins.version>2.249.3</jenkins.version>
<java.level>8</java.level>
<!-- TODO: remove once FindBugs issues are resolved -->
<findbugs.failOnError>false</findbugs.failOnError>
<spotbugs.failOnError>false</spotbugs.failOnError>
<spotbugs.effort>Max</spotbugs.effort>
<spotbugs.threshold>Medium</spotbugs.threshold>
</properties>

<issueManagement>
Expand Down Expand Up @@ -251,12 +253,10 @@
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.6</version>
</dependency>
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>1.11</version>
</dependency>
<dependency>
<groupId>xml-apis</groupId>
Expand All @@ -265,18 +265,6 @@
<type>jar</type>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.hamcrest</groupId>
<artifactId>hamcrest-core</artifactId>
<version>1.3</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.hamcrest</groupId>
<artifactId>hamcrest-library</artifactId>
<version>1.3</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-all</artifactId>
Expand All @@ -293,6 +281,16 @@
<artifactId>junit</artifactId>
<version>1.11</version>
</dependency>
<dependency>
<groupId>org.jenkins-ci.plugins</groupId>
<artifactId>credentials</artifactId>
<version>2.3.13</version>
</dependency>
<dependency>
<groupId>org.jenkins-ci.plugins</groupId>
<artifactId>plain-credentials</artifactId>
<version>1.7</version>
</dependency>
</dependencies>

<repositories>
Expand Down
29 changes: 28 additions & 1 deletion src/main/java/hudson/plugins/testlink/TestLinkBuilder.java
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,18 @@
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.logging.Level;
import java.util.logging.Logger;

import org.apache.commons.lang3.StringUtils;
import org.jenkinsci.plugins.plaincredentials.StringCredentials;
import org.kohsuke.stapler.DataBoundConstructor;

import com.cloudbees.plugins.credentials.CredentialsMatcher;
import com.cloudbees.plugins.credentials.CredentialsMatchers;
import com.cloudbees.plugins.credentials.CredentialsProvider;

import br.eti.kinoshita.testlinkjavaapi.TestLinkAPI;
import br.eti.kinoshita.testlinkjavaapi.constants.ExecutionStatus;
import br.eti.kinoshita.testlinkjavaapi.model.Build;
Expand All @@ -57,8 +63,10 @@
import hudson.plugins.testlink.result.TestCaseWrapper;
import hudson.plugins.testlink.util.Messages;
import hudson.plugins.testlink.util.TestLinkHelper;
import hudson.security.ACL;
import hudson.tasks.BuildStep;
import hudson.tasks.Builder;
import jenkins.model.Jenkins;

/**
* A builder to add a TestLink build step.
Expand Down Expand Up @@ -94,6 +102,19 @@ public TestLinkBuilder(String testLinkName, String testProjectName,
failIfNoResults, failOnNotRun, resultSeekers);
}

/**
* Get the credential ID.
* @param credentialId credential ID
* @return either the credential with the devKey, or {@code null}
*/
private Optional<StringCredentials> getCredential(String credentialId) {
final List<StringCredentials> lookupCredentials = CredentialsProvider.lookupCredentials(
StringCredentials.class, Jenkins.getInstance(), ACL.SYSTEM, null, null);
CredentialsMatcher credentialsMatcher = CredentialsMatchers.withId(credentialId);
return Optional.of(CredentialsMatchers.firstOrNull(lookupCredentials,
credentialsMatcher));
}

/**
* Called when the job is executed.
*/
Expand All @@ -113,12 +134,18 @@ public boolean perform(AbstractBuild<?, ?> build, Launcher launcher,
throw new AbortException(Messages.TestLinkBuilder_InvalidTLAPI());
}

final String credentialsId = installation.getCredentialsId();
final String testLinkDevKey = this
.getCredential(credentialsId)
.orElseThrow(() -> new AbortException("Invalid credential ID " + credentialsId))
.getSecret()
.getPlainText();

TestLinkHelper.setTestLinkJavaAPIProperties(installation.getTestLinkJavaAPIProperties(), listener);

final TestLinkSite testLinkSite;
final TestCaseWrapper[] automatedTestCases;
final String testLinkUrl = installation.getUrl();
final String testLinkDevKey = installation.getDevKey();
TestPlan testPlan;
listener.getLogger().println(Messages.TestLinkBuilder_UsedTLURL(testLinkUrl));

Expand Down
33 changes: 28 additions & 5 deletions src/main/java/hudson/plugins/testlink/TestLinkInstallation.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,19 @@
package hudson.plugins.testlink;

import java.io.Serializable;
import java.util.List;

import org.jenkinsci.plugins.plaincredentials.StringCredentials;
import org.kohsuke.stapler.DataBoundConstructor;

import com.cloudbees.plugins.credentials.CredentialsMatcher;
import com.cloudbees.plugins.credentials.CredentialsMatchers;
import com.cloudbees.plugins.credentials.CredentialsProvider;

import hudson.security.ACL;
import hudson.util.Secret;
import jenkins.model.Jenkins;

/**
* Represents the TestLink installation in Hudson global configuration.
*
Expand All @@ -48,20 +58,20 @@ public class TestLinkInstallation implements Serializable {
private String url;

/**
* A valid user dev key
* Jenkins credentials ID (must contain the API Key)
*/
private String devKey;
private String credentialsId;

/**
* TestLink Java API properties
*/
private String testLinkJavaAPIProperties;

@DataBoundConstructor
public TestLinkInstallation(String name, String url, String devKey, String testLinkJavaAPIProperties) {
public TestLinkInstallation(String name, String url, String credentialsId, String testLinkJavaAPIProperties) {
this.name = name;
this.url = url;
this.devKey = devKey;
this.credentialsId = credentialsId;
this.testLinkJavaAPIProperties = testLinkJavaAPIProperties;
}

Expand All @@ -73,8 +83,21 @@ public String getUrl() {
return this.url;
}

public String getCredentialsId() {
return credentialsId;
}

public String getDevKey() {
return this.devKey;
List<StringCredentials> lookupCredentials = CredentialsProvider.lookupCredentials(
StringCredentials.class, Jenkins.getInstance(), ACL.SYSTEM, null, null);
CredentialsMatcher credentialsMatcher = CredentialsMatchers.withId(credentialsId);
StringCredentials devKeyCredential = CredentialsMatchers.firstOrNull(lookupCredentials,
credentialsMatcher);
if (devKeyCredential != null) {
final Secret secret = devKeyCredential.getSecret();
return secret.getPlainText();
}
return null;
}

public String getTestLinkJavaAPIProperties() {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<?jelly escape-by-default='true'?>
<j:jelly xmlns:j="jelly:core" xmlns:st="jelly:stapler" xmlns:d="jelly:define" xmlns:l="/lib/layout" xmlns:t="/lib/hudson" xmlns:f="/lib/form">
<j:jelly xmlns:j="jelly:core" xmlns:st="jelly:stapler" xmlns:d="jelly:define" xmlns:l="/lib/layout" xmlns:t="/lib/hudson" xmlns:f="/lib/form" xmlns:c="/lib/credentials">

<f:section title="TestLink">
<f:entry title="${%TestLink Installation}"
Expand All @@ -18,9 +18,8 @@
checkUrl="'${rootURL}/builder/TestLinkBuilder/checkMandatory?value='+escape(this.value)" />
</f:entry>

<f:entry title="${%Developer Key}">
<f:textbox name="TestLink.devKey" value="${inst.devKey}"
checkUrl="'${rootURL}/builder/TestLinkBuilder/checkMandatory?value='+escape(this.value)" />
<f:entry title="${%Credentials}" field="credentialsId">
<c:select/>
</f:entry>

<f:advanced>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,38 +24,62 @@
package hudson.plugins.testlink;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;

import java.io.IOException;

import org.jenkinsci.plugins.plaincredentials.StringCredentials;
import org.jenkinsci.plugins.plaincredentials.impl.StringCredentialsImpl;
import org.junit.Rule;
import org.junit.Test;
import org.jvnet.hudson.test.JenkinsRule;

import com.cloudbees.plugins.credentials.CredentialsProvider;
import com.cloudbees.plugins.credentials.CredentialsScope;
import com.cloudbees.plugins.credentials.CredentialsStore;
import com.cloudbees.plugins.credentials.domains.Domain;

import hudson.util.Secret;

/**
* Tests the TestLinkBuilderInstallation class.
*
*
* @see {@link TestLinkInstallation}
*
*
* @author Bruno P. Kinoshita - http://www.kinoshita.eti.br
* @since 2.1
*/
public class TestTestLinkBuilderInstallation
{

@Rule
public JenkinsRule r = new JenkinsRule();

/**
* Tests with a TestLinkBuilderInstallation object.
* @throws IOException when adding a credentials, if it fails
*/
@Test
public void testInstallation()
public void testInstallation() throws IOException
{
TestLinkInstallation inst =
final String credentialsId = "tl-test-api-key";
final CredentialsStore store = CredentialsProvider.lookupStores(r.getInstance()).iterator().next();
final Secret secret = Secret.fromString("068848");
final StringCredentials credentials = new StringCredentialsImpl(
CredentialsScope.GLOBAL,
credentialsId,
"Test devKey used for unit tests",
secret);
store.addCredentials(Domain.global(), credentials);
final TestLinkInstallation inst =
new TestLinkInstallation(
"TestLink 1.9.1",
"http://localhost/testlink-1.9.1/lib/api/xml-rpc.php",
"068848", "");

assertNotNull( inst );

assertEquals( inst.getName(), "TestLink 1.9.1" );
assertEquals( inst.getUrl(), "http://localhost/testlink-1.9.1/lib/api/xml-rpc.php" );
assertEquals( inst.getDevKey(), "068848" );
credentialsId,
"");

assertEquals(inst.getName(), "TestLink 1.9.1");
assertEquals(inst.getUrl(), "http://localhost/testlink-1.9.1/lib/api/xml-rpc.php");
assertEquals(inst.getDevKey(), "068848");
}

}