From 3a77b9ed8d3cf5798bcee70f18b2f724717ce9a7 Mon Sep 17 00:00:00 2001 From: Damian Jesionek Date: Fri, 13 Mar 2020 16:59:00 +0100 Subject: [PATCH 01/45] Main places now manage private key through ssh-credentials plugin --- pom.xml | 14 ++++++ .../hudson/plugins/ec2/AmazonEC2Cloud.java | 45 +++++++++++++++---- .../java/hudson/plugins/ec2/EC2Cloud.java | 39 +++++++++++----- .../ec2/AmazonEC2Cloud/config-entries.jelly | 11 +++-- 4 files changed, 87 insertions(+), 22 deletions(-) diff --git a/pom.xml b/pom.xml index d68f8528e..d4cd0409f 100644 --- a/pom.xml +++ b/pom.xml @@ -101,11 +101,25 @@ THE SOFTWARE. + + + org.jenkins-ci.plugins + credentials + 2.1.17 + + org.jenkins-ci.plugins aws-credentials 1.11 + + + org.jenkins-ci.plugins + ssh-credentials + 1.14 + + org.jenkins-ci.plugins bouncycastle-api diff --git a/src/main/java/hudson/plugins/ec2/AmazonEC2Cloud.java b/src/main/java/hudson/plugins/ec2/AmazonEC2Cloud.java index c04304f6e..017ef88fe 100644 --- a/src/main/java/hudson/plugins/ec2/AmazonEC2Cloud.java +++ b/src/main/java/hudson/plugins/ec2/AmazonEC2Cloud.java @@ -24,10 +24,17 @@ package hudson.plugins.ec2; import com.amazonaws.SdkClientException; +import com.cloudbees.jenkins.plugins.sshcredentials.impl.BasicSSHUserPrivateKey; +import com.cloudbees.plugins.credentials.CredentialsMatcher; +import com.cloudbees.plugins.credentials.CredentialsProvider; +import com.cloudbees.plugins.credentials.common.StandardListBoxModel; +import com.cloudbees.plugins.credentials.domains.DomainRequirement; import com.google.common.annotations.VisibleForTesting; import hudson.Extension; import hudson.Util; import hudson.model.Failure; +import hudson.model.Item; +import hudson.model.ItemGroup; import hudson.plugins.ec2.util.AmazonEC2Factory; import hudson.slaves.Cloud; import hudson.util.FormValidation; @@ -38,15 +45,13 @@ import java.net.URL; import java.util.List; import java.util.Locale; +import java.util.Objects; import javax.annotation.Nullable; import javax.servlet.ServletException; import jenkins.model.Jenkins; -import org.kohsuke.stapler.DataBoundConstructor; -import org.kohsuke.stapler.DataBoundSetter; -import org.kohsuke.stapler.QueryParameter; -import org.kohsuke.stapler.StaplerResponse; +import org.kohsuke.stapler.*; import com.amazonaws.auth.AWSCredentialsProvider; import com.amazonaws.services.ec2.AmazonEC2; @@ -70,8 +75,8 @@ public class AmazonEC2Cloud extends EC2Cloud { private boolean noDelayProvisioning; @DataBoundConstructor - public AmazonEC2Cloud(String cloudName, boolean useInstanceProfileForCredentials, String credentialsId, String region, String privateKey, String instanceCapStr, List templates, String roleArn, String roleSessionName) { - super(createCloudId(cloudName), useInstanceProfileForCredentials, credentialsId, privateKey, instanceCapStr, templates, roleArn, roleSessionName); + public AmazonEC2Cloud(String cloudName, boolean useInstanceProfileForCredentials, String credentialsId, String region, String sshKeysCredentialsId, String instanceCapStr, List templates, String roleArn, String roleSessionName) { + super(createCloudId(cloudName), useInstanceProfileForCredentials, credentialsId, sshKeysCredentialsId, instanceCapStr, templates, roleArn, roleSessionName); this.region = region; } @@ -187,6 +192,30 @@ public ListBoxModel doFillRegionItems( return model; } + public ListBoxModel doFillSshKeysCredentialsIdItems( + @AncestorInPath Item item, + @QueryParameter String sshKeysCredentialsId + ) { + + //CredentialsProvider.lookupCredentials(BasicSSHUserPrivateKey.class,) + + StandardListBoxModel result = new StandardListBoxModel(); + if (item == null) { + if (!Jenkins.get().hasPermission(Jenkins.ADMINISTER)) { + return result.includeCurrentValue(sshKeysCredentialsId); + } + } else { + if (!item.hasPermission(Item.EXTENDED_READ) + && !item.hasPermission(CredentialsProvider.USE_ITEM)) { + return result.includeCurrentValue(sshKeysCredentialsId); + } + } + + return result + .includeMatchingAs(null, (ItemGroup) null, BasicSSHUserPrivateKey.class, null, null) + .includeCurrentValue(sshKeysCredentialsId); + } + // Will use the alternate EC2 endpoint if provided by the UI (via a @QueryParameter field), or use the default // value if not specified. @VisibleForTesting @@ -203,7 +232,7 @@ public FormValidation doTestConnection( @QueryParameter String region, @QueryParameter boolean useInstanceProfileForCredentials, @QueryParameter String credentialsId, - @QueryParameter String privateKey, + @QueryParameter String sshKeysCredentialsId, @QueryParameter String roleArn, @QueryParameter String roleSessionName) @@ -213,7 +242,7 @@ public FormValidation doTestConnection( region = DEFAULT_EC2_HOST; } - return super.doTestConnection(getEc2EndpointUrl(region), useInstanceProfileForCredentials, credentialsId, privateKey, roleArn, roleSessionName, region); + return super.doTestConnection(getEc2EndpointUrl(region), useInstanceProfileForCredentials, credentialsId, sshKeysCredentialsId, roleArn, roleSessionName, region); } } } diff --git a/src/main/java/hudson/plugins/ec2/EC2Cloud.java b/src/main/java/hudson/plugins/ec2/EC2Cloud.java index ce042d76b..833b7b4f3 100644 --- a/src/main/java/hudson/plugins/ec2/EC2Cloud.java +++ b/src/main/java/hudson/plugins/ec2/EC2Cloud.java @@ -25,6 +25,7 @@ import com.amazonaws.services.securitytoken.AWSSecurityTokenServiceClientBuilder; import com.cloudbees.jenkins.plugins.awscredentials.AWSCredentialsImpl; import com.cloudbees.jenkins.plugins.awscredentials.AmazonWebServicesCredentials; +import com.cloudbees.jenkins.plugins.sshcredentials.impl.BasicSSHUserPrivateKey; import com.cloudbees.plugins.credentials.Credentials; import com.cloudbees.plugins.credentials.CredentialsMatchers; import com.cloudbees.plugins.credentials.CredentialsProvider; @@ -33,6 +34,7 @@ import com.cloudbees.plugins.credentials.SystemCredentialsProvider; import com.cloudbees.plugins.credentials.common.StandardListBoxModel; import com.cloudbees.plugins.credentials.domains.Domain; +import hudson.model.*; import hudson.plugins.ec2.util.AmazonEC2Factory; import hudson.security.ACL; @@ -66,8 +68,6 @@ import javax.servlet.ServletException; import hudson.Extension; -import hudson.model.PeriodicWork; -import hudson.model.TaskListener; import hudson.security.Permission; import hudson.util.ListBoxModel; import jenkins.model.Jenkins; @@ -105,10 +105,6 @@ import com.amazonaws.services.s3.model.GeneratePresignedUrlRequest; import hudson.ProxyConfiguration; -import hudson.model.Computer; -import hudson.model.Descriptor; -import hudson.model.Label; -import hudson.model.Node; import hudson.slaves.Cloud; import hudson.slaves.NodeProvisioner.PlannedNode; import hudson.util.FormValidation; @@ -170,14 +166,15 @@ public abstract class EC2Cloud extends Cloud { private transient volatile AmazonEC2 connection; - protected EC2Cloud(String id, boolean useInstanceProfileForCredentials, String credentialsId, String privateKey, + protected EC2Cloud(String id, boolean useInstanceProfileForCredentials, String credentialsId, String sshKeysCredentialsId, String instanceCapStr, List templates, String roleArn, String roleSessionName) { super(id); this.useInstanceProfileForCredentials = useInstanceProfileForCredentials; this.roleArn = roleArn; this.roleSessionName = roleSessionName; this.credentialsId = credentialsId; - this.privateKey = new EC2PrivateKey(privateKey); + + this.privateKey = new EC2PrivateKey(getSshCredential(sshKeysCredentialsId).getPrivateKey()); ///'################################################################################# TODO if (templates == null) { this.templates = Collections.emptyList(); @@ -896,6 +893,16 @@ public static URL checkEndPoint(String url) throws FormValidation { } } + private static BasicSSHUserPrivateKey getSshCredential(String id){ + return CredentialsMatchers.firstOrNull( + CredentialsProvider.lookupCredentials( + BasicSSHUserPrivateKey.class, // (1) + (ItemGroup) null, + null, + Collections.emptyList()), + CredentialsMatchers.withId(id)); + } + public static abstract class DescriptorImpl extends Descriptor { public InstanceType[] getInstanceTypes() { @@ -914,9 +921,16 @@ public FormValidation doCheckUseInstanceProfileForCredentials(@QueryParameter bo return FormValidation.ok(); } - public FormValidation doCheckPrivateKey(@QueryParameter String value) throws IOException, ServletException { + public FormValidation doCheckSshKeysCredentialsId(@QueryParameter String value) throws IOException, ServletException { + + if (value == null || value.isEmpty()){ + return FormValidation.error("No ssh credentials selected"); + } + + String privateKey = getSshCredential(value).getPrivateKey(); + boolean hasStart = false, hasEnd = false; - BufferedReader br = new BufferedReader(new StringReader(value)); + BufferedReader br = new BufferedReader(new StringReader(privateKey)); String line; while ((line = br.readLine()) != null) { if (line.equals("-----BEGIN RSA PRIVATE KEY-----")) @@ -932,10 +946,13 @@ public FormValidation doCheckPrivateKey(@QueryParameter String value) throws IOE return FormValidation.ok(); } - protected FormValidation doTestConnection(URL ec2endpoint, boolean useInstanceProfileForCredentials, String credentialsId, String privateKey, String roleArn, String roleSessionName, String region) + protected FormValidation doTestConnection(URL ec2endpoint, boolean useInstanceProfileForCredentials, String credentialsId, String sshKeysCredentialsId, String roleArn, String roleSessionName, String region) throws IOException, ServletException { Jenkins.get().checkPermission(Jenkins.ADMINISTER); try { + + String privateKey = getSshCredential(sshKeysCredentialsId).getPrivateKey(); + AWSCredentialsProvider credentialsProvider = createCredentialsProvider(useInstanceProfileForCredentials, credentialsId, roleArn, roleSessionName, region); AmazonEC2 ec2 = AmazonEC2Factory.getInstance().connect(credentialsProvider, ec2endpoint); ec2.describeInstances(); diff --git a/src/main/resources/hudson/plugins/ec2/AmazonEC2Cloud/config-entries.jelly b/src/main/resources/hudson/plugins/ec2/AmazonEC2Cloud/config-entries.jelly index e41b46992..b1b9e8676 100644 --- a/src/main/resources/hudson/plugins/ec2/AmazonEC2Cloud/config-entries.jelly +++ b/src/main/resources/hudson/plugins/ec2/AmazonEC2Cloud/config-entries.jelly @@ -36,9 +36,14 @@ THE SOFTWARE. - + + + + + + @@ -53,5 +58,5 @@ THE SOFTWARE. - + From 4aac4c01abe80e5462f7e8ed88e6b91e1e5fb9d3 Mon Sep 17 00:00:00 2001 From: Damian Jesionek Date: Mon, 16 Mar 2020 19:48:12 +0100 Subject: [PATCH 02/45] Now credentials id is being peristed instead of private key itself --- src/main/java/hudson/plugins/ec2/EC2Cloud.java | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/src/main/java/hudson/plugins/ec2/EC2Cloud.java b/src/main/java/hudson/plugins/ec2/EC2Cloud.java index 833b7b4f3..3d3725708 100644 --- a/src/main/java/hudson/plugins/ec2/EC2Cloud.java +++ b/src/main/java/hudson/plugins/ec2/EC2Cloud.java @@ -153,7 +153,9 @@ public abstract class EC2Cloud extends Cloud { @Deprecated private transient Secret secretKey; - private final EC2PrivateKey privateKey; + private String sshKeysCredentialsId; + + private transient EC2PrivateKey privateKey; /** * Upper bound on how many instances we may provision. @@ -173,8 +175,7 @@ protected EC2Cloud(String id, boolean useInstanceProfileForCredentials, String c this.roleArn = roleArn; this.roleSessionName = roleSessionName; this.credentialsId = credentialsId; - - this.privateKey = new EC2PrivateKey(getSshCredential(sshKeysCredentialsId).getPrivateKey()); ///'################################################################################# TODO + this.sshKeysCredentialsId = sshKeysCredentialsId; if (templates == null) { this.templates = Collections.emptyList(); @@ -197,6 +198,11 @@ protected EC2Cloud(String id, boolean useInstanceProfileForCredentials, String c protected Object readResolve() { this.slaveCountingLock = new ReentrantLock(); + + if (this.sshKeysCredentialsId != null) + this.privateKey = new EC2PrivateKey(getSshCredential(sshKeysCredentialsId).getPrivateKey()); ///'################################################################################# TODO + + for (SlaveTemplate t : templates) t.parent = this; if (this.accessId != null && this.secretKey != null && credentialsId == null) { @@ -262,6 +268,10 @@ public String getCredentialsId() { return credentialsId; } + public String getSshKeysCredentialsId() { + return sshKeysCredentialsId; + } + public EC2PrivateKey getPrivateKey() { return privateKey; } From aecb6bcdc7400653b5895cafaa25d4412bb10971 Mon Sep 17 00:00:00 2001 From: Damian Jesionek Date: Fri, 13 Mar 2020 16:59:00 +0100 Subject: [PATCH 03/45] [JENKINS-56927] Main places now manage private key through ssh-credentials plugin --- pom.xml | 14 ++++++ .../hudson/plugins/ec2/AmazonEC2Cloud.java | 45 +++++++++++++++---- .../java/hudson/plugins/ec2/EC2Cloud.java | 39 +++++++++++----- .../ec2/AmazonEC2Cloud/config-entries.jelly | 11 +++-- 4 files changed, 87 insertions(+), 22 deletions(-) diff --git a/pom.xml b/pom.xml index d68f8528e..d4cd0409f 100644 --- a/pom.xml +++ b/pom.xml @@ -101,11 +101,25 @@ THE SOFTWARE. + + + org.jenkins-ci.plugins + credentials + 2.1.17 + + org.jenkins-ci.plugins aws-credentials 1.11 + + + org.jenkins-ci.plugins + ssh-credentials + 1.14 + + org.jenkins-ci.plugins bouncycastle-api diff --git a/src/main/java/hudson/plugins/ec2/AmazonEC2Cloud.java b/src/main/java/hudson/plugins/ec2/AmazonEC2Cloud.java index c04304f6e..017ef88fe 100644 --- a/src/main/java/hudson/plugins/ec2/AmazonEC2Cloud.java +++ b/src/main/java/hudson/plugins/ec2/AmazonEC2Cloud.java @@ -24,10 +24,17 @@ package hudson.plugins.ec2; import com.amazonaws.SdkClientException; +import com.cloudbees.jenkins.plugins.sshcredentials.impl.BasicSSHUserPrivateKey; +import com.cloudbees.plugins.credentials.CredentialsMatcher; +import com.cloudbees.plugins.credentials.CredentialsProvider; +import com.cloudbees.plugins.credentials.common.StandardListBoxModel; +import com.cloudbees.plugins.credentials.domains.DomainRequirement; import com.google.common.annotations.VisibleForTesting; import hudson.Extension; import hudson.Util; import hudson.model.Failure; +import hudson.model.Item; +import hudson.model.ItemGroup; import hudson.plugins.ec2.util.AmazonEC2Factory; import hudson.slaves.Cloud; import hudson.util.FormValidation; @@ -38,15 +45,13 @@ import java.net.URL; import java.util.List; import java.util.Locale; +import java.util.Objects; import javax.annotation.Nullable; import javax.servlet.ServletException; import jenkins.model.Jenkins; -import org.kohsuke.stapler.DataBoundConstructor; -import org.kohsuke.stapler.DataBoundSetter; -import org.kohsuke.stapler.QueryParameter; -import org.kohsuke.stapler.StaplerResponse; +import org.kohsuke.stapler.*; import com.amazonaws.auth.AWSCredentialsProvider; import com.amazonaws.services.ec2.AmazonEC2; @@ -70,8 +75,8 @@ public class AmazonEC2Cloud extends EC2Cloud { private boolean noDelayProvisioning; @DataBoundConstructor - public AmazonEC2Cloud(String cloudName, boolean useInstanceProfileForCredentials, String credentialsId, String region, String privateKey, String instanceCapStr, List templates, String roleArn, String roleSessionName) { - super(createCloudId(cloudName), useInstanceProfileForCredentials, credentialsId, privateKey, instanceCapStr, templates, roleArn, roleSessionName); + public AmazonEC2Cloud(String cloudName, boolean useInstanceProfileForCredentials, String credentialsId, String region, String sshKeysCredentialsId, String instanceCapStr, List templates, String roleArn, String roleSessionName) { + super(createCloudId(cloudName), useInstanceProfileForCredentials, credentialsId, sshKeysCredentialsId, instanceCapStr, templates, roleArn, roleSessionName); this.region = region; } @@ -187,6 +192,30 @@ public ListBoxModel doFillRegionItems( return model; } + public ListBoxModel doFillSshKeysCredentialsIdItems( + @AncestorInPath Item item, + @QueryParameter String sshKeysCredentialsId + ) { + + //CredentialsProvider.lookupCredentials(BasicSSHUserPrivateKey.class,) + + StandardListBoxModel result = new StandardListBoxModel(); + if (item == null) { + if (!Jenkins.get().hasPermission(Jenkins.ADMINISTER)) { + return result.includeCurrentValue(sshKeysCredentialsId); + } + } else { + if (!item.hasPermission(Item.EXTENDED_READ) + && !item.hasPermission(CredentialsProvider.USE_ITEM)) { + return result.includeCurrentValue(sshKeysCredentialsId); + } + } + + return result + .includeMatchingAs(null, (ItemGroup) null, BasicSSHUserPrivateKey.class, null, null) + .includeCurrentValue(sshKeysCredentialsId); + } + // Will use the alternate EC2 endpoint if provided by the UI (via a @QueryParameter field), or use the default // value if not specified. @VisibleForTesting @@ -203,7 +232,7 @@ public FormValidation doTestConnection( @QueryParameter String region, @QueryParameter boolean useInstanceProfileForCredentials, @QueryParameter String credentialsId, - @QueryParameter String privateKey, + @QueryParameter String sshKeysCredentialsId, @QueryParameter String roleArn, @QueryParameter String roleSessionName) @@ -213,7 +242,7 @@ public FormValidation doTestConnection( region = DEFAULT_EC2_HOST; } - return super.doTestConnection(getEc2EndpointUrl(region), useInstanceProfileForCredentials, credentialsId, privateKey, roleArn, roleSessionName, region); + return super.doTestConnection(getEc2EndpointUrl(region), useInstanceProfileForCredentials, credentialsId, sshKeysCredentialsId, roleArn, roleSessionName, region); } } } diff --git a/src/main/java/hudson/plugins/ec2/EC2Cloud.java b/src/main/java/hudson/plugins/ec2/EC2Cloud.java index ce042d76b..833b7b4f3 100644 --- a/src/main/java/hudson/plugins/ec2/EC2Cloud.java +++ b/src/main/java/hudson/plugins/ec2/EC2Cloud.java @@ -25,6 +25,7 @@ import com.amazonaws.services.securitytoken.AWSSecurityTokenServiceClientBuilder; import com.cloudbees.jenkins.plugins.awscredentials.AWSCredentialsImpl; import com.cloudbees.jenkins.plugins.awscredentials.AmazonWebServicesCredentials; +import com.cloudbees.jenkins.plugins.sshcredentials.impl.BasicSSHUserPrivateKey; import com.cloudbees.plugins.credentials.Credentials; import com.cloudbees.plugins.credentials.CredentialsMatchers; import com.cloudbees.plugins.credentials.CredentialsProvider; @@ -33,6 +34,7 @@ import com.cloudbees.plugins.credentials.SystemCredentialsProvider; import com.cloudbees.plugins.credentials.common.StandardListBoxModel; import com.cloudbees.plugins.credentials.domains.Domain; +import hudson.model.*; import hudson.plugins.ec2.util.AmazonEC2Factory; import hudson.security.ACL; @@ -66,8 +68,6 @@ import javax.servlet.ServletException; import hudson.Extension; -import hudson.model.PeriodicWork; -import hudson.model.TaskListener; import hudson.security.Permission; import hudson.util.ListBoxModel; import jenkins.model.Jenkins; @@ -105,10 +105,6 @@ import com.amazonaws.services.s3.model.GeneratePresignedUrlRequest; import hudson.ProxyConfiguration; -import hudson.model.Computer; -import hudson.model.Descriptor; -import hudson.model.Label; -import hudson.model.Node; import hudson.slaves.Cloud; import hudson.slaves.NodeProvisioner.PlannedNode; import hudson.util.FormValidation; @@ -170,14 +166,15 @@ public abstract class EC2Cloud extends Cloud { private transient volatile AmazonEC2 connection; - protected EC2Cloud(String id, boolean useInstanceProfileForCredentials, String credentialsId, String privateKey, + protected EC2Cloud(String id, boolean useInstanceProfileForCredentials, String credentialsId, String sshKeysCredentialsId, String instanceCapStr, List templates, String roleArn, String roleSessionName) { super(id); this.useInstanceProfileForCredentials = useInstanceProfileForCredentials; this.roleArn = roleArn; this.roleSessionName = roleSessionName; this.credentialsId = credentialsId; - this.privateKey = new EC2PrivateKey(privateKey); + + this.privateKey = new EC2PrivateKey(getSshCredential(sshKeysCredentialsId).getPrivateKey()); ///'################################################################################# TODO if (templates == null) { this.templates = Collections.emptyList(); @@ -896,6 +893,16 @@ public static URL checkEndPoint(String url) throws FormValidation { } } + private static BasicSSHUserPrivateKey getSshCredential(String id){ + return CredentialsMatchers.firstOrNull( + CredentialsProvider.lookupCredentials( + BasicSSHUserPrivateKey.class, // (1) + (ItemGroup) null, + null, + Collections.emptyList()), + CredentialsMatchers.withId(id)); + } + public static abstract class DescriptorImpl extends Descriptor { public InstanceType[] getInstanceTypes() { @@ -914,9 +921,16 @@ public FormValidation doCheckUseInstanceProfileForCredentials(@QueryParameter bo return FormValidation.ok(); } - public FormValidation doCheckPrivateKey(@QueryParameter String value) throws IOException, ServletException { + public FormValidation doCheckSshKeysCredentialsId(@QueryParameter String value) throws IOException, ServletException { + + if (value == null || value.isEmpty()){ + return FormValidation.error("No ssh credentials selected"); + } + + String privateKey = getSshCredential(value).getPrivateKey(); + boolean hasStart = false, hasEnd = false; - BufferedReader br = new BufferedReader(new StringReader(value)); + BufferedReader br = new BufferedReader(new StringReader(privateKey)); String line; while ((line = br.readLine()) != null) { if (line.equals("-----BEGIN RSA PRIVATE KEY-----")) @@ -932,10 +946,13 @@ public FormValidation doCheckPrivateKey(@QueryParameter String value) throws IOE return FormValidation.ok(); } - protected FormValidation doTestConnection(URL ec2endpoint, boolean useInstanceProfileForCredentials, String credentialsId, String privateKey, String roleArn, String roleSessionName, String region) + protected FormValidation doTestConnection(URL ec2endpoint, boolean useInstanceProfileForCredentials, String credentialsId, String sshKeysCredentialsId, String roleArn, String roleSessionName, String region) throws IOException, ServletException { Jenkins.get().checkPermission(Jenkins.ADMINISTER); try { + + String privateKey = getSshCredential(sshKeysCredentialsId).getPrivateKey(); + AWSCredentialsProvider credentialsProvider = createCredentialsProvider(useInstanceProfileForCredentials, credentialsId, roleArn, roleSessionName, region); AmazonEC2 ec2 = AmazonEC2Factory.getInstance().connect(credentialsProvider, ec2endpoint); ec2.describeInstances(); diff --git a/src/main/resources/hudson/plugins/ec2/AmazonEC2Cloud/config-entries.jelly b/src/main/resources/hudson/plugins/ec2/AmazonEC2Cloud/config-entries.jelly index e41b46992..b1b9e8676 100644 --- a/src/main/resources/hudson/plugins/ec2/AmazonEC2Cloud/config-entries.jelly +++ b/src/main/resources/hudson/plugins/ec2/AmazonEC2Cloud/config-entries.jelly @@ -36,9 +36,14 @@ THE SOFTWARE. - + + + + + + @@ -53,5 +58,5 @@ THE SOFTWARE. - + From 30843098847accad137645f1e2f3535126d199e7 Mon Sep 17 00:00:00 2001 From: Damian Jesionek Date: Mon, 16 Mar 2020 19:48:12 +0100 Subject: [PATCH 04/45] [JENKINS-56927] Now credentials id is being peristed instead of private key itself --- src/main/java/hudson/plugins/ec2/EC2Cloud.java | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/src/main/java/hudson/plugins/ec2/EC2Cloud.java b/src/main/java/hudson/plugins/ec2/EC2Cloud.java index 833b7b4f3..3d3725708 100644 --- a/src/main/java/hudson/plugins/ec2/EC2Cloud.java +++ b/src/main/java/hudson/plugins/ec2/EC2Cloud.java @@ -153,7 +153,9 @@ public abstract class EC2Cloud extends Cloud { @Deprecated private transient Secret secretKey; - private final EC2PrivateKey privateKey; + private String sshKeysCredentialsId; + + private transient EC2PrivateKey privateKey; /** * Upper bound on how many instances we may provision. @@ -173,8 +175,7 @@ protected EC2Cloud(String id, boolean useInstanceProfileForCredentials, String c this.roleArn = roleArn; this.roleSessionName = roleSessionName; this.credentialsId = credentialsId; - - this.privateKey = new EC2PrivateKey(getSshCredential(sshKeysCredentialsId).getPrivateKey()); ///'################################################################################# TODO + this.sshKeysCredentialsId = sshKeysCredentialsId; if (templates == null) { this.templates = Collections.emptyList(); @@ -197,6 +198,11 @@ protected EC2Cloud(String id, boolean useInstanceProfileForCredentials, String c protected Object readResolve() { this.slaveCountingLock = new ReentrantLock(); + + if (this.sshKeysCredentialsId != null) + this.privateKey = new EC2PrivateKey(getSshCredential(sshKeysCredentialsId).getPrivateKey()); ///'################################################################################# TODO + + for (SlaveTemplate t : templates) t.parent = this; if (this.accessId != null && this.secretKey != null && credentialsId == null) { @@ -262,6 +268,10 @@ public String getCredentialsId() { return credentialsId; } + public String getSshKeysCredentialsId() { + return sshKeysCredentialsId; + } + public EC2PrivateKey getPrivateKey() { return privateKey; } From 29ca034d3acf078b15747afa4d096a1809439f12 Mon Sep 17 00:00:00 2001 From: Damian Jesionek Date: Tue, 17 Mar 2020 13:28:59 +0100 Subject: [PATCH 05/45] [JENKINS-56927] First credential migration changes --- .../java/hudson/plugins/ec2/EC2Cloud.java | 33 ++++++++++++------- 1 file changed, 21 insertions(+), 12 deletions(-) diff --git a/src/main/java/hudson/plugins/ec2/EC2Cloud.java b/src/main/java/hudson/plugins/ec2/EC2Cloud.java index 3d3725708..392dbff43 100644 --- a/src/main/java/hudson/plugins/ec2/EC2Cloud.java +++ b/src/main/java/hudson/plugins/ec2/EC2Cloud.java @@ -32,6 +32,7 @@ import com.cloudbees.plugins.credentials.CredentialsScope; import com.cloudbees.plugins.credentials.CredentialsStore; import com.cloudbees.plugins.credentials.SystemCredentialsProvider; +import com.cloudbees.plugins.credentials.common.StandardCredentials; import com.cloudbees.plugins.credentials.common.StandardListBoxModel; import com.cloudbees.plugins.credentials.domains.Domain; import hudson.model.*; @@ -47,15 +48,7 @@ import java.net.MalformedURLException; import java.net.Proxy; import java.net.URL; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.Date; -import java.util.EnumSet; -import java.util.HashSet; -import java.util.List; -import java.util.Set; -import java.util.UUID; +import java.util.*; import java.util.concurrent.Callable; import java.util.concurrent.TimeUnit; import java.util.concurrent.locks.ReentrantLock; @@ -155,7 +148,7 @@ public abstract class EC2Cloud extends Cloud { private String sshKeysCredentialsId; - private transient EC2PrivateKey privateKey; + private EC2PrivateKey privateKey; /** * Upper bound on how many instances we may provision. @@ -199,17 +192,30 @@ protected EC2Cloud(String id, boolean useInstanceProfileForCredentials, String c protected Object readResolve() { this.slaveCountingLock = new ReentrantLock(); - if (this.sshKeysCredentialsId != null) - this.privateKey = new EC2PrivateKey(getSshCredential(sshKeysCredentialsId).getPrivateKey()); ///'################################################################################# TODO + if (this.sshKeysCredentialsId == null && this.privateKey != null){ + Optional keyCredential = SystemCredentialsProvider.getInstance().getCredentials() + .stream() + .filter((cred) -> cred instanceof BasicSSHUserPrivateKey) + .filter((cred) -> ((BasicSSHUserPrivateKey)cred).getPrivateKey().trim().equals(this.privateKey.getPrivateKey().trim())) + .map(cred -> (BasicSSHUserPrivateKey)cred) + .findFirst(); + System.out.println("Test"); + + } if (this.sshKeysCredentialsId != null) { + this.privateKey = new EC2PrivateKey(getSshCredential(sshKeysCredentialsId).getPrivateKey()); ///'################################################################################# TODO + } for (SlaveTemplate t : templates) t.parent = this; + + if (this.accessId != null && this.secretKey != null && credentialsId == null) { String secretKeyEncryptedValue = this.secretKey.getEncryptedValue(); // REPLACE this.accessId and this.secretId by a credential SystemCredentialsProvider systemCredentialsProvider = SystemCredentialsProvider.getInstance(); + // ITERATE ON EXISTING CREDS AND DON'T CREATE IF EXIST for (Credentials credentials: systemCredentialsProvider.getCredentials()) { if (credentials instanceof AmazonWebServicesCredentials) { @@ -225,6 +231,7 @@ protected Object readResolve() { } } } + // CREATE for (CredentialsStore credentialsStore: CredentialsProvider.lookupStores(Jenkins.get())) { @@ -246,9 +253,11 @@ protected Object readResolve() { } } + // PROBLEM, GLOBAL STORE NOT FOUND LOGGER.log(Level.WARNING, "EC2 Plugin could not migrate credentials to the Jenkins Global Credentials Store, EC2 Plugin for cloud {0} must be manually reconfigured", getDisplayName()); } + return this; } From e06e13440aca30b13d84d379b0c79227aaa426f2 Mon Sep 17 00:00:00 2001 From: Damian Jesionek Date: Tue, 17 Mar 2020 14:15:37 +0100 Subject: [PATCH 06/45] [JENKINS-56927] Refactored migration code a bit and added migration of ssh keys --- .../java/hudson/plugins/ec2/EC2Cloud.java | 74 ++++++++++++------- 1 file changed, 48 insertions(+), 26 deletions(-) diff --git a/src/main/java/hudson/plugins/ec2/EC2Cloud.java b/src/main/java/hudson/plugins/ec2/EC2Cloud.java index 392dbff43..4d136495e 100644 --- a/src/main/java/hudson/plugins/ec2/EC2Cloud.java +++ b/src/main/java/hudson/plugins/ec2/EC2Cloud.java @@ -32,9 +32,9 @@ import com.cloudbees.plugins.credentials.CredentialsScope; import com.cloudbees.plugins.credentials.CredentialsStore; import com.cloudbees.plugins.credentials.SystemCredentialsProvider; -import com.cloudbees.plugins.credentials.common.StandardCredentials; import com.cloudbees.plugins.credentials.common.StandardListBoxModel; import com.cloudbees.plugins.credentials.domains.Domain; +import edu.umd.cs.findbugs.annotations.NonNull; import hudson.model.*; import hudson.plugins.ec2.util.AmazonEC2Factory; import hudson.security.ACL; @@ -61,7 +61,6 @@ import javax.servlet.ServletException; import hudson.Extension; -import hudson.security.Permission; import hudson.util.ListBoxModel; import jenkins.model.Jenkins; import jenkins.model.JenkinsLocationConfiguration; @@ -79,7 +78,6 @@ import com.amazonaws.auth.InstanceProfileCredentialsProvider; import com.amazonaws.auth.AWSStaticCredentialsProvider; import com.amazonaws.services.ec2.AmazonEC2; -import com.amazonaws.services.ec2.model.CreateKeyPairRequest; import com.amazonaws.services.ec2.model.DescribeSpotInstanceRequestsRequest; import com.amazonaws.services.ec2.model.DescribeInstancesRequest; import com.amazonaws.services.ec2.model.DescribeInstancesResult; @@ -93,7 +91,6 @@ import com.amazonaws.services.ec2.model.SpotInstanceRequest; import com.amazonaws.services.ec2.model.Tag; import com.amazonaws.services.s3.AmazonS3; -import com.amazonaws.services.s3.AmazonS3Client; import com.amazonaws.services.s3.AmazonS3ClientBuilder; import com.amazonaws.services.s3.model.GeneratePresignedUrlRequest; @@ -193,6 +190,7 @@ protected Object readResolve() { this.slaveCountingLock = new ReentrantLock(); if (this.sshKeysCredentialsId == null && this.privateKey != null){ + // GET matching private key credential from Credential API if exists Optional keyCredential = SystemCredentialsProvider.getInstance().getCredentials() .stream() .filter((cred) -> cred instanceof BasicSSHUserPrivateKey) @@ -200,16 +198,35 @@ protected Object readResolve() { .map(cred -> (BasicSSHUserPrivateKey)cred) .findFirst(); - System.out.println("Test"); + if (keyCredential.isPresent()){ + // SET this.sshKeysCredentialsId with the found credential + sshKeysCredentialsId = keyCredential.get().getId(); + } else { + // CREATE new credential + String credsId = UUID.randomUUID().toString(); + addNewGlobalCredential( + new BasicSSHUserPrivateKey(CredentialsScope.SYSTEM, credsId, "", + new BasicSSHUserPrivateKey.PrivateKeySource() { + @NonNull + @Override + public List getPrivateKeys() { + return Collections.singletonList(privateKey.getPrivateKey()); + } + }, "", "EC2 Cloud Private Key - " + getDisplayName())); + + sshKeysCredentialsId = credsId; + } + + } - } if (this.sshKeysCredentialsId != null) { - this.privateKey = new EC2PrivateKey(getSshCredential(sshKeysCredentialsId).getPrivateKey()); ///'################################################################################# TODO + // Make sure this.privateKey variable exists as before and that it is taken from credentials + if (this.sshKeysCredentialsId != null) { + this.privateKey = new EC2PrivateKey(getSshCredential(sshKeysCredentialsId).getPrivateKey()); } for (SlaveTemplate t : templates) t.parent = this; - if (this.accessId != null && this.secretKey != null && credentialsId == null) { String secretKeyEncryptedValue = this.secretKey.getEncryptedValue(); // REPLACE this.accessId and this.secretId by a credential @@ -233,26 +250,15 @@ protected Object readResolve() { } // CREATE - for (CredentialsStore credentialsStore: CredentialsProvider.lookupStores(Jenkins.get())) { - - if (credentialsStore instanceof SystemCredentialsProvider.StoreImpl) { + String credsId = UUID.randomUUID().toString(); + addNewGlobalCredential(new AWSCredentialsImpl( + CredentialsScope.SYSTEM, credsId, this.accessId, secretKeyEncryptedValue, + "EC2 Cloud - " + getDisplayName())); - try { - String credsId = UUID.randomUUID().toString(); - credentialsStore.addCredentials(Domain.global(), new AWSCredentialsImpl( - CredentialsScope.SYSTEM, credsId, this.accessId, secretKeyEncryptedValue, - "EC2 Cloud - " + getDisplayName())); - this.credentialsId = credsId; - this.accessId = null; - this.secretKey = null; - return this; - } catch (IOException e) { - this.credentialsId = null; - LOGGER.log(Level.WARNING, "Exception converting legacy configuration to the new credentials API", e); - } - } + this.credentialsId = credsId; + this.accessId = null; + this.secretKey = null; - } // PROBLEM, GLOBAL STORE NOT FOUND LOGGER.log(Level.WARNING, "EC2 Plugin could not migrate credentials to the Jenkins Global Credentials Store, EC2 Plugin for cloud {0} must be manually reconfigured", getDisplayName()); @@ -261,6 +267,22 @@ protected Object readResolve() { return this; } + private void addNewGlobalCredential(Credentials credentials){ + for (CredentialsStore credentialsStore: CredentialsProvider.lookupStores(Jenkins.get())) { + + if (credentialsStore instanceof SystemCredentialsProvider.StoreImpl) { + + try { + credentialsStore.addCredentials(Domain.global(), credentials); + } catch (IOException e) { + this.credentialsId = null; + LOGGER.log(Level.WARNING, "Exception converting legacy configuration to the new credentials API", e); + } + } + + } + } + public boolean isUseInstanceProfileForCredentials() { return useInstanceProfileForCredentials; } From 788a387d8fce295ba2941675a6620cd6adecb65e Mon Sep 17 00:00:00 2001 From: Damian Jesionek Date: Tue, 17 Mar 2020 14:59:09 +0100 Subject: [PATCH 07/45] [JENKINS-56927] Added trimming of migrated private key --- .../java/hudson/plugins/ec2/EC2Cloud.java | 20 ++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/src/main/java/hudson/plugins/ec2/EC2Cloud.java b/src/main/java/hudson/plugins/ec2/EC2Cloud.java index 4d136495e..5c96399bd 100644 --- a/src/main/java/hudson/plugins/ec2/EC2Cloud.java +++ b/src/main/java/hudson/plugins/ec2/EC2Cloud.java @@ -204,15 +204,17 @@ protected Object readResolve() { } else { // CREATE new credential String credsId = UUID.randomUUID().toString(); - addNewGlobalCredential( - new BasicSSHUserPrivateKey(CredentialsScope.SYSTEM, credsId, "", - new BasicSSHUserPrivateKey.PrivateKeySource() { - @NonNull - @Override - public List getPrivateKeys() { - return Collections.singletonList(privateKey.getPrivateKey()); - } - }, "", "EC2 Cloud Private Key - " + getDisplayName())); + + BasicSSHUserPrivateKey sshKeyCredentials = new BasicSSHUserPrivateKey(CredentialsScope.SYSTEM, credsId, "key", + new BasicSSHUserPrivateKey.PrivateKeySource() { + @NonNull + @Override + public List getPrivateKeys() { + return Collections.singletonList(privateKey.getPrivateKey().trim()); + } + }, "", "EC2 Cloud Private Key - " + getDisplayName()); + + addNewGlobalCredential(sshKeyCredentials); sshKeysCredentialsId = credsId; } From 9fec334d7317762c392b3d7cad03dbf54fb52951 Mon Sep 17 00:00:00 2001 From: Damian Jesionek Date: Wed, 18 Mar 2020 09:24:48 +0100 Subject: [PATCH 08/45] [JENKINS-56927] Removed privateKey from persisted data --- src/main/java/hudson/plugins/ec2/EC2Cloud.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/hudson/plugins/ec2/EC2Cloud.java b/src/main/java/hudson/plugins/ec2/EC2Cloud.java index 5c96399bd..a46a13ee2 100644 --- a/src/main/java/hudson/plugins/ec2/EC2Cloud.java +++ b/src/main/java/hudson/plugins/ec2/EC2Cloud.java @@ -145,7 +145,7 @@ public abstract class EC2Cloud extends Cloud { private String sshKeysCredentialsId; - private EC2PrivateKey privateKey; + private transient EC2PrivateKey privateKey; // Transient from now on, should maybe be deprecated and the usage be replaced everywhere? /** * Upper bound on how many instances we may provision. From 560ffa67143322f317d446edc76370bd842c6e67 Mon Sep 17 00:00:00 2001 From: Damian Jesionek Date: Wed, 18 Mar 2020 13:09:33 +0100 Subject: [PATCH 09/45] [JENKINS-56927] Now handling reference to missing credentials --- .../java/hudson/plugins/ec2/EC2Cloud.java | 30 ++++++++++++++++--- 1 file changed, 26 insertions(+), 4 deletions(-) diff --git a/src/main/java/hudson/plugins/ec2/EC2Cloud.java b/src/main/java/hudson/plugins/ec2/EC2Cloud.java index a46a13ee2..b9951d118 100644 --- a/src/main/java/hudson/plugins/ec2/EC2Cloud.java +++ b/src/main/java/hudson/plugins/ec2/EC2Cloud.java @@ -223,7 +223,10 @@ public List getPrivateKeys() { // Make sure this.privateKey variable exists as before and that it is taken from credentials if (this.sshKeysCredentialsId != null) { - this.privateKey = new EC2PrivateKey(getSshCredential(sshKeysCredentialsId).getPrivateKey()); + BasicSSHUserPrivateKey privateKeyCredential = getSshCredential(sshKeysCredentialsId); + if (privateKeyCredential != null) { + this.privateKey = new EC2PrivateKey(privateKeyCredential.getPrivateKey()); + } } for (SlaveTemplate t : templates) @@ -937,13 +940,20 @@ public static URL checkEndPoint(String url) throws FormValidation { } private static BasicSSHUserPrivateKey getSshCredential(String id){ - return CredentialsMatchers.firstOrNull( + + BasicSSHUserPrivateKey credential = CredentialsMatchers.firstOrNull( CredentialsProvider.lookupCredentials( BasicSSHUserPrivateKey.class, // (1) (ItemGroup) null, null, Collections.emptyList()), CredentialsMatchers.withId(id)); + + if (credential == null){ + LOGGER.log(Level.WARNING, "EC2 Plugin could not find the specified credentials ({0}) in the Jenkins Global Credentials Store, EC2 Plugin for cloud must be manually reconfigured", new String[]{id}); + } + + return credential; } public static abstract class DescriptorImpl extends Descriptor { @@ -970,7 +980,13 @@ public FormValidation doCheckSshKeysCredentialsId(@QueryParameter String value) return FormValidation.error("No ssh credentials selected"); } - String privateKey = getSshCredential(value).getPrivateKey(); + BasicSSHUserPrivateKey sshCredential = getSshCredential(value); + String privateKey = ""; + if (sshCredential != null) { + privateKey = sshCredential.getPrivateKey(); + } else { + return FormValidation.error("Failed to find credential \"" + value + "\" in store."); + } boolean hasStart = false, hasEnd = false; BufferedReader br = new BufferedReader(new StringReader(privateKey)); @@ -994,7 +1010,13 @@ protected FormValidation doTestConnection(URL ec2endpoint, boolean useInstancePr Jenkins.get().checkPermission(Jenkins.ADMINISTER); try { - String privateKey = getSshCredential(sshKeysCredentialsId).getPrivateKey(); + BasicSSHUserPrivateKey sshCredential = getSshCredential(sshKeysCredentialsId); + String privateKey = ""; + if (sshCredential != null) { + privateKey = sshCredential.getPrivateKey(); + } else { + return FormValidation.error("Failed to find credential \"" + sshKeysCredentialsId + "\" in store."); + } AWSCredentialsProvider credentialsProvider = createCredentialsProvider(useInstanceProfileForCredentials, credentialsId, roleArn, roleSessionName, region); AmazonEC2 ec2 = AmazonEC2Factory.getInstance().connect(credentialsProvider, ec2endpoint); From 7f7ad8f6daee13afd29e21359c7edfd548cca199 Mon Sep 17 00:00:00 2001 From: Damian Jesionek Date: Wed, 18 Mar 2020 13:11:19 +0100 Subject: [PATCH 10/45] [JENKINS-56927] Removed test for private key input field --- .../java/hudson/plugins/ec2/AmazonEC2CloudTest.java | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/src/test/java/hudson/plugins/ec2/AmazonEC2CloudTest.java b/src/test/java/hudson/plugins/ec2/AmazonEC2CloudTest.java index b4d1099d9..e00fe3220 100644 --- a/src/test/java/hudson/plugins/ec2/AmazonEC2CloudTest.java +++ b/src/test/java/hudson/plugins/ec2/AmazonEC2CloudTest.java @@ -81,16 +81,6 @@ public void testPrivateKeyRemainsUnchangedAfterUpdatingOtherFields() throws Exce r.assertEqualBeans(cloud, actual, "region,useInstanceProfileForCredentials,privateKey,instanceCap,roleArn,roleSessionName"); } - @Test - public void testPrivateKeyUpdate() throws Exception { - HtmlForm form = getConfigForm(); - form.getOneHtmlElementByAttribute("input", "class", "secret-update-btn").click(); - form.getTextAreaByName("_.privateKey").setText("new secret key"); - r.submit(form); - AmazonEC2Cloud actual = r.jenkins.clouds.get(AmazonEC2Cloud.class); - assertEquals("new secret key", actual.getPrivateKey().getPrivateKey()); - } - private HtmlForm getConfigForm() throws IOException, SAXException { return r.createWebClient().goTo("configure").getFormByName("config"); } From 509e06246b8579d77e3a5ab27e91f29dc877d642 Mon Sep 17 00:00:00 2001 From: Damian Jesionek Date: Wed, 18 Mar 2020 13:12:17 +0100 Subject: [PATCH 11/45] [JENKINS-56927] BouncyCastleProvider is now being injected in private key tests --- src/test/java/hudson/plugins/ec2/EC2PrivateKeyTest.java | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/test/java/hudson/plugins/ec2/EC2PrivateKeyTest.java b/src/test/java/hudson/plugins/ec2/EC2PrivateKeyTest.java index 06aab4fe3..163928982 100644 --- a/src/test/java/hudson/plugins/ec2/EC2PrivateKeyTest.java +++ b/src/test/java/hudson/plugins/ec2/EC2PrivateKeyTest.java @@ -23,12 +23,15 @@ */ package hudson.plugins.ec2; +import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.jvnet.hudson.test.Issue; import org.jvnet.hudson.test.JenkinsRule; import java.io.IOException; +import java.security.Security; + import com.amazonaws.AmazonClientException; import static org.junit.Assert.assertEquals; @@ -41,6 +44,12 @@ public class EC2PrivateKeyTest { @Rule public JenkinsRule r = new JenkinsRule(); + @Before + public void init(){ + // Tests using the BouncyCastleProvider failed without that + Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider()); + } + private EC2PrivateKey getPrivateKey() { return new EC2PrivateKey("-----BEGIN RSA PRIVATE KEY-----\n" + "MIIEowIBAAKCAQEAlpK/pGxCRoHpbIObxYW53fl4qA+EQNHuSveNyxt+6m/HAdRLhEMGHe7/b7dR\n" From 6681aca8b88f24e80ea6dabaec384e8a6dd1446c Mon Sep 17 00:00:00 2001 From: Damian Jesionek Date: Wed, 18 Mar 2020 14:41:37 +0100 Subject: [PATCH 12/45] [JENKINS-56927] Fixed tests where private key dummy is used --- src/main/java/hudson/plugins/ec2/EC2Cloud.java | 6 ++++++ .../plugins/ec2/AmazonEC2CloudUnitTest.java | 9 +++++++++ .../plugins/ec2/EC2RetentionStrategyTest.java | 15 ++++++++++----- .../hudson/plugins/ec2/EC2SlaveMonitorTest.java | 14 ++++++++++++-- 4 files changed, 37 insertions(+), 7 deletions(-) diff --git a/src/main/java/hudson/plugins/ec2/EC2Cloud.java b/src/main/java/hudson/plugins/ec2/EC2Cloud.java index b9951d118..bb11a4526 100644 --- a/src/main/java/hudson/plugins/ec2/EC2Cloud.java +++ b/src/main/java/hudson/plugins/ec2/EC2Cloud.java @@ -34,6 +34,7 @@ import com.cloudbees.plugins.credentials.SystemCredentialsProvider; import com.cloudbees.plugins.credentials.common.StandardListBoxModel; import com.cloudbees.plugins.credentials.domains.Domain; +import com.google.common.annotations.VisibleForTesting; import edu.umd.cs.findbugs.annotations.NonNull; import hudson.model.*; import hudson.plugins.ec2.util.AmazonEC2Factory; @@ -292,6 +293,11 @@ public boolean isUseInstanceProfileForCredentials() { return useInstanceProfileForCredentials; } + @VisibleForTesting + void setPrivateKey(String key) { + this.privateKey = new EC2PrivateKey(key); + } + public String getRoleArn() { return roleArn; } diff --git a/src/test/java/hudson/plugins/ec2/AmazonEC2CloudUnitTest.java b/src/test/java/hudson/plugins/ec2/AmazonEC2CloudUnitTest.java index 095aabde6..b2d155ce4 100644 --- a/src/test/java/hudson/plugins/ec2/AmazonEC2CloudUnitTest.java +++ b/src/test/java/hudson/plugins/ec2/AmazonEC2CloudUnitTest.java @@ -23,7 +23,10 @@ */ package hudson.plugins.ec2; +import hudson.plugins.ec2.util.PrivateKeyHelper; +import org.junit.Rule; import org.junit.Test; +import org.jvnet.hudson.test.JenkinsRule; import java.net.MalformedURLException; import java.net.URL; @@ -36,6 +39,10 @@ * Unit tests related to {@link AmazonEC2Cloud}, but do not require a Jenkins instance. */ public class AmazonEC2CloudUnitTest { + + @Rule + public JenkinsRule r = new JenkinsRule(); + @Test public void testEC2EndpointURLCreation() throws MalformedURLException { AmazonEC2Cloud.DescriptorImpl descriptor = new AmazonEC2Cloud.DescriptorImpl(); @@ -50,6 +57,7 @@ public void testInstaceCap() throws Exception { AmazonEC2Cloud cloud = new AmazonEC2Cloud("us-east-1", true, "abc", "us-east-1", "{}", null, Collections.emptyList(), "roleArn", "roleSessionName"); + cloud.setPrivateKey(PrivateKeyHelper.generate()); assertEquals(cloud.getInstanceCap(), Integer.MAX_VALUE); assertEquals(cloud.getInstanceCapStr(), ""); @@ -58,6 +66,7 @@ public void testInstaceCap() throws Exception { cloud = new AmazonEC2Cloud("us-east-1", true, "abc", "us-east-1", "{}", capStr, Collections.emptyList(), "roleArn", "roleSessionName"); + cloud.setPrivateKey(PrivateKeyHelper.generate()); assertEquals(cloud.getInstanceCap(), cap); assertEquals(cloud.getInstanceCapStr(), capStr); } diff --git a/src/test/java/hudson/plugins/ec2/EC2RetentionStrategyTest.java b/src/test/java/hudson/plugins/ec2/EC2RetentionStrategyTest.java index 8debf9cb2..be21f2a46 100644 --- a/src/test/java/hudson/plugins/ec2/EC2RetentionStrategyTest.java +++ b/src/test/java/hudson/plugins/ec2/EC2RetentionStrategyTest.java @@ -209,9 +209,10 @@ public void testRetentionDespiteIdleWithMinimumInstances() throws Exception { InstanceType.M1Large, false, "ttt", Node.Mode.NORMAL, "foo ami", "bar", "bbb", "aaa", "10", "fff", null, "-Xmx1g", false, "subnet 456", null, null, 2, 0, "10", null, true, true, false, "", false, "", false, false, true, ConnectionStrategy.PRIVATE_IP, 0, Collections.emptyList()); - AmazonEC2Cloud cloud = new AmazonEC2Cloud("us-east-1", true, "abc", "us-east-1", PrivateKeyHelper.generate(), "3", + AmazonEC2Cloud cloud = new AmazonEC2Cloud("us-east-1", true, "abc", "us-east-1", "", "3", Collections .singletonList(template), "roleArn", "roleSessionName"); + cloud.setPrivateKey(PrivateKeyHelper.generate()); r.jenkins.clouds.add(cloud); r.configRoundtrip(); @@ -288,9 +289,10 @@ public void testRetentionDespiteIdleWithMinimumInstanceActiveTimeRange() throws //Set fixed clock to be able to test properly MinimumInstanceChecker.clock = Clock.fixed(localDateTime.atZone(ZoneId.systemDefault()).toInstant(), ZoneId.systemDefault()); - AmazonEC2Cloud cloud = new AmazonEC2Cloud("us-east-1", true, "abc", "us-east-1", PrivateKeyHelper.generate(), "3", + AmazonEC2Cloud cloud = new AmazonEC2Cloud("us-east-1", true, "abc", "us-east-1", "", "3", Collections .singletonList(template), "roleArn", "roleSessionName"); + cloud.setPrivateKey(PrivateKeyHelper.generate()); r.jenkins.clouds.add(cloud); r.configRoundtrip(); @@ -344,9 +346,10 @@ public void testRetentionIdleWithMinimumInstanceInactiveTimeRange() throws Excep //Set fixed clock to be able to test properly MinimumInstanceChecker.clock = Clock.fixed(localDateTime.atZone(ZoneId.systemDefault()).toInstant(), ZoneId.systemDefault()); - AmazonEC2Cloud cloud = new AmazonEC2Cloud("us-east-1", true, "abc", "us-east-1", PrivateKeyHelper.generate(), "3", + AmazonEC2Cloud cloud = new AmazonEC2Cloud("us-east-1", true, "abc", "us-east-1", "", "3", Collections .singletonList(template), "roleArn", "roleSessionName"); + cloud.setPrivateKey(PrivateKeyHelper.generate()); r.jenkins.clouds.add(cloud); r.configRoundtrip(); @@ -385,9 +388,10 @@ public void testRetentionDespiteIdleWithMinimumInstanceActiveTimeRangeAfterMidni //Set fixed clock to be able to test properly MinimumInstanceChecker.clock = Clock.fixed(localDateTime.atZone(ZoneId.systemDefault()).toInstant(), ZoneId.systemDefault()); - AmazonEC2Cloud cloud = new AmazonEC2Cloud("us-east-1", true, "abc", "us-east-1", PrivateKeyHelper.generate(), "3", + AmazonEC2Cloud cloud = new AmazonEC2Cloud("us-east-1", true, "abc", "us-east-1", "", "3", Collections .singletonList(template), "roleArn", "roleSessionName"); + cloud.setPrivateKey(PrivateKeyHelper.generate()); r.jenkins.clouds.add(cloud); r.configRoundtrip(); @@ -439,9 +443,10 @@ public void testRetentionStopsAfterActiveRangeEnds() throws Exception { LocalDateTime localDateTime = LocalDateTime.of(2019, Month.SEPTEMBER, 24, 14, 0); //Tuesday MinimumInstanceChecker.clock = Clock.fixed(localDateTime.atZone(ZoneId.systemDefault()).toInstant(), ZoneId.systemDefault()); - AmazonEC2Cloud cloud = new AmazonEC2Cloud("us-east-1", true, "abc", "us-east-1", PrivateKeyHelper.generate(), "3", + AmazonEC2Cloud cloud = new AmazonEC2Cloud("us-east-1", true, "abc", "us-east-1", "", "3", Collections .singletonList(template), "roleArn", "roleSessionName"); + cloud.setPrivateKey(PrivateKeyHelper.generate()); r.jenkins.clouds.add(cloud); r.configRoundtrip(); diff --git a/src/test/java/hudson/plugins/ec2/EC2SlaveMonitorTest.java b/src/test/java/hudson/plugins/ec2/EC2SlaveMonitorTest.java index a8d48c8c0..deba41847 100644 --- a/src/test/java/hudson/plugins/ec2/EC2SlaveMonitorTest.java +++ b/src/test/java/hudson/plugins/ec2/EC2SlaveMonitorTest.java @@ -1,9 +1,11 @@ package hudson.plugins.ec2; +import java.security.Security; import java.util.Arrays; import java.util.Collections; import org.junit.Assert; +import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.jvnet.hudson.test.JenkinsRule; @@ -19,10 +21,17 @@ public class EC2SlaveMonitorTest { @Rule public JenkinsRule r = new JenkinsRule(); + @Before + public void init(){ + // Tests using the BouncyCastleProvider failed without that + Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider()); + } + @Test public void testMinimumNumberOfInstances() throws Exception { SlaveTemplate template = new SlaveTemplate("ami1", EC2AbstractSlave.TEST_ZONE, null, "default", "foo", InstanceType.M1Large, false, "ttt", Node.Mode.NORMAL, "foo ami", "bar", "bbb", "aaa", "10", "fff", null, "-Xmx1g", false, "subnet 456", null, null, 2, null, null, true, true, false, "", false, "", false, false, true, ConnectionStrategy.PRIVATE_IP, 0); - AmazonEC2Cloud cloud = new AmazonEC2Cloud("us-east-1", true, "abc", "us-east-1", PrivateKeyHelper.generate(), "3", Collections.singletonList(template), "roleArn", "roleSessionName"); + AmazonEC2Cloud cloud = new AmazonEC2Cloud("us-east-1", true, "abc", "us-east-1", "", "3", Collections.singletonList(template), "roleArn", "roleSessionName"); + cloud.setPrivateKey(PrivateKeyHelper.generate()); r.jenkins.clouds.add(cloud); r.configRoundtrip(); @@ -41,7 +50,8 @@ public void testMinimumNumberOfSpareInstances() throws Exception { "", false, false, true, ConnectionStrategy.PRIVATE_IP, 0, null); - AmazonEC2Cloud cloud = new AmazonEC2Cloud("us-east-1", true, "abc", "us-east-1", PrivateKeyHelper.generate(), "3", Collections.singletonList(template), "roleArn", "roleSessionName"); + AmazonEC2Cloud cloud = new AmazonEC2Cloud("us-east-1", true, "abc", "us-east-1", "", "3", Collections.singletonList(template), "roleArn", "roleSessionName"); + cloud.setPrivateKey(PrivateKeyHelper.generate()); r.jenkins.clouds.add(cloud); r.configRoundtrip(); Assert.assertEquals(2, Arrays.stream(Jenkins.get().getComputers()).filter(computer -> computer instanceof EC2Computer).count()); From 0e516c337af180c9894d16f2fda96df5db93c0bd Mon Sep 17 00:00:00 2001 From: Damian Jesionek Date: Thu, 19 Mar 2020 13:14:35 +0100 Subject: [PATCH 13/45] [JENKINS-56927] Fixed backwards compatibility for tests --- .../hudson/plugins/ec2/AmazonEC2Cloud.java | 10 +++++-- .../java/hudson/plugins/ec2/EC2Cloud.java | 29 +++++++++---------- .../plugins/ec2/AmazonEC2CloudUnitTest.java | 6 ++-- .../plugins/ec2/EC2RetentionStrategyTest.java | 15 ++++------ .../plugins/ec2/EC2SlaveMonitorTest.java | 6 ++-- 5 files changed, 30 insertions(+), 36 deletions(-) diff --git a/src/main/java/hudson/plugins/ec2/AmazonEC2Cloud.java b/src/main/java/hudson/plugins/ec2/AmazonEC2Cloud.java index 017ef88fe..584c382e9 100644 --- a/src/main/java/hudson/plugins/ec2/AmazonEC2Cloud.java +++ b/src/main/java/hudson/plugins/ec2/AmazonEC2Cloud.java @@ -75,8 +75,14 @@ public class AmazonEC2Cloud extends EC2Cloud { private boolean noDelayProvisioning; @DataBoundConstructor - public AmazonEC2Cloud(String cloudName, boolean useInstanceProfileForCredentials, String credentialsId, String region, String sshKeysCredentialsId, String instanceCapStr, List templates, String roleArn, String roleSessionName) { - super(createCloudId(cloudName), useInstanceProfileForCredentials, credentialsId, sshKeysCredentialsId, instanceCapStr, templates, roleArn, roleSessionName); + public AmazonEC2Cloud(String cloudName, boolean useInstanceProfileForCredentials, String credentialsId, String region, String privateKey, String sshKeysCredentialsId, String instanceCapStr, List templates, String roleArn, String roleSessionName) { + super(createCloudId(cloudName), useInstanceProfileForCredentials, credentialsId, privateKey, sshKeysCredentialsId, instanceCapStr, templates, roleArn, roleSessionName); + this.region = region; + } + + @Deprecated + public AmazonEC2Cloud(String cloudName, boolean useInstanceProfileForCredentials, String credentialsId, String region, String privateKey, String instanceCapStr, List templates, String roleArn, String roleSessionName) { + super(createCloudId(cloudName), useInstanceProfileForCredentials, credentialsId, privateKey, instanceCapStr, templates, roleArn, roleSessionName); this.region = region; } diff --git a/src/main/java/hudson/plugins/ec2/EC2Cloud.java b/src/main/java/hudson/plugins/ec2/EC2Cloud.java index 90d1bff58..4e967634c 100644 --- a/src/main/java/hudson/plugins/ec2/EC2Cloud.java +++ b/src/main/java/hudson/plugins/ec2/EC2Cloud.java @@ -34,11 +34,8 @@ import com.cloudbees.plugins.credentials.SystemCredentialsProvider; import com.cloudbees.plugins.credentials.common.StandardListBoxModel; import com.cloudbees.plugins.credentials.domains.Domain; -<<<<<<< HEAD import com.google.common.annotations.VisibleForTesting; import edu.umd.cs.findbugs.annotations.NonNull; -======= ->>>>>>> 4aac4c01abe80e5462f7e8ed88e6b91e1e5fb9d3 import hudson.model.*; import hudson.plugins.ec2.util.AmazonEC2Factory; import hudson.security.ACL; @@ -65,10 +62,6 @@ import javax.servlet.ServletException; import hudson.Extension; -<<<<<<< HEAD -======= -import hudson.security.Permission; ->>>>>>> 4aac4c01abe80e5462f7e8ed88e6b91e1e5fb9d3 import hudson.util.ListBoxModel; import jenkins.model.Jenkins; import jenkins.model.JenkinsLocationConfiguration; @@ -150,9 +143,9 @@ public abstract class EC2Cloud extends Cloud { @CheckForNull @Deprecated private transient Secret secretKey; - + @CheckForNull private String sshKeysCredentialsId; - + @CheckForNull private transient EC2PrivateKey privateKey; // Transient from now on, should maybe be deprecated and the usage be replaced everywhere? /** @@ -166,8 +159,8 @@ public abstract class EC2Cloud extends Cloud { private transient volatile AmazonEC2 connection; - protected EC2Cloud(String id, boolean useInstanceProfileForCredentials, String credentialsId, String sshKeysCredentialsId, - String instanceCapStr, List templates, String roleArn, String roleSessionName) { + protected EC2Cloud(String id, boolean useInstanceProfileForCredentials, String credentialsId, String privateKey, String sshKeysCredentialsId, + String instanceCapStr, List templates, String roleArn, String roleSessionName) { super(id); this.useInstanceProfileForCredentials = useInstanceProfileForCredentials; this.roleArn = roleArn; @@ -175,6 +168,9 @@ protected EC2Cloud(String id, boolean useInstanceProfileForCredentials, String c this.credentialsId = credentialsId; this.sshKeysCredentialsId = sshKeysCredentialsId; + if (privateKey != null) + this.privateKey = new EC2PrivateKey(privateKey); + if (templates == null) { this.templates = Collections.emptyList(); } else { @@ -190,6 +186,12 @@ protected EC2Cloud(String id, boolean useInstanceProfileForCredentials, String c readResolve(); // set parents } + @Deprecated + protected EC2Cloud(String id, boolean useInstanceProfileForCredentials, String credentialsId, String privateKey, + String instanceCapStr, List templates, String roleArn, String roleSessionName) { + this(id, useInstanceProfileForCredentials, credentialsId, privateKey, null, instanceCapStr, templates, roleArn, roleSessionName); + } + public abstract URL getEc2EndpointUrl() throws IOException; public abstract URL getS3EndpointUrl() throws IOException; @@ -299,11 +301,6 @@ public boolean isUseInstanceProfileForCredentials() { return useInstanceProfileForCredentials; } - @VisibleForTesting - void setPrivateKey(String key) { - this.privateKey = new EC2PrivateKey(key); - } - public String getRoleArn() { return roleArn; } diff --git a/src/test/java/hudson/plugins/ec2/AmazonEC2CloudUnitTest.java b/src/test/java/hudson/plugins/ec2/AmazonEC2CloudUnitTest.java index b2d155ce4..6eb879f99 100644 --- a/src/test/java/hudson/plugins/ec2/AmazonEC2CloudUnitTest.java +++ b/src/test/java/hudson/plugins/ec2/AmazonEC2CloudUnitTest.java @@ -55,18 +55,16 @@ public void testEC2EndpointURLCreation() throws MalformedURLException { @Test public void testInstaceCap() throws Exception { AmazonEC2Cloud cloud = new AmazonEC2Cloud("us-east-1", true, "abc", "us-east-1", - "{}", null, Collections.emptyList(), + PrivateKeyHelper.generate(), null, Collections.emptyList(), "roleArn", "roleSessionName"); - cloud.setPrivateKey(PrivateKeyHelper.generate()); assertEquals(cloud.getInstanceCap(), Integer.MAX_VALUE); assertEquals(cloud.getInstanceCapStr(), ""); final int cap = 3; final String capStr = String.valueOf(cap); cloud = new AmazonEC2Cloud("us-east-1", true, "abc", "us-east-1", - "{}", capStr, Collections.emptyList(), + PrivateKeyHelper.generate(), capStr, Collections.emptyList(), "roleArn", "roleSessionName"); - cloud.setPrivateKey(PrivateKeyHelper.generate()); assertEquals(cloud.getInstanceCap(), cap); assertEquals(cloud.getInstanceCapStr(), capStr); } diff --git a/src/test/java/hudson/plugins/ec2/EC2RetentionStrategyTest.java b/src/test/java/hudson/plugins/ec2/EC2RetentionStrategyTest.java index be21f2a46..8debf9cb2 100644 --- a/src/test/java/hudson/plugins/ec2/EC2RetentionStrategyTest.java +++ b/src/test/java/hudson/plugins/ec2/EC2RetentionStrategyTest.java @@ -209,10 +209,9 @@ public void testRetentionDespiteIdleWithMinimumInstances() throws Exception { InstanceType.M1Large, false, "ttt", Node.Mode.NORMAL, "foo ami", "bar", "bbb", "aaa", "10", "fff", null, "-Xmx1g", false, "subnet 456", null, null, 2, 0, "10", null, true, true, false, "", false, "", false, false, true, ConnectionStrategy.PRIVATE_IP, 0, Collections.emptyList()); - AmazonEC2Cloud cloud = new AmazonEC2Cloud("us-east-1", true, "abc", "us-east-1", "", "3", + AmazonEC2Cloud cloud = new AmazonEC2Cloud("us-east-1", true, "abc", "us-east-1", PrivateKeyHelper.generate(), "3", Collections .singletonList(template), "roleArn", "roleSessionName"); - cloud.setPrivateKey(PrivateKeyHelper.generate()); r.jenkins.clouds.add(cloud); r.configRoundtrip(); @@ -289,10 +288,9 @@ public void testRetentionDespiteIdleWithMinimumInstanceActiveTimeRange() throws //Set fixed clock to be able to test properly MinimumInstanceChecker.clock = Clock.fixed(localDateTime.atZone(ZoneId.systemDefault()).toInstant(), ZoneId.systemDefault()); - AmazonEC2Cloud cloud = new AmazonEC2Cloud("us-east-1", true, "abc", "us-east-1", "", "3", + AmazonEC2Cloud cloud = new AmazonEC2Cloud("us-east-1", true, "abc", "us-east-1", PrivateKeyHelper.generate(), "3", Collections .singletonList(template), "roleArn", "roleSessionName"); - cloud.setPrivateKey(PrivateKeyHelper.generate()); r.jenkins.clouds.add(cloud); r.configRoundtrip(); @@ -346,10 +344,9 @@ public void testRetentionIdleWithMinimumInstanceInactiveTimeRange() throws Excep //Set fixed clock to be able to test properly MinimumInstanceChecker.clock = Clock.fixed(localDateTime.atZone(ZoneId.systemDefault()).toInstant(), ZoneId.systemDefault()); - AmazonEC2Cloud cloud = new AmazonEC2Cloud("us-east-1", true, "abc", "us-east-1", "", "3", + AmazonEC2Cloud cloud = new AmazonEC2Cloud("us-east-1", true, "abc", "us-east-1", PrivateKeyHelper.generate(), "3", Collections .singletonList(template), "roleArn", "roleSessionName"); - cloud.setPrivateKey(PrivateKeyHelper.generate()); r.jenkins.clouds.add(cloud); r.configRoundtrip(); @@ -388,10 +385,9 @@ public void testRetentionDespiteIdleWithMinimumInstanceActiveTimeRangeAfterMidni //Set fixed clock to be able to test properly MinimumInstanceChecker.clock = Clock.fixed(localDateTime.atZone(ZoneId.systemDefault()).toInstant(), ZoneId.systemDefault()); - AmazonEC2Cloud cloud = new AmazonEC2Cloud("us-east-1", true, "abc", "us-east-1", "", "3", + AmazonEC2Cloud cloud = new AmazonEC2Cloud("us-east-1", true, "abc", "us-east-1", PrivateKeyHelper.generate(), "3", Collections .singletonList(template), "roleArn", "roleSessionName"); - cloud.setPrivateKey(PrivateKeyHelper.generate()); r.jenkins.clouds.add(cloud); r.configRoundtrip(); @@ -443,10 +439,9 @@ public void testRetentionStopsAfterActiveRangeEnds() throws Exception { LocalDateTime localDateTime = LocalDateTime.of(2019, Month.SEPTEMBER, 24, 14, 0); //Tuesday MinimumInstanceChecker.clock = Clock.fixed(localDateTime.atZone(ZoneId.systemDefault()).toInstant(), ZoneId.systemDefault()); - AmazonEC2Cloud cloud = new AmazonEC2Cloud("us-east-1", true, "abc", "us-east-1", "", "3", + AmazonEC2Cloud cloud = new AmazonEC2Cloud("us-east-1", true, "abc", "us-east-1", PrivateKeyHelper.generate(), "3", Collections .singletonList(template), "roleArn", "roleSessionName"); - cloud.setPrivateKey(PrivateKeyHelper.generate()); r.jenkins.clouds.add(cloud); r.configRoundtrip(); diff --git a/src/test/java/hudson/plugins/ec2/EC2SlaveMonitorTest.java b/src/test/java/hudson/plugins/ec2/EC2SlaveMonitorTest.java index deba41847..a8def2cc7 100644 --- a/src/test/java/hudson/plugins/ec2/EC2SlaveMonitorTest.java +++ b/src/test/java/hudson/plugins/ec2/EC2SlaveMonitorTest.java @@ -30,8 +30,7 @@ public void init(){ @Test public void testMinimumNumberOfInstances() throws Exception { SlaveTemplate template = new SlaveTemplate("ami1", EC2AbstractSlave.TEST_ZONE, null, "default", "foo", InstanceType.M1Large, false, "ttt", Node.Mode.NORMAL, "foo ami", "bar", "bbb", "aaa", "10", "fff", null, "-Xmx1g", false, "subnet 456", null, null, 2, null, null, true, true, false, "", false, "", false, false, true, ConnectionStrategy.PRIVATE_IP, 0); - AmazonEC2Cloud cloud = new AmazonEC2Cloud("us-east-1", true, "abc", "us-east-1", "", "3", Collections.singletonList(template), "roleArn", "roleSessionName"); - cloud.setPrivateKey(PrivateKeyHelper.generate()); + AmazonEC2Cloud cloud = new AmazonEC2Cloud("us-east-1", true, "abc", "us-east-1", PrivateKeyHelper.generate(), "3", Collections.singletonList(template), "roleArn", "roleSessionName"); r.jenkins.clouds.add(cloud); r.configRoundtrip(); @@ -50,8 +49,7 @@ public void testMinimumNumberOfSpareInstances() throws Exception { "", false, false, true, ConnectionStrategy.PRIVATE_IP, 0, null); - AmazonEC2Cloud cloud = new AmazonEC2Cloud("us-east-1", true, "abc", "us-east-1", "", "3", Collections.singletonList(template), "roleArn", "roleSessionName"); - cloud.setPrivateKey(PrivateKeyHelper.generate()); + AmazonEC2Cloud cloud = new AmazonEC2Cloud("us-east-1", true, "abc", "us-east-1", PrivateKeyHelper.generate(), "3", Collections.singletonList(template), "roleArn", "roleSessionName"); r.jenkins.clouds.add(cloud); r.configRoundtrip(); Assert.assertEquals(2, Arrays.stream(Jenkins.get().getComputers()).filter(computer -> computer instanceof EC2Computer).count()); From df859e3aaf8e1459da85a2ed9ba70665f2fecdcf Mon Sep 17 00:00:00 2001 From: Damian Jesionek Date: Thu, 19 Mar 2020 13:18:53 +0100 Subject: [PATCH 14/45] [JENKINS-56927] Updated config as code export test --- src/test/resources/hudson/plugins/ec2/UnixData.yml | 2 +- src/test/resources/hudson/plugins/ec2/UnixDataExport.yml | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/test/resources/hudson/plugins/ec2/UnixData.yml b/src/test/resources/hudson/plugins/ec2/UnixData.yml index f247240fe..ea9b61c0b 100644 --- a/src/test/resources/hudson/plugins/ec2/UnixData.yml +++ b/src/test/resources/hudson/plugins/ec2/UnixData.yml @@ -4,7 +4,7 @@ jenkins: - amazonEC2: cloudName: "production" useInstanceProfileForCredentials: true - privateKey: "${PRIVATE_KEY}" + sshKeysCredentialsId: "random credentials id" templates: - description: ami: "ami-12345" diff --git a/src/test/resources/hudson/plugins/ec2/UnixDataExport.yml b/src/test/resources/hudson/plugins/ec2/UnixDataExport.yml index 781b4eab1..1b585cbbd 100644 --- a/src/test/resources/hudson/plugins/ec2/UnixDataExport.yml +++ b/src/test/resources/hudson/plugins/ec2/UnixDataExport.yml @@ -1,6 +1,7 @@ - amazonEC2: cloudName: "production" region: "us-east-1" + sshKeysCredentialsId: "random credentials id" templates: - ami: "ami-12345" amiType: From c9578bc9f912d61b25405a04b1b5fd464c78176e Mon Sep 17 00:00:00 2001 From: Damian Jesionek Date: Thu, 19 Mar 2020 15:34:45 +0100 Subject: [PATCH 15/45] [JENKINS-56927] Implemented private key credential store for eucalyptus --- .../hudson/plugins/ec2/AmazonEC2Cloud.java | 5 +-- .../java/hudson/plugins/ec2/Eucalyptus.java | 41 ++++++++++++++++++- .../ec2/Eucalyptus/config-entries.jelly | 4 +- 3 files changed, 42 insertions(+), 8 deletions(-) diff --git a/src/main/java/hudson/plugins/ec2/AmazonEC2Cloud.java b/src/main/java/hudson/plugins/ec2/AmazonEC2Cloud.java index 584c382e9..d2662ea4e 100644 --- a/src/main/java/hudson/plugins/ec2/AmazonEC2Cloud.java +++ b/src/main/java/hudson/plugins/ec2/AmazonEC2Cloud.java @@ -200,10 +200,7 @@ public ListBoxModel doFillRegionItems( public ListBoxModel doFillSshKeysCredentialsIdItems( @AncestorInPath Item item, - @QueryParameter String sshKeysCredentialsId - ) { - - //CredentialsProvider.lookupCredentials(BasicSSHUserPrivateKey.class,) + @QueryParameter String sshKeysCredentialsId) { StandardListBoxModel result = new StandardListBoxModel(); if (item == null) { diff --git a/src/main/java/hudson/plugins/ec2/Eucalyptus.java b/src/main/java/hudson/plugins/ec2/Eucalyptus.java index 666704c32..2e275c2cf 100644 --- a/src/main/java/hudson/plugins/ec2/Eucalyptus.java +++ b/src/main/java/hudson/plugins/ec2/Eucalyptus.java @@ -23,7 +23,12 @@ */ package hudson.plugins.ec2; +import com.cloudbees.jenkins.plugins.sshcredentials.impl.BasicSSHUserPrivateKey; +import com.cloudbees.plugins.credentials.CredentialsProvider; +import com.cloudbees.plugins.credentials.common.StandardListBoxModel; import hudson.Extension; +import hudson.model.Item; +import hudson.model.ItemGroup; import hudson.util.FormValidation; import java.io.IOException; @@ -32,6 +37,9 @@ import javax.servlet.ServletException; +import hudson.util.ListBoxModel; +import jenkins.model.Jenkins; +import org.kohsuke.stapler.AncestorInPath; import org.kohsuke.stapler.DataBoundConstructor; import org.kohsuke.stapler.QueryParameter; import org.kohsuke.stapler.StaplerResponse; @@ -47,6 +55,14 @@ public class Eucalyptus extends EC2Cloud { private final URL s3endpoint; @DataBoundConstructor + public Eucalyptus(URL ec2endpoint, URL s3endpoint, boolean useInstanceProfileForCredentials, String credentialsId, String privateKey, String sshKeysCredentialsId, String instanceCapStr, List templates, String roleArn, String roleSessionName) + throws IOException { + super("eucalyptus", useInstanceProfileForCredentials, credentialsId, privateKey, sshKeysCredentialsId, instanceCapStr, templates, roleArn, roleSessionName); + this.ec2endpoint = ec2endpoint; + this.s3endpoint = s3endpoint; + } + + @Deprecated public Eucalyptus(URL ec2endpoint, URL s3endpoint, boolean useInstanceProfileForCredentials, String credentialsId, String privateKey, String instanceCapStr, List templates, String roleArn, String roleSessionName) throws IOException { super("eucalyptus", useInstanceProfileForCredentials, credentialsId, privateKey, instanceCapStr, templates, roleArn, roleSessionName); @@ -71,11 +87,32 @@ public String getDisplayName() { return "Eucalyptus"; } + public ListBoxModel doFillSshKeysCredentialsIdItems( + @AncestorInPath Item item, + @QueryParameter String sshKeysCredentialsId) { + + StandardListBoxModel result = new StandardListBoxModel(); + if (item == null) { + if (!Jenkins.get().hasPermission(Jenkins.ADMINISTER)) { + return result.includeCurrentValue(sshKeysCredentialsId); + } + } else { + if (!item.hasPermission(Item.EXTENDED_READ) + && !item.hasPermission(CredentialsProvider.USE_ITEM)) { + return result.includeCurrentValue(sshKeysCredentialsId); + } + } + + return result + .includeMatchingAs(null, (ItemGroup) null, BasicSSHUserPrivateKey.class, null, null) + .includeCurrentValue(sshKeysCredentialsId); + } + @Override @RequirePOST - public FormValidation doTestConnection(@QueryParameter URL ec2endpoint, @QueryParameter boolean useInstanceProfileForCredentials, @QueryParameter String credentialsId, @QueryParameter String privateKey, @QueryParameter String roleArn, @QueryParameter String roleSessionName, @QueryParameter String region) + public FormValidation doTestConnection(@QueryParameter URL ec2endpoint, @QueryParameter boolean useInstanceProfileForCredentials, @QueryParameter String credentialsId, @QueryParameter String sshKeysCredentialsId, @QueryParameter String roleArn, @QueryParameter String roleSessionName, @QueryParameter String region) throws IOException, ServletException { - return super.doTestConnection(ec2endpoint, useInstanceProfileForCredentials, credentialsId, privateKey, roleArn, roleSessionName, region); + return super.doTestConnection(ec2endpoint, useInstanceProfileForCredentials, credentialsId, sshKeysCredentialsId, roleArn, roleSessionName, region); } } } diff --git a/src/main/resources/hudson/plugins/ec2/Eucalyptus/config-entries.jelly b/src/main/resources/hudson/plugins/ec2/Eucalyptus/config-entries.jelly index af7176e37..926c8ca9d 100644 --- a/src/main/resources/hudson/plugins/ec2/Eucalyptus/config-entries.jelly +++ b/src/main/resources/hudson/plugins/ec2/Eucalyptus/config-entries.jelly @@ -31,8 +31,8 @@ THE SOFTWARE. - - + + From 551dd3b977ca59f0df75b4d9e05f30a2ac0043f5 Mon Sep 17 00:00:00 2001 From: Damian Jesionek Date: Thu, 19 Mar 2020 16:46:55 +0100 Subject: [PATCH 16/45] [JENKINS-56927] Resolving of credential id now happens on demand and key is prevented to be showed in CasC export --- .../java/hudson/plugins/ec2/EC2Cloud.java | 88 ++++++++++--------- .../hudson/plugins/ec2/SlaveTemplate.java | 2 +- .../plugins/ec2/ssh/EC2UnixLauncher.java | 2 +- .../plugins/ec2/win/EC2WindowsLauncher.java | 8 +- .../ec2/util/AmazonEC2FactoryMockImpl.java | 2 +- 5 files changed, 50 insertions(+), 52 deletions(-) diff --git a/src/main/java/hudson/plugins/ec2/EC2Cloud.java b/src/main/java/hudson/plugins/ec2/EC2Cloud.java index 4e967634c..497ead428 100644 --- a/src/main/java/hudson/plugins/ec2/EC2Cloud.java +++ b/src/main/java/hudson/plugins/ec2/EC2Cloud.java @@ -34,12 +34,12 @@ import com.cloudbees.plugins.credentials.SystemCredentialsProvider; import com.cloudbees.plugins.credentials.common.StandardListBoxModel; import com.cloudbees.plugins.credentials.domains.Domain; -import com.google.common.annotations.VisibleForTesting; import edu.umd.cs.findbugs.annotations.NonNull; import hudson.model.*; import hudson.plugins.ec2.util.AmazonEC2Factory; import hudson.security.ACL; +import java.beans.Transient; import java.io.BufferedReader; import java.io.IOException; import java.io.PrintStream; @@ -145,8 +145,6 @@ public abstract class EC2Cloud extends Cloud { private transient Secret secretKey; @CheckForNull private String sshKeysCredentialsId; - @CheckForNull - private transient EC2PrivateKey privateKey; // Transient from now on, should maybe be deprecated and the usage be replaced everywhere? /** * Upper bound on how many instances we may provision. @@ -168,8 +166,9 @@ protected EC2Cloud(String id, boolean useInstanceProfileForCredentials, String c this.credentialsId = credentialsId; this.sshKeysCredentialsId = sshKeysCredentialsId; - if (privateKey != null) - this.privateKey = new EC2PrivateKey(privateKey); + if (this.sshKeysCredentialsId == null && privateKey != null){ + migratePrivateSshKeyToCredential(privateKey); + } if (templates == null) { this.templates = Collections.emptyList(); @@ -196,47 +195,39 @@ protected EC2Cloud(String id, boolean useInstanceProfileForCredentials, String c public abstract URL getS3EndpointUrl() throws IOException; - protected Object readResolve() { - this.slaveCountingLock = new ReentrantLock(); + private void migratePrivateSshKeyToCredential(String privateKey){ + // GET matching private key credential from Credential API if exists + Optional keyCredential = SystemCredentialsProvider.getInstance().getCredentials() + .stream() + .filter((cred) -> cred instanceof BasicSSHUserPrivateKey) + .filter((cred) -> ((BasicSSHUserPrivateKey)cred).getPrivateKey().trim().equals(privateKey.trim())) + .map(cred -> (BasicSSHUserPrivateKey)cred) + .findFirst(); + + if (keyCredential.isPresent()){ + // SET this.sshKeysCredentialsId with the found credential + sshKeysCredentialsId = keyCredential.get().getId(); + } else { + // CREATE new credential + String credsId = UUID.randomUUID().toString(); - if (this.sshKeysCredentialsId == null && this.privateKey != null){ - // GET matching private key credential from Credential API if exists - Optional keyCredential = SystemCredentialsProvider.getInstance().getCredentials() - .stream() - .filter((cred) -> cred instanceof BasicSSHUserPrivateKey) - .filter((cred) -> ((BasicSSHUserPrivateKey)cred).getPrivateKey().trim().equals(this.privateKey.getPrivateKey().trim())) - .map(cred -> (BasicSSHUserPrivateKey)cred) - .findFirst(); - - if (keyCredential.isPresent()){ - // SET this.sshKeysCredentialsId with the found credential - sshKeysCredentialsId = keyCredential.get().getId(); - } else { - // CREATE new credential - String credsId = UUID.randomUUID().toString(); - - BasicSSHUserPrivateKey sshKeyCredentials = new BasicSSHUserPrivateKey(CredentialsScope.SYSTEM, credsId, "key", - new BasicSSHUserPrivateKey.PrivateKeySource() { - @NonNull - @Override - public List getPrivateKeys() { - return Collections.singletonList(privateKey.getPrivateKey().trim()); - } - }, "", "EC2 Cloud Private Key - " + getDisplayName()); + BasicSSHUserPrivateKey sshKeyCredentials = new BasicSSHUserPrivateKey(CredentialsScope.SYSTEM, credsId, "key", + new BasicSSHUserPrivateKey.PrivateKeySource() { + @NonNull + @Override + public List getPrivateKeys() { + return Collections.singletonList(privateKey.trim()); + } + }, "", "EC2 Cloud Private Key - " + getDisplayName()); - addNewGlobalCredential(sshKeyCredentials); + addNewGlobalCredential(sshKeyCredentials); - sshKeysCredentialsId = credsId; - } + sshKeysCredentialsId = credsId; } + } - // Make sure this.privateKey variable exists as before and that it is taken from credentials - if (this.sshKeysCredentialsId != null) { - BasicSSHUserPrivateKey privateKeyCredential = getSshCredential(sshKeysCredentialsId); - if (privateKeyCredential != null) { - this.privateKey = new EC2PrivateKey(privateKeyCredential.getPrivateKey()); - } - } + protected Object readResolve() { + this.slaveCountingLock = new ReentrantLock(); for (SlaveTemplate t : templates) t.parent = this; @@ -317,8 +308,9 @@ public String getSshKeysCredentialsId() { return sshKeysCredentialsId; } + @Deprecated public EC2PrivateKey getPrivateKey() { - return privateKey; + return null; // This enforces that CasC will never output privateKey on export } public String getInstanceCapStr() { @@ -369,7 +361,7 @@ public SlaveTemplate getTemplate(Label label) { */ public synchronized KeyPair getKeyPair() throws AmazonClientException, IOException { if (usableKeyPair == null) - usableKeyPair = privateKey.find(connect()); + usableKeyPair = resolvePrivateKey(this).find(connect()); return usableKeyPair; } @@ -948,6 +940,16 @@ public static URL checkEndPoint(String url) throws FormValidation { } } + public static EC2PrivateKey resolvePrivateKey(EC2Cloud cloud){ + if (cloud.sshKeysCredentialsId != null) { + BasicSSHUserPrivateKey privateKeyCredential = getSshCredential(cloud.sshKeysCredentialsId); + if (privateKeyCredential != null) { + return new EC2PrivateKey(privateKeyCredential.getPrivateKey()); + } + } + return null; + } + private static BasicSSHUserPrivateKey getSshCredential(String id){ BasicSSHUserPrivateKey credential = CredentialsMatchers.firstOrNull( diff --git a/src/main/java/hudson/plugins/ec2/SlaveTemplate.java b/src/main/java/hudson/plugins/ec2/SlaveTemplate.java index 4f542a0f2..8826448aa 100644 --- a/src/main/java/hudson/plugins/ec2/SlaveTemplate.java +++ b/src/main/java/hudson/plugins/ec2/SlaveTemplate.java @@ -1232,7 +1232,7 @@ protected EC2SpotSlave newSpotSlave(SpotInstanceRequest sir) throws FormExceptio * Get a KeyPair from the configured information for the slave template */ private KeyPair getKeyPair(AmazonEC2 ec2) throws IOException, AmazonClientException { - KeyPair keyPair = parent.getPrivateKey().find(ec2); + KeyPair keyPair = EC2Cloud.resolvePrivateKey(parent).find(ec2); if (keyPair == null) { throw new AmazonClientException("No matching keypair found on EC2. Is the EC2 private key a valid one?"); } diff --git a/src/main/java/hudson/plugins/ec2/ssh/EC2UnixLauncher.java b/src/main/java/hudson/plugins/ec2/ssh/EC2UnixLauncher.java index 0a71b06c7..24d6123cc 100644 --- a/src/main/java/hudson/plugins/ec2/ssh/EC2UnixLauncher.java +++ b/src/main/java/hudson/plugins/ec2/ssh/EC2UnixLauncher.java @@ -289,7 +289,7 @@ private boolean executeRemote(EC2Computer computer, Connection conn, String chec } private File createIdentityKeyFile(EC2Computer computer) throws IOException { - String privateKey = computer.getCloud().getPrivateKey().getPrivateKey(); + String privateKey = EC2Cloud.resolvePrivateKey(computer.getCloud()).getPrivateKey(); File tempFile = File.createTempFile("ec2_", ".pem"); try { diff --git a/src/main/java/hudson/plugins/ec2/win/EC2WindowsLauncher.java b/src/main/java/hudson/plugins/ec2/win/EC2WindowsLauncher.java index b176289ac..57cbe19c4 100644 --- a/src/main/java/hudson/plugins/ec2/win/EC2WindowsLauncher.java +++ b/src/main/java/hudson/plugins/ec2/win/EC2WindowsLauncher.java @@ -2,11 +2,7 @@ import hudson.model.Descriptor; import hudson.model.TaskListener; -import hudson.plugins.ec2.EC2AbstractSlave; -import hudson.plugins.ec2.EC2Computer; -import hudson.plugins.ec2.EC2ComputerLauncher; -import hudson.plugins.ec2.EC2HostAddressProvider; -import hudson.plugins.ec2.SlaveTemplate; +import hudson.plugins.ec2.*; import hudson.plugins.ec2.win.winrm.WindowsProcess; import hudson.remoting.Channel; import hudson.remoting.Channel.Listener; @@ -157,7 +153,7 @@ private WinConnection connectToWinRM(EC2Computer computer, EC2AbstractSlave node Thread.sleep(sleepBetweenAttempts); continue; } - String password = node.getCloud().getPrivateKey().decryptWindowsPassword(passwordData); + String password = EC2Cloud.resolvePrivateKey(node.getCloud()).decryptWindowsPassword(passwordData); if (!node.getRemoteAdmin().equals("Administrator")) { logger.println("WARNING: For password retrieval remote admin must be Administrator, ignoring user provided value"); } diff --git a/src/test/java/hudson/plugins/ec2/util/AmazonEC2FactoryMockImpl.java b/src/test/java/hudson/plugins/ec2/util/AmazonEC2FactoryMockImpl.java index 3edcc3a17..1c7fd19a4 100644 --- a/src/test/java/hudson/plugins/ec2/util/AmazonEC2FactoryMockImpl.java +++ b/src/test/java/hudson/plugins/ec2/util/AmazonEC2FactoryMockImpl.java @@ -102,7 +102,7 @@ private static Image createMockImage(String amiId) { private static void mockDescribeKeyPairs(AmazonEC2Client mock) { Mockito.doAnswer(invocationOnMock -> { KeyPairInfo keyPairInfo = new KeyPairInfo(); - keyPairInfo.setKeyFingerprint(Jenkins.get().clouds.get(AmazonEC2Cloud.class).getPrivateKey().getFingerprint()); + keyPairInfo.setKeyFingerprint(EC2Cloud.resolvePrivateKey(Jenkins.get().clouds.get(AmazonEC2Cloud.class)).getFingerprint()); return new DescribeKeyPairsResult().withKeyPairs(keyPairInfo); }).when(mock).describeKeyPairs(); } From 5eaa1a4fb585e67fb4447ffe454b2a4efab4346b Mon Sep 17 00:00:00 2001 From: Damian Jesionek Date: Thu, 19 Mar 2020 17:10:33 +0100 Subject: [PATCH 17/45] [JENKINS-56927] Minor code cleanup --- pom.xml | 4 ---- src/main/java/hudson/plugins/ec2/EC2Cloud.java | 1 - .../plugins/ec2/AmazonEC2Cloud/config-entries.jelly | 11 +++-------- 3 files changed, 3 insertions(+), 13 deletions(-) diff --git a/pom.xml b/pom.xml index d4cd0409f..411ea40df 100644 --- a/pom.xml +++ b/pom.xml @@ -101,25 +101,21 @@ THE SOFTWARE. - org.jenkins-ci.plugins credentials 2.1.17 - org.jenkins-ci.plugins aws-credentials 1.11 - org.jenkins-ci.plugins ssh-credentials 1.14 - org.jenkins-ci.plugins bouncycastle-api diff --git a/src/main/java/hudson/plugins/ec2/EC2Cloud.java b/src/main/java/hudson/plugins/ec2/EC2Cloud.java index 497ead428..f334d7ef6 100644 --- a/src/main/java/hudson/plugins/ec2/EC2Cloud.java +++ b/src/main/java/hudson/plugins/ec2/EC2Cloud.java @@ -39,7 +39,6 @@ import hudson.plugins.ec2.util.AmazonEC2Factory; import hudson.security.ACL; -import java.beans.Transient; import java.io.BufferedReader; import java.io.IOException; import java.io.PrintStream; diff --git a/src/main/resources/hudson/plugins/ec2/AmazonEC2Cloud/config-entries.jelly b/src/main/resources/hudson/plugins/ec2/AmazonEC2Cloud/config-entries.jelly index b1b9e8676..983bf1311 100644 --- a/src/main/resources/hudson/plugins/ec2/AmazonEC2Cloud/config-entries.jelly +++ b/src/main/resources/hudson/plugins/ec2/AmazonEC2Cloud/config-entries.jelly @@ -36,14 +36,9 @@ THE SOFTWARE. - - - - - - + + + From 4868bb103e0fa9f47e082ace1b03de8f329f7ccc Mon Sep 17 00:00:00 2001 From: Damian Jesionek Date: Fri, 20 Mar 2020 09:20:36 +0100 Subject: [PATCH 18/45] [JENKINS-56927] Fixed bugs found by spotbugs --- src/main/java/hudson/plugins/ec2/AmazonEC2Cloud.java | 9 +++++---- src/main/java/hudson/plugins/ec2/EC2Cloud.java | 3 --- src/main/java/hudson/plugins/ec2/Eucalyptus.java | 9 ++++++--- 3 files changed, 11 insertions(+), 10 deletions(-) diff --git a/src/main/java/hudson/plugins/ec2/AmazonEC2Cloud.java b/src/main/java/hudson/plugins/ec2/AmazonEC2Cloud.java index d2662ea4e..b9e188899 100644 --- a/src/main/java/hudson/plugins/ec2/AmazonEC2Cloud.java +++ b/src/main/java/hudson/plugins/ec2/AmazonEC2Cloud.java @@ -25,7 +25,7 @@ import com.amazonaws.SdkClientException; import com.cloudbees.jenkins.plugins.sshcredentials.impl.BasicSSHUserPrivateKey; -import com.cloudbees.plugins.credentials.CredentialsMatcher; +import com.cloudbees.plugins.credentials.CredentialsMatchers; import com.cloudbees.plugins.credentials.CredentialsProvider; import com.cloudbees.plugins.credentials.common.StandardListBoxModel; import com.cloudbees.plugins.credentials.domains.DomainRequirement; @@ -34,8 +34,8 @@ import hudson.Util; import hudson.model.Failure; import hudson.model.Item; -import hudson.model.ItemGroup; import hudson.plugins.ec2.util.AmazonEC2Factory; +import hudson.security.ACL; import hudson.slaves.Cloud; import hudson.util.FormValidation; import hudson.util.ListBoxModel; @@ -43,9 +43,9 @@ import java.io.IOException; import java.net.MalformedURLException; import java.net.URL; +import java.util.Collections; import java.util.List; import java.util.Locale; -import java.util.Objects; import javax.annotation.Nullable; import javax.servlet.ServletException; @@ -215,7 +215,8 @@ public ListBoxModel doFillSshKeysCredentialsIdItems( } return result - .includeMatchingAs(null, (ItemGroup) null, BasicSSHUserPrivateKey.class, null, null) + .includeMatchingAs(Jenkins.getAuthentication(), Jenkins.getInstanceOrNull(), BasicSSHUserPrivateKey.class, Collections.emptyList(), CredentialsMatchers.always()) + .includeMatchingAs(ACL.SYSTEM, Jenkins.getInstanceOrNull(), BasicSSHUserPrivateKey.class, Collections.emptyList(), CredentialsMatchers.always()) .includeCurrentValue(sshKeysCredentialsId); } diff --git a/src/main/java/hudson/plugins/ec2/EC2Cloud.java b/src/main/java/hudson/plugins/ec2/EC2Cloud.java index f334d7ef6..b6cfc5a1c 100644 --- a/src/main/java/hudson/plugins/ec2/EC2Cloud.java +++ b/src/main/java/hudson/plugins/ec2/EC2Cloud.java @@ -1032,9 +1032,6 @@ protected FormValidation doTestConnection(URL ec2endpoint, boolean useInstancePr AmazonEC2 ec2 = AmazonEC2Factory.getInstance().connect(credentialsProvider, ec2endpoint); ec2.describeInstances(); - if (privateKey == null) - return FormValidation.error("Private key is not specified. Please fill the private key field with a valid one."); - if (privateKey.trim().length() > 0) { // check if this key exists EC2PrivateKey pk = new EC2PrivateKey(privateKey); diff --git a/src/main/java/hudson/plugins/ec2/Eucalyptus.java b/src/main/java/hudson/plugins/ec2/Eucalyptus.java index 2e275c2cf..c0fea6a8c 100644 --- a/src/main/java/hudson/plugins/ec2/Eucalyptus.java +++ b/src/main/java/hudson/plugins/ec2/Eucalyptus.java @@ -24,15 +24,18 @@ package hudson.plugins.ec2; import com.cloudbees.jenkins.plugins.sshcredentials.impl.BasicSSHUserPrivateKey; +import com.cloudbees.plugins.credentials.CredentialsMatchers; import com.cloudbees.plugins.credentials.CredentialsProvider; import com.cloudbees.plugins.credentials.common.StandardListBoxModel; +import com.cloudbees.plugins.credentials.domains.DomainRequirement; import hudson.Extension; import hudson.model.Item; -import hudson.model.ItemGroup; +import hudson.security.ACL; import hudson.util.FormValidation; import java.io.IOException; import java.net.URL; +import java.util.Collections; import java.util.List; import javax.servlet.ServletException; @@ -42,7 +45,6 @@ import org.kohsuke.stapler.AncestorInPath; import org.kohsuke.stapler.DataBoundConstructor; import org.kohsuke.stapler.QueryParameter; -import org.kohsuke.stapler.StaplerResponse; import org.kohsuke.stapler.interceptor.RequirePOST; /** @@ -104,7 +106,8 @@ public ListBoxModel doFillSshKeysCredentialsIdItems( } return result - .includeMatchingAs(null, (ItemGroup) null, BasicSSHUserPrivateKey.class, null, null) + .includeMatchingAs(Jenkins.getAuthentication(), Jenkins.getInstanceOrNull(), BasicSSHUserPrivateKey.class, Collections.emptyList(), CredentialsMatchers.always()) + .includeMatchingAs(ACL.SYSTEM, Jenkins.getInstanceOrNull(), BasicSSHUserPrivateKey.class, Collections.emptyList(), CredentialsMatchers.always()) .includeCurrentValue(sshKeysCredentialsId); } From 997fdc80f51dde8241e1e6c2029da268b193268e Mon Sep 17 00:00:00 2001 From: Damian Jesionek Date: Fri, 20 Mar 2020 10:08:16 +0100 Subject: [PATCH 19/45] [JENKINS-56927] Fixed warnings found by spotbugs --- .../hudson/plugins/ec2/AmazonEC2Cloud.java | 20 +++--------------- .../java/hudson/plugins/ec2/Eucalyptus.java | 21 +++---------------- 2 files changed, 6 insertions(+), 35 deletions(-) diff --git a/src/main/java/hudson/plugins/ec2/AmazonEC2Cloud.java b/src/main/java/hudson/plugins/ec2/AmazonEC2Cloud.java index b9e188899..790058bdb 100644 --- a/src/main/java/hudson/plugins/ec2/AmazonEC2Cloud.java +++ b/src/main/java/hudson/plugins/ec2/AmazonEC2Cloud.java @@ -26,14 +26,12 @@ import com.amazonaws.SdkClientException; import com.cloudbees.jenkins.plugins.sshcredentials.impl.BasicSSHUserPrivateKey; import com.cloudbees.plugins.credentials.CredentialsMatchers; -import com.cloudbees.plugins.credentials.CredentialsProvider; import com.cloudbees.plugins.credentials.common.StandardListBoxModel; import com.cloudbees.plugins.credentials.domains.DomainRequirement; import com.google.common.annotations.VisibleForTesting; import hudson.Extension; import hudson.Util; import hudson.model.Failure; -import hudson.model.Item; import hudson.plugins.ec2.util.AmazonEC2Factory; import hudson.security.ACL; import hudson.slaves.Cloud; @@ -198,25 +196,13 @@ public ListBoxModel doFillRegionItems( return model; } - public ListBoxModel doFillSshKeysCredentialsIdItems( - @AncestorInPath Item item, - @QueryParameter String sshKeysCredentialsId) { + public ListBoxModel doFillSshKeysCredentialsIdItems(@QueryParameter String sshKeysCredentialsId) { StandardListBoxModel result = new StandardListBoxModel(); - if (item == null) { - if (!Jenkins.get().hasPermission(Jenkins.ADMINISTER)) { - return result.includeCurrentValue(sshKeysCredentialsId); - } - } else { - if (!item.hasPermission(Item.EXTENDED_READ) - && !item.hasPermission(CredentialsProvider.USE_ITEM)) { - return result.includeCurrentValue(sshKeysCredentialsId); - } - } return result - .includeMatchingAs(Jenkins.getAuthentication(), Jenkins.getInstanceOrNull(), BasicSSHUserPrivateKey.class, Collections.emptyList(), CredentialsMatchers.always()) - .includeMatchingAs(ACL.SYSTEM, Jenkins.getInstanceOrNull(), BasicSSHUserPrivateKey.class, Collections.emptyList(), CredentialsMatchers.always()) + .includeMatchingAs(Jenkins.getAuthentication(), Jenkins.get(), BasicSSHUserPrivateKey.class, Collections.emptyList(), CredentialsMatchers.always()) + .includeMatchingAs(ACL.SYSTEM, Jenkins.get(), BasicSSHUserPrivateKey.class, Collections.emptyList(), CredentialsMatchers.always()) .includeCurrentValue(sshKeysCredentialsId); } diff --git a/src/main/java/hudson/plugins/ec2/Eucalyptus.java b/src/main/java/hudson/plugins/ec2/Eucalyptus.java index c0fea6a8c..acf74b86b 100644 --- a/src/main/java/hudson/plugins/ec2/Eucalyptus.java +++ b/src/main/java/hudson/plugins/ec2/Eucalyptus.java @@ -25,11 +25,9 @@ import com.cloudbees.jenkins.plugins.sshcredentials.impl.BasicSSHUserPrivateKey; import com.cloudbees.plugins.credentials.CredentialsMatchers; -import com.cloudbees.plugins.credentials.CredentialsProvider; import com.cloudbees.plugins.credentials.common.StandardListBoxModel; import com.cloudbees.plugins.credentials.domains.DomainRequirement; import hudson.Extension; -import hudson.model.Item; import hudson.security.ACL; import hudson.util.FormValidation; @@ -42,7 +40,6 @@ import hudson.util.ListBoxModel; import jenkins.model.Jenkins; -import org.kohsuke.stapler.AncestorInPath; import org.kohsuke.stapler.DataBoundConstructor; import org.kohsuke.stapler.QueryParameter; import org.kohsuke.stapler.interceptor.RequirePOST; @@ -89,25 +86,13 @@ public String getDisplayName() { return "Eucalyptus"; } - public ListBoxModel doFillSshKeysCredentialsIdItems( - @AncestorInPath Item item, - @QueryParameter String sshKeysCredentialsId) { + public ListBoxModel doFillSshKeysCredentialsIdItems(@QueryParameter String sshKeysCredentialsId) { StandardListBoxModel result = new StandardListBoxModel(); - if (item == null) { - if (!Jenkins.get().hasPermission(Jenkins.ADMINISTER)) { - return result.includeCurrentValue(sshKeysCredentialsId); - } - } else { - if (!item.hasPermission(Item.EXTENDED_READ) - && !item.hasPermission(CredentialsProvider.USE_ITEM)) { - return result.includeCurrentValue(sshKeysCredentialsId); - } - } return result - .includeMatchingAs(Jenkins.getAuthentication(), Jenkins.getInstanceOrNull(), BasicSSHUserPrivateKey.class, Collections.emptyList(), CredentialsMatchers.always()) - .includeMatchingAs(ACL.SYSTEM, Jenkins.getInstanceOrNull(), BasicSSHUserPrivateKey.class, Collections.emptyList(), CredentialsMatchers.always()) + .includeMatchingAs(Jenkins.getAuthentication(), Jenkins.get(), BasicSSHUserPrivateKey.class, Collections.emptyList(), CredentialsMatchers.always()) + .includeMatchingAs(ACL.SYSTEM, Jenkins.get(), BasicSSHUserPrivateKey.class, Collections.emptyList(), CredentialsMatchers.always()) .includeCurrentValue(sshKeysCredentialsId); } From ab02e81bf7a7ca62fe5550ef883e6dec2a65cf20 Mon Sep 17 00:00:00 2001 From: djesionek Date: Wed, 8 Apr 2020 19:45:27 +0200 Subject: [PATCH 20/45] [JENKINS-56927] Apply update of deps as suggested Co-Authored-By: Matt Sicker --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 411ea40df..f4d5a861e 100644 --- a/pom.xml +++ b/pom.xml @@ -104,7 +104,7 @@ THE SOFTWARE. org.jenkins-ci.plugins credentials - 2.1.17 + 2.3.5 org.jenkins-ci.plugins @@ -114,7 +114,7 @@ THE SOFTWARE. org.jenkins-ci.plugins ssh-credentials - 1.14 + 1.18.1 org.jenkins-ci.plugins From 1e8bf07119fefbb86a6b30cb80a5a99d99ba1521 Mon Sep 17 00:00:00 2001 From: djesionek Date: Wed, 8 Apr 2020 19:46:31 +0200 Subject: [PATCH 21/45] [JENKINS-56927] Removed user scoping of credentials as suggested Co-Authored-By: Matt Sicker --- .../hudson/plugins/ec2/AmazonEC2Cloud/config-entries.jelly | 2 +- .../hudson/plugins/ec2/Eucalyptus/config-entries.jelly | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/resources/hudson/plugins/ec2/AmazonEC2Cloud/config-entries.jelly b/src/main/resources/hudson/plugins/ec2/AmazonEC2Cloud/config-entries.jelly index 983bf1311..b852445c4 100644 --- a/src/main/resources/hudson/plugins/ec2/AmazonEC2Cloud/config-entries.jelly +++ b/src/main/resources/hudson/plugins/ec2/AmazonEC2Cloud/config-entries.jelly @@ -37,7 +37,7 @@ THE SOFTWARE. - + diff --git a/src/main/resources/hudson/plugins/ec2/Eucalyptus/config-entries.jelly b/src/main/resources/hudson/plugins/ec2/Eucalyptus/config-entries.jelly index 926c8ca9d..9e1b58a6e 100644 --- a/src/main/resources/hudson/plugins/ec2/Eucalyptus/config-entries.jelly +++ b/src/main/resources/hudson/plugins/ec2/Eucalyptus/config-entries.jelly @@ -32,7 +32,7 @@ THE SOFTWARE. - + From 6ecfe8ff9741b70da0905278c0dc76171f26b1d7 Mon Sep 17 00:00:00 2001 From: Damian Jesionek Date: Wed, 8 Apr 2020 21:33:55 +0200 Subject: [PATCH 22/45] [JENKINS-56927] Added permission checks as suggested --- src/main/java/hudson/plugins/ec2/AmazonEC2Cloud.java | 1 + src/main/java/hudson/plugins/ec2/EC2Cloud.java | 1 + src/main/java/hudson/plugins/ec2/Eucalyptus.java | 1 + 3 files changed, 3 insertions(+) diff --git a/src/main/java/hudson/plugins/ec2/AmazonEC2Cloud.java b/src/main/java/hudson/plugins/ec2/AmazonEC2Cloud.java index 790058bdb..378f70aea 100644 --- a/src/main/java/hudson/plugins/ec2/AmazonEC2Cloud.java +++ b/src/main/java/hudson/plugins/ec2/AmazonEC2Cloud.java @@ -197,6 +197,7 @@ public ListBoxModel doFillRegionItems( } public ListBoxModel doFillSshKeysCredentialsIdItems(@QueryParameter String sshKeysCredentialsId) { + Jenkins.get().checkPermission(Jenkins.ADMINISTER); StandardListBoxModel result = new StandardListBoxModel(); diff --git a/src/main/java/hudson/plugins/ec2/EC2Cloud.java b/src/main/java/hudson/plugins/ec2/EC2Cloud.java index b6cfc5a1c..eb92cb77a 100644 --- a/src/main/java/hudson/plugins/ec2/EC2Cloud.java +++ b/src/main/java/hudson/plugins/ec2/EC2Cloud.java @@ -985,6 +985,7 @@ public FormValidation doCheckUseInstanceProfileForCredentials(@QueryParameter bo } public FormValidation doCheckSshKeysCredentialsId(@QueryParameter String value) throws IOException, ServletException { + Jenkins.get().checkPermission(Jenkins.ADMINISTER); if (value == null || value.isEmpty()){ return FormValidation.error("No ssh credentials selected"); diff --git a/src/main/java/hudson/plugins/ec2/Eucalyptus.java b/src/main/java/hudson/plugins/ec2/Eucalyptus.java index acf74b86b..67eb9115f 100644 --- a/src/main/java/hudson/plugins/ec2/Eucalyptus.java +++ b/src/main/java/hudson/plugins/ec2/Eucalyptus.java @@ -87,6 +87,7 @@ public String getDisplayName() { } public ListBoxModel doFillSshKeysCredentialsIdItems(@QueryParameter String sshKeysCredentialsId) { + Jenkins.get().checkPermission(Jenkins.ADMINISTER); StandardListBoxModel result = new StandardListBoxModel(); From 197e2fef53e1b93bc7517b1c260a7d8be1793d1a Mon Sep 17 00:00:00 2001 From: Damian Jesionek Date: Wed, 8 Apr 2020 21:35:27 +0200 Subject: [PATCH 23/45] [JENKINS-56927] Pulled duplicates to common superclass --- pom.xml | 4 ++-- src/main/java/hudson/plugins/ec2/AmazonEC2Cloud.java | 11 ----------- src/main/java/hudson/plugins/ec2/EC2Cloud.java | 12 ++++++++++++ src/main/java/hudson/plugins/ec2/Eucalyptus.java | 11 ----------- 4 files changed, 14 insertions(+), 24 deletions(-) diff --git a/pom.xml b/pom.xml index f4d5a861e..411ea40df 100644 --- a/pom.xml +++ b/pom.xml @@ -104,7 +104,7 @@ THE SOFTWARE. org.jenkins-ci.plugins credentials - 2.3.5 + 2.1.17 org.jenkins-ci.plugins @@ -114,7 +114,7 @@ THE SOFTWARE. org.jenkins-ci.plugins ssh-credentials - 1.18.1 + 1.14 org.jenkins-ci.plugins diff --git a/src/main/java/hudson/plugins/ec2/AmazonEC2Cloud.java b/src/main/java/hudson/plugins/ec2/AmazonEC2Cloud.java index 378f70aea..f5701245f 100644 --- a/src/main/java/hudson/plugins/ec2/AmazonEC2Cloud.java +++ b/src/main/java/hudson/plugins/ec2/AmazonEC2Cloud.java @@ -196,17 +196,6 @@ public ListBoxModel doFillRegionItems( return model; } - public ListBoxModel doFillSshKeysCredentialsIdItems(@QueryParameter String sshKeysCredentialsId) { - Jenkins.get().checkPermission(Jenkins.ADMINISTER); - - StandardListBoxModel result = new StandardListBoxModel(); - - return result - .includeMatchingAs(Jenkins.getAuthentication(), Jenkins.get(), BasicSSHUserPrivateKey.class, Collections.emptyList(), CredentialsMatchers.always()) - .includeMatchingAs(ACL.SYSTEM, Jenkins.get(), BasicSSHUserPrivateKey.class, Collections.emptyList(), CredentialsMatchers.always()) - .includeCurrentValue(sshKeysCredentialsId); - } - // Will use the alternate EC2 endpoint if provided by the UI (via a @QueryParameter field), or use the default // value if not specified. @VisibleForTesting diff --git a/src/main/java/hudson/plugins/ec2/EC2Cloud.java b/src/main/java/hudson/plugins/ec2/EC2Cloud.java index eb92cb77a..c34f8d1d2 100644 --- a/src/main/java/hudson/plugins/ec2/EC2Cloud.java +++ b/src/main/java/hudson/plugins/ec2/EC2Cloud.java @@ -34,6 +34,7 @@ import com.cloudbees.plugins.credentials.SystemCredentialsProvider; import com.cloudbees.plugins.credentials.common.StandardListBoxModel; import com.cloudbees.plugins.credentials.domains.Domain; +import com.cloudbees.plugins.credentials.domains.DomainRequirement; import edu.umd.cs.findbugs.annotations.NonNull; import hudson.model.*; import hudson.plugins.ec2.util.AmazonEC2Factory; @@ -984,6 +985,17 @@ public FormValidation doCheckUseInstanceProfileForCredentials(@QueryParameter bo return FormValidation.ok(); } + public ListBoxModel doFillSshKeysCredentialsIdItems(@QueryParameter String sshKeysCredentialsId) { + Jenkins.get().checkPermission(Jenkins.ADMINISTER); + + StandardListBoxModel result = new StandardListBoxModel(); + + return result + .includeMatchingAs(Jenkins.getAuthentication(), Jenkins.get(), BasicSSHUserPrivateKey.class, Collections.emptyList(), CredentialsMatchers.always()) + .includeMatchingAs(ACL.SYSTEM, Jenkins.get(), BasicSSHUserPrivateKey.class, Collections.emptyList(), CredentialsMatchers.always()) + .includeCurrentValue(sshKeysCredentialsId); + } + public FormValidation doCheckSshKeysCredentialsId(@QueryParameter String value) throws IOException, ServletException { Jenkins.get().checkPermission(Jenkins.ADMINISTER); diff --git a/src/main/java/hudson/plugins/ec2/Eucalyptus.java b/src/main/java/hudson/plugins/ec2/Eucalyptus.java index 67eb9115f..c3853a014 100644 --- a/src/main/java/hudson/plugins/ec2/Eucalyptus.java +++ b/src/main/java/hudson/plugins/ec2/Eucalyptus.java @@ -86,17 +86,6 @@ public String getDisplayName() { return "Eucalyptus"; } - public ListBoxModel doFillSshKeysCredentialsIdItems(@QueryParameter String sshKeysCredentialsId) { - Jenkins.get().checkPermission(Jenkins.ADMINISTER); - - StandardListBoxModel result = new StandardListBoxModel(); - - return result - .includeMatchingAs(Jenkins.getAuthentication(), Jenkins.get(), BasicSSHUserPrivateKey.class, Collections.emptyList(), CredentialsMatchers.always()) - .includeMatchingAs(ACL.SYSTEM, Jenkins.get(), BasicSSHUserPrivateKey.class, Collections.emptyList(), CredentialsMatchers.always()) - .includeCurrentValue(sshKeysCredentialsId); - } - @Override @RequirePOST public FormValidation doTestConnection(@QueryParameter URL ec2endpoint, @QueryParameter boolean useInstanceProfileForCredentials, @QueryParameter String credentialsId, @QueryParameter String sshKeysCredentialsId, @QueryParameter String roleArn, @QueryParameter String roleSessionName, @QueryParameter String region) From d04f9ad10a42311403b7d0418c4a4016a8fc6313 Mon Sep 17 00:00:00 2001 From: Damian Jesionek Date: Wed, 8 Apr 2020 21:36:41 +0200 Subject: [PATCH 24/45] Revert "[JENKINS-56927] Pulled duplicates to common superclass" This reverts commit 197e2fef53e1b93bc7517b1c260a7d8be1793d1a. --- pom.xml | 4 ++-- src/main/java/hudson/plugins/ec2/AmazonEC2Cloud.java | 11 +++++++++++ src/main/java/hudson/plugins/ec2/EC2Cloud.java | 12 ------------ src/main/java/hudson/plugins/ec2/Eucalyptus.java | 11 +++++++++++ 4 files changed, 24 insertions(+), 14 deletions(-) diff --git a/pom.xml b/pom.xml index 411ea40df..f4d5a861e 100644 --- a/pom.xml +++ b/pom.xml @@ -104,7 +104,7 @@ THE SOFTWARE. org.jenkins-ci.plugins credentials - 2.1.17 + 2.3.5 org.jenkins-ci.plugins @@ -114,7 +114,7 @@ THE SOFTWARE. org.jenkins-ci.plugins ssh-credentials - 1.14 + 1.18.1 org.jenkins-ci.plugins diff --git a/src/main/java/hudson/plugins/ec2/AmazonEC2Cloud.java b/src/main/java/hudson/plugins/ec2/AmazonEC2Cloud.java index f5701245f..378f70aea 100644 --- a/src/main/java/hudson/plugins/ec2/AmazonEC2Cloud.java +++ b/src/main/java/hudson/plugins/ec2/AmazonEC2Cloud.java @@ -196,6 +196,17 @@ public ListBoxModel doFillRegionItems( return model; } + public ListBoxModel doFillSshKeysCredentialsIdItems(@QueryParameter String sshKeysCredentialsId) { + Jenkins.get().checkPermission(Jenkins.ADMINISTER); + + StandardListBoxModel result = new StandardListBoxModel(); + + return result + .includeMatchingAs(Jenkins.getAuthentication(), Jenkins.get(), BasicSSHUserPrivateKey.class, Collections.emptyList(), CredentialsMatchers.always()) + .includeMatchingAs(ACL.SYSTEM, Jenkins.get(), BasicSSHUserPrivateKey.class, Collections.emptyList(), CredentialsMatchers.always()) + .includeCurrentValue(sshKeysCredentialsId); + } + // Will use the alternate EC2 endpoint if provided by the UI (via a @QueryParameter field), or use the default // value if not specified. @VisibleForTesting diff --git a/src/main/java/hudson/plugins/ec2/EC2Cloud.java b/src/main/java/hudson/plugins/ec2/EC2Cloud.java index c34f8d1d2..eb92cb77a 100644 --- a/src/main/java/hudson/plugins/ec2/EC2Cloud.java +++ b/src/main/java/hudson/plugins/ec2/EC2Cloud.java @@ -34,7 +34,6 @@ import com.cloudbees.plugins.credentials.SystemCredentialsProvider; import com.cloudbees.plugins.credentials.common.StandardListBoxModel; import com.cloudbees.plugins.credentials.domains.Domain; -import com.cloudbees.plugins.credentials.domains.DomainRequirement; import edu.umd.cs.findbugs.annotations.NonNull; import hudson.model.*; import hudson.plugins.ec2.util.AmazonEC2Factory; @@ -985,17 +984,6 @@ public FormValidation doCheckUseInstanceProfileForCredentials(@QueryParameter bo return FormValidation.ok(); } - public ListBoxModel doFillSshKeysCredentialsIdItems(@QueryParameter String sshKeysCredentialsId) { - Jenkins.get().checkPermission(Jenkins.ADMINISTER); - - StandardListBoxModel result = new StandardListBoxModel(); - - return result - .includeMatchingAs(Jenkins.getAuthentication(), Jenkins.get(), BasicSSHUserPrivateKey.class, Collections.emptyList(), CredentialsMatchers.always()) - .includeMatchingAs(ACL.SYSTEM, Jenkins.get(), BasicSSHUserPrivateKey.class, Collections.emptyList(), CredentialsMatchers.always()) - .includeCurrentValue(sshKeysCredentialsId); - } - public FormValidation doCheckSshKeysCredentialsId(@QueryParameter String value) throws IOException, ServletException { Jenkins.get().checkPermission(Jenkins.ADMINISTER); diff --git a/src/main/java/hudson/plugins/ec2/Eucalyptus.java b/src/main/java/hudson/plugins/ec2/Eucalyptus.java index c3853a014..67eb9115f 100644 --- a/src/main/java/hudson/plugins/ec2/Eucalyptus.java +++ b/src/main/java/hudson/plugins/ec2/Eucalyptus.java @@ -86,6 +86,17 @@ public String getDisplayName() { return "Eucalyptus"; } + public ListBoxModel doFillSshKeysCredentialsIdItems(@QueryParameter String sshKeysCredentialsId) { + Jenkins.get().checkPermission(Jenkins.ADMINISTER); + + StandardListBoxModel result = new StandardListBoxModel(); + + return result + .includeMatchingAs(Jenkins.getAuthentication(), Jenkins.get(), BasicSSHUserPrivateKey.class, Collections.emptyList(), CredentialsMatchers.always()) + .includeMatchingAs(ACL.SYSTEM, Jenkins.get(), BasicSSHUserPrivateKey.class, Collections.emptyList(), CredentialsMatchers.always()) + .includeCurrentValue(sshKeysCredentialsId); + } + @Override @RequirePOST public FormValidation doTestConnection(@QueryParameter URL ec2endpoint, @QueryParameter boolean useInstanceProfileForCredentials, @QueryParameter String credentialsId, @QueryParameter String sshKeysCredentialsId, @QueryParameter String roleArn, @QueryParameter String roleSessionName, @QueryParameter String region) From 6b0822aa18978d8b1b0045d2cbe3583e33f16ed0 Mon Sep 17 00:00:00 2001 From: Damian Jesionek Date: Wed, 8 Apr 2020 21:38:07 +0200 Subject: [PATCH 25/45] [JENKINS-56927] Pulled duplicates to common superclass --- src/main/java/hudson/plugins/ec2/AmazonEC2Cloud.java | 11 ----------- src/main/java/hudson/plugins/ec2/EC2Cloud.java | 12 ++++++++++++ src/main/java/hudson/plugins/ec2/Eucalyptus.java | 11 ----------- 3 files changed, 12 insertions(+), 22 deletions(-) diff --git a/src/main/java/hudson/plugins/ec2/AmazonEC2Cloud.java b/src/main/java/hudson/plugins/ec2/AmazonEC2Cloud.java index 378f70aea..f5701245f 100644 --- a/src/main/java/hudson/plugins/ec2/AmazonEC2Cloud.java +++ b/src/main/java/hudson/plugins/ec2/AmazonEC2Cloud.java @@ -196,17 +196,6 @@ public ListBoxModel doFillRegionItems( return model; } - public ListBoxModel doFillSshKeysCredentialsIdItems(@QueryParameter String sshKeysCredentialsId) { - Jenkins.get().checkPermission(Jenkins.ADMINISTER); - - StandardListBoxModel result = new StandardListBoxModel(); - - return result - .includeMatchingAs(Jenkins.getAuthentication(), Jenkins.get(), BasicSSHUserPrivateKey.class, Collections.emptyList(), CredentialsMatchers.always()) - .includeMatchingAs(ACL.SYSTEM, Jenkins.get(), BasicSSHUserPrivateKey.class, Collections.emptyList(), CredentialsMatchers.always()) - .includeCurrentValue(sshKeysCredentialsId); - } - // Will use the alternate EC2 endpoint if provided by the UI (via a @QueryParameter field), or use the default // value if not specified. @VisibleForTesting diff --git a/src/main/java/hudson/plugins/ec2/EC2Cloud.java b/src/main/java/hudson/plugins/ec2/EC2Cloud.java index eb92cb77a..c34f8d1d2 100644 --- a/src/main/java/hudson/plugins/ec2/EC2Cloud.java +++ b/src/main/java/hudson/plugins/ec2/EC2Cloud.java @@ -34,6 +34,7 @@ import com.cloudbees.plugins.credentials.SystemCredentialsProvider; import com.cloudbees.plugins.credentials.common.StandardListBoxModel; import com.cloudbees.plugins.credentials.domains.Domain; +import com.cloudbees.plugins.credentials.domains.DomainRequirement; import edu.umd.cs.findbugs.annotations.NonNull; import hudson.model.*; import hudson.plugins.ec2.util.AmazonEC2Factory; @@ -984,6 +985,17 @@ public FormValidation doCheckUseInstanceProfileForCredentials(@QueryParameter bo return FormValidation.ok(); } + public ListBoxModel doFillSshKeysCredentialsIdItems(@QueryParameter String sshKeysCredentialsId) { + Jenkins.get().checkPermission(Jenkins.ADMINISTER); + + StandardListBoxModel result = new StandardListBoxModel(); + + return result + .includeMatchingAs(Jenkins.getAuthentication(), Jenkins.get(), BasicSSHUserPrivateKey.class, Collections.emptyList(), CredentialsMatchers.always()) + .includeMatchingAs(ACL.SYSTEM, Jenkins.get(), BasicSSHUserPrivateKey.class, Collections.emptyList(), CredentialsMatchers.always()) + .includeCurrentValue(sshKeysCredentialsId); + } + public FormValidation doCheckSshKeysCredentialsId(@QueryParameter String value) throws IOException, ServletException { Jenkins.get().checkPermission(Jenkins.ADMINISTER); diff --git a/src/main/java/hudson/plugins/ec2/Eucalyptus.java b/src/main/java/hudson/plugins/ec2/Eucalyptus.java index 67eb9115f..c3853a014 100644 --- a/src/main/java/hudson/plugins/ec2/Eucalyptus.java +++ b/src/main/java/hudson/plugins/ec2/Eucalyptus.java @@ -86,17 +86,6 @@ public String getDisplayName() { return "Eucalyptus"; } - public ListBoxModel doFillSshKeysCredentialsIdItems(@QueryParameter String sshKeysCredentialsId) { - Jenkins.get().checkPermission(Jenkins.ADMINISTER); - - StandardListBoxModel result = new StandardListBoxModel(); - - return result - .includeMatchingAs(Jenkins.getAuthentication(), Jenkins.get(), BasicSSHUserPrivateKey.class, Collections.emptyList(), CredentialsMatchers.always()) - .includeMatchingAs(ACL.SYSTEM, Jenkins.get(), BasicSSHUserPrivateKey.class, Collections.emptyList(), CredentialsMatchers.always()) - .includeCurrentValue(sshKeysCredentialsId); - } - @Override @RequirePOST public FormValidation doTestConnection(@QueryParameter URL ec2endpoint, @QueryParameter boolean useInstanceProfileForCredentials, @QueryParameter String credentialsId, @QueryParameter String sshKeysCredentialsId, @QueryParameter String roleArn, @QueryParameter String roleSessionName, @QueryParameter String region) From c10c3f0a49db4dd1d60f0de0546eea8b3839962e Mon Sep 17 00:00:00 2001 From: Damian Jesionek Date: Wed, 8 Apr 2020 21:59:45 +0200 Subject: [PATCH 26/45] [JENKINS-56927] Resolved dependency errors with bom --- pom.xml | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/pom.xml b/pom.xml index f4d5a861e..fc724c4f5 100644 --- a/pom.xml +++ b/pom.xml @@ -83,10 +83,12 @@ THE SOFTWARE. 1.50 -SNAPSHOT - 2.150.1 + 2.190.3 8 1.35 1.11.700 + + 1.7.26 @@ -144,7 +146,7 @@ THE SOFTWARE. org.jenkins-ci.plugins trilead-api - 1.0.3 + 1.0.5 io.jenkins.temp.jelly @@ -241,7 +243,7 @@ THE SOFTWARE. org.jenkins-ci.plugins structs - 1.17 + 1.20 test @@ -260,6 +262,13 @@ THE SOFTWARE. + + org.jenkins-ci.main + jenkins-bom + ${jenkins.version} + pom + import + org.hamcrest hamcrest-core From 37ab647d4bfc462040557657a7cdc41922309553 Mon Sep 17 00:00:00 2001 From: Damian Jesionek Date: Mon, 13 Apr 2020 14:24:26 +0200 Subject: [PATCH 27/45] JENKINS-56927: Replaced star imports --- .../hudson/plugins/ec2/AmazonEC2Cloud.java | 12 ++-- .../java/hudson/plugins/ec2/EC2Cloud.java | 21 ++++++- .../java/hudson/plugins/ec2/Eucalyptus.java | 8 --- .../hudson/plugins/ec2/SlaveTemplate.java | 61 ++++++++++++++++++- 4 files changed, 81 insertions(+), 21 deletions(-) diff --git a/src/main/java/hudson/plugins/ec2/AmazonEC2Cloud.java b/src/main/java/hudson/plugins/ec2/AmazonEC2Cloud.java index f5701245f..2b05bf26c 100644 --- a/src/main/java/hudson/plugins/ec2/AmazonEC2Cloud.java +++ b/src/main/java/hudson/plugins/ec2/AmazonEC2Cloud.java @@ -24,16 +24,11 @@ package hudson.plugins.ec2; import com.amazonaws.SdkClientException; -import com.cloudbees.jenkins.plugins.sshcredentials.impl.BasicSSHUserPrivateKey; -import com.cloudbees.plugins.credentials.CredentialsMatchers; -import com.cloudbees.plugins.credentials.common.StandardListBoxModel; -import com.cloudbees.plugins.credentials.domains.DomainRequirement; import com.google.common.annotations.VisibleForTesting; import hudson.Extension; import hudson.Util; import hudson.model.Failure; import hudson.plugins.ec2.util.AmazonEC2Factory; -import hudson.security.ACL; import hudson.slaves.Cloud; import hudson.util.FormValidation; import hudson.util.ListBoxModel; @@ -41,7 +36,6 @@ import java.io.IOException; import java.net.MalformedURLException; import java.net.URL; -import java.util.Collections; import java.util.List; import java.util.Locale; import javax.annotation.Nullable; @@ -49,13 +43,15 @@ import jenkins.model.Jenkins; -import org.kohsuke.stapler.*; +import org.kohsuke.stapler.DataBoundConstructor; +import org.kohsuke.stapler.DataBoundSetter; +import org.kohsuke.stapler.QueryParameter; +import org.kohsuke.stapler.interceptor.RequirePOST; import com.amazonaws.auth.AWSCredentialsProvider; import com.amazonaws.services.ec2.AmazonEC2; import com.amazonaws.services.ec2.model.DescribeRegionsResult; import com.amazonaws.services.ec2.model.Region; -import org.kohsuke.stapler.interceptor.RequirePOST; /** * The original implementation of {@link EC2Cloud}. diff --git a/src/main/java/hudson/plugins/ec2/EC2Cloud.java b/src/main/java/hudson/plugins/ec2/EC2Cloud.java index 934f06606..a4f743bb6 100644 --- a/src/main/java/hudson/plugins/ec2/EC2Cloud.java +++ b/src/main/java/hudson/plugins/ec2/EC2Cloud.java @@ -36,7 +36,15 @@ import com.cloudbees.plugins.credentials.domains.Domain; import com.cloudbees.plugins.credentials.domains.DomainRequirement; import edu.umd.cs.findbugs.annotations.NonNull; -import hudson.model.*; +import hudson.Extension; +import hudson.ProxyConfiguration; +import hudson.model.Computer; +import hudson.model.Descriptor; +import hudson.model.ItemGroup; +import hudson.model.Label; +import hudson.model.Node; +import hudson.model.PeriodicWork; +import hudson.model.TaskListener; import hudson.plugins.ec2.util.AmazonEC2Factory; import hudson.security.ACL; @@ -49,7 +57,16 @@ import java.net.MalformedURLException; import java.net.Proxy; import java.net.URL; -import java.util.*; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Date; +import java.util.EnumSet; +import java.util.HashSet; +import java.util.List; +import java.util.Optional; +import java.util.Set; +import java.util.UUID; import java.util.concurrent.Callable; import java.util.concurrent.TimeUnit; import java.util.concurrent.locks.ReentrantLock; diff --git a/src/main/java/hudson/plugins/ec2/Eucalyptus.java b/src/main/java/hudson/plugins/ec2/Eucalyptus.java index c3853a014..b53356066 100644 --- a/src/main/java/hudson/plugins/ec2/Eucalyptus.java +++ b/src/main/java/hudson/plugins/ec2/Eucalyptus.java @@ -23,23 +23,15 @@ */ package hudson.plugins.ec2; -import com.cloudbees.jenkins.plugins.sshcredentials.impl.BasicSSHUserPrivateKey; -import com.cloudbees.plugins.credentials.CredentialsMatchers; -import com.cloudbees.plugins.credentials.common.StandardListBoxModel; -import com.cloudbees.plugins.credentials.domains.DomainRequirement; import hudson.Extension; -import hudson.security.ACL; import hudson.util.FormValidation; import java.io.IOException; import java.net.URL; -import java.util.Collections; import java.util.List; import javax.servlet.ServletException; -import hudson.util.ListBoxModel; -import jenkins.model.Jenkins; import org.kohsuke.stapler.DataBoundConstructor; import org.kohsuke.stapler.QueryParameter; import org.kohsuke.stapler.interceptor.RequirePOST; diff --git a/src/main/java/hudson/plugins/ec2/SlaveTemplate.java b/src/main/java/hudson/plugins/ec2/SlaveTemplate.java index 2eee9a2a8..30f95a4a8 100644 --- a/src/main/java/hudson/plugins/ec2/SlaveTemplate.java +++ b/src/main/java/hudson/plugins/ec2/SlaveTemplate.java @@ -41,7 +41,12 @@ import javax.servlet.ServletException; -import hudson.plugins.ec2.util.*; +import hudson.plugins.ec2.util.AmazonEC2Factory; +import hudson.plugins.ec2.util.DeviceMappingParser; +import hudson.plugins.ec2.util.EC2AgentConfig; +import hudson.plugins.ec2.util.EC2AgentFactory; +import hudson.plugins.ec2.util.MinimumInstanceChecker; +import hudson.plugins.ec2.util.MinimumNumberOfInstancesTimeRangeConfig; import hudson.XmlFile; import hudson.model.listeners.SaveableListener; @@ -61,12 +66,62 @@ import com.amazonaws.AmazonServiceException; import com.amazonaws.auth.AWSCredentialsProvider; import com.amazonaws.services.ec2.AmazonEC2; -import com.amazonaws.services.ec2.model.*; +import com.amazonaws.services.ec2.model.AmazonEC2Exception; +import com.amazonaws.services.ec2.model.AvailabilityZone; +import com.amazonaws.services.ec2.model.BlockDeviceMapping; +import com.amazonaws.services.ec2.model.CancelSpotInstanceRequestsRequest; +import com.amazonaws.services.ec2.model.CreateTagsRequest; +import com.amazonaws.services.ec2.model.CreditSpecificationRequest; +import com.amazonaws.services.ec2.model.DescribeAvailabilityZonesResult; +import com.amazonaws.services.ec2.model.DescribeImagesRequest; +import com.amazonaws.services.ec2.model.DescribeInstancesRequest; +import com.amazonaws.services.ec2.model.DescribeInstancesResult; +import com.amazonaws.services.ec2.model.DescribeSecurityGroupsRequest; +import com.amazonaws.services.ec2.model.DescribeSecurityGroupsResult; +import com.amazonaws.services.ec2.model.DescribeSpotInstanceRequestsRequest; +import com.amazonaws.services.ec2.model.DescribeSpotPriceHistoryRequest; +import com.amazonaws.services.ec2.model.DescribeSpotPriceHistoryResult; +import com.amazonaws.services.ec2.model.DescribeSubnetsRequest; +import com.amazonaws.services.ec2.model.DescribeSubnetsResult; +import com.amazonaws.services.ec2.model.Filter; +import com.amazonaws.services.ec2.model.IamInstanceProfileSpecification; +import com.amazonaws.services.ec2.model.Image; +import com.amazonaws.services.ec2.model.Instance; +import com.amazonaws.services.ec2.model.InstanceMarketOptionsRequest; +import com.amazonaws.services.ec2.model.InstanceNetworkInterfaceSpecification; +import com.amazonaws.services.ec2.model.InstanceStateName; +import com.amazonaws.services.ec2.model.InstanceType; +import com.amazonaws.services.ec2.model.KeyPair; +import com.amazonaws.services.ec2.model.LaunchSpecification; +import com.amazonaws.services.ec2.model.MarketType; +import com.amazonaws.services.ec2.model.Placement; +import com.amazonaws.services.ec2.model.RequestSpotInstancesRequest; +import com.amazonaws.services.ec2.model.RequestSpotInstancesResult; +import com.amazonaws.services.ec2.model.Reservation; +import com.amazonaws.services.ec2.model.ResourceType; +import com.amazonaws.services.ec2.model.RunInstancesRequest; +import com.amazonaws.services.ec2.model.SecurityGroup; +import com.amazonaws.services.ec2.model.ShutdownBehavior; +import com.amazonaws.services.ec2.model.SpotInstanceRequest; +import com.amazonaws.services.ec2.model.SpotMarketOptions; +import com.amazonaws.services.ec2.model.SpotPlacement; +import com.amazonaws.services.ec2.model.SpotPrice; +import com.amazonaws.services.ec2.model.StartInstancesRequest; +import com.amazonaws.services.ec2.model.StartInstancesResult; +import com.amazonaws.services.ec2.model.Subnet; +import com.amazonaws.services.ec2.model.Tag; +import com.amazonaws.services.ec2.model.TagSpecification; import hudson.Extension; import hudson.Util; -import hudson.model.*; +import hudson.model.Describable; +import hudson.model.Descriptor; import hudson.model.Descriptor.FormException; +import hudson.model.Hudson; +import hudson.model.Label; +import hudson.model.Node; +import hudson.model.Saveable; +import hudson.model.TaskListener; import hudson.model.labels.LabelAtom; import hudson.slaves.NodeProperty; import hudson.slaves.NodePropertyDescriptor; From 81ee5886bfb4c1311a66c27e84d955a91761976a Mon Sep 17 00:00:00 2001 From: Damian Jesionek Date: Mon, 13 Apr 2020 14:31:31 +0200 Subject: [PATCH 28/45] JENKINS-56927: Applied suggested changes --- pom.xml | 2 +- src/main/java/hudson/plugins/ec2/EC2Cloud.java | 10 ++++++++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/pom.xml b/pom.xml index 98963075d..fb9534933 100644 --- a/pom.xml +++ b/pom.xml @@ -146,7 +146,7 @@ THE SOFTWARE. org.jenkins-ci.plugins trilead-api - 1.0.5 + 1.0.5 io.jenkins.temp.jelly diff --git a/src/main/java/hudson/plugins/ec2/EC2Cloud.java b/src/main/java/hudson/plugins/ec2/EC2Cloud.java index a4f743bb6..a9f21a432 100644 --- a/src/main/java/hudson/plugins/ec2/EC2Cloud.java +++ b/src/main/java/hudson/plugins/ec2/EC2Cloud.java @@ -321,6 +321,7 @@ public String getCredentialsId() { return credentialsId; } + @CheckForNull public String getSshKeysCredentialsId() { return sshKeysCredentialsId; } @@ -376,9 +377,14 @@ public SlaveTemplate getTemplate(Label label) { /** * Gets the {@link KeyPairInfo} used for the launch. */ + @CheckForNull public synchronized KeyPair getKeyPair() throws AmazonClientException, IOException { - if (usableKeyPair == null) - usableKeyPair = resolvePrivateKey(this).find(connect()); + if (usableKeyPair == null) { + EC2PrivateKey ec2PrivateKey = resolvePrivateKey(this); + if (ec2PrivateKey != null) { + usableKeyPair = ec2PrivateKey.find(connect()); + } + } return usableKeyPair; } From 9b1c4a2a3adbb9dec906a8fe295e2df423836e0d Mon Sep 17 00:00:00 2001 From: Damian Jesionek Date: Mon, 13 Apr 2020 14:53:04 +0200 Subject: [PATCH 29/45] JENKINS-56927: Removed changes made on test --- src/test/java/hudson/plugins/ec2/EC2PrivateKeyTest.java | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/test/java/hudson/plugins/ec2/EC2PrivateKeyTest.java b/src/test/java/hudson/plugins/ec2/EC2PrivateKeyTest.java index 163928982..5cd9cef20 100644 --- a/src/test/java/hudson/plugins/ec2/EC2PrivateKeyTest.java +++ b/src/test/java/hudson/plugins/ec2/EC2PrivateKeyTest.java @@ -44,12 +44,6 @@ public class EC2PrivateKeyTest { @Rule public JenkinsRule r = new JenkinsRule(); - @Before - public void init(){ - // Tests using the BouncyCastleProvider failed without that - Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider()); - } - private EC2PrivateKey getPrivateKey() { return new EC2PrivateKey("-----BEGIN RSA PRIVATE KEY-----\n" + "MIIEowIBAAKCAQEAlpK/pGxCRoHpbIObxYW53fl4qA+EQNHuSveNyxt+6m/HAdRLhEMGHe7/b7dR\n" From 2d9d7af512bbdc51412b847a5785f7a5e198c0f3 Mon Sep 17 00:00:00 2001 From: Damian Jesionek Date: Mon, 13 Apr 2020 15:01:03 +0200 Subject: [PATCH 30/45] JENKINS-56927: Applied suggested changes --- src/main/java/hudson/plugins/ec2/EC2Cloud.java | 1 + src/test/java/hudson/plugins/ec2/AmazonEC2CloudUnitTest.java | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main/java/hudson/plugins/ec2/EC2Cloud.java b/src/main/java/hudson/plugins/ec2/EC2Cloud.java index a9f21a432..59f279784 100644 --- a/src/main/java/hudson/plugins/ec2/EC2Cloud.java +++ b/src/main/java/hudson/plugins/ec2/EC2Cloud.java @@ -963,6 +963,7 @@ public static URL checkEndPoint(String url) throws FormValidation { } } + @CheckForNull public static EC2PrivateKey resolvePrivateKey(EC2Cloud cloud){ if (cloud.sshKeysCredentialsId != null) { BasicSSHUserPrivateKey privateKeyCredential = getSshCredential(cloud.sshKeysCredentialsId); diff --git a/src/test/java/hudson/plugins/ec2/AmazonEC2CloudUnitTest.java b/src/test/java/hudson/plugins/ec2/AmazonEC2CloudUnitTest.java index 6eb879f99..3e1dd60fc 100644 --- a/src/test/java/hudson/plugins/ec2/AmazonEC2CloudUnitTest.java +++ b/src/test/java/hudson/plugins/ec2/AmazonEC2CloudUnitTest.java @@ -40,8 +40,8 @@ */ public class AmazonEC2CloudUnitTest { - @Rule - public JenkinsRule r = new JenkinsRule(); + /*@Rule + public JenkinsRule r = new JenkinsRule();*/ @Test public void testEC2EndpointURLCreation() throws MalformedURLException { From 9c3a07da4f27ac52d0c2bb6cd1c70c145efaf8d2 Mon Sep 17 00:00:00 2001 From: Damian Jesionek Date: Mon, 13 Apr 2020 15:02:00 +0200 Subject: [PATCH 31/45] JENKINS-56927: Reverted incidental change --- src/test/java/hudson/plugins/ec2/AmazonEC2CloudUnitTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/java/hudson/plugins/ec2/AmazonEC2CloudUnitTest.java b/src/test/java/hudson/plugins/ec2/AmazonEC2CloudUnitTest.java index 3e1dd60fc..6eb879f99 100644 --- a/src/test/java/hudson/plugins/ec2/AmazonEC2CloudUnitTest.java +++ b/src/test/java/hudson/plugins/ec2/AmazonEC2CloudUnitTest.java @@ -40,8 +40,8 @@ */ public class AmazonEC2CloudUnitTest { - /*@Rule - public JenkinsRule r = new JenkinsRule();*/ + @Rule + public JenkinsRule r = new JenkinsRule(); @Test public void testEC2EndpointURLCreation() throws MalformedURLException { From cf3b2e6dc084fdfe4562cac0d7892a35c494c8bf Mon Sep 17 00:00:00 2001 From: Damian Jesionek Date: Tue, 28 Apr 2020 11:31:31 +0200 Subject: [PATCH 32/45] [JENKINS-56927] Fixed warnings found by spotbugs --- src/main/java/hudson/plugins/ec2/SlaveTemplate.java | 12 +++++++++++- .../hudson/plugins/ec2/ssh/EC2UnixLauncher.java | 13 +++++++++++-- .../java/hudson/plugins/ec2/EC2PrivateKeyTest.java | 6 ++++++ 3 files changed, 28 insertions(+), 3 deletions(-) diff --git a/src/main/java/hudson/plugins/ec2/SlaveTemplate.java b/src/main/java/hudson/plugins/ec2/SlaveTemplate.java index 30f95a4a8..3015a4f85 100644 --- a/src/main/java/hudson/plugins/ec2/SlaveTemplate.java +++ b/src/main/java/hudson/plugins/ec2/SlaveTemplate.java @@ -39,6 +39,7 @@ import java.util.stream.Collectors; import java.util.stream.Stream; +import javax.annotation.CheckForNull; import javax.servlet.ServletException; import hudson.plugins.ec2.util.AmazonEC2Factory; @@ -770,6 +771,10 @@ private List provisionOndemand(int number, EnumSet 0) { diff --git a/src/test/java/hudson/plugins/ec2/EC2PrivateKeyTest.java b/src/test/java/hudson/plugins/ec2/EC2PrivateKeyTest.java index 5cd9cef20..fe69152a5 100644 --- a/src/test/java/hudson/plugins/ec2/EC2PrivateKeyTest.java +++ b/src/test/java/hudson/plugins/ec2/EC2PrivateKeyTest.java @@ -44,6 +44,12 @@ public class EC2PrivateKeyTest { @Rule public JenkinsRule r = new JenkinsRule(); + /*@Before + public void init(){ + // Tests using the BouncyCastleProvider failed without that + Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider()); + }*/ + private EC2PrivateKey getPrivateKey() { return new EC2PrivateKey("-----BEGIN RSA PRIVATE KEY-----\n" + "MIIEowIBAAKCAQEAlpK/pGxCRoHpbIObxYW53fl4qA+EQNHuSveNyxt+6m/HAdRLhEMGHe7/b7dR\n" From fcf19de9c40a8ec6c91d33386ecf9e0637b99dca Mon Sep 17 00:00:00 2001 From: Damian Jesionek Date: Tue, 28 Apr 2020 13:19:25 +0200 Subject: [PATCH 33/45] [JENKINS-56927] Fixed warnings found by spotbugs --- .../java/hudson/plugins/ec2/win/EC2WindowsLauncher.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/main/java/hudson/plugins/ec2/win/EC2WindowsLauncher.java b/src/main/java/hudson/plugins/ec2/win/EC2WindowsLauncher.java index 57cbe19c4..798304e16 100644 --- a/src/main/java/hudson/plugins/ec2/win/EC2WindowsLauncher.java +++ b/src/main/java/hudson/plugins/ec2/win/EC2WindowsLauncher.java @@ -153,7 +153,11 @@ private WinConnection connectToWinRM(EC2Computer computer, EC2AbstractSlave node Thread.sleep(sleepBetweenAttempts); continue; } - String password = EC2Cloud.resolvePrivateKey(node.getCloud()).decryptWindowsPassword(passwordData); + EC2PrivateKey ec2PrivateKey = EC2Cloud.resolvePrivateKey(node.getCloud()); + String password = ""; + if (ec2PrivateKey != null){ + password = ec2PrivateKey.decryptWindowsPassword(passwordData); + } if (!node.getRemoteAdmin().equals("Administrator")) { logger.println("WARNING: For password retrieval remote admin must be Administrator, ignoring user provided value"); } From ee072ebfcb28afd108cc25f71ab70b17485ac437 Mon Sep 17 00:00:00 2001 From: Damian Jesionek Date: Wed, 29 Apr 2020 12:30:18 +0200 Subject: [PATCH 34/45] [JENKINS-56927] Fixed tests --- .../java/hudson/plugins/ec2/EC2Cloud.java | 26 +++++++++---------- .../hudson/plugins/ec2/SlaveTemplate.java | 9 +------ .../plugins/ec2/ssh/EC2UnixLauncher.java | 2 +- .../plugins/ec2/win/EC2WindowsLauncher.java | 2 +- .../plugins/ec2/AmazonEC2CloudUnitTest.java | 2 +- .../hudson/plugins/ec2/EC2PrivateKeyTest.java | 8 ------ .../hudson/plugins/ec2/SlaveTemplateTest.java | 18 ++++++++++--- .../ec2/util/AmazonEC2FactoryMockImpl.java | 2 +- 8 files changed, 31 insertions(+), 38 deletions(-) diff --git a/src/main/java/hudson/plugins/ec2/EC2Cloud.java b/src/main/java/hudson/plugins/ec2/EC2Cloud.java index 988650214..7c0395d67 100644 --- a/src/main/java/hudson/plugins/ec2/EC2Cloud.java +++ b/src/main/java/hudson/plugins/ec2/EC2Cloud.java @@ -78,7 +78,6 @@ import javax.annotation.CheckForNull; import javax.servlet.ServletException; -import hudson.Extension; import hudson.util.ListBoxModel; import jenkins.model.Jenkins; import jenkins.model.JenkinsLocationConfiguration; @@ -113,7 +112,6 @@ import com.amazonaws.services.s3.AmazonS3ClientBuilder; import com.amazonaws.services.s3.model.GeneratePresignedUrlRequest; -import hudson.ProxyConfiguration; import hudson.slaves.Cloud; import hudson.slaves.NodeProvisioner.PlannedNode; import hudson.util.FormValidation; @@ -209,6 +207,17 @@ protected EC2Cloud(String id, boolean useInstanceProfileForCredentials, String c this(id, useInstanceProfileForCredentials, credentialsId, privateKey, null, instanceCapStr, templates, roleArn, roleSessionName); } + @CheckForNull + public EC2PrivateKey resolvePrivateKey(){ + if (getSshKeysCredentialsId() != null) { + BasicSSHUserPrivateKey privateKeyCredential = getSshCredential(getSshKeysCredentialsId()); + if (privateKeyCredential != null) { + return new EC2PrivateKey(privateKeyCredential.getPrivateKey()); + } + } + return null; + } + public abstract URL getEc2EndpointUrl() throws IOException; public abstract URL getS3EndpointUrl() throws IOException; @@ -381,7 +390,7 @@ public SlaveTemplate getTemplate(Label label) { @CheckForNull public synchronized KeyPair getKeyPair() throws AmazonClientException, IOException { if (usableKeyPair == null) { - EC2PrivateKey ec2PrivateKey = resolvePrivateKey(this); + EC2PrivateKey ec2PrivateKey = this.resolvePrivateKey(); if (ec2PrivateKey != null) { usableKeyPair = ec2PrivateKey.find(connect()); } @@ -989,17 +998,6 @@ public static URL checkEndPoint(String url) throws FormValidation { } } - @CheckForNull - public static EC2PrivateKey resolvePrivateKey(EC2Cloud cloud){ - if (cloud.sshKeysCredentialsId != null) { - BasicSSHUserPrivateKey privateKeyCredential = getSshCredential(cloud.sshKeysCredentialsId); - if (privateKeyCredential != null) { - return new EC2PrivateKey(privateKeyCredential.getPrivateKey()); - } - } - return null; - } - private static BasicSSHUserPrivateKey getSshCredential(String id){ BasicSSHUserPrivateKey credential = CredentialsMatchers.firstOrNull( diff --git a/src/main/java/hudson/plugins/ec2/SlaveTemplate.java b/src/main/java/hudson/plugins/ec2/SlaveTemplate.java index ac35a86c9..7070c380e 100644 --- a/src/main/java/hudson/plugins/ec2/SlaveTemplate.java +++ b/src/main/java/hudson/plugins/ec2/SlaveTemplate.java @@ -27,10 +27,8 @@ import java.util.Base64; import java.util.Collection; import java.util.Collections; -import java.util.Date; import java.util.EnumSet; import java.util.HashSet; -import java.util.LinkedList; import java.util.List; import java.util.Objects; import java.util.Set; @@ -68,20 +66,16 @@ import com.amazonaws.auth.AWSCredentialsProvider; import com.amazonaws.services.ec2.AmazonEC2; import com.amazonaws.services.ec2.model.AmazonEC2Exception; -import com.amazonaws.services.ec2.model.AvailabilityZone; import com.amazonaws.services.ec2.model.BlockDeviceMapping; import com.amazonaws.services.ec2.model.CancelSpotInstanceRequestsRequest; import com.amazonaws.services.ec2.model.CreateTagsRequest; import com.amazonaws.services.ec2.model.CreditSpecificationRequest; -import com.amazonaws.services.ec2.model.DescribeAvailabilityZonesResult; import com.amazonaws.services.ec2.model.DescribeImagesRequest; import com.amazonaws.services.ec2.model.DescribeInstancesRequest; import com.amazonaws.services.ec2.model.DescribeInstancesResult; import com.amazonaws.services.ec2.model.DescribeSecurityGroupsRequest; import com.amazonaws.services.ec2.model.DescribeSecurityGroupsResult; import com.amazonaws.services.ec2.model.DescribeSpotInstanceRequestsRequest; -import com.amazonaws.services.ec2.model.DescribeSpotPriceHistoryRequest; -import com.amazonaws.services.ec2.model.DescribeSpotPriceHistoryResult; import com.amazonaws.services.ec2.model.DescribeSubnetsRequest; import com.amazonaws.services.ec2.model.DescribeSubnetsResult; import com.amazonaws.services.ec2.model.Filter; @@ -106,7 +100,6 @@ import com.amazonaws.services.ec2.model.SpotInstanceRequest; import com.amazonaws.services.ec2.model.SpotMarketOptions; import com.amazonaws.services.ec2.model.SpotPlacement; -import com.amazonaws.services.ec2.model.SpotPrice; import com.amazonaws.services.ec2.model.StartInstancesRequest; import com.amazonaws.services.ec2.model.StartInstancesResult; import com.amazonaws.services.ec2.model.Subnet; @@ -1302,7 +1295,7 @@ protected EC2SpotSlave newSpotSlave(SpotInstanceRequest sir) throws FormExceptio */ @CheckForNull private KeyPair getKeyPair(AmazonEC2 ec2) throws IOException, AmazonClientException { - EC2PrivateKey ec2PrivateKey = EC2Cloud.resolvePrivateKey(parent); + EC2PrivateKey ec2PrivateKey = getParent().resolvePrivateKey(); if (ec2PrivateKey == null) { throw new AmazonClientException("No keypair credential found. Please configure a credential in the Jenkins configuration."); } diff --git a/src/main/java/hudson/plugins/ec2/ssh/EC2UnixLauncher.java b/src/main/java/hudson/plugins/ec2/ssh/EC2UnixLauncher.java index 48ebe60ed..851dfbeda 100644 --- a/src/main/java/hudson/plugins/ec2/ssh/EC2UnixLauncher.java +++ b/src/main/java/hudson/plugins/ec2/ssh/EC2UnixLauncher.java @@ -289,7 +289,7 @@ private boolean executeRemote(EC2Computer computer, Connection conn, String chec } private File createIdentityKeyFile(EC2Computer computer) throws IOException { - EC2PrivateKey ec2PrivateKey = EC2Cloud.resolvePrivateKey(computer.getCloud()); + EC2PrivateKey ec2PrivateKey = computer.getCloud().resolvePrivateKey(); String privateKey = ""; if (ec2PrivateKey != null){ privateKey = ec2PrivateKey.getPrivateKey(); diff --git a/src/main/java/hudson/plugins/ec2/win/EC2WindowsLauncher.java b/src/main/java/hudson/plugins/ec2/win/EC2WindowsLauncher.java index 798304e16..3773b15ec 100644 --- a/src/main/java/hudson/plugins/ec2/win/EC2WindowsLauncher.java +++ b/src/main/java/hudson/plugins/ec2/win/EC2WindowsLauncher.java @@ -153,7 +153,7 @@ private WinConnection connectToWinRM(EC2Computer computer, EC2AbstractSlave node Thread.sleep(sleepBetweenAttempts); continue; } - EC2PrivateKey ec2PrivateKey = EC2Cloud.resolvePrivateKey(node.getCloud()); + EC2PrivateKey ec2PrivateKey = node.getCloud().resolvePrivateKey(); String password = ""; if (ec2PrivateKey != null){ password = ec2PrivateKey.decryptWindowsPassword(passwordData); diff --git a/src/test/java/hudson/plugins/ec2/AmazonEC2CloudUnitTest.java b/src/test/java/hudson/plugins/ec2/AmazonEC2CloudUnitTest.java index 5bc5052db..c2acb7815 100644 --- a/src/test/java/hudson/plugins/ec2/AmazonEC2CloudUnitTest.java +++ b/src/test/java/hudson/plugins/ec2/AmazonEC2CloudUnitTest.java @@ -98,7 +98,7 @@ public void testInstaceCap() throws Exception { public void testSpotInstanceCount() throws Exception { final int numberOfSpotInstanceRequests = 105; AmazonEC2Cloud cloud = PowerMockito.spy(new AmazonEC2Cloud("us-east-1", true, "abc", "us-east-1", - "{}", null, Collections.emptyList(), + PrivateKeyHelper.generate(), null, Collections.emptyList(), "roleArn", "roleSessionName")); PowerMockito.mockStatic(Jenkins.class); Jenkins jenkinsMock = mock(Jenkins.class); diff --git a/src/test/java/hudson/plugins/ec2/EC2PrivateKeyTest.java b/src/test/java/hudson/plugins/ec2/EC2PrivateKeyTest.java index fe69152a5..2126b1635 100644 --- a/src/test/java/hudson/plugins/ec2/EC2PrivateKeyTest.java +++ b/src/test/java/hudson/plugins/ec2/EC2PrivateKeyTest.java @@ -23,14 +23,12 @@ */ package hudson.plugins.ec2; -import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.jvnet.hudson.test.Issue; import org.jvnet.hudson.test.JenkinsRule; import java.io.IOException; -import java.security.Security; import com.amazonaws.AmazonClientException; @@ -44,12 +42,6 @@ public class EC2PrivateKeyTest { @Rule public JenkinsRule r = new JenkinsRule(); - /*@Before - public void init(){ - // Tests using the BouncyCastleProvider failed without that - Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider()); - }*/ - private EC2PrivateKey getPrivateKey() { return new EC2PrivateKey("-----BEGIN RSA PRIVATE KEY-----\n" + "MIIEowIBAAKCAQEAlpK/pGxCRoHpbIObxYW53fl4qA+EQNHuSveNyxt+6m/HAdRLhEMGHe7/b7dR\n" diff --git a/src/test/java/hudson/plugins/ec2/SlaveTemplateTest.java b/src/test/java/hudson/plugins/ec2/SlaveTemplateTest.java index 075047d85..494acaa43 100644 --- a/src/test/java/hudson/plugins/ec2/SlaveTemplateTest.java +++ b/src/test/java/hudson/plugins/ec2/SlaveTemplateTest.java @@ -49,16 +49,22 @@ import hudson.plugins.ec2.SlaveTemplate.ProvisionOptions; import hudson.plugins.ec2.util.MinimumNumberOfInstancesTimeRangeConfig; import com.amazonaws.services.ec2.model.Reservation; +import hudson.plugins.ec2.util.PrivateKeyHelper; import jenkins.model.Jenkins; import net.sf.json.JSONObject; +import org.apache.commons.math3.analysis.function.Power; import org.junit.Assert; +import org.junit.Before; import org.junit.Rule; import org.junit.Test; +import org.junit.runner.RunWith; import org.jvnet.hudson.test.Issue; import org.jvnet.hudson.test.JenkinsRule; import org.mockito.ArgumentCaptor; +import org.powermock.api.mockito.PowerMockito; +import org.powermock.modules.junit4.PowerMockRunner; import java.util.ArrayList; import java.util.Collections; @@ -71,10 +77,8 @@ import static org.hamcrest.MatcherAssert.assertThat; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; -import static org.mockito.Mockito.verify; import static org.mockito.Matchers.any; +import static org.mockito.Mockito.*; /** * Basic test to validate SlaveTemplate. @@ -83,6 +87,11 @@ public class SlaveTemplateTest { @Rule public JenkinsRule r = new JenkinsRule(); + @Before + public void prepareCredentialStore(){ + + } + @Test public void testConfigRoundtrip() throws Exception { String ami = "ami1"; @@ -507,7 +516,8 @@ private AmazonEC2 setupTestForProvisioning(SlaveTemplate template) throws Except mockedKeyPair.setKeyName("some-key-name"); when(mockedPrivateKey.find(mockedEC2)).thenReturn(mockedKeyPair); when(mockedCloud.connect()).thenReturn(mockedEC2); - when(mockedCloud.getPrivateKey()).thenReturn(mockedPrivateKey); + when(mockedCloud.resolvePrivateKey()).thenReturn(mockedPrivateKey); + template.parent = mockedCloud; DescribeImagesResult mockedImagesResult = mock(DescribeImagesResult.class); diff --git a/src/test/java/hudson/plugins/ec2/util/AmazonEC2FactoryMockImpl.java b/src/test/java/hudson/plugins/ec2/util/AmazonEC2FactoryMockImpl.java index da1ed1e66..6d033b3f6 100644 --- a/src/test/java/hudson/plugins/ec2/util/AmazonEC2FactoryMockImpl.java +++ b/src/test/java/hudson/plugins/ec2/util/AmazonEC2FactoryMockImpl.java @@ -131,7 +131,7 @@ private static Image createMockImage(String amiId) { private static void mockDescribeKeyPairs(AmazonEC2Client mock) { Mockito.doAnswer(invocationOnMock -> { KeyPairInfo keyPairInfo = new KeyPairInfo(); - keyPairInfo.setKeyFingerprint(EC2Cloud.resolvePrivateKey(Jenkins.get().clouds.get(AmazonEC2Cloud.class)).getFingerprint()); + keyPairInfo.setKeyFingerprint(Jenkins.get().clouds.get(AmazonEC2Cloud.class).resolvePrivateKey().getFingerprint()); return new DescribeKeyPairsResult().withKeyPairs(keyPairInfo); }).when(mock).describeKeyPairs(); } From 398da8db51b804d5bb5bb8cb4c649f50dfdb1664 Mon Sep 17 00:00:00 2001 From: Damian Jesionek Date: Wed, 29 Apr 2020 13:48:22 +0200 Subject: [PATCH 35/45] [JENKINS-56927] Fixed AmazonEC2CloudUnitTest and removed JenkinsRule --- .../hudson/plugins/ec2/AmazonEC2CloudUnitTest.java | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/src/test/java/hudson/plugins/ec2/AmazonEC2CloudUnitTest.java b/src/test/java/hudson/plugins/ec2/AmazonEC2CloudUnitTest.java index c2acb7815..16213a7a5 100644 --- a/src/test/java/hudson/plugins/ec2/AmazonEC2CloudUnitTest.java +++ b/src/test/java/hudson/plugins/ec2/AmazonEC2CloudUnitTest.java @@ -23,10 +23,7 @@ */ package hudson.plugins.ec2; -import hudson.plugins.ec2.util.PrivateKeyHelper; -import org.junit.Rule; import org.junit.Test; -import org.jvnet.hudson.test.JenkinsRule; import com.amazonaws.services.ec2.model.Tag; @@ -65,9 +62,6 @@ @PrepareForTest({EC2Cloud.class, Jenkins.class}) public class AmazonEC2CloudUnitTest { - @Rule - public JenkinsRule r = new JenkinsRule(); - @Test public void testEC2EndpointURLCreation() throws MalformedURLException { AmazonEC2Cloud.DescriptorImpl descriptor = new AmazonEC2Cloud.DescriptorImpl(); @@ -80,7 +74,7 @@ public void testEC2EndpointURLCreation() throws MalformedURLException { @Test public void testInstaceCap() throws Exception { AmazonEC2Cloud cloud = new AmazonEC2Cloud("us-east-1", true, "abc", "us-east-1", - PrivateKeyHelper.generate(), null, Collections.emptyList(), + null, "key", null, Collections.emptyList(), "roleArn", "roleSessionName"); assertEquals(cloud.getInstanceCap(), Integer.MAX_VALUE); assertEquals(cloud.getInstanceCapStr(), ""); @@ -88,7 +82,7 @@ public void testInstaceCap() throws Exception { final int cap = 3; final String capStr = String.valueOf(cap); cloud = new AmazonEC2Cloud("us-east-1", true, "abc", "us-east-1", - PrivateKeyHelper.generate(), capStr, Collections.emptyList(), + null, "key", capStr, Collections.emptyList(), "roleArn", "roleSessionName"); assertEquals(cloud.getInstanceCap(), cap); assertEquals(cloud.getInstanceCapStr(), capStr); @@ -98,7 +92,7 @@ public void testInstaceCap() throws Exception { public void testSpotInstanceCount() throws Exception { final int numberOfSpotInstanceRequests = 105; AmazonEC2Cloud cloud = PowerMockito.spy(new AmazonEC2Cloud("us-east-1", true, "abc", "us-east-1", - PrivateKeyHelper.generate(), null, Collections.emptyList(), + null, "key", null, Collections.emptyList(), "roleArn", "roleSessionName")); PowerMockito.mockStatic(Jenkins.class); Jenkins jenkinsMock = mock(Jenkins.class); From 8992e193f1b301aa6bf22dd5ee40277fc5302b8a Mon Sep 17 00:00:00 2001 From: Damian Jesionek Date: Wed, 29 Apr 2020 15:04:54 +0200 Subject: [PATCH 36/45] [JENKINS-56927] Fixed und updated AmazonEC2CloudTest --- .../java/hudson/plugins/ec2/AmazonEC2CloudTest.java | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/test/java/hudson/plugins/ec2/AmazonEC2CloudTest.java b/src/test/java/hudson/plugins/ec2/AmazonEC2CloudTest.java index e00fe3220..978c36b3c 100644 --- a/src/test/java/hudson/plugins/ec2/AmazonEC2CloudTest.java +++ b/src/test/java/hudson/plugins/ec2/AmazonEC2CloudTest.java @@ -24,6 +24,7 @@ package hudson.plugins.ec2; import com.amazonaws.services.ec2.AmazonEC2; +import com.gargoylesoftware.htmlunit.ElementNotFoundException; import com.gargoylesoftware.htmlunit.html.HtmlForm; import com.gargoylesoftware.htmlunit.html.HtmlTextInput; import org.junit.Assert; @@ -51,7 +52,7 @@ public class AmazonEC2CloudTest { @Before public void setUp() throws Exception { - cloud = new AmazonEC2Cloud("us-east-1", true, "abc", "us-east-1", "ghi", "3", Collections.emptyList(), "roleArn", "roleSessionName"); + cloud = new AmazonEC2Cloud("us-east-1", true, "abc", "us-east-1", null, "ghi", "3", Collections.emptyList(), "roleArn", "roleSessionName"); r.jenkins.clouds.add(cloud); } @@ -71,17 +72,19 @@ public void testAmazonEC2FactoryGetInstance() throws Exception { } @Test - public void testPrivateKeyRemainsUnchangedAfterUpdatingOtherFields() throws Exception { + public void testSshKeysCredentialsIdRemainsUnchangedAfterUpdatingOtherFields() throws Exception { HtmlForm form = getConfigForm(); HtmlTextInput input = form.getInputByName("_.cloudName"); + input.setText("test-cloud-2"); r.submit(form); AmazonEC2Cloud actual = r.jenkins.clouds.get(AmazonEC2Cloud.class); assertEquals("test-cloud-2", actual.getCloudName()); - r.assertEqualBeans(cloud, actual, "region,useInstanceProfileForCredentials,privateKey,instanceCap,roleArn,roleSessionName"); + r.assertEqualBeans(cloud, actual, "region,useInstanceProfileForCredentials,sshKeysCredentialsId,instanceCap,roleArn,roleSessionName"); } private HtmlForm getConfigForm() throws IOException, SAXException { - return r.createWebClient().goTo("configure").getFormByName("config"); + return r.createWebClient().goTo("configureClouds").getFormByName("config"); } + } From 718ee57d6cdef1aa061560fdbe8aed6ab95db7ec Mon Sep 17 00:00:00 2001 From: Damian Jesionek Date: Wed, 29 Apr 2020 15:25:21 +0200 Subject: [PATCH 37/45] [JENKINS-56927] Fixed possible bug --- src/main/java/hudson/plugins/ec2/EC2Cloud.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/hudson/plugins/ec2/EC2Cloud.java b/src/main/java/hudson/plugins/ec2/EC2Cloud.java index 7c0395d67..86aceda88 100644 --- a/src/main/java/hudson/plugins/ec2/EC2Cloud.java +++ b/src/main/java/hudson/plugins/ec2/EC2Cloud.java @@ -209,8 +209,8 @@ protected EC2Cloud(String id, boolean useInstanceProfileForCredentials, String c @CheckForNull public EC2PrivateKey resolvePrivateKey(){ - if (getSshKeysCredentialsId() != null) { - BasicSSHUserPrivateKey privateKeyCredential = getSshCredential(getSshKeysCredentialsId()); + if (sshKeysCredentialsId != null) { + BasicSSHUserPrivateKey privateKeyCredential = getSshCredential(sshKeysCredentialsId); if (privateKeyCredential != null) { return new EC2PrivateKey(privateKeyCredential.getPrivateKey()); } From 2930157292ca6ebe88febcedd5d78b3291fea319 Mon Sep 17 00:00:00 2001 From: Damian Jesionek Date: Wed, 29 Apr 2020 15:49:01 +0200 Subject: [PATCH 38/45] [JENKINS-56927] Added reverse compatibility for old configuration location --- src/test/java/hudson/plugins/ec2/AmazonEC2CloudTest.java | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/test/java/hudson/plugins/ec2/AmazonEC2CloudTest.java b/src/test/java/hudson/plugins/ec2/AmazonEC2CloudTest.java index 978c36b3c..d5d870d13 100644 --- a/src/test/java/hudson/plugins/ec2/AmazonEC2CloudTest.java +++ b/src/test/java/hudson/plugins/ec2/AmazonEC2CloudTest.java @@ -25,6 +25,7 @@ import com.amazonaws.services.ec2.AmazonEC2; import com.gargoylesoftware.htmlunit.ElementNotFoundException; +import com.gargoylesoftware.htmlunit.FailingHttpStatusCodeException; import com.gargoylesoftware.htmlunit.html.HtmlForm; import com.gargoylesoftware.htmlunit.html.HtmlTextInput; import org.junit.Assert; @@ -84,7 +85,12 @@ public void testSshKeysCredentialsIdRemainsUnchangedAfterUpdatingOtherFields() t } private HtmlForm getConfigForm() throws IOException, SAXException { - return r.createWebClient().goTo("configureClouds").getFormByName("config"); + try { + return r.createWebClient().goTo("configureClouds").getFormByName("config"); + } catch (FailingHttpStatusCodeException ex){ // Fallback for older jenkins versions + return r.createWebClient().goTo("configure").getFormByName("config"); + } + } } From 70584620ec69fa9edaa9df9878a723f96a8d16ef Mon Sep 17 00:00:00 2001 From: Damian Jesionek Date: Thu, 7 May 2020 10:07:14 +0200 Subject: [PATCH 39/45] [JENKINS-56927] Fixed RequireUpperBoundDeps for enforcer --- pom.xml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/pom.xml b/pom.xml index 402927286..8ca433106 100644 --- a/pom.xml +++ b/pom.xml @@ -286,6 +286,11 @@ THE SOFTWARE. import pom + + org.apache.commons + commons-compress + 1.19 + From d6c35d1ac265bc87b382699d44882443d4aebf14 Mon Sep 17 00:00:00 2001 From: Damian Jesionek Date: Tue, 12 May 2020 08:36:03 +0200 Subject: [PATCH 40/45] [JENKINS-56927] Made suggested changes --- src/main/java/hudson/plugins/ec2/EC2Cloud.java | 1 + src/test/java/hudson/plugins/ec2/SlaveTemplateTest.java | 5 ----- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/src/main/java/hudson/plugins/ec2/EC2Cloud.java b/src/main/java/hudson/plugins/ec2/EC2Cloud.java index d3b0c23a9..6bb6e1cab 100644 --- a/src/main/java/hudson/plugins/ec2/EC2Cloud.java +++ b/src/main/java/hudson/plugins/ec2/EC2Cloud.java @@ -1002,6 +1002,7 @@ public static URL checkEndPoint(String url) throws FormValidation { } } + @CheckForNull private static BasicSSHUserPrivateKey getSshCredential(String id){ BasicSSHUserPrivateKey credential = CredentialsMatchers.firstOrNull( diff --git a/src/test/java/hudson/plugins/ec2/SlaveTemplateTest.java b/src/test/java/hudson/plugins/ec2/SlaveTemplateTest.java index 9d16290c5..c28a42ee2 100644 --- a/src/test/java/hudson/plugins/ec2/SlaveTemplateTest.java +++ b/src/test/java/hudson/plugins/ec2/SlaveTemplateTest.java @@ -86,11 +86,6 @@ public class SlaveTemplateTest { @Rule public JenkinsRule r = new JenkinsRule(); - @Before - public void prepareCredentialStore(){ - - } - @Test public void testConfigRoundtrip() throws Exception { String ami = "ami1"; From a4ed92a428cb4d367312481dcad0adca7df3a101 Mon Sep 17 00:00:00 2001 From: Damian Jesionek Date: Tue, 12 May 2020 08:36:56 +0200 Subject: [PATCH 41/45] [JENKINS-56927] Readded privateKey attribute as requested --- src/main/java/hudson/plugins/ec2/EC2Cloud.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/main/java/hudson/plugins/ec2/EC2Cloud.java b/src/main/java/hudson/plugins/ec2/EC2Cloud.java index 6bb6e1cab..b86a130fb 100644 --- a/src/main/java/hudson/plugins/ec2/EC2Cloud.java +++ b/src/main/java/hudson/plugins/ec2/EC2Cloud.java @@ -161,6 +161,8 @@ public abstract class EC2Cloud extends Cloud { @Deprecated private transient Secret secretKey; @CheckForNull + private EC2PrivateKey privateKey; + @CheckForNull private String sshKeysCredentialsId; /** @@ -181,6 +183,9 @@ protected EC2Cloud(String id, boolean useInstanceProfileForCredentials, String c this.roleArn = roleArn; this.roleSessionName = roleSessionName; this.credentialsId = credentialsId; + if (privateKey != null) { + this.privateKey = new EC2PrivateKey(privateKey); + } this.sshKeysCredentialsId = sshKeysCredentialsId; if (this.sshKeysCredentialsId == null && privateKey != null){ From eeac05114cabb5f309d7d216ed4f648154671dac Mon Sep 17 00:00:00 2001 From: Damian Jesionek Date: Tue, 12 May 2020 08:52:25 +0200 Subject: [PATCH 42/45] [JENKINS-56927] Rewritten migration trigger to include privateKey attribute with precedence --- src/main/java/hudson/plugins/ec2/EC2Cloud.java | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/main/java/hudson/plugins/ec2/EC2Cloud.java b/src/main/java/hudson/plugins/ec2/EC2Cloud.java index b86a130fb..ca72f0c75 100644 --- a/src/main/java/hudson/plugins/ec2/EC2Cloud.java +++ b/src/main/java/hudson/plugins/ec2/EC2Cloud.java @@ -161,7 +161,8 @@ public abstract class EC2Cloud extends Cloud { @Deprecated private transient Secret secretKey; @CheckForNull - private EC2PrivateKey privateKey; + @Deprecated + private transient EC2PrivateKey privateKey; @CheckForNull private String sshKeysCredentialsId; @@ -183,14 +184,13 @@ protected EC2Cloud(String id, boolean useInstanceProfileForCredentials, String c this.roleArn = roleArn; this.roleSessionName = roleSessionName; this.credentialsId = credentialsId; - if (privateKey != null) { - this.privateKey = new EC2PrivateKey(privateKey); - } this.sshKeysCredentialsId = sshKeysCredentialsId; - if (this.sshKeysCredentialsId == null && privateKey != null){ - migratePrivateSshKeyToCredential(privateKey); + if (this.sshKeysCredentialsId == null && ( this.privateKey != null || privateKey != null)){ + migratePrivateSshKeyToCredential(this.privateKey != null ? this.privateKey.getPrivateKey() : privateKey); } + this.privateKey = null; // This enforces it not to be persisted and that CasC will never output privateKey on export + if (templates == null) { this.templates = Collections.emptyList(); @@ -344,7 +344,7 @@ public String getSshKeysCredentialsId() { @Deprecated public EC2PrivateKey getPrivateKey() { - return null; // This enforces that CasC will never output privateKey on export + return privateKey; } public String getInstanceCapStr() { From 1e627c66e9e6698946cbd96f79fa34cadb03c841 Mon Sep 17 00:00:00 2001 From: Damian Jesionek Date: Tue, 26 May 2020 08:47:37 +0200 Subject: [PATCH 43/45] [JENKINS-56927] Better error handling in the case of a missing private key in EC2WindowsLauncher --- .../java/hudson/plugins/ec2/win/EC2WindowsLauncher.java | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/main/java/hudson/plugins/ec2/win/EC2WindowsLauncher.java b/src/main/java/hudson/plugins/ec2/win/EC2WindowsLauncher.java index 1d4f40b7e..7c8c9e38c 100644 --- a/src/main/java/hudson/plugins/ec2/win/EC2WindowsLauncher.java +++ b/src/main/java/hudson/plugins/ec2/win/EC2WindowsLauncher.java @@ -168,10 +168,12 @@ private WinConnection connectToWinRM(EC2Computer computer, EC2AbstractSlave node continue; } EC2PrivateKey ec2PrivateKey = node.getCloud().resolvePrivateKey(); - String password = ""; - if (ec2PrivateKey != null){ - password = ec2PrivateKey.decryptWindowsPassword(passwordData); + if (ec2PrivateKey == null){ + logger.println("Waiting for privateKey to be available. Consider checking the credentials in the cloud configuration. Sleeping 10s."); + Thread.sleep(sleepBetweenAttempts); + continue; } + String password = ec2PrivateKey.decryptWindowsPassword(passwordData); if (!node.getRemoteAdmin().equals("Administrator")) { logger.println("WARNING: For password retrieval remote admin must be Administrator, ignoring user provided value"); } From 657d0de2ed649394197d3f411fc496a0aee7badc Mon Sep 17 00:00:00 2001 From: Damian Jesionek Date: Wed, 27 May 2020 16:59:19 +0200 Subject: [PATCH 44/45] [JENKINS-56927] Added @RequirePOST to doCheckSshKeysCredentialsId --- src/main/java/hudson/plugins/ec2/EC2Cloud.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/hudson/plugins/ec2/EC2Cloud.java b/src/main/java/hudson/plugins/ec2/EC2Cloud.java index ca72f0c75..c15661b7e 100644 --- a/src/main/java/hudson/plugins/ec2/EC2Cloud.java +++ b/src/main/java/hudson/plugins/ec2/EC2Cloud.java @@ -1054,6 +1054,7 @@ public ListBoxModel doFillSshKeysCredentialsIdItems(@QueryParameter String sshKe .includeCurrentValue(sshKeysCredentialsId); } + @RequirePOST public FormValidation doCheckSshKeysCredentialsId(@QueryParameter String value) throws IOException, ServletException { Jenkins.get().checkPermission(Jenkins.ADMINISTER); From 2d08f6c82a6eb7078cf899f5164112e7fe88ee82 Mon Sep 17 00:00:00 2001 From: Damian Jesionek Date: Sun, 9 Aug 2020 13:09:35 +0200 Subject: [PATCH 45/45] [JENKINS-56927] Fixed test with new constructor --- src/test/java/hudson/plugins/ec2/EC2CloudTest.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/test/java/hudson/plugins/ec2/EC2CloudTest.java b/src/test/java/hudson/plugins/ec2/EC2CloudTest.java index 12c393da3..40ac36588 100644 --- a/src/test/java/hudson/plugins/ec2/EC2CloudTest.java +++ b/src/test/java/hudson/plugins/ec2/EC2CloudTest.java @@ -33,9 +33,9 @@ public class EC2CloudTest { @Test public void testReattachOrphanStoppedNodes() throws Exception { /* Mocked items */ - AmazonEC2Cloud cloud = new AmazonEC2Cloud("us-east-1", true, "abc", "us-east-1", - "{}", null, Collections.emptyList(), - "roleArn", "roleSessionName"); + AmazonEC2Cloud cloud = new AmazonEC2Cloud("us-east-1", true, + "abc", "us-east-1", null, "ghi", + "3", Collections.emptyList(), "roleArn", "roleSessionName"); EC2Cloud spyCloud = PowerMockito.spy(cloud); AmazonEC2 mockEc2 = PowerMockito.mock(AmazonEC2.class); Jenkins mockJenkins = PowerMockito.mock(Jenkins.class);