mirror of https://github.com/apache/jclouds.git
Issue 719: add sha1 support to SshKeys
This commit is contained in:
parent
bf4db76152
commit
7e5a6e68cf
|
@ -30,6 +30,7 @@ import javax.inject.Singleton;
|
|||
|
||||
import org.jclouds.compute.domain.Template;
|
||||
import org.jclouds.compute.options.TemplateOptions;
|
||||
import static org.jclouds.crypto.SshKeys.*;
|
||||
import org.jclouds.ec2.compute.domain.RegionAndName;
|
||||
import org.jclouds.ec2.compute.domain.RegionNameAndIngressRules;
|
||||
import org.jclouds.ec2.compute.options.EC2TemplateOptions;
|
||||
|
@ -114,9 +115,9 @@ public class CreateKeyPairAndSecurityGroupsAsNeededAndReturnRunOptions {
|
|||
keyPairName = createOrImportKeyPair(region, group, options);
|
||||
} else if (keyPairName != null) {
|
||||
if (options.getOverridingCredentials() != null && options.getOverridingCredentials().credential != null) {
|
||||
KeyPair keyPair = KeyPair.builder().region(region).keyName(keyPairName).keyFingerprint("//TODO")
|
||||
.keyMaterial(options.getOverridingCredentials().credential).build();
|
||||
|
||||
String pem = options.getOverridingCredentials().credential;
|
||||
KeyPair keyPair = KeyPair.builder().region(region).keyName(keyPairName).fingerprint(
|
||||
fingerprintPrivateKey(pem)).sha1OfPrivateKey(sha1PrivateKey(pem)).keyMaterial(pem).build();
|
||||
RegionAndName key = new RegionAndName(region, keyPairName);
|
||||
credentialsMap.asMap().put(key, keyPair);
|
||||
}
|
||||
|
@ -124,7 +125,9 @@ public class CreateKeyPairAndSecurityGroupsAsNeededAndReturnRunOptions {
|
|||
|
||||
if (options.getRunScript() != null) {
|
||||
RegionAndName regionAndName = new RegionAndName(region, keyPairName);
|
||||
String message = String.format("no private key configured for: %s; please use options.overrideLoginCredentialWith(rsa_private_text)",
|
||||
String message = String
|
||||
.format(
|
||||
"no private key configured for: %s; please use options.overrideLoginCredentialWith(rsa_private_text)",
|
||||
regionAndName);
|
||||
// test to see if this is in cache.
|
||||
try {
|
||||
|
@ -158,8 +161,8 @@ public class CreateKeyPairAndSecurityGroupsAsNeededAndReturnRunOptions {
|
|||
false);
|
||||
groups.addAll(EC2TemplateOptions.class.cast(options).getGroups());
|
||||
} else {
|
||||
regionNameAndIngessRulesForMarkerGroup = new RegionNameAndIngressRules(region, markerGroup,
|
||||
options.getInboundPorts(), true);
|
||||
regionNameAndIngessRulesForMarkerGroup = new RegionNameAndIngressRules(region, markerGroup, options
|
||||
.getInboundPorts(), true);
|
||||
}
|
||||
// this will create if not yet exists.
|
||||
securityGroupMap.getUnchecked(regionNameAndIngessRulesForMarkerGroup);
|
||||
|
|
|
@ -20,6 +20,7 @@ package org.jclouds.ec2.domain;
|
|||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
import org.jclouds.crypto.SshKeys;
|
||||
import org.jclouds.javax.annotation.Nullable;
|
||||
|
||||
/**
|
||||
|
@ -32,8 +33,8 @@ import org.jclouds.javax.annotation.Nullable;
|
|||
public class KeyPair implements Comparable<KeyPair> {
|
||||
@Override
|
||||
public String toString() {
|
||||
return "[region=" + region + ", keyName=" + keyName + ", keyFingerprint=" + keyFingerprint + ", keyMaterial?="
|
||||
+ (keyMaterial != null) + "]";
|
||||
return "[region=" + region + ", keyName=" + keyName + ", fingerprint=" + fingerprint + ", sha1OfPrivateKey="
|
||||
+ sha1OfPrivateKey + ", keyMaterial?=" + (keyMaterial != null) + "]";
|
||||
}
|
||||
|
||||
public static Builder builder() {
|
||||
|
@ -43,7 +44,8 @@ public class KeyPair implements Comparable<KeyPair> {
|
|||
public static class Builder {
|
||||
private String region;
|
||||
private String keyName;
|
||||
private String keyFingerprint;
|
||||
private String fingerprint;
|
||||
private String sha1OfPrivateKey;
|
||||
private String keyMaterial;
|
||||
|
||||
public Builder region(String region) {
|
||||
|
@ -56,8 +58,8 @@ public class KeyPair implements Comparable<KeyPair> {
|
|||
return this;
|
||||
}
|
||||
|
||||
public Builder keyFingerprint(String keyFingerprint) {
|
||||
this.keyFingerprint = keyFingerprint;
|
||||
public Builder sha1OfPrivateKey(String sha1OfPrivateKey) {
|
||||
this.sha1OfPrivateKey = sha1OfPrivateKey;
|
||||
return this;
|
||||
}
|
||||
|
||||
|
@ -66,27 +68,38 @@ public class KeyPair implements Comparable<KeyPair> {
|
|||
return this;
|
||||
}
|
||||
|
||||
public Builder fingerprint(String fingerprint) {
|
||||
this.fingerprint = fingerprint;
|
||||
return this;
|
||||
}
|
||||
|
||||
public KeyPair build() {
|
||||
return new KeyPair(region, keyName, keyFingerprint, keyMaterial);
|
||||
if (fingerprint == null && keyMaterial != null)
|
||||
fingerprint(SshKeys.fingerprintPrivateKey(keyMaterial));
|
||||
return new KeyPair(region, keyName, sha1OfPrivateKey, keyMaterial, fingerprint);
|
||||
}
|
||||
|
||||
public static Builder fromKeyPair(KeyPair in) {
|
||||
return new Builder().region(in.getRegion()).keyName(in.getKeyName()).keyFingerprint(in.getKeyFingerprint())
|
||||
return new Builder().region(in.getRegion()).keyName(in.getKeyName()).sha1OfPrivateKey(in.getKeyFingerprint())
|
||||
.keyMaterial(in.getKeyMaterial());
|
||||
}
|
||||
}
|
||||
|
||||
private final String region;
|
||||
private final String keyName;
|
||||
private final String keyFingerprint;
|
||||
private final String sha1OfPrivateKey;
|
||||
@Nullable
|
||||
private final String keyMaterial;
|
||||
@Nullable
|
||||
private final String fingerprint;
|
||||
|
||||
public KeyPair(String region, String keyName, String keyFingerprint, @Nullable String keyMaterial) {
|
||||
public KeyPair(String region, String keyName, String sha1OfPrivateKey, @Nullable String keyMaterial,
|
||||
@Nullable String fingerprint) {
|
||||
this.region = checkNotNull(region, "region");
|
||||
this.keyName = checkNotNull(keyName, "keyName");
|
||||
this.keyFingerprint = checkNotNull(keyFingerprint, "keyFingerprint");
|
||||
this.sha1OfPrivateKey = checkNotNull(sha1OfPrivateKey, "sha1OfPrivateKey");
|
||||
this.keyMaterial = keyMaterial;// nullable on list
|
||||
this.fingerprint = fingerprint;// nullable on list
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -104,10 +117,30 @@ public class KeyPair implements Comparable<KeyPair> {
|
|||
}
|
||||
|
||||
/**
|
||||
* A SHA-1 digest of the DER encoded private key.
|
||||
* @see #getSha1OfPrivateKey
|
||||
*/
|
||||
@Deprecated
|
||||
public String getKeyFingerprint() {
|
||||
return keyFingerprint;
|
||||
return sha1OfPrivateKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* A SHA-1 digest of the DER encoded private key.
|
||||
*
|
||||
* @see SshKeys#sha1
|
||||
*/
|
||||
public String getSha1OfPrivateKey() {
|
||||
return sha1OfPrivateKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* fingerprint per the following <a
|
||||
* href="http://tools.ietf.org/html/draft-friedl-secsh-fingerprint-00" >spec</a>
|
||||
*
|
||||
* @see SshKeys#fingerprint
|
||||
*/
|
||||
public String getFingerprint() {
|
||||
return fingerprint;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -128,10 +161,11 @@ public class KeyPair implements Comparable<KeyPair> {
|
|||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + ((keyFingerprint == null) ? 0 : keyFingerprint.hashCode());
|
||||
result = prime * result + ((fingerprint == null) ? 0 : fingerprint.hashCode());
|
||||
result = prime * result + ((keyMaterial == null) ? 0 : keyMaterial.hashCode());
|
||||
result = prime * result + ((keyName == null) ? 0 : keyName.hashCode());
|
||||
result = prime * result + ((region == null) ? 0 : region.hashCode());
|
||||
result = prime * result + ((sha1OfPrivateKey == null) ? 0 : sha1OfPrivateKey.hashCode());
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -144,10 +178,10 @@ public class KeyPair implements Comparable<KeyPair> {
|
|||
if (getClass() != obj.getClass())
|
||||
return false;
|
||||
KeyPair other = (KeyPair) obj;
|
||||
if (keyFingerprint == null) {
|
||||
if (other.keyFingerprint != null)
|
||||
if (fingerprint == null) {
|
||||
if (other.fingerprint != null)
|
||||
return false;
|
||||
} else if (!keyFingerprint.equals(other.keyFingerprint))
|
||||
} else if (!fingerprint.equals(other.fingerprint))
|
||||
return false;
|
||||
if (keyMaterial == null) {
|
||||
if (other.keyMaterial != null)
|
||||
|
@ -164,6 +198,11 @@ public class KeyPair implements Comparable<KeyPair> {
|
|||
return false;
|
||||
} else if (!region.equals(other.region))
|
||||
return false;
|
||||
if (sha1OfPrivateKey == null) {
|
||||
if (other.sha1OfPrivateKey != null)
|
||||
return false;
|
||||
} else if (!sha1OfPrivateKey.equals(other.sha1OfPrivateKey))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -18,12 +18,15 @@
|
|||
*/
|
||||
package org.jclouds.ec2.xml;
|
||||
|
||||
import static org.jclouds.util.SaxUtils.currentOrNull;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import org.jclouds.aws.util.AWSUtils;
|
||||
import org.jclouds.ec2.domain.KeyPair;
|
||||
import org.jclouds.ec2.domain.KeyPair.Builder;
|
||||
import org.jclouds.http.functions.ParseSax;
|
||||
import org.jclouds.location.Region;
|
||||
|
||||
|
@ -36,16 +39,18 @@ import com.google.common.collect.Sets;
|
|||
* />
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
public class DescribeKeyPairsResponseHandler extends
|
||||
ParseSax.HandlerForGeneratedRequestWithResult<Set<KeyPair>> {
|
||||
public class DescribeKeyPairsResponseHandler extends ParseSax.HandlerForGeneratedRequestWithResult<Set<KeyPair>> {
|
||||
private final String defaultRegion;
|
||||
private Builder builder;
|
||||
|
||||
@Inject
|
||||
@Region
|
||||
String defaultRegion;
|
||||
public DescribeKeyPairsResponseHandler(@Region String defaultRegion) {
|
||||
this.defaultRegion = defaultRegion;
|
||||
builder = KeyPair.builder().region(defaultRegion);
|
||||
}
|
||||
|
||||
private StringBuilder currentText = new StringBuilder();
|
||||
private Set<KeyPair> keyPairs = Sets.newLinkedHashSet();
|
||||
private String keyFingerprint;
|
||||
private String keyName;
|
||||
|
||||
public Set<KeyPair> getResult() {
|
||||
return keyPairs;
|
||||
|
@ -54,16 +59,19 @@ public class DescribeKeyPairsResponseHandler extends
|
|||
public void endElement(String uri, String name, String qName) {
|
||||
|
||||
if (qName.equals("keyFingerprint")) {
|
||||
this.keyFingerprint = currentText.toString().trim();
|
||||
builder.sha1OfPrivateKey(currentOrNull(currentText));
|
||||
} else if (qName.equals("item")) {
|
||||
String region = AWSUtils.findRegionInArgsOrNull(getRequest());
|
||||
if (region == null)
|
||||
region = defaultRegion;
|
||||
keyPairs.add(new KeyPair(region, keyName, keyFingerprint, null));
|
||||
} else if (qName.equals("keyName")) {
|
||||
this.keyName = currentText.toString().trim();
|
||||
if (region != null)
|
||||
builder.region(region);
|
||||
try {
|
||||
keyPairs.add(builder.build());
|
||||
} finally {
|
||||
builder = KeyPair.builder().region(defaultRegion);
|
||||
}
|
||||
} else if (qName.equals("keyName")) {
|
||||
builder.keyName(currentOrNull(currentText));
|
||||
}
|
||||
|
||||
currentText = new StringBuilder();
|
||||
}
|
||||
|
||||
|
|
|
@ -18,10 +18,13 @@
|
|||
*/
|
||||
package org.jclouds.ec2.xml;
|
||||
|
||||
import static org.jclouds.util.SaxUtils.currentOrNull;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import org.jclouds.aws.util.AWSUtils;
|
||||
import org.jclouds.ec2.domain.KeyPair;
|
||||
import org.jclouds.ec2.domain.KeyPair.Builder;
|
||||
import org.jclouds.http.functions.ParseSax;
|
||||
import org.jclouds.location.Region;
|
||||
|
||||
|
@ -33,31 +36,36 @@ import org.jclouds.location.Region;
|
|||
* @author Adrian Cole
|
||||
*/
|
||||
public class KeyPairResponseHandler extends ParseSax.HandlerForGeneratedRequestWithResult<KeyPair> {
|
||||
private final String defaultRegion;
|
||||
private Builder builder;
|
||||
|
||||
@Inject
|
||||
@Region
|
||||
String defaultRegion;
|
||||
public KeyPairResponseHandler(@Region String defaultRegion) {
|
||||
this.defaultRegion = defaultRegion;
|
||||
builder = KeyPair.builder().region(defaultRegion);
|
||||
}
|
||||
|
||||
private StringBuilder currentText = new StringBuilder();
|
||||
private String keyFingerprint;
|
||||
private String keyMaterial;
|
||||
private String keyName;
|
||||
|
||||
public KeyPair getResult() {
|
||||
String region = AWSUtils.findRegionInArgsOrNull(getRequest());
|
||||
if (region == null)
|
||||
region = defaultRegion;
|
||||
return new KeyPair(region, keyName, keyFingerprint, keyMaterial);
|
||||
if (region != null)
|
||||
builder.region(region);
|
||||
try {
|
||||
return builder.build();
|
||||
} finally {
|
||||
builder = KeyPair.builder().region(defaultRegion);
|
||||
}
|
||||
}
|
||||
|
||||
public void endElement(String uri, String name, String qName) {
|
||||
|
||||
if (qName.equals("keyFingerprint")) {
|
||||
this.keyFingerprint = currentText.toString().trim();
|
||||
builder.sha1OfPrivateKey(currentOrNull(currentText));
|
||||
} else if (qName.equals("keyMaterial")) {
|
||||
this.keyMaterial = currentText.toString().trim();
|
||||
builder.keyMaterial(currentOrNull(currentText));
|
||||
} else if (qName.equals("keyName")) {
|
||||
this.keyName = currentText.toString().trim();
|
||||
builder.keyName(currentOrNull(currentText));
|
||||
}
|
||||
|
||||
currentText = new StringBuilder();
|
||||
}
|
||||
|
||||
|
|
|
@ -57,6 +57,34 @@ import com.google.common.collect.ImmutableSet;
|
|||
@Test(groups = "unit", singleThreaded = true, testName = "CreateKeyPairAndSecurityGroupsAsNeededAndReturnRunOptionsTest")
|
||||
public class CreateKeyPairAndSecurityGroupsAsNeededAndReturnRunOptionsTest {
|
||||
|
||||
public static final Credentials CREDENTIALS = new Credentials(null, "-----BEGIN RSA PRIVATE KEY-----\n"
|
||||
+ "MIIEowIBAAKCAQEA0CbFlhSdbMdad2ux2BVqk6Ut5fLKb0CdbqubGcEBfwsSz9Rp4Ile76P90MpV\n"
|
||||
+ "W1BGKL5V4MO+flG6dZnRWPVmgrNVyDTmEsALiMGjfEwbACEZ1A8C6mPa36wWO7MlxuyMjg8OczTB\n"
|
||||
+ "EXnHNDpxE5a6KowJtzFlmgjHk2Y+Q42UIqPx47lQUv5bdMDCnfNNomSzTVRjOZLUkDja+ybCKdux\n"
|
||||
+ "gqTsuInhuBRMx+wxff8Z43ECdJV6UPoXK3der1dlZunxGCFkCeYq0kCX7FZ7PV35X744jqhD8P+7\n"
|
||||
+ "y5prO4W+M3DWgChUx0OlbDbSHtDVlcfdbj/+4AKYKU6rQOqh+4DPDQIDAQABAoIBAHjQuEiXKJSV\n"
|
||||
+ "1U2RZcVtENInws9AL/2I/Jfa5Qh6vTqXG9EjklywfzkK72x7tDVvD3ngmAoAs5WwLFDL+fXvYhOk\n"
|
||||
+ "sbql8ZCahVdYRWME7XsSu2IZYHDZipXe1XzLS7b9X8uos5Ns4E8bZuNKtI1RJDdD1vPMqRNR2z0T\n"
|
||||
+ "0Dn3eC7t+t+t7PWaK5AXu2ot7DoOeG1QhqJbwd5pMkIn2ydBILytgmDk/2P3EtJGePIJIeQBicmw\n"
|
||||
+ "Z0KrJFa/K2cC8AtmMJUoZMo+mh1yemDbDLCZW30PjFHbZtcszS2cydAgq/HDFkZynvZG0zhbx/To\n"
|
||||
+ "jzcNza1AyypYwOwb2/9/ulXZp0UCgYEA+QFgWDfYLH2zwjU5b6e0UbIyd/X/yRZ+L8lOEBd0Bbu8\n"
|
||||
+ "qO3txaDbwi7o2mG7pJENHJ3u62CHjgTGDNW9V9Q8eNoGtj3uHvMvi7FdDEK8B6izdZyR7hmZmQ/5\n"
|
||||
+ "MIldelyiGZlz1KBSoy4FsCpA7hV7cI6H6x+Im24NxG90/wd/EgMCgYEA1f+cUyUisIO3yKOCf0hQ\n"
|
||||
+ "aL289q2//F2cbvBxtki6I8JzTg1H3oTO2WVrXQeCA3a/yiuRUatgGH4mxrpCF6byVJyqrEWAj4kU\n"
|
||||
+ "uTbhMgIYhLGoaF1e+vMirCRXUXox0i5X976ASzHn64V9JSd1B+UbKfpcFTYYnChmrRDzmhKN1a8C\n"
|
||||
+ "gYBTvIHAyO7ab18/BRUOllAOVSWhr8lXv0eqHEEzKh/rOaoFCRY3qpOcZpgJsGogumK1Z+sLnoeX\n"
|
||||
+ "W8WaVVp6KbY4UeGF8aedItyvVnLbB6ohzTqkZ4Wvk05S6cs75kXYO0SL5U3NiCiiFXz2NA9nwTOk\n"
|
||||
+ "s1nD2PPgiQ76Kx0mEkhKLwKBgFhHEJqv+AZu37Kx2NRe5WS/2KK9/DPD/hM5tv7mM3sq7Nvm2J3v\n"
|
||||
+ "lVDS6J5AyZ5aLzXcER9qncKcz6wtC7SsFs1Wr4VPSoBroRPikrVJbgnXK8yZr+O/xq7Scv7WdJTq\n"
|
||||
+ "rzkw6cWbObvLnltkUn/GQBVqBPBvF2nbtLdyBbuqKb5bAoGBAI1+aoJnvXEXxT4UHrMkQcY0eXRz\n"
|
||||
+ "3UdbzJmtjMW9CR6l9s11mV6PcZP4qnODp3nd6a+lPeL3wVYQ47DsTJ/Bx5dI17zA5mU57n6mV0a3\n"
|
||||
+ "DbSoPKSdaKTQdo2THnVE9P9sPKZWueAcsE4Yw/qcTjoxrtUnAH/AXN250v0tkKIOvMhu\n"
|
||||
+ "-----END RSA PRIVATE KEY-----");
|
||||
|
||||
public static final KeyPair KEYPAIR = KeyPair.builder().region(Region.AP_SOUTHEAST_1).keyName("myKeyPair")
|
||||
.sha1OfPrivateKey("13:36:74:b9:56:bb:07:96:c0:19:ab:00:7f:9f:06:d2:16:a0:45:32").fingerprint(
|
||||
"60:15:d1:f1:d9:e2:3c:e2:ee:a9:64:6a:42:a7:34:0c").keyMaterial(CREDENTIALS.credential).build();
|
||||
|
||||
private static final Provider<RunInstancesOptions> OPTIONS_PROVIDER = new javax.inject.Provider<RunInstancesOptions>() {
|
||||
|
||||
@Override
|
||||
|
@ -69,7 +97,7 @@ public class CreateKeyPairAndSecurityGroupsAsNeededAndReturnRunOptionsTest {
|
|||
public void testExecuteWithDefaultOptionsEC2() throws SecurityException, NoSuchMethodException {
|
||||
// setup constants
|
||||
String region = Region.AP_SOUTHEAST_1;
|
||||
String tag = "tag";
|
||||
String group = "group";
|
||||
Hardware size = EC2HardwareBuilder.m1_small32().build();
|
||||
String systemGeneratedKeyPairName = "systemGeneratedKeyPair";
|
||||
String generatedGroup = "group";
|
||||
|
@ -95,9 +123,9 @@ public class CreateKeyPairAndSecurityGroupsAsNeededAndReturnRunOptionsTest {
|
|||
expect(template.getHardware()).andReturn(size).atLeastOnce();
|
||||
expect(template.getOptions()).andReturn(options).atLeastOnce();
|
||||
expect(options.getBlockDeviceMappings()).andReturn(ImmutableSet.<BlockDeviceMapping> of()).atLeastOnce();
|
||||
expect(strategy.createNewKeyPairUnlessUserSpecifiedOtherwise(region, tag, options)).andReturn(
|
||||
expect(strategy.createNewKeyPairUnlessUserSpecifiedOtherwise(region, group, options)).andReturn(
|
||||
systemGeneratedKeyPairName);
|
||||
expect(strategy.getSecurityGroupsForTagAndOptions(region, tag, options)).andReturn(generatedGroups);
|
||||
expect(strategy.getSecurityGroupsForTagAndOptions(region, group, options)).andReturn(generatedGroups);
|
||||
expect(options.getUserData()).andReturn(null);
|
||||
|
||||
// replay mocks
|
||||
|
@ -106,7 +134,7 @@ public class CreateKeyPairAndSecurityGroupsAsNeededAndReturnRunOptionsTest {
|
|||
replay(strategy);
|
||||
|
||||
// run
|
||||
RunInstancesOptions customize = strategy.execute(region, tag, template);
|
||||
RunInstancesOptions customize = strategy.execute(region, group, template);
|
||||
assertEquals(customize.buildQueryParameters(), ImmutableMultimap.<String, String> of());
|
||||
assertEquals(customize.buildFormParameters().entries(), ImmutableMultimap.<String, String> of("InstanceType",
|
||||
size.getProviderId(), "SecurityGroup.1", generatedGroup, "KeyName", systemGeneratedKeyPairName)
|
||||
|
@ -124,7 +152,7 @@ public class CreateKeyPairAndSecurityGroupsAsNeededAndReturnRunOptionsTest {
|
|||
public void testExecuteWithUserData() throws SecurityException, NoSuchMethodException {
|
||||
// setup constants
|
||||
String region = Region.AP_SOUTHEAST_1;
|
||||
String tag = "tag";
|
||||
String group = "group";
|
||||
Hardware size = EC2HardwareBuilder.m1_small32().build();
|
||||
String systemGeneratedKeyPairName = "systemGeneratedKeyPair";
|
||||
String generatedGroup = "group";
|
||||
|
@ -150,9 +178,9 @@ public class CreateKeyPairAndSecurityGroupsAsNeededAndReturnRunOptionsTest {
|
|||
expect(template.getHardware()).andReturn(size).atLeastOnce();
|
||||
expect(template.getOptions()).andReturn(options).atLeastOnce();
|
||||
expect(options.getBlockDeviceMappings()).andReturn(ImmutableSet.<BlockDeviceMapping> of()).atLeastOnce();
|
||||
expect(strategy.createNewKeyPairUnlessUserSpecifiedOtherwise(region, tag, options)).andReturn(
|
||||
expect(strategy.createNewKeyPairUnlessUserSpecifiedOtherwise(region, group, options)).andReturn(
|
||||
systemGeneratedKeyPairName);
|
||||
expect(strategy.getSecurityGroupsForTagAndOptions(region, tag, options)).andReturn(generatedGroups);
|
||||
expect(strategy.getSecurityGroupsForTagAndOptions(region, group, options)).andReturn(generatedGroups);
|
||||
expect(options.getUserData()).andReturn("hello".getBytes());
|
||||
|
||||
// replay mocks
|
||||
|
@ -161,7 +189,7 @@ public class CreateKeyPairAndSecurityGroupsAsNeededAndReturnRunOptionsTest {
|
|||
replay(strategy);
|
||||
|
||||
// run
|
||||
RunInstancesOptions customize = strategy.execute(region, tag, template);
|
||||
RunInstancesOptions customize = strategy.execute(region, group, template);
|
||||
assertEquals(customize.buildQueryParameters(), ImmutableMultimap.<String, String> of());
|
||||
assertEquals(customize.buildFormParameters().entries(), ImmutableMultimap.<String, String> of("InstanceType",
|
||||
size.getProviderId(), "SecurityGroup.1", "group", "KeyName", systemGeneratedKeyPairName, "UserData",
|
||||
|
@ -179,7 +207,7 @@ public class CreateKeyPairAndSecurityGroupsAsNeededAndReturnRunOptionsTest {
|
|||
public void testCreateNewKeyPairUnlessUserSpecifiedOtherwise_reusesKeyWhenToldTo() {
|
||||
// setup constants
|
||||
String region = Region.AP_SOUTHEAST_1;
|
||||
String tag = "tag";
|
||||
String group = "group";
|
||||
String userSuppliedKeyPair = "myKeyPair";
|
||||
|
||||
// create mocks
|
||||
|
@ -198,7 +226,7 @@ public class CreateKeyPairAndSecurityGroupsAsNeededAndReturnRunOptionsTest {
|
|||
replayStrategy(strategy);
|
||||
|
||||
// run
|
||||
assertEquals(strategy.createNewKeyPairUnlessUserSpecifiedOtherwise(region, tag, options), userSuppliedKeyPair);
|
||||
assertEquals(strategy.createNewKeyPairUnlessUserSpecifiedOtherwise(region, group, options), userSuppliedKeyPair);
|
||||
|
||||
// verify mocks
|
||||
verify(options);
|
||||
|
@ -210,7 +238,7 @@ public class CreateKeyPairAndSecurityGroupsAsNeededAndReturnRunOptionsTest {
|
|||
public void testCreateNewKeyPairUnlessUserSpecifiedOtherwise_reusesKeyWhenToldToWithRunScriptButNoCredentials() {
|
||||
// setup constants
|
||||
String region = Region.AP_SOUTHEAST_1;
|
||||
String tag = "tag";
|
||||
String group = "group";
|
||||
String userSuppliedKeyPair = "myKeyPair";
|
||||
|
||||
// create mocks
|
||||
|
@ -232,7 +260,7 @@ public class CreateKeyPairAndSecurityGroupsAsNeededAndReturnRunOptionsTest {
|
|||
replayStrategy(strategy);
|
||||
|
||||
// run
|
||||
assertEquals(strategy.createNewKeyPairUnlessUserSpecifiedOtherwise(region, tag, options), userSuppliedKeyPair);
|
||||
assertEquals(strategy.createNewKeyPairUnlessUserSpecifiedOtherwise(region, group, options), userSuppliedKeyPair);
|
||||
|
||||
// verify mocks
|
||||
verify(options);
|
||||
|
@ -243,7 +271,7 @@ public class CreateKeyPairAndSecurityGroupsAsNeededAndReturnRunOptionsTest {
|
|||
public void testCreateNewKeyPairUnlessUserSpecifiedOtherwise_reusesKeyWhenToldToWithRunScriptAndCredentialsAlreadyInMap() {
|
||||
// setup constants
|
||||
String region = Region.AP_SOUTHEAST_1;
|
||||
String tag = "tag";
|
||||
String group = "group";
|
||||
String userSuppliedKeyPair = "myKeyPair";
|
||||
|
||||
// create mocks
|
||||
|
@ -264,7 +292,7 @@ public class CreateKeyPairAndSecurityGroupsAsNeededAndReturnRunOptionsTest {
|
|||
replayStrategy(strategy);
|
||||
|
||||
// run
|
||||
assertEquals(strategy.createNewKeyPairUnlessUserSpecifiedOtherwise(region, tag, options), userSuppliedKeyPair);
|
||||
assertEquals(strategy.createNewKeyPairUnlessUserSpecifiedOtherwise(region, group, options), userSuppliedKeyPair);
|
||||
|
||||
// verify mocks
|
||||
verify(options);
|
||||
|
@ -276,7 +304,7 @@ public class CreateKeyPairAndSecurityGroupsAsNeededAndReturnRunOptionsTest {
|
|||
public void testCreateNewKeyPairUnlessUserSpecifiedOtherwise_reusesKeyWhenToldToWithRunScriptAndCredentialsSpecified() {
|
||||
// setup constants
|
||||
String region = Region.AP_SOUTHEAST_1;
|
||||
String tag = "tag";
|
||||
String group = "group";
|
||||
String userSuppliedKeyPair = "myKeyPair";
|
||||
|
||||
// create mocks
|
||||
|
@ -287,11 +315,11 @@ public class CreateKeyPairAndSecurityGroupsAsNeededAndReturnRunOptionsTest {
|
|||
|
||||
// setup expectations
|
||||
expect(options.getKeyPair()).andReturn(userSuppliedKeyPair);
|
||||
expect(options.getOverridingCredentials()).andReturn(new Credentials(null, "MyRsa")).atLeastOnce();
|
||||
expect(options.getOverridingCredentials()).andReturn(CREDENTIALS).atLeastOnce();
|
||||
expect(strategy.credentialsMap.asMap()).andReturn(backing);
|
||||
expect(
|
||||
backing.put(new RegionAndName(region, userSuppliedKeyPair), KeyPair.builder().region(region).keyName(
|
||||
userSuppliedKeyPair).keyFingerprint("//TODO").keyMaterial("MyRsa").build())).andReturn(null);
|
||||
|
||||
// Notice that the fingerprint and sha1 generated
|
||||
expect(backing.put(new RegionAndName(region, userSuppliedKeyPair), KEYPAIR)).andReturn(null);
|
||||
expect(options.getRunScript()).andReturn(Statements.exec("echo foo"));
|
||||
expect(strategy.credentialsMap.getUnchecked(new RegionAndName(region, userSuppliedKeyPair))).andReturn(keyPair);
|
||||
|
||||
|
@ -302,7 +330,7 @@ public class CreateKeyPairAndSecurityGroupsAsNeededAndReturnRunOptionsTest {
|
|||
replayStrategy(strategy);
|
||||
|
||||
// run
|
||||
assertEquals(strategy.createNewKeyPairUnlessUserSpecifiedOtherwise(region, tag, options), userSuppliedKeyPair);
|
||||
assertEquals(strategy.createNewKeyPairUnlessUserSpecifiedOtherwise(region, group, options), userSuppliedKeyPair);
|
||||
|
||||
// verify mocks
|
||||
verify(options);
|
||||
|
@ -315,7 +343,7 @@ public class CreateKeyPairAndSecurityGroupsAsNeededAndReturnRunOptionsTest {
|
|||
throws ExecutionException {
|
||||
// setup constants
|
||||
String region = Region.AP_SOUTHEAST_1;
|
||||
String tag = "tag";
|
||||
String group = "group";
|
||||
String userSuppliedKeyPair = null;
|
||||
boolean shouldAutomaticallyCreateKeyPair = true;
|
||||
String systemGeneratedKeyPairName = "systemGeneratedKeyPair";
|
||||
|
@ -329,7 +357,7 @@ public class CreateKeyPairAndSecurityGroupsAsNeededAndReturnRunOptionsTest {
|
|||
expect(options.getKeyPair()).andReturn(userSuppliedKeyPair);
|
||||
expect(options.shouldAutomaticallyCreateKeyPair()).andReturn(shouldAutomaticallyCreateKeyPair);
|
||||
expect(keyPair.getKeyName()).andReturn(systemGeneratedKeyPairName).atLeastOnce();
|
||||
expect(strategy.credentialsMap.getUnchecked(new RegionAndName(region, tag))).andReturn(keyPair);
|
||||
expect(strategy.credentialsMap.getUnchecked(new RegionAndName(region, group))).andReturn(keyPair);
|
||||
expect(options.getRunScript()).andReturn(null);
|
||||
|
||||
// replay mocks
|
||||
|
@ -338,7 +366,7 @@ public class CreateKeyPairAndSecurityGroupsAsNeededAndReturnRunOptionsTest {
|
|||
replayStrategy(strategy);
|
||||
|
||||
// run
|
||||
assertEquals(strategy.createNewKeyPairUnlessUserSpecifiedOtherwise(region, tag, options),
|
||||
assertEquals(strategy.createNewKeyPairUnlessUserSpecifiedOtherwise(region, group, options),
|
||||
systemGeneratedKeyPairName);
|
||||
|
||||
// verify mocks
|
||||
|
@ -350,7 +378,7 @@ public class CreateKeyPairAndSecurityGroupsAsNeededAndReturnRunOptionsTest {
|
|||
public void testCreateNewKeyPairUnlessUserSpecifiedOtherwise_doesntCreateAKeyPairAndReturnsNullWhenToldNotTo() {
|
||||
// setup constants
|
||||
String region = Region.AP_SOUTHEAST_1;
|
||||
String tag = "tag";
|
||||
String group = "group";
|
||||
String userSuppliedKeyPair = null;
|
||||
boolean shouldAutomaticallyCreateKeyPair = false; // here's the important
|
||||
// part!
|
||||
|
@ -371,7 +399,7 @@ public class CreateKeyPairAndSecurityGroupsAsNeededAndReturnRunOptionsTest {
|
|||
replayStrategy(strategy);
|
||||
|
||||
// run
|
||||
assertEquals(strategy.createNewKeyPairUnlessUserSpecifiedOtherwise(region, tag, options), null);
|
||||
assertEquals(strategy.createNewKeyPairUnlessUserSpecifiedOtherwise(region, group, options), null);
|
||||
|
||||
// verify mocks
|
||||
verify(options);
|
||||
|
@ -383,8 +411,8 @@ public class CreateKeyPairAndSecurityGroupsAsNeededAndReturnRunOptionsTest {
|
|||
throws ExecutionException {
|
||||
// setup constants
|
||||
String region = Region.AP_SOUTHEAST_1;
|
||||
String tag = "tag";
|
||||
String generatedMarkerGroup = "jclouds#tag#" + Region.AP_SOUTHEAST_1;
|
||||
String group = "group";
|
||||
String generatedMarkerGroup = "jclouds#group#" + Region.AP_SOUTHEAST_1;
|
||||
Set<String> groupIds = ImmutableSet.<String> of();
|
||||
int[] ports = new int[] {};
|
||||
boolean shouldAuthorizeSelf = true;
|
||||
|
@ -399,14 +427,14 @@ public class CreateKeyPairAndSecurityGroupsAsNeededAndReturnRunOptionsTest {
|
|||
expect(options.getInboundPorts()).andReturn(ports).atLeastOnce();
|
||||
RegionNameAndIngressRules regionNameAndIngressRules = new RegionNameAndIngressRules(region, generatedMarkerGroup,
|
||||
ports, shouldAuthorizeSelf);
|
||||
expect(strategy.securityGroupMap.getUnchecked(regionNameAndIngressRules)).andReturn(tag);
|
||||
expect(strategy.securityGroupMap.getUnchecked(regionNameAndIngressRules)).andReturn(group);
|
||||
|
||||
// replay mocks
|
||||
replay(options);
|
||||
replayStrategy(strategy);
|
||||
|
||||
// run
|
||||
assertEquals(strategy.getSecurityGroupsForTagAndOptions(region, tag, options), returnVal);
|
||||
assertEquals(strategy.getSecurityGroupsForTagAndOptions(region, group, options), returnVal);
|
||||
|
||||
// verify mocks
|
||||
verify(options);
|
||||
|
@ -417,8 +445,8 @@ public class CreateKeyPairAndSecurityGroupsAsNeededAndReturnRunOptionsTest {
|
|||
throws ExecutionException {
|
||||
// setup constants
|
||||
String region = Region.AP_SOUTHEAST_1;
|
||||
String tag = "tag";
|
||||
String generatedMarkerGroup = "jclouds#tag#" + Region.AP_SOUTHEAST_1;
|
||||
String group = "group";
|
||||
String generatedMarkerGroup = "jclouds#group#" + Region.AP_SOUTHEAST_1;
|
||||
Set<String> groupIds = ImmutableSet.<String> of();
|
||||
int[] ports = new int[] { 22, 80 };
|
||||
boolean shouldAuthorizeSelf = true;
|
||||
|
@ -440,7 +468,7 @@ public class CreateKeyPairAndSecurityGroupsAsNeededAndReturnRunOptionsTest {
|
|||
replayStrategy(strategy);
|
||||
|
||||
// run
|
||||
assertEquals(strategy.getSecurityGroupsForTagAndOptions(region, tag, options), returnVal);
|
||||
assertEquals(strategy.getSecurityGroupsForTagAndOptions(region, group, options), returnVal);
|
||||
|
||||
// verify mocks
|
||||
verify(options);
|
||||
|
@ -451,8 +479,8 @@ public class CreateKeyPairAndSecurityGroupsAsNeededAndReturnRunOptionsTest {
|
|||
throws ExecutionException {
|
||||
// setup constants
|
||||
String region = Region.AP_SOUTHEAST_1;
|
||||
String tag = "tag";
|
||||
String generatedMarkerGroup = "jclouds#tag#" + Region.AP_SOUTHEAST_1;
|
||||
String group = "group";
|
||||
String generatedMarkerGroup = "jclouds#group#" + Region.AP_SOUTHEAST_1;
|
||||
Set<String> groupIds = ImmutableSet.<String> of();
|
||||
int[] ports = new int[] {};
|
||||
boolean shouldAuthorizeSelf = true;
|
||||
|
@ -474,7 +502,7 @@ public class CreateKeyPairAndSecurityGroupsAsNeededAndReturnRunOptionsTest {
|
|||
replayStrategy(strategy);
|
||||
|
||||
// run
|
||||
assertEquals(strategy.getSecurityGroupsForTagAndOptions(region, tag, options), returnVal);
|
||||
assertEquals(strategy.getSecurityGroupsForTagAndOptions(region, group, options), returnVal);
|
||||
|
||||
// verify mocks
|
||||
verify(options);
|
||||
|
@ -484,8 +512,8 @@ public class CreateKeyPairAndSecurityGroupsAsNeededAndReturnRunOptionsTest {
|
|||
public void testGetSecurityGroupsForTagAndOptions_reusesGroupByDefaultWhenNoPortsAreSpecifiedWhenDoesExistAndAcceptsUserSuppliedGroups() {
|
||||
// setup constants
|
||||
String region = Region.AP_SOUTHEAST_1;
|
||||
String tag = "tag";
|
||||
String generatedMarkerGroup = "jclouds#tag#" + Region.AP_SOUTHEAST_1;
|
||||
String group = "group";
|
||||
String generatedMarkerGroup = "jclouds#group#" + Region.AP_SOUTHEAST_1;
|
||||
Set<String> groupIds = ImmutableSet.<String> of("group1", "group2");
|
||||
int[] ports = new int[] {};
|
||||
boolean shouldAuthorizeSelf = true;
|
||||
|
@ -501,14 +529,15 @@ public class CreateKeyPairAndSecurityGroupsAsNeededAndReturnRunOptionsTest {
|
|||
RegionNameAndIngressRules regionNameAndIngressRules = new RegionNameAndIngressRules(region, generatedMarkerGroup,
|
||||
ports, shouldAuthorizeSelf);
|
||||
|
||||
expect(strategy.securityGroupMap.getUnchecked(regionNameAndIngressRules)).andReturn(groupExisted ? "tag" : null);
|
||||
expect(strategy.securityGroupMap.getUnchecked(regionNameAndIngressRules))
|
||||
.andReturn(groupExisted ? "group" : null);
|
||||
|
||||
// replay mocks
|
||||
replay(options);
|
||||
replayStrategy(strategy);
|
||||
|
||||
// run
|
||||
assertEquals(strategy.getSecurityGroupsForTagAndOptions(region, tag, options), returnVal);
|
||||
assertEquals(strategy.getSecurityGroupsForTagAndOptions(region, group, options), returnVal);
|
||||
|
||||
// verify mocks
|
||||
verify(options);
|
||||
|
|
|
@ -39,7 +39,7 @@ import com.google.common.collect.ImmutableSet;
|
|||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
//NOTE:without testName, this will not call @Before* and fail w/NPE during surefire
|
||||
// NOTE:without testName, this will not call @Before* and fail w/NPE during surefire
|
||||
@Test(groups = "unit", testName = "DescribeKeyPairsResponseHandlerTest")
|
||||
public class DescribeKeyPairsResponseHandlerTest extends BaseEC2HandlerTest {
|
||||
public void testApplyInputStream() {
|
||||
|
@ -47,10 +47,9 @@ public class DescribeKeyPairsResponseHandlerTest extends BaseEC2HandlerTest {
|
|||
InputStream is = getClass().getResourceAsStream("/describe_keypairs.xml");
|
||||
|
||||
Set<KeyPair> expected = ImmutableSet.of(new KeyPair(defaultRegion, "gsg-keypair",
|
||||
"1f:51:ae:28:bf:89:e9:d8:1f:25:5d:37:2d:7d:b8:ca:9f:f5:f1:6f", null));
|
||||
"1f:51:ae:28:bf:89:e9:d8:1f:25:5d:37:2d:7d:b8:ca:9f:f5:f1:6f", null, null));
|
||||
|
||||
DescribeKeyPairsResponseHandler handler = injector
|
||||
.getInstance(DescribeKeyPairsResponseHandler.class);
|
||||
DescribeKeyPairsResponseHandler handler = injector.getInstance(DescribeKeyPairsResponseHandler.class);
|
||||
addDefaultRegionToHandler(handler);
|
||||
Set<KeyPair> result = factory.create(handler).parse(is);
|
||||
assertEquals(result, expected);
|
||||
|
@ -58,7 +57,7 @@ public class DescribeKeyPairsResponseHandlerTest extends BaseEC2HandlerTest {
|
|||
|
||||
private void addDefaultRegionToHandler(ParseSax.HandlerWithResult<?> handler) {
|
||||
GeneratedHttpRequest<?> request = createMock(GeneratedHttpRequest.class);
|
||||
expect(request.getArgs()).andReturn(ImmutableList.<Object>of());
|
||||
expect(request.getArgs()).andReturn(ImmutableList.<Object> of());
|
||||
replay(request);
|
||||
handler.setContext(request);
|
||||
}
|
||||
|
|
|
@ -23,8 +23,10 @@ import static org.easymock.classextension.EasyMock.createMock;
|
|||
import static org.easymock.classextension.EasyMock.replay;
|
||||
import static org.testng.Assert.assertEquals;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
import org.jclouds.crypto.SshKeys;
|
||||
import org.jclouds.ec2.domain.KeyPair;
|
||||
import org.jclouds.http.functions.ParseSax;
|
||||
import org.jclouds.rest.internal.GeneratedHttpRequest;
|
||||
|
@ -37,51 +39,53 @@ import com.google.common.collect.ImmutableList;
|
|||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
//NOTE:without testName, this will not call @Before* and fail w/NPE during surefire
|
||||
// NOTE:without testName, this will not call @Before* and fail w/NPE during surefire
|
||||
@Test(groups = "unit", testName = "KeyPairResponseHandlerTest")
|
||||
public class KeyPairResponseHandlerTest extends BaseEC2HandlerTest {
|
||||
public void testApplyInputStream() {
|
||||
public void testApplyInputStream() throws IOException {
|
||||
|
||||
InputStream is = getClass().getResourceAsStream("/create_keypair.xml");
|
||||
|
||||
KeyPair expected = new KeyPair(
|
||||
defaultRegion,
|
||||
"gsg-keypair",
|
||||
"1f:51:ae:28:bf:89:e9:d8:1f:25:5d:37:2d:7d:b8:ca:9f:f5:f1:6f",
|
||||
KeyPair expected = KeyPair.builder().region(defaultRegion).keyName("adriancole-ec21").sha1OfPrivateKey(
|
||||
"13:36:74:b9:56:bb:07:96:c0:19:ab:00:7f:9f:06:d2:16:a0:45:32").keyMaterial(
|
||||
"-----BEGIN RSA PRIVATE KEY-----\n"
|
||||
+ "MIIEoQIBAAKCAQBuLFg5ujHrtm1jnutSuoO8Xe56LlT+HM8v/xkaa39EstM3/aFxTHgElQiJLChp\n"
|
||||
+ "HungXQ29VTc8rc1bW0lkdi23OH5eqkMHGhvEwqa0HWASUMll4o3o/IX+0f2UcPoKCOVUR+jx71Sg\n"
|
||||
+ "5AU52EQfanIn3ZQ8lFW7Edp5a3q4DhjGlUKToHVbicL5E+g45zfB95wIyywWZfeW/UUF3LpGZyq/\n"
|
||||
+ "ebIUlq1qTbHkLbCC2r7RTn8vpQWp47BGVYGtGSBMpTRP5hnbzzuqj3itkiLHjU39S2sJCJ0TrJx5\n"
|
||||
+ "i8BygR4s3mHKBj8l+ePQxG1kGbF6R4yg6sECmXn17MRQVXODNHZbAgMBAAECggEAY1tsiUsIwDl5\n"
|
||||
+ "91CXirkYGuVfLyLflXenxfI50mDFms/mumTqloHO7tr0oriHDR5K7wMcY/YY5YkcXNo7mvUVD1pM\n"
|
||||
+ "ZNUJs7rw9gZRTrf7LylaJ58kOcyajw8TsC4e4LPbFaHwS1d6K8rXh64o6WgW4SrsB6ICmr1kGQI7\n"
|
||||
+ "3wcfgt5ecIu4TZf0OE9IHjn+2eRlsrjBdeORi7KiUNC/pAG23I6MdDOFEQRcCSigCj+4/mciFUSA\n"
|
||||
+ "SWS4dMbrpb9FNSIcf9dcLxVM7/6KxgJNfZc9XWzUw77Jg8x92Zd0fVhHOux5IZC+UvSKWB4dyfcI\n"
|
||||
+ "tE8C3p9bbU9VGyY5vLCAiIb4qQKBgQDLiO24GXrIkswF32YtBBMuVgLGCwU9h9HlO9mKAc2m8Cm1\n"
|
||||
+ "jUE5IpzRjTedc9I2qiIMUTwtgnw42auSCzbUeYMURPtDqyQ7p6AjMujp9EPemcSVOK9vXYL0Ptco\n"
|
||||
+ "xW9MC0dtV6iPkCN7gOqiZXPRKaFbWADp16p8UAIvS/a5XXk5jwKBgQCKkpHi2EISh1uRkhxljyWC\n"
|
||||
+ "iDCiK6JBRsMvpLbc0v5dKwP5alo1fmdR5PJaV2qvZSj5CYNpMAy1/EDNTY5OSIJU+0KFmQbyhsbm\n"
|
||||
+ "rdLNLDL4+TcnT7c62/aH01ohYaf/VCbRhtLlBfqGoQc7+sAc8vmKkesnF7CqCEKDyF/dhrxYdQKB\n"
|
||||
+ "gC0iZzzNAapayz1+JcVTwwEid6j9JqNXbBc+Z2YwMi+T0Fv/P/hwkX/ypeOXnIUcw0Ih/YtGBVAC\n"
|
||||
+ "DQbsz7LcY1HqXiHKYNWNvXgwwO+oiChjxvEkSdsTTIfnK4VSCvU9BxDbQHjdiNDJbL6oar92UN7V\n"
|
||||
+ "rBYvChJZF7LvUH4YmVpHAoGAbZ2X7XvoeEO+uZ58/BGKOIGHByHBDiXtzMhdJr15HTYjxK7OgTZm\n"
|
||||
+ "gK+8zp4L9IbvLGDMJO8vft32XPEWuvI8twCzFH+CsWLQADZMZKSsBasOZ/h1FwhdMgCMcY+Qlzd4\n"
|
||||
+ "JZKjTSu3i7vhvx6RzdSedXEMNTZWN4qlIx3kR5aHcukCgYA9T+Zrvm1F0seQPbLknn7EqhXIjBaT\n"
|
||||
+ "P8TTvW/6bdPi23ExzxZn7KOdrfclYRph1LHMpAONv/x2xALIf91UB+v5ohy1oDoasL0gij1houRe\n"
|
||||
+ "2ERKKdwz0ZL9SWq6VTdhr/5G994CK72fy5WhyERbDjUIdHaK3M849JJuf8cSrvSb4g==\n"
|
||||
+ "-----END RSA PRIVATE KEY-----");
|
||||
+ "MIIEowIBAAKCAQEA0CbFlhSdbMdad2ux2BVqk6Ut5fLKb0CdbqubGcEBfwsSz9Rp4Ile76P90MpV\n"
|
||||
+ "W1BGKL5V4MO+flG6dZnRWPVmgrNVyDTmEsALiMGjfEwbACEZ1A8C6mPa36wWO7MlxuyMjg8OczTB\n"
|
||||
+ "EXnHNDpxE5a6KowJtzFlmgjHk2Y+Q42UIqPx47lQUv5bdMDCnfNNomSzTVRjOZLUkDja+ybCKdux\n"
|
||||
+ "gqTsuInhuBRMx+wxff8Z43ECdJV6UPoXK3der1dlZunxGCFkCeYq0kCX7FZ7PV35X744jqhD8P+7\n"
|
||||
+ "y5prO4W+M3DWgChUx0OlbDbSHtDVlcfdbj/+4AKYKU6rQOqh+4DPDQIDAQABAoIBAHjQuEiXKJSV\n"
|
||||
+ "1U2RZcVtENInws9AL/2I/Jfa5Qh6vTqXG9EjklywfzkK72x7tDVvD3ngmAoAs5WwLFDL+fXvYhOk\n"
|
||||
+ "sbql8ZCahVdYRWME7XsSu2IZYHDZipXe1XzLS7b9X8uos5Ns4E8bZuNKtI1RJDdD1vPMqRNR2z0T\n"
|
||||
+ "0Dn3eC7t+t+t7PWaK5AXu2ot7DoOeG1QhqJbwd5pMkIn2ydBILytgmDk/2P3EtJGePIJIeQBicmw\n"
|
||||
+ "Z0KrJFa/K2cC8AtmMJUoZMo+mh1yemDbDLCZW30PjFHbZtcszS2cydAgq/HDFkZynvZG0zhbx/To\n"
|
||||
+ "jzcNza1AyypYwOwb2/9/ulXZp0UCgYEA+QFgWDfYLH2zwjU5b6e0UbIyd/X/yRZ+L8lOEBd0Bbu8\n"
|
||||
+ "qO3txaDbwi7o2mG7pJENHJ3u62CHjgTGDNW9V9Q8eNoGtj3uHvMvi7FdDEK8B6izdZyR7hmZmQ/5\n"
|
||||
+ "MIldelyiGZlz1KBSoy4FsCpA7hV7cI6H6x+Im24NxG90/wd/EgMCgYEA1f+cUyUisIO3yKOCf0hQ\n"
|
||||
+ "aL289q2//F2cbvBxtki6I8JzTg1H3oTO2WVrXQeCA3a/yiuRUatgGH4mxrpCF6byVJyqrEWAj4kU\n"
|
||||
+ "uTbhMgIYhLGoaF1e+vMirCRXUXox0i5X976ASzHn64V9JSd1B+UbKfpcFTYYnChmrRDzmhKN1a8C\n"
|
||||
+ "gYBTvIHAyO7ab18/BRUOllAOVSWhr8lXv0eqHEEzKh/rOaoFCRY3qpOcZpgJsGogumK1Z+sLnoeX\n"
|
||||
+ "W8WaVVp6KbY4UeGF8aedItyvVnLbB6ohzTqkZ4Wvk05S6cs75kXYO0SL5U3NiCiiFXz2NA9nwTOk\n"
|
||||
+ "s1nD2PPgiQ76Kx0mEkhKLwKBgFhHEJqv+AZu37Kx2NRe5WS/2KK9/DPD/hM5tv7mM3sq7Nvm2J3v\n"
|
||||
+ "lVDS6J5AyZ5aLzXcER9qncKcz6wtC7SsFs1Wr4VPSoBroRPikrVJbgnXK8yZr+O/xq7Scv7WdJTq\n"
|
||||
+ "rzkw6cWbObvLnltkUn/GQBVqBPBvF2nbtLdyBbuqKb5bAoGBAI1+aoJnvXEXxT4UHrMkQcY0eXRz\n"
|
||||
+ "3UdbzJmtjMW9CR6l9s11mV6PcZP4qnODp3nd6a+lPeL3wVYQ47DsTJ/Bx5dI17zA5mU57n6mV0a3\n"
|
||||
+ "DbSoPKSdaKTQdo2THnVE9P9sPKZWueAcsE4Yw/qcTjoxrtUnAH/AXN250v0tkKIOvMhu\n"
|
||||
+ "-----END RSA PRIVATE KEY-----").build();
|
||||
|
||||
KeyPairResponseHandler handler = injector.getInstance(KeyPairResponseHandler.class);
|
||||
addDefaultRegionToHandler(handler);
|
||||
KeyPair result = factory.create(handler).parse(is);
|
||||
|
||||
assertEquals(result, expected);
|
||||
|
||||
assert SshKeys.privateKeyHasSha1(result.getKeyMaterial(), result.getSha1OfPrivateKey());
|
||||
assert SshKeys.privateKeyHasFingerprint(result.getKeyMaterial(), result.getFingerprint());
|
||||
|
||||
}
|
||||
|
||||
private void addDefaultRegionToHandler(ParseSax.HandlerWithResult<?> handler) {
|
||||
GeneratedHttpRequest<?> request = createMock(GeneratedHttpRequest.class);
|
||||
expect(request.getArgs()).andReturn(ImmutableList.<Object>of()).atLeastOnce();
|
||||
expect(request.getArgs()).andReturn(ImmutableList.<Object> of()).atLeastOnce();
|
||||
replay(request);
|
||||
handler.setContext(request);
|
||||
}
|
||||
|
|
|
@ -1,27 +1,28 @@
|
|||
<CreateKeyPairResponse xmlns="http://ec2.amazonaws.com/doc/2009-11-30/">
|
||||
<keyName>gsg-keypair</keyName>
|
||||
<keyFingerprint>1f:51:ae:28:bf:89:e9:d8:1f:25:5d:37:2d:7d:b8:ca:9f:f5:f1:6f</keyFingerprint>
|
||||
<CreateKeyPairResponse xmlns="http://ec2.amazonaws.com/doc/2011-05-15/">
|
||||
<requestId>bb5e3a3c-e254-454d-ba29-d607cdf6357a</requestId>
|
||||
<keyName>adriancole-ec21</keyName>
|
||||
<keyFingerprint>13:36:74:b9:56:bb:07:96:c0:19:ab:00:7f:9f:06:d2:16:a0:45:32</keyFingerprint>
|
||||
<keyMaterial>-----BEGIN RSA PRIVATE KEY-----
|
||||
MIIEoQIBAAKCAQBuLFg5ujHrtm1jnutSuoO8Xe56LlT+HM8v/xkaa39EstM3/aFxTHgElQiJLChp
|
||||
HungXQ29VTc8rc1bW0lkdi23OH5eqkMHGhvEwqa0HWASUMll4o3o/IX+0f2UcPoKCOVUR+jx71Sg
|
||||
5AU52EQfanIn3ZQ8lFW7Edp5a3q4DhjGlUKToHVbicL5E+g45zfB95wIyywWZfeW/UUF3LpGZyq/
|
||||
ebIUlq1qTbHkLbCC2r7RTn8vpQWp47BGVYGtGSBMpTRP5hnbzzuqj3itkiLHjU39S2sJCJ0TrJx5
|
||||
i8BygR4s3mHKBj8l+ePQxG1kGbF6R4yg6sECmXn17MRQVXODNHZbAgMBAAECggEAY1tsiUsIwDl5
|
||||
91CXirkYGuVfLyLflXenxfI50mDFms/mumTqloHO7tr0oriHDR5K7wMcY/YY5YkcXNo7mvUVD1pM
|
||||
ZNUJs7rw9gZRTrf7LylaJ58kOcyajw8TsC4e4LPbFaHwS1d6K8rXh64o6WgW4SrsB6ICmr1kGQI7
|
||||
3wcfgt5ecIu4TZf0OE9IHjn+2eRlsrjBdeORi7KiUNC/pAG23I6MdDOFEQRcCSigCj+4/mciFUSA
|
||||
SWS4dMbrpb9FNSIcf9dcLxVM7/6KxgJNfZc9XWzUw77Jg8x92Zd0fVhHOux5IZC+UvSKWB4dyfcI
|
||||
tE8C3p9bbU9VGyY5vLCAiIb4qQKBgQDLiO24GXrIkswF32YtBBMuVgLGCwU9h9HlO9mKAc2m8Cm1
|
||||
jUE5IpzRjTedc9I2qiIMUTwtgnw42auSCzbUeYMURPtDqyQ7p6AjMujp9EPemcSVOK9vXYL0Ptco
|
||||
xW9MC0dtV6iPkCN7gOqiZXPRKaFbWADp16p8UAIvS/a5XXk5jwKBgQCKkpHi2EISh1uRkhxljyWC
|
||||
iDCiK6JBRsMvpLbc0v5dKwP5alo1fmdR5PJaV2qvZSj5CYNpMAy1/EDNTY5OSIJU+0KFmQbyhsbm
|
||||
rdLNLDL4+TcnT7c62/aH01ohYaf/VCbRhtLlBfqGoQc7+sAc8vmKkesnF7CqCEKDyF/dhrxYdQKB
|
||||
gC0iZzzNAapayz1+JcVTwwEid6j9JqNXbBc+Z2YwMi+T0Fv/P/hwkX/ypeOXnIUcw0Ih/YtGBVAC
|
||||
DQbsz7LcY1HqXiHKYNWNvXgwwO+oiChjxvEkSdsTTIfnK4VSCvU9BxDbQHjdiNDJbL6oar92UN7V
|
||||
rBYvChJZF7LvUH4YmVpHAoGAbZ2X7XvoeEO+uZ58/BGKOIGHByHBDiXtzMhdJr15HTYjxK7OgTZm
|
||||
gK+8zp4L9IbvLGDMJO8vft32XPEWuvI8twCzFH+CsWLQADZMZKSsBasOZ/h1FwhdMgCMcY+Qlzd4
|
||||
JZKjTSu3i7vhvx6RzdSedXEMNTZWN4qlIx3kR5aHcukCgYA9T+Zrvm1F0seQPbLknn7EqhXIjBaT
|
||||
P8TTvW/6bdPi23ExzxZn7KOdrfclYRph1LHMpAONv/x2xALIf91UB+v5ohy1oDoasL0gij1houRe
|
||||
2ERKKdwz0ZL9SWq6VTdhr/5G994CK72fy5WhyERbDjUIdHaK3M849JJuf8cSrvSb4g==
|
||||
MIIEowIBAAKCAQEA0CbFlhSdbMdad2ux2BVqk6Ut5fLKb0CdbqubGcEBfwsSz9Rp4Ile76P90MpV
|
||||
W1BGKL5V4MO+flG6dZnRWPVmgrNVyDTmEsALiMGjfEwbACEZ1A8C6mPa36wWO7MlxuyMjg8OczTB
|
||||
EXnHNDpxE5a6KowJtzFlmgjHk2Y+Q42UIqPx47lQUv5bdMDCnfNNomSzTVRjOZLUkDja+ybCKdux
|
||||
gqTsuInhuBRMx+wxff8Z43ECdJV6UPoXK3der1dlZunxGCFkCeYq0kCX7FZ7PV35X744jqhD8P+7
|
||||
y5prO4W+M3DWgChUx0OlbDbSHtDVlcfdbj/+4AKYKU6rQOqh+4DPDQIDAQABAoIBAHjQuEiXKJSV
|
||||
1U2RZcVtENInws9AL/2I/Jfa5Qh6vTqXG9EjklywfzkK72x7tDVvD3ngmAoAs5WwLFDL+fXvYhOk
|
||||
sbql8ZCahVdYRWME7XsSu2IZYHDZipXe1XzLS7b9X8uos5Ns4E8bZuNKtI1RJDdD1vPMqRNR2z0T
|
||||
0Dn3eC7t+t+t7PWaK5AXu2ot7DoOeG1QhqJbwd5pMkIn2ydBILytgmDk/2P3EtJGePIJIeQBicmw
|
||||
Z0KrJFa/K2cC8AtmMJUoZMo+mh1yemDbDLCZW30PjFHbZtcszS2cydAgq/HDFkZynvZG0zhbx/To
|
||||
jzcNza1AyypYwOwb2/9/ulXZp0UCgYEA+QFgWDfYLH2zwjU5b6e0UbIyd/X/yRZ+L8lOEBd0Bbu8
|
||||
qO3txaDbwi7o2mG7pJENHJ3u62CHjgTGDNW9V9Q8eNoGtj3uHvMvi7FdDEK8B6izdZyR7hmZmQ/5
|
||||
MIldelyiGZlz1KBSoy4FsCpA7hV7cI6H6x+Im24NxG90/wd/EgMCgYEA1f+cUyUisIO3yKOCf0hQ
|
||||
aL289q2//F2cbvBxtki6I8JzTg1H3oTO2WVrXQeCA3a/yiuRUatgGH4mxrpCF6byVJyqrEWAj4kU
|
||||
uTbhMgIYhLGoaF1e+vMirCRXUXox0i5X976ASzHn64V9JSd1B+UbKfpcFTYYnChmrRDzmhKN1a8C
|
||||
gYBTvIHAyO7ab18/BRUOllAOVSWhr8lXv0eqHEEzKh/rOaoFCRY3qpOcZpgJsGogumK1Z+sLnoeX
|
||||
W8WaVVp6KbY4UeGF8aedItyvVnLbB6ohzTqkZ4Wvk05S6cs75kXYO0SL5U3NiCiiFXz2NA9nwTOk
|
||||
s1nD2PPgiQ76Kx0mEkhKLwKBgFhHEJqv+AZu37Kx2NRe5WS/2KK9/DPD/hM5tv7mM3sq7Nvm2J3v
|
||||
lVDS6J5AyZ5aLzXcER9qncKcz6wtC7SsFs1Wr4VPSoBroRPikrVJbgnXK8yZr+O/xq7Scv7WdJTq
|
||||
rzkw6cWbObvLnltkUn/GQBVqBPBvF2nbtLdyBbuqKb5bAoGBAI1+aoJnvXEXxT4UHrMkQcY0eXRz
|
||||
3UdbzJmtjMW9CR6l9s11mV6PcZP4qnODp3nd6a+lPeL3wVYQ47DsTJ/Bx5dI17zA5mU57n6mV0a3
|
||||
DbSoPKSdaKTQdo2THnVE9P9sPKZWueAcsE4Yw/qcTjoxrtUnAH/AXN250v0tkKIOvMhu
|
||||
-----END RSA PRIVATE KEY-----</keyMaterial>
|
||||
</CreateKeyPairResponse>
|
|
@ -141,6 +141,37 @@ public class CryptoStreams {
|
|||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes and returns the SHA1 value for a supplied input stream. A digest
|
||||
* object is created and disposed of at runtime, consider using
|
||||
* {@link #digest} to be more efficient.
|
||||
*
|
||||
* @param supplier
|
||||
* the input stream factory
|
||||
*
|
||||
* @return the result of {@link MessageDigest#digest()} after updating the
|
||||
* sha1 object with all of the bytes in the stream
|
||||
* @throws IOException
|
||||
* if an I/O error occurs
|
||||
*/
|
||||
public static byte[] sha1(InputSupplier<? extends InputStream> supplier) throws IOException {
|
||||
try {
|
||||
return digest(supplier, MessageDigest.getInstance("SHA1"));
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
Throwables.propagate(e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static byte[] sha1(byte[] in) {
|
||||
try {
|
||||
return sha1(ByteStreams.newInputStreamSupplier(in));
|
||||
} catch (IOException e) {
|
||||
Throwables.propagate(e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes and returns the MD5 value for a supplied input stream. A digest
|
||||
* object is created and disposed of at runtime, consider using
|
||||
|
|
|
@ -316,7 +316,7 @@ public class Pems {
|
|||
}
|
||||
|
||||
// TODO find a way to do this without using bouncycastle
|
||||
static byte[] getEncoded(RSAPrivateCrtKey key) {
|
||||
public static byte[] getEncoded(RSAPrivateCrtKey key) {
|
||||
RSAPrivateKeyStructure keyStruct = new RSAPrivateKeyStructure(key.getModulus(), key.getPublicExponent(),
|
||||
key.getPrivateExponent(), key.getPrimeP(), key.getPrimeQ(), key.getPrimeExponentP(),
|
||||
key.getPrimeExponentQ(), key.getCrtCoefficient());
|
||||
|
|
|
@ -31,12 +31,14 @@ import java.io.IOException;
|
|||
import java.io.InputStream;
|
||||
import java.io.StringWriter;
|
||||
import java.math.BigInteger;
|
||||
import java.security.KeyFactory;
|
||||
import java.security.KeyPair;
|
||||
import java.security.KeyPairGenerator;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.SecureRandom;
|
||||
import java.security.interfaces.RSAPrivateKey;
|
||||
import java.security.interfaces.RSAPublicKey;
|
||||
import java.security.spec.InvalidKeySpecException;
|
||||
import java.security.spec.KeySpec;
|
||||
import java.security.spec.RSAPrivateCrtKeySpec;
|
||||
import java.security.spec.RSAPublicKeySpec;
|
||||
|
@ -52,8 +54,8 @@ import com.google.common.base.Joiner;
|
|||
import com.google.common.base.Splitter;
|
||||
import com.google.common.base.Throwables;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.ImmutableMap.Builder;
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.google.common.collect.ImmutableMap.Builder;
|
||||
import com.google.common.io.InputSupplier;
|
||||
|
||||
/**
|
||||
|
@ -68,27 +70,29 @@ import com.google.common.io.InputSupplier;
|
|||
public class SshKeys {
|
||||
|
||||
/**
|
||||
* Executes {@link Pems#publicKeySpecFromOpenSSH(InputSupplier)} on the
|
||||
* string which was OpenSSH Base64 Encoded {@code id_rsa.pub}
|
||||
* Executes {@link Pems#publicKeySpecFromOpenSSH(InputSupplier)} on the string which was OpenSSH
|
||||
* Base64 Encoded {@code id_rsa.pub}
|
||||
*
|
||||
* @param idRsaPub
|
||||
* formatted {@code ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAB...}
|
||||
* @see Pems#publicKeySpecFromOpenSSH(InputSupplier)
|
||||
*/
|
||||
public static RSAPublicKeySpec publicKeySpecFromOpenSSH(String idRsaPub) throws IOException {
|
||||
public static RSAPublicKeySpec publicKeySpecFromOpenSSH(String idRsaPub) {
|
||||
try {
|
||||
return publicKeySpecFromOpenSSH(InputSuppliers.of(idRsaPub));
|
||||
} catch (IOException e) {
|
||||
propagate(e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@link RSAPublicKeySpec} which was OpenSSH Base64 Encoded
|
||||
* {@code id_rsa.pub}
|
||||
* Returns {@link RSAPublicKeySpec} which was OpenSSH Base64 Encoded {@code id_rsa.pub}
|
||||
*
|
||||
* @param supplier
|
||||
* the input stream factory, formatted
|
||||
* {@code ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAB...}
|
||||
* the input stream factory, formatted {@code ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAB...}
|
||||
*
|
||||
* @return the {@link RSAPublicKeySpec} which was OpenSSH Base64 Encoded
|
||||
* {@code id_rsa.pub}
|
||||
* @return the {@link RSAPublicKeySpec} which was OpenSSH Base64 Encoded {@code id_rsa.pub}
|
||||
* @throws IOException
|
||||
* if an I/O error occurs
|
||||
*/
|
||||
|
@ -132,8 +136,7 @@ public class SshKeys {
|
|||
}
|
||||
|
||||
/**
|
||||
* return a "public" -> rsa public key, "private" -> its corresponding
|
||||
* private key
|
||||
* return a "public" -> rsa public key, "private" -> its corresponding private key
|
||||
*/
|
||||
public static Map<String, String> generate() {
|
||||
try {
|
||||
|
@ -177,23 +180,18 @@ public class SshKeys {
|
|||
* RSA private key in PEM format
|
||||
* @param publicKeyOpenSSH
|
||||
* RSA public key in OpenSSH format
|
||||
* @return true if the keypair are matches
|
||||
* @return true if the keypairs match
|
||||
*/
|
||||
public static boolean privateKeyMatchesPublicKey(String privateKeyPEM, String publicKeyOpenSSH) {
|
||||
try {
|
||||
KeySpec privateKeySpec = privateKeySpec(privateKeyPEM);
|
||||
checkArgument(privateKeySpec instanceof RSAPrivateCrtKeySpec,
|
||||
"incorrect format expected RSAPrivateCrtKeySpec was %s", privateKeySpec);
|
||||
return privateKeyMatchesPublicKey(RSAPrivateCrtKeySpec.class.cast(privateKeySpec),
|
||||
publicKeySpecFromOpenSSH(publicKeyOpenSSH));
|
||||
} catch (IOException e) {
|
||||
propagate(e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if the keypair are matches
|
||||
* @return true if the keypairs match
|
||||
*/
|
||||
public static boolean privateKeyMatchesPublicKey(RSAPrivateCrtKeySpec privateKey, RSAPublicKeySpec publicKey) {
|
||||
return privateKey.getPublicExponent().equals(publicKey.getPublicExponent())
|
||||
|
@ -201,15 +199,123 @@ public class SshKeys {
|
|||
}
|
||||
|
||||
/**
|
||||
* Create a fingerprint per the following <a
|
||||
* href="http://tools.ietf.org/html/draft-friedl-secsh-fingerprint-00"
|
||||
* >spec</a>
|
||||
* @return true if the keypair has the same fingerprint as supplied
|
||||
*/
|
||||
public static boolean privateKeyHasFingerprint(RSAPrivateCrtKeySpec privateKey, String fingerprint) {
|
||||
return fingerprint(privateKey.getPublicExponent(), privateKey.getModulus()).equals(fingerprint);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param privateKeyPEM
|
||||
* RSA private key in PEM format
|
||||
* @param fingerprint
|
||||
* ex. {@code 2b:a9:62:95:5b:8b:1d:61:e0:92:f7:03:10:e9:db:d9}
|
||||
* @return true if the keypair has the same fingerprint as supplied
|
||||
*/
|
||||
public static boolean privateKeyHasFingerprint(String privateKeyPEM, String fingerprint) {
|
||||
KeySpec privateKeySpec = privateKeySpec(privateKeyPEM);
|
||||
checkArgument(privateKeySpec instanceof RSAPrivateCrtKeySpec,
|
||||
"incorrect format expected RSAPrivateCrtKeySpec was %s", privateKeySpec);
|
||||
return privateKeyHasFingerprint(RSAPrivateCrtKeySpec.class.cast(privateKeySpec), fingerprint);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param privateKeyPEM
|
||||
* RSA private key in PEM format
|
||||
* @return fingerprint ex. {@code 2b:a9:62:95:5b:8b:1d:61:e0:92:f7:03:10:e9:db:d9}
|
||||
*/
|
||||
public static String fingerprintPrivateKey(String privateKeyPEM) {
|
||||
KeySpec privateKeySpec = privateKeySpec(privateKeyPEM);
|
||||
checkArgument(privateKeySpec instanceof RSAPrivateCrtKeySpec,
|
||||
"incorrect format expected RSAPrivateCrtKeySpec was %s", privateKeySpec);
|
||||
RSAPrivateCrtKeySpec certKeySpec = RSAPrivateCrtKeySpec.class.cast(privateKeySpec);
|
||||
return fingerprint(certKeySpec.getPublicExponent(), certKeySpec.getModulus());
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if the keypair has the same SHA1 fingerprint as supplied
|
||||
*/
|
||||
public static boolean privateKeyHasSha1(RSAPrivateCrtKeySpec privateKey, String fingerprint) {
|
||||
return sha1(privateKey).equals(fingerprint);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param privateKeyPEM
|
||||
* RSA private key in PEM format
|
||||
* @param sha1HexColonDelimited
|
||||
* ex. {@code 2b:a9:62:95:5b:8b:1d:61:e0:92:f7:03:10:e9:db:d9}
|
||||
* @return true if the keypair has the same fingerprint as supplied
|
||||
*/
|
||||
public static boolean privateKeyHasSha1(String privateKeyPEM, String sha1HexColonDelimited) {
|
||||
KeySpec privateKeySpec = privateKeySpec(privateKeyPEM);
|
||||
checkArgument(privateKeySpec instanceof RSAPrivateCrtKeySpec,
|
||||
"incorrect format expected RSAPrivateCrtKeySpec was %s", privateKeySpec);
|
||||
return privateKeyHasSha1(RSAPrivateCrtKeySpec.class.cast(privateKeySpec), sha1HexColonDelimited);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param privateKeyPEM
|
||||
* RSA private key in PEM format
|
||||
* @return sha1HexColonDelimited ex. {@code 2b:a9:62:95:5b:8b:1d:61:e0:92:f7:03:10:e9:db:d9}
|
||||
*/
|
||||
public static String sha1PrivateKey(String privateKeyPEM) {
|
||||
KeySpec privateKeySpec = privateKeySpec(privateKeyPEM);
|
||||
checkArgument(privateKeySpec instanceof RSAPrivateCrtKeySpec,
|
||||
"incorrect format expected RSAPrivateCrtKeySpec was %s", privateKeySpec);
|
||||
RSAPrivateCrtKeySpec certKeySpec = RSAPrivateCrtKeySpec.class.cast(privateKeySpec);
|
||||
return sha1(certKeySpec);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a SHA-1 digest of the DER encoded private key.
|
||||
*
|
||||
* @param publicExponent
|
||||
* @param modulus
|
||||
*
|
||||
* @return hex fingerprint ex.
|
||||
* {@code 2b:a9:62:95:5b:8b:1d:61:e0:92:f7:03:10:e9:db:d9}
|
||||
* @return hex sha1HexColonDelimited ex. {@code 2b:a9:62:95:5b:8b:1d:61:e0:92:f7:03:10:e9:db:d9}
|
||||
*/
|
||||
public static String sha1(RSAPrivateCrtKeySpec privateKey) {
|
||||
try {
|
||||
String sha1 = Joiner.on(":").join(
|
||||
Splitter.fixedLength(2).split(
|
||||
hex(CryptoStreams.sha1(KeyFactory.getInstance("RSA").generatePrivate(privateKey)
|
||||
.getEncoded()))));
|
||||
return sha1;
|
||||
} catch (InvalidKeySpecException e) {
|
||||
propagate(e);
|
||||
return null;
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
propagate(e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if the keypair has the same fingerprint as supplied
|
||||
*/
|
||||
public static boolean publicKeyHasFingerprint(RSAPublicKeySpec publicKey, String fingerprint) {
|
||||
return fingerprint(publicKey.getPublicExponent(), publicKey.getModulus()).equals(fingerprint);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param publicKeyOpenSSH
|
||||
* RSA public key in OpenSSH format
|
||||
* @param fingerprint
|
||||
* ex. {@code 2b:a9:62:95:5b:8b:1d:61:e0:92:f7:03:10:e9:db:d9}
|
||||
* @return true if the keypair has the same fingerprint as supplied
|
||||
*/
|
||||
public static boolean publicKeyHasFingerprint(String publicKeyOpenSSH, String fingerprint) {
|
||||
return publicKeyHasFingerprint(publicKeySpecFromOpenSSH(publicKeyOpenSSH), fingerprint);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a fingerprint per the following <a
|
||||
* href="http://tools.ietf.org/html/draft-friedl-secsh-fingerprint-00" >spec</a>
|
||||
*
|
||||
* @param publicExponent
|
||||
* @param modulus
|
||||
*
|
||||
* @return hex fingerprint ex. {@code 2b:a9:62:95:5b:8b:1d:61:e0:92:f7:03:10:e9:db:d9}
|
||||
*/
|
||||
public static String fingerprint(BigInteger publicExponent, BigInteger modulus) {
|
||||
byte[] keyBlob = keyBlob(publicExponent, modulus);
|
||||
|
|
|
@ -20,7 +20,9 @@ package org.jclouds.crypto;
|
|||
|
||||
import static org.jclouds.crypto.SshKeys.fingerprint;
|
||||
import static org.jclouds.crypto.SshKeys.generate;
|
||||
import static org.jclouds.crypto.SshKeys.privateKeyHasFingerprint;
|
||||
import static org.jclouds.crypto.SshKeys.privateKeyMatchesPublicKey;
|
||||
import static org.jclouds.crypto.SshKeys.privateKeyHasSha1;
|
||||
import static org.jclouds.crypto.SshKeys.publicKeySpecFromOpenSSH;
|
||||
import static org.testng.Assert.assertEquals;
|
||||
|
||||
|
@ -45,6 +47,7 @@ import org.testng.annotations.Test;
|
|||
public class SshKeysTest {
|
||||
|
||||
String expectedFingerprint = "2b:a9:62:95:5b:8b:1d:61:e0:92:f7:03:10:e9:db:d9";
|
||||
String expectedSha1 = "c8:01:34:c0:3c:8c:91:ac:e1:da:cf:72:15:d7:f2:e5:99:5b:28:d4";
|
||||
|
||||
@Test
|
||||
public void testCanReadRsaAndCompareFingerprintOnPublicRSAKey() throws IOException {
|
||||
|
@ -62,6 +65,32 @@ public class SshKeysTest {
|
|||
assertEquals(fingerPrint, expectedFingerprint);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPrivateKeyMatchesFingerprintTyped() throws IOException {
|
||||
String privKey = Strings2.toStringAndClose(getClass().getResourceAsStream("/test"));
|
||||
RSAPrivateCrtKeySpec privateKey = (RSAPrivateCrtKeySpec) Pems.privateKeySpec(privKey);
|
||||
assert privateKeyHasFingerprint(privateKey, expectedFingerprint);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPrivateKeyMatchesFingerprintString() throws IOException {
|
||||
String privKey = Strings2.toStringAndClose(getClass().getResourceAsStream("/test"));
|
||||
assert privateKeyHasFingerprint(privKey, expectedFingerprint);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPrivateKeyMatchesSha1Typed() throws IOException {
|
||||
String privKey = Strings2.toStringAndClose(getClass().getResourceAsStream("/test"));
|
||||
RSAPrivateCrtKeySpec privateKey = (RSAPrivateCrtKeySpec) Pems.privateKeySpec(privKey);
|
||||
assert privateKeyHasSha1(privateKey, expectedSha1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPrivateKeyMatchesSha1String() throws IOException {
|
||||
String privKey = Strings2.toStringAndClose(getClass().getResourceAsStream("/test"));
|
||||
assert privateKeyHasSha1(privKey, expectedSha1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPrivateKeyMatchesPublicKeyTyped() throws IOException {
|
||||
String privKey = Strings2.toStringAndClose(getClass().getResourceAsStream("/test"));
|
||||
|
|
|
@ -25,11 +25,11 @@ import static com.google.common.base.Predicates.instanceOf;
|
|||
import static com.google.common.base.Predicates.or;
|
||||
import static com.google.common.base.Throwables.getCausalChain;
|
||||
import static com.google.common.collect.Iterables.any;
|
||||
import static org.jclouds.crypto.SshKeys.fingerprint;
|
||||
import static org.jclouds.crypto.SshKeys.fingerprintPrivateKey;
|
||||
import static org.jclouds.crypto.SshKeys.sha1PrivateKey;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.security.spec.RSAPrivateCrtKeySpec;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
|
@ -50,7 +50,6 @@ import net.schmizz.sshj.xfer.InMemorySourceFile;
|
|||
|
||||
import org.apache.commons.io.input.ProxyInputStream;
|
||||
import org.jclouds.compute.domain.ExecResponse;
|
||||
import org.jclouds.crypto.Pems;
|
||||
import org.jclouds.http.handlers.BackoffLimitedRetryHandler;
|
||||
import org.jclouds.io.Payload;
|
||||
import org.jclouds.io.Payloads;
|
||||
|
@ -140,11 +139,12 @@ public class SshjSshClient implements SshClient {
|
|||
this.password = password;
|
||||
this.privateKey = privateKey;
|
||||
if (privateKey == null) {
|
||||
this.toString = String.format("%s@%s:%d", username, host, port);
|
||||
this.toString = String.format("%s:password@%s:%d", username, host, port);
|
||||
} else {
|
||||
RSAPrivateCrtKeySpec key = (RSAPrivateCrtKeySpec) Pems.privateKeySpec(new String(privateKey));
|
||||
String fingerPrint = fingerprint(key.getPublicExponent(), key.getModulus());
|
||||
this.toString = String.format("%s:[%s]@%s:%d", username, fingerPrint, host, port);
|
||||
String fingerPrint = fingerprintPrivateKey(new String(privateKey));
|
||||
String sha1 = sha1PrivateKey(new String(privateKey));
|
||||
this.toString = String.format("%s:rsa[fingerprint(%s),sha1(%s)]@%s:%d", username, fingerPrint, sha1, host,
|
||||
port);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -198,7 +198,7 @@ public class SshjSshClient implements SshClient {
|
|||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format("SSHClient(%s)", SshjSshClient.this.toString());
|
||||
return String.format("SSHClient(timeout=%d)", timeoutMillis);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -266,7 +266,7 @@ public class SshjSshClient implements SshClient {
|
|||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "SFTPClient(" + SshjSshClient.this.toString() + ")";
|
||||
return "SFTPClient()";
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -293,7 +293,7 @@ public class SshjSshClient implements SshClient {
|
|||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Payload(" + SshjSshClient.this.toString() + ")[" + path + "]";
|
||||
return "Payload(path=[" + path + "])";
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -351,7 +351,7 @@ public class SshjSshClient implements SshClient {
|
|||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Put(" + SshjSshClient.this.toString() + ")[" + path + "]";
|
||||
return "Put(path=[" + path + "])";
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -362,8 +362,8 @@ public class SshjSshClient implements SshClient {
|
|||
|
||||
@VisibleForTesting
|
||||
boolean shouldRetry(Exception from) {
|
||||
Predicate<Throwable> predicate = retryAuth ? Predicates.<Throwable>or(retryPredicate, instanceOf(AuthorizationException.class))
|
||||
: retryPredicate;
|
||||
Predicate<Throwable> predicate = retryAuth ? Predicates.<Throwable> or(retryPredicate,
|
||||
instanceOf(AuthorizationException.class)) : retryPredicate;
|
||||
if (any(getCausalChain(from), predicate))
|
||||
return true;
|
||||
if (!retryableMessages.equals(""))
|
||||
|
@ -402,7 +402,7 @@ public class SshjSshClient implements SshClient {
|
|||
|
||||
@Override
|
||||
public String toString() {
|
||||
return toString ;
|
||||
return toString;
|
||||
}
|
||||
|
||||
@PreDestroy
|
||||
|
@ -436,7 +436,7 @@ public class SshjSshClient implements SshClient {
|
|||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Session(" + SshjSshClient.this.toString() + ")";
|
||||
return "Session()";
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -473,7 +473,7 @@ public class SshjSshClient implements SshClient {
|
|||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ExecResponse(" + SshjSshClient.this.toString() + ")[" + command + "]";
|
||||
return "ExecResponse(command=[" + command + "])";
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -23,6 +23,8 @@ import static org.easymock.classextension.EasyMock.createMock;
|
|||
import static org.easymock.classextension.EasyMock.replay;
|
||||
import static org.easymock.classextension.EasyMock.verify;
|
||||
import static org.jclouds.aws.ec2.compute.AWSEC2TemplateOptions.Builder.keyPair;
|
||||
import static org.jclouds.ec2.compute.strategy.CreateKeyPairAndSecurityGroupsAsNeededAndReturnRunOptionsTest.CREDENTIALS;
|
||||
import static org.jclouds.ec2.compute.strategy.CreateKeyPairAndSecurityGroupsAsNeededAndReturnRunOptionsTest.KEYPAIR;
|
||||
import static org.testng.Assert.assertEquals;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
@ -471,10 +473,8 @@ public class CreateKeyPairPlacementAndSecurityGroupsAsNeededAndReturnRunOptionsT
|
|||
expect(backing.containsKey(new RegionAndName(region, group))).andReturn(false);
|
||||
expect(options.getKeyPair()).andReturn(userSuppliedKeyPair);
|
||||
expect(options.getPublicKey()).andReturn(null).times(2);
|
||||
expect(options.getOverridingCredentials()).andReturn(new Credentials(null, "MyRsa")).atLeastOnce();
|
||||
expect(
|
||||
backing.put(new RegionAndName(region, userSuppliedKeyPair), KeyPair.builder().region(region).keyName(
|
||||
userSuppliedKeyPair).keyFingerprint("//TODO").keyMaterial("MyRsa").build())).andReturn(null);
|
||||
expect(options.getOverridingCredentials()).andReturn(CREDENTIALS).atLeastOnce();
|
||||
expect(backing.put(new RegionAndName(region, userSuppliedKeyPair), KEYPAIR)).andReturn(null);
|
||||
expect(options.getRunScript()).andReturn(Statements.exec("echo foo"));
|
||||
expect(strategy.credentialsMap.getUnchecked(new RegionAndName(region, userSuppliedKeyPair))).andReturn(keyPair);
|
||||
|
||||
|
@ -504,17 +504,19 @@ public class CreateKeyPairPlacementAndSecurityGroupsAsNeededAndReturnRunOptionsT
|
|||
// create mocks
|
||||
CreateKeyPairPlacementAndSecurityGroupsAsNeededAndReturnRunOptions strategy = setupStrategy();
|
||||
AWSEC2TemplateOptions options = keyPair(group).authorizePublicKey("ssh-rsa").overrideCredentialsWith(
|
||||
new Credentials("foo", "private"));
|
||||
KeyPair keyPair = new KeyPair(region, group, "//TODO", null);
|
||||
new Credentials("foo", CREDENTIALS.credential));
|
||||
KeyPair keyPair = new KeyPair(region, group, "//TODO", null, null);
|
||||
ConcurrentMap<RegionAndName, KeyPair> backing = createMock(ConcurrentMap.class);
|
||||
|
||||
// setup expectations
|
||||
expect(strategy.credentialsMap.asMap()).andReturn(backing).atLeastOnce();
|
||||
expect(backing.containsKey(new RegionAndName(region, group))).andReturn(false);
|
||||
expect(strategy.importExistingKeyPair.apply(new RegionNameAndPublicKeyMaterial(region, group, "private")))
|
||||
.andReturn(keyPair);
|
||||
expect(backing.put(new RegionAndName(region, group), keyPair.toBuilder().keyMaterial("private").build()))
|
||||
.andReturn(null);
|
||||
expect(
|
||||
strategy.importExistingKeyPair.apply(new RegionNameAndPublicKeyMaterial(region, group,
|
||||
CREDENTIALS.credential))).andReturn(keyPair);
|
||||
expect(
|
||||
backing.put(new RegionAndName(region, group), keyPair.toBuilder().keyMaterial(CREDENTIALS.credential)
|
||||
.build())).andReturn(null);
|
||||
|
||||
// replay mocks
|
||||
replay(backing);
|
||||
|
@ -539,7 +541,7 @@ public class CreateKeyPairPlacementAndSecurityGroupsAsNeededAndReturnRunOptionsT
|
|||
// create mocks
|
||||
CreateKeyPairPlacementAndSecurityGroupsAsNeededAndReturnRunOptions strategy = setupStrategy();
|
||||
|
||||
KeyPair keyPair = new KeyPair(region, "jclouds#" + group, "fingerprint", null);
|
||||
KeyPair keyPair = new KeyPair(region, "jclouds#" + group, "fingerprint", null, null);
|
||||
|
||||
ConcurrentMap<RegionAndName, KeyPair> backing = createMock(ConcurrentMap.class);
|
||||
|
||||
|
|
Loading…
Reference in New Issue