Skip to content
Open
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
Original file line number Diff line number Diff line change
Expand Up @@ -40,14 +40,17 @@ public static Optional<StandardCredentials> create(String arn, String name, Stri
final String type = tags.getOrDefault(Tags.type, "");
final String username = tags.getOrDefault(Tags.username, "");
final String filename = tags.getOrDefault(Tags.filename, name);
final Boolean maskUsername = tags.getOrDefault(Tags.maskUsername, "").equalsIgnoreCase("false")
? false
: true;

switch (type) {
case Type.string:
return Optional.of(new AwsStringCredentials(name, description, new SecretSupplier(client, arn)));
case Type.usernamePassword:
return Optional.of(new AwsUsernamePasswordCredentials(name, description, new SecretSupplier(client, arn), username));
return Optional.of(new AwsUsernamePasswordCredentials(name, description, new SecretSupplier(client, arn), username, maskUsername));
case Type.sshUserPrivateKey:
return Optional.of(new AwsSshUserPrivateKey(name, description, new StringSupplier(client, arn), username));
return Optional.of(new AwsSshUserPrivateKey(name, description, new StringSupplier(client, arn), username, maskUsername));
case Type.certificate:
return Optional.of(new AwsCertificateCredentials(name, description, new SecretBytesSupplier(client, arn)));
case Type.file:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ public abstract class Tags {
public static final String filename = namespace + "filename";
public static final String type = namespace + "type";
public static final String username = namespace + "username";
public static final String maskUsername = namespace + "maskUsername";

private Tags() {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,13 @@ public class AwsSshUserPrivateKey extends BaseStandardCredentials implements SSH

private final Supplier<String> privateKey;
private final String username;
private final Boolean maskUsername;

public AwsSshUserPrivateKey(String id, String description, Supplier<String> privateKey, String username) {
public AwsSshUserPrivateKey(String id, String description, Supplier<String> privateKey, String username, Boolean maskUsername) {
super(id, description);
this.privateKey = privateKey;
this.username = username;
this.maskUsername = maskUsername;
}

@NonNull
Expand All @@ -38,6 +40,11 @@ public Secret getPassphrase() {
return NO_PASSPHRASE;
}

@Override
public boolean isUsernameSecret() {
return maskUsername;
}

@NonNull
@Override
public List<String> getPrivateKeys() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ public Class<AwsSshUserPrivateKey> type() {

@Override
public AwsSshUserPrivateKey snapshot(AwsSshUserPrivateKey credential) {
return new AwsSshUserPrivateKey(credential.getId(), credential.getDescription(), new StringSnapshot(credential.getPrivateKey()), credential.getUsername());
return new AwsSshUserPrivateKey(credential.getId(), credential.getDescription(), new StringSnapshot(credential.getPrivateKey()), credential.getUsername(), credential.isUsernameSecret());
}

private static class StringSnapshot extends Snapshot<String> {
Expand All @@ -23,4 +23,3 @@ private static class StringSnapshot extends Snapshot<String> {
}
}
}

Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,13 @@ public class AwsUsernamePasswordCredentials extends BaseStandardCredentials impl

private final Supplier<Secret> password;
private final String username;
private final Boolean maskUsername;

public AwsUsernamePasswordCredentials(String id, String description, Supplier<Secret> password, String username) {
public AwsUsernamePasswordCredentials(String id, String description, Supplier<Secret> password, String username, Boolean maskUsername) {
super(id, description);
this.password = password;
this.username = username;
this.maskUsername = maskUsername;
}

@NonNull
Expand All @@ -35,6 +37,11 @@ public String getUsername() {
return username;
}

@Override
public boolean isUsernameSecret() {
return maskUsername;
}

@Extension
@SuppressWarnings("unused")
public static class DescriptorImpl extends BaseStandardCredentialsDescriptor {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ public Class<AwsUsernamePasswordCredentials> type() {

@Override
public AwsUsernamePasswordCredentials snapshot(AwsUsernamePasswordCredentials credential) {
return new AwsUsernamePasswordCredentials(credential.getId(), credential.getDescription(), new SecretSnapshot(credential.getPassword()), credential.getUsername());
return new AwsUsernamePasswordCredentials(credential.getId(), credential.getDescription(), new SecretSnapshot(credential.getPassword()), credential.getUsername(), credential.isUsernameSecret());
}

private static class SecretSnapshot extends Snapshot<Secret> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ public class SSHUserPrivateKeyIT implements CredentialsTests {
@ConfiguredWithCode(value = "/integration.yml")
public void shouldSupportListView() {
// Given
final var secret = createSshUserPrivateKeySecret(USERNAME, PRIVATE_KEY);
final var secret = createSshUserPrivateKeySecret(USERNAME, PRIVATE_KEY, true);

// When
final var credentialList = jenkins.getCredentials().list(SSHUserPrivateKey.class);
Expand All @@ -45,11 +45,25 @@ public void shouldSupportListView() {
.containsOption(secret.getName(), secret.getName());
}

@Test
@ConfiguredWithCode(value = "/integration.yml")
public void shouldSupportListViewUnmasked() {
// Given
final var secret = createSshUserPrivateKeySecret(USERNAME, PRIVATE_KEY, false);

// When
final var credentialList = jenkins.getCredentials().list(SSHUserPrivateKey.class);

// Then
assertThat(credentialList)
.containsOption(USERNAME, secret.getName());
}

@Test
@ConfiguredWithCode(value = "/integration.yml")
public void shouldHaveId() {
// Given
final var secret = createSshUserPrivateKeySecret(USERNAME, PRIVATE_KEY);
final var secret = createSshUserPrivateKeySecret(USERNAME, PRIVATE_KEY, true);

// When
final var credential = lookup(SSHUserPrivateKey.class, secret.getName());
Expand All @@ -63,7 +77,7 @@ public void shouldHaveId() {
@ConfiguredWithCode(value = "/integration.yml")
public void shouldHaveUsername() {
// Given
final var secret = createSshUserPrivateKeySecret(USERNAME, PRIVATE_KEY);
final var secret = createSshUserPrivateKeySecret(USERNAME, PRIVATE_KEY, true);

// When
final var credential = lookup(SSHUserPrivateKey.class, secret.getName());
Expand All @@ -77,7 +91,7 @@ public void shouldHaveUsername() {
@ConfiguredWithCode(value = "/integration.yml")
public void shouldHavePrivateKey() {
// Given
final var secret = createSshUserPrivateKeySecret(USERNAME, PRIVATE_KEY);
final var secret = createSshUserPrivateKeySecret(USERNAME, PRIVATE_KEY, true);

// When
final var credential = lookup(SSHUserPrivateKey.class, secret.getName());
Expand All @@ -91,7 +105,7 @@ public void shouldHavePrivateKey() {
@ConfiguredWithCode(value = "/integration.yml")
public void shouldHaveEmptyPassphrase() {
// Given
final var secret = createSshUserPrivateKeySecret(USERNAME, PRIVATE_KEY);
final var secret = createSshUserPrivateKeySecret(USERNAME, PRIVATE_KEY, true);

// When
final var credential = lookup(SSHUserPrivateKey.class, secret.getName());
Expand All @@ -104,7 +118,7 @@ public void shouldHaveEmptyPassphrase() {
@Test
@ConfiguredWithCode(value = "/integration.yml")
public void shouldHaveDescriptorIcon() {
final var secret = createSshUserPrivateKeySecret(USERNAME, PRIVATE_KEY);
final var secret = createSshUserPrivateKeySecret(USERNAME, PRIVATE_KEY, true);

final var ours = lookup(SSHUserPrivateKey.class, secret.getName());

Expand All @@ -118,7 +132,7 @@ public void shouldHaveDescriptorIcon() {
@ConfiguredWithCode(value = "/integration.yml")
public void shouldSupportWithCredentialsBinding() {
// Given
final var secret = createSshUserPrivateKeySecret(USERNAME, PRIVATE_KEY);
final var secret = createSshUserPrivateKeySecret(USERNAME, PRIVATE_KEY, true);

// When
final var run = runPipeline("",
Expand All @@ -134,11 +148,31 @@ public void shouldSupportWithCredentialsBinding() {
.hasLogContaining("Credential: {username: ****, keyFile: ****}");
}

@Test
@ConfiguredWithCode(value = "/integration.yml")
public void shouldSupportWithCredentialsBindingUnmasked() {
// Given
final var secret = createSshUserPrivateKeySecret(USERNAME, PRIVATE_KEY, false);

// When
final var run = runPipeline("",
"node {",
" withCredentials([sshUserPrivateKey(credentialsId: '" + secret.getName() + "', keyFileVariable: 'KEYFILE', usernameVariable: 'USERNAME')]) {",
" echo \"Credential: {username: $USERNAME, keyFile: $KEYFILE}\"",
" }",
"}");

// Then
assertThat(run)
.hasResult(hudson.model.Result.SUCCESS)
.hasLogContaining("Credential: {username: joe, keyFile: ****}");
}

@Test
@ConfiguredWithCode(value = "/integration.yml")
public void shouldSupportEnvironmentBinding() {
// Given
final var secret = createSshUserPrivateKeySecret(USERNAME, PRIVATE_KEY);
final var secret = createSshUserPrivateKeySecret(USERNAME, PRIVATE_KEY, true);

// When
final var run = runPipeline("",
Expand All @@ -162,11 +196,39 @@ public void shouldSupportEnvironmentBinding() {
.hasLogContaining("{variable: ****, username: ****}");
}

@Test
@ConfiguredWithCode(value = "/integration.yml")
public void shouldSupportEnvironmentBindingUnmasked() {
// Given
final var secret = createSshUserPrivateKeySecret(USERNAME, PRIVATE_KEY, false);

// When
final var run = runPipeline("",
"pipeline {",
" agent any",
" stages {",
" stage('Example') {",
" environment {",
" FOO = credentials('" + secret.getName() + "')",
" }",
" steps {",
" echo \"{variable: $FOO, username: $FOO_USR}\"",
" }",
" }",
" }",
"}");

// Then
assertThat(run)
.hasResult(hudson.model.Result.SUCCESS)
.hasLogContaining("{variable: ****, username: joe}");
}

@Test
@ConfiguredWithCode(value = "/integration.yml")
public void shouldSupportSnapshots() {
// Given
final CreateSecretResult foo = createSshUserPrivateKeySecret(USERNAME, PRIVATE_KEY);
final CreateSecretResult foo = createSshUserPrivateKeySecret(USERNAME, PRIVATE_KEY, true);
final SSHUserPrivateKey before = lookup(SSHUserPrivateKey.class, foo.getName());

// When
Expand All @@ -180,10 +242,11 @@ public void shouldSupportSnapshots() {
.hasId(before.getId());
}

private CreateSecretResult createSshUserPrivateKeySecret(String username, String privateKey) {
private CreateSecretResult createSshUserPrivateKeySecret(String username, String privateKey, Boolean maskUsername) {
final var tags = List.of(
AwsTags.type(Type.sshUserPrivateKey),
AwsTags.username(username));
AwsTags.username(username),
AwsTags.maskUsername(String.valueOf(maskUsername)));

final var request = new CreateSecretRequest()
.withName(CredentialNames.random())
Expand Down
Loading