Skip to content

Commit

Permalink
[SECURITY-1303][SECURITY-1279]
Browse files Browse the repository at this point in the history
  • Loading branch information
oleg-nenashev authored and daniel-beck committed Jul 29, 2019
1 parent 434e795 commit 73afe3c
Show file tree
Hide file tree
Showing 13 changed files with 702 additions and 28 deletions.
14 changes: 14 additions & 0 deletions integrations/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,13 @@
<version>1.20</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.jenkins-ci.plugins</groupId>
<artifactId>email-ext</artifactId>
<version>2.66</version>
<scope>test</scope>
</dependency>


<dependency>
<groupId>org.jenkins-ci.plugins</groupId>
Expand Down Expand Up @@ -101,6 +108,13 @@
<scope>test</scope>
</dependency>

<dependency>
<groupId>org.jenkins-ci.plugins</groupId>
<artifactId>ssh-credentials</artifactId>
<version>1.17</version>
<scope>test</scope>
</dependency>

<dependency>
<groupId>org.jenkins-ci.plugins</groupId>
<artifactId>github-branch-source</artifactId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,26 +2,33 @@

import com.cloudbees.jenkins.plugins.sshcredentials.impl.BasicSSHUserPrivateKey;
import com.cloudbees.plugins.credentials.CredentialsProvider;
import com.cloudbees.plugins.credentials.CredentialsScope;
import com.cloudbees.plugins.credentials.casc.CredentialsRootConfigurator;
import com.cloudbees.plugins.credentials.common.StandardUsernamePasswordCredentials;
import com.cloudbees.plugins.credentials.impl.UsernamePasswordCredentialsImpl;
import hudson.ExtensionList;
import hudson.util.Secret;
import io.jenkins.plugins.casc.impl.configurators.DataBoundConfigurator;
import io.jenkins.plugins.casc.misc.ConfiguredWithCode;
import io.jenkins.plugins.casc.misc.JenkinsConfiguredWithCodeRule;
import io.jenkins.plugins.casc.model.CNode;
import io.jenkins.plugins.casc.model.Mapping;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import javax.annotation.Nonnull;
import jenkins.model.Jenkins;
import org.junit.Rule;
import org.junit.Test;
import org.jvnet.hudson.test.Issue;

import static java.util.Objects.requireNonNull;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.core.IsNot.not;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;

public class CredentialsTest {

Expand Down Expand Up @@ -99,4 +106,24 @@ public void testExportSSHCredentials() throws Exception {
assertThat(requireNonNull(Secret.decrypt(sshKeyExported)).getPlainText(), is("sp0ds9d+skkfjf"));
}

@Test
@Issue("SECURITY-1404")
public void checkUsernamePasswordIsSecret() {
Attribute a = getFromDatabound(UsernamePasswordCredentialsImpl.class, "password");
assertTrue("Attribute 'password' should be secret", a.isSecret(
new UsernamePasswordCredentialsImpl(CredentialsScope.GLOBAL, "1", "2", "3", "4")));
}

@Nonnull
private <T> Attribute<T,?> getFromDatabound(Class<T> clazz, @Nonnull String attributeName) {
DataBoundConfigurator<T> cfg = new DataBoundConfigurator<T>(clazz);
Set<Attribute<T,?>> attributes = cfg.describe();
for (Attribute<T,?> a : attributes) {
if(attributeName.equals(a.getName())) {
return a;
}
}
throw new AssertionError("Cannot find databound attribute " + attributeName + " in " + clazz);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package io.jenkins.plugins.casc;

import hudson.plugins.emailext.ExtendedEmailPublisher;
import io.jenkins.plugins.casc.misc.ConfiguredWithCode;
import io.jenkins.plugins.casc.misc.JenkinsConfiguredWithCodeRule;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.RuleChain;
import org.jvnet.hudson.test.Issue;
import org.jvnet.hudson.test.LoggerRule;

import static io.jenkins.plugins.casc.misc.Util.assertLogContains;
import static io.jenkins.plugins.casc.misc.Util.assertNotInLog;
import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.CoreMatchers.not;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThat;

public class MailExtTest {

public JenkinsConfiguredWithCodeRule j = new JenkinsConfiguredWithCodeRule();
public LoggerRule logging = new LoggerRule();

@Rule
public RuleChain chain= RuleChain
.outerRule(logging.record(Logger.getLogger(Attribute.class.getName()), Level.INFO).capture(2048))
.around(j);

private static final String SMTP_PASSWORD = "myPassword";

@Test
@ConfiguredWithCode("MailExtTest.yml")
@Issue("SECURITY-1404")
public void shouldNotExportOrLogCredentials() throws Exception {
assertEquals(SMTP_PASSWORD, ExtendedEmailPublisher.descriptor().getSmtpPassword().getPlainText());
assertLogContains(logging, "smtpPassword =");
assertNotInLog(logging, SMTP_PASSWORD);

// Verify that the password does not get exported
String exportedConfig = j.exportToString(false);
assertThat("No entry was exported for SMTP credentials", exportedConfig, containsString("smtpPassword"));
assertThat("There should be no SMTP password in the exported YAML", exportedConfig, not(containsString(SMTP_PASSWORD)));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
package io.jenkins.plugins.casc;

import com.cloudbees.jenkins.plugins.sshcredentials.impl.BasicSSHUserPrivateKey;
import com.cloudbees.plugins.credentials.Credentials;
import com.cloudbees.plugins.credentials.CredentialsProvider;
import com.cloudbees.plugins.credentials.common.StandardUsernamePasswordCredentials;
import io.jenkins.plugins.casc.misc.ConfiguredWithCode;
import io.jenkins.plugins.casc.misc.JenkinsConfiguredWithCodeRule;
import java.util.Collections;
import java.util.List;
import java.util.logging.Level;
import jenkins.model.Jenkins;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.RuleChain;
import org.jvnet.hudson.test.Issue;
import org.jvnet.hudson.test.LoggerRule;

import static io.jenkins.plugins.casc.misc.Util.assertNotInLog;
import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.CoreMatchers.not;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThat;

/**
* Integration tests for the SSH Credentials Plugin.
*/
public class SSHCredentialsTest {

public JenkinsConfiguredWithCodeRule j = new JenkinsConfiguredWithCodeRule();
public LoggerRule logging = new LoggerRule();

@Rule
public RuleChain chain= RuleChain
.outerRule(logging.record("io.jenkins.plugins.casc.Attribute", Level.INFO).capture(2048))
.around(j);

private static final String CREDENTIALS_PASSWORD = "password-of-userid";
private static final String PRIVATE_KEY = "sp0ds9d+skkfjf";

@Test
@ConfiguredWithCode("SSHCredentialsTest.yml")
@Issue("SECURITY-1279")
public void shouldNotExportOrLogCredentials() throws Exception {
StandardUsernamePasswordCredentials creds = getCredentials(StandardUsernamePasswordCredentials.class);
assertEquals(CREDENTIALS_PASSWORD, creds.getPassword().getPlainText());
assertNotInLog(logging, CREDENTIALS_PASSWORD);

BasicSSHUserPrivateKey certKey = getCredentials(BasicSSHUserPrivateKey.class);
assertEquals(PRIVATE_KEY, certKey.getPrivateKey());
assertNotInLog(logging, PRIVATE_KEY);

// Verify that the password does not get exported
String exportedConfig = j.exportToString(false);
assertThat("There should be no password in the exported YAML", exportedConfig, not(containsString(CREDENTIALS_PASSWORD)));
assertThat("There should be no private key in the exported YAML", exportedConfig, not(containsString(PRIVATE_KEY)));
}

private <T extends Credentials> T getCredentials(Class<T> clazz) {
List<T> creds = CredentialsProvider.lookupCredentials(
clazz, Jenkins.getInstanceOrNull(),
null, Collections.emptyList());
assertEquals(1, creds.size());
return (T)creds.get(0);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
unclassified:
extendedEmailPublisher:
smtpUsername: email@acmecorp.com
smtpPassword: myPassword
defaultContentType: text/plain
defaultSubject: "Build $BUILD_NUMBER - $BUILD_STATUS"
defaultBody: "Check console output at $BUILD_URL"
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
jenkins:
systemMessage: Jenkins with SSH Credentials for JCasC test

credentials:
system:
domainCredentials:
- credentials:
- usernamePassword:
scope: SYSTEM
id: "userid"
username: "username-of-userid"
password: "password-of-userid"
- basicSSHUserPrivateKey:
scope: SYSTEM
id: "userid2"
username: "username-of-userid2"
passphrase: "passphrase-of-userid2"
description: "the description of userid2"
privateKeySource:
directEntry:
privateKey: "sp0ds9d+skkfjf"
Loading

0 comments on commit 73afe3c

Please sign in to comment.