diff --git a/docs/pom.xml b/docs/pom.xml
index b41839ae..abc036ed 100644
--- a/docs/pom.xml
+++ b/docs/pom.xml
@@ -6,7 +6,7 @@
org.springframework.cloud
spring-cloud-config
- 1.4.0.BUILD-SNAPSHOT
+ 1.3.2.BUILD-SNAPSHOT
..
diff --git a/docs/src/main/asciidoc/spring-cloud-config.adoc b/docs/src/main/asciidoc/spring-cloud-config.adoc
index 55146702..f4ab6f8a 100644
--- a/docs/src/main/asciidoc/spring-cloud-config.adoc
+++ b/docs/src/main/asciidoc/spring-cloud-config.adoc
@@ -151,8 +151,8 @@ This repository implementation maps the `{label}` parameter of the
HTTP resource to a git label (commit id, branch name or tag). If the
git branch or tag name contains a slash ("/") then the label in the
HTTP URL should be specified with the special string "(\_)" instead (to
-avoid ambiguity with other URL paths). For example, if the label is
-`foo/bar`, replacing the slash would result in a label that looks like
+avoid ambiguity with other URL paths). For example, if the label is
+`foo/bar`, replacing the slash would result in a label that looks like
`foo(_)bar`. Be careful with the brackets in
the URL if you are using a command line client like curl (e.g. escape
them from the shell with quotes '').
@@ -351,7 +351,7 @@ https://git-codecommit.${AWS_REGION}.amazonaws.com/${repopath}.
If you provide a username and password with an AWS CodeCommit URI, then these must be
the http://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSGettingStartedGuide/AWSCredentials.html[AWS accessKeyId and secretAccessKey]
to be used to access the repository. If you do not specify a username and password,
-then the accessKeyId and secretAccessKey will be retrieved using the
+then the accessKeyId and secretAccessKey will be retrieved using the
http://docs.aws.amazon.com/sdk-for-java/v1/developer-guide/credentials.html[AWS Default Credential Provider Chain].
If your Git URI matches the CodeCommit URI pattern (above) then you must provide
@@ -364,7 +364,7 @@ classpath, then the AWS Code Commit credential provider will not be created rega
===== Git SSH configuration using properties
-By default, Spring Cloud Config Server uses SSH configuration files such as `~/.ssh/known_hosts` and `/etc/ssh/ssh_config` when connecting to Git repositories using an SSH URI.
+By default, the JGit library used by Spring Cloud Config Server uses SSH configuration files such as `~/.ssh/known_hosts` and `/etc/ssh/ssh_config` when connecting to Git repositories using an SSH URI.
In cloud environments such as Cloud Foundry, the local filesystem may be ephemeral or not easily accessible. For cases such as these, SSH configuration can be set using
Java properties. In order to activate property based SSH configuration, the property `spring.cloud.config.server.git.ignoreLocalSshSettings` must be set to `true`.
Example:
@@ -416,7 +416,7 @@ Example:
|Property Name |Remarks
|*ignoreLocalSshSettings*
-|If true, use property based SSH config instead of file based
+|If true, use property based SSH config instead of file based. Must be set at as `spring.cloud.config.server.git.ignoreLocalSshSettings`, *not* inside a repository definition.
|*privateKey*
|Valid SSH private key. Must be set if `ignoreLocalSshSettings` is true and Git URI is SSH format
diff --git a/spring-cloud-config-server/src/main/java/org/springframework/cloud/config/server/config/TransportConfiguration.java b/spring-cloud-config-server/src/main/java/org/springframework/cloud/config/server/config/TransportConfiguration.java
index f5199cd1..a8d3721c 100644
--- a/spring-cloud-config-server/src/main/java/org/springframework/cloud/config/server/config/TransportConfiguration.java
+++ b/spring-cloud-config-server/src/main/java/org/springframework/cloud/config/server/config/TransportConfiguration.java
@@ -64,10 +64,12 @@ public class TransportConfiguration {
@Override
public void configure(Transport transport) {
- SshTransport sshTransport = (SshTransport) transport;
- sshTransport.setSshSessionFactory(
- new PropertyBasedSshSessionFactory(
- new SshUriPropertyProcessor(sshUriProperties).getSshKeysByHostname(), new JSch()));
+ if (transport instanceof SshTransport) {
+ SshTransport sshTransport = (SshTransport) transport;
+ sshTransport.setSshSessionFactory(
+ new PropertyBasedSshSessionFactory(
+ new SshUriPropertyProcessor(sshUriProperties).getSshKeysByHostname(), new JSch()));
+ }
}
}
diff --git a/spring-cloud-config-server/src/main/java/org/springframework/cloud/config/server/environment/JGitEnvironmentRepository.java b/spring-cloud-config-server/src/main/java/org/springframework/cloud/config/server/environment/JGitEnvironmentRepository.java
index 8df63428..7ad63742 100644
--- a/spring-cloud-config-server/src/main/java/org/springframework/cloud/config/server/environment/JGitEnvironmentRepository.java
+++ b/spring-cloud-config-server/src/main/java/org/springframework/cloud/config/server/environment/JGitEnvironmentRepository.java
@@ -21,6 +21,7 @@ import java.io.IOException;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
+
import org.eclipse.jgit.api.CheckoutCommand;
import org.eclipse.jgit.api.CloneCommand;
import org.eclipse.jgit.api.CreateBranchCommand.SetupUpstreamMode;
diff --git a/spring-cloud-config-server/src/main/java/org/springframework/cloud/config/server/ssh/HostKeyAlgoSupported.java b/spring-cloud-config-server/src/main/java/org/springframework/cloud/config/server/ssh/HostKeyAlgoSupported.java
new file mode 100644
index 00000000..68fae7d0
--- /dev/null
+++ b/spring-cloud-config-server/src/main/java/org/springframework/cloud/config/server/ssh/HostKeyAlgoSupported.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.cloud.config.server.ssh;
+
+import org.springframework.validation.annotation.Validated;
+
+import javax.validation.Constraint;
+import javax.validation.Payload;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Beans annotated with {@link HostKeyAlgoSupported} and {@link Validated} will have the constraints applied.
+ *
+ * @author Ollie Hughes
+ **/
+@Constraint(validatedBy = HostKeyAlgoSupportedValidator.class)
+@Target(ElementType.TYPE)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface HostKeyAlgoSupported {
+ String message() default "{HostKeyAlgoSupported.message}";
+ Class>[] groups() default {};
+ Class extends Payload>[] payload() default {};
+}
diff --git a/spring-cloud-config-server/src/main/java/org/springframework/cloud/config/server/ssh/HostKeyAlgoSupportedValidator.java b/spring-cloud-config-server/src/main/java/org/springframework/cloud/config/server/ssh/HostKeyAlgoSupportedValidator.java
new file mode 100644
index 00000000..335fe3a4
--- /dev/null
+++ b/spring-cloud-config-server/src/main/java/org/springframework/cloud/config/server/ssh/HostKeyAlgoSupportedValidator.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.cloud.config.server.ssh;
+
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Set;
+import javax.validation.ConstraintValidator;
+import javax.validation.ConstraintValidatorContext;
+
+import org.springframework.validation.annotation.Validated;
+
+import static java.lang.String.format;
+import static org.springframework.cloud.config.server.ssh.SshPropertyValidator.isSshUri;
+import static org.springframework.util.StringUtils.hasText;
+
+/**
+ * JSR-303 Cross Field validator that ensures that a {@link SshUriProperties} bean for the constraints:
+ * - If host key algo is supported
+ *
+ * Beans annotated with {@link HostKeyAlgoSupported} and {@link Validated} will have the constraints applied.
+ *
+ * @author Ollie Hughes
+ */
+public class HostKeyAlgoSupportedValidator implements ConstraintValidator {
+ private static final String GIT_PROPERTY_PREFIX = "spring.cloud.config.server.git.";
+ private final SshPropertyValidator sshPropertyValidator = new SshPropertyValidator();
+ private static final Set VALID_HOST_KEY_ALGORITHMS = new LinkedHashSet<>(Arrays.asList(
+ "ssh-dss","ssh-rsa","ecdsa-sha2-nistp256","ecdsa-sha2-nistp384","ecdsa-sha2-nistp521"));
+
+ @Override
+ public void initialize(HostKeyAlgoSupported constrainAnnotation) {
+ //No special initialization of validator required
+ }
+
+ @Override
+ public boolean isValid(SshUriProperties sshUriProperties, ConstraintValidatorContext context) {
+ context.disableDefaultConstraintViolation();
+ Set validationResults = new HashSet<>();
+ List extractedProperties = sshPropertyValidator.extractRepoProperties(sshUriProperties);
+
+ for (SshUriProperties extractedProperty : extractedProperties) {
+ if (sshUriProperties.isIgnoreLocalSshSettings() && isSshUri(extractedProperty.getUri())) {
+ validationResults.add(isHostKeySpecifiedWhenAlgorithmSet(extractedProperty, context));
+ }
+ }
+ return !validationResults.contains(false);
+ }
+
+ private boolean isHostKeySpecifiedWhenAlgorithmSet(SshUriProperties sshUriProperties, ConstraintValidatorContext context) {
+ if (hasText(sshUriProperties.getHostKeyAlgorithm())
+ && !VALID_HOST_KEY_ALGORITHMS.contains(sshUriProperties.getHostKeyAlgorithm())) {
+
+ context.buildConstraintViolationWithTemplate(
+ format("Property '%shostKeyAlgorithm' must be one of %s", GIT_PROPERTY_PREFIX, VALID_HOST_KEY_ALGORITHMS))
+ .addConstraintViolation();
+ return false;
+ }
+ return true;
+ }
+
+}
diff --git a/spring-cloud-config-server/src/main/java/org/springframework/cloud/config/server/ssh/HostKeyAndAlgoBothExist.java b/spring-cloud-config-server/src/main/java/org/springframework/cloud/config/server/ssh/HostKeyAndAlgoBothExist.java
new file mode 100644
index 00000000..b0464526
--- /dev/null
+++ b/spring-cloud-config-server/src/main/java/org/springframework/cloud/config/server/ssh/HostKeyAndAlgoBothExist.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.cloud.config.server.ssh;
+
+import org.springframework.validation.annotation.Validated;
+
+import javax.validation.Constraint;
+import javax.validation.Payload;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Beans annotated with {@link HostKeyAndAlgoBothExist} and {@link Validated} will have the constraints applied.
+ * @author Ollie Hughes
+ */
+@Constraint(validatedBy = HostKeyAndAlgoBothExistValidator.class)
+@Target(ElementType.TYPE)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface HostKeyAndAlgoBothExist {
+ String message() default "{HostKeyAndAlgoBothExist.message}";
+ Class>[] groups() default {};
+ Class extends Payload>[] payload() default {};
+}
diff --git a/spring-cloud-config-server/src/main/java/org/springframework/cloud/config/server/ssh/HostKeyAndAlgoBothExistValidator.java b/spring-cloud-config-server/src/main/java/org/springframework/cloud/config/server/ssh/HostKeyAndAlgoBothExistValidator.java
new file mode 100644
index 00000000..1c4439ca
--- /dev/null
+++ b/spring-cloud-config-server/src/main/java/org/springframework/cloud/config/server/ssh/HostKeyAndAlgoBothExistValidator.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.cloud.config.server.ssh;
+
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import javax.validation.ConstraintValidator;
+import javax.validation.ConstraintValidatorContext;
+
+import org.springframework.validation.annotation.Validated;
+
+import static java.lang.String.format;
+import static org.springframework.cloud.config.server.ssh.SshPropertyValidator.isSshUri;
+import static org.springframework.util.StringUtils.hasText;
+
+/**
+ * JSR-303 Cross Field validator that ensures that a {@link SshUriProperties} bean for the constraints:
+ * - If host key is set then host key algo must also be set
+ * - If host key algo is set then host key must also be set
+ *
+ * Beans annotated with {@link HostKeyAndAlgoBothExist} and {@link Validated} will have the constraints applied.
+ *
+ * @author Ollie Hughes
+ */
+public class HostKeyAndAlgoBothExistValidator implements ConstraintValidator {
+ private static final String GIT_PROPERTY_PREFIX = "spring.cloud.config.server.git.";
+ private final SshPropertyValidator sshPropertyValidator = new SshPropertyValidator();
+
+ @Override
+ public void initialize(HostKeyAndAlgoBothExist constrainAnnotation) {
+ //No special initialization of validator required
+ }
+
+ @Override
+ public boolean isValid(SshUriProperties sshUriProperties, ConstraintValidatorContext context) {
+ Set validationResults = new HashSet<>();
+ List extractedProperties = sshPropertyValidator.extractRepoProperties(sshUriProperties);
+
+ for (SshUriProperties extractedProperty : extractedProperties) {
+ if (sshUriProperties.isIgnoreLocalSshSettings() && isSshUri(extractedProperty.getUri())) {
+ validationResults.add(
+ isAlgorithmSpecifiedWhenHostKeySet(extractedProperty, context)
+ && isHostKeySpecifiedWhenAlgorithmSet(extractedProperty, context));
+ }
+ }
+ return !validationResults.contains(false);
+ }
+
+ private boolean isHostKeySpecifiedWhenAlgorithmSet(SshUriProperties sshUriProperties, ConstraintValidatorContext context) {
+ if (hasText(sshUriProperties.getHostKeyAlgorithm()) && !hasText(sshUriProperties.getHostKey())) {
+ context.disableDefaultConstraintViolation();
+ context.buildConstraintViolationWithTemplate(
+ format("Property '%shostKey' must be set when '%shostKeyAlgorithm' is specified", GIT_PROPERTY_PREFIX, GIT_PROPERTY_PREFIX))
+ .addConstraintViolation();
+ return false;
+ }
+ return true;
+ }
+
+ private boolean isAlgorithmSpecifiedWhenHostKeySet(SshUriProperties sshUriProperties, ConstraintValidatorContext context) {
+ if (hasText(sshUriProperties.getHostKey()) && !hasText(sshUriProperties.getHostKeyAlgorithm())) {
+ context.disableDefaultConstraintViolation();
+ context.buildConstraintViolationWithTemplate(
+ format("Property '%shostKeyAlgorithm' must be set when '%shostKey' is specified", GIT_PROPERTY_PREFIX, GIT_PROPERTY_PREFIX))
+ .addConstraintViolation();
+ return false;
+ }
+ return true;
+ }
+}
diff --git a/spring-cloud-config-server/src/main/java/org/springframework/cloud/config/server/ssh/PrivateKeyIsValid.java b/spring-cloud-config-server/src/main/java/org/springframework/cloud/config/server/ssh/PrivateKeyIsValid.java
new file mode 100644
index 00000000..6a0a831b
--- /dev/null
+++ b/spring-cloud-config-server/src/main/java/org/springframework/cloud/config/server/ssh/PrivateKeyIsValid.java
@@ -0,0 +1,24 @@
+package org.springframework.cloud.config.server.ssh;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import javax.validation.Constraint;
+import javax.validation.Payload;
+
+import org.springframework.validation.annotation.Validated;
+
+/**
+* Beans annotated with {@link PrivateKeyValidator} and {@link Validated} will have the constraints applied.
+*
+* @author Ollie Hughes
+*/
+@Constraint(validatedBy = PrivateKeyValidator.class)
+@Target(ElementType.TYPE)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface PrivateKeyIsValid {
+ String message() default "{PrivateKeyIsValid.message}";
+ Class>[] groups() default {};
+ Class extends Payload>[] payload() default {};
+}
diff --git a/spring-cloud-config-server/src/main/java/org/springframework/cloud/config/server/ssh/PrivateKeyValidator.java b/spring-cloud-config-server/src/main/java/org/springframework/cloud/config/server/ssh/PrivateKeyValidator.java
new file mode 100644
index 00000000..900de013
--- /dev/null
+++ b/spring-cloud-config-server/src/main/java/org/springframework/cloud/config/server/ssh/PrivateKeyValidator.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.cloud.config.server.ssh;
+
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import javax.validation.ConstraintValidator;
+import javax.validation.ConstraintValidatorContext;
+
+import com.jcraft.jsch.JSch;
+import com.jcraft.jsch.JSchException;
+import com.jcraft.jsch.KeyPair;
+
+import org.springframework.validation.annotation.Validated;
+
+import static java.lang.String.format;
+import static org.springframework.cloud.config.server.ssh.SshPropertyValidator.isSshUri;
+import static org.springframework.util.StringUtils.hasText;
+
+/**
+ * JSR-303 Cross Field validator that ensures that a {@link SshUriProperties} bean for the constraints:
+ * - Private key is present and can be correctly parsed using {@link com.jcraft.jsch.KeyPair}
+ *
+ * Beans annotated with {@link PrivateKeyValidator} and {@link Validated} will have the constraints applied.
+ *
+ * @author Ollie Hughes
+ */
+public class PrivateKeyValidator implements ConstraintValidator {
+ private static final String GIT_PROPERTY_PREFIX = "spring.cloud.config.server.git.";
+ private final SshPropertyValidator sshPropertyValidator = new SshPropertyValidator();
+
+ @Override
+ public void initialize(PrivateKeyIsValid constrainAnnotation) {
+ //No special initialization of validator required
+ }
+
+ @Override
+ public boolean isValid(SshUriProperties sshUriProperties, ConstraintValidatorContext context) {
+ context.disableDefaultConstraintViolation();
+ Set validationResults = new HashSet<>();
+ List extractedProperties = sshPropertyValidator.extractRepoProperties(sshUriProperties);
+
+ for (SshUriProperties extractedProperty : extractedProperties) {
+ if (sshUriProperties.isIgnoreLocalSshSettings() && isSshUri(extractedProperty.getUri())) {
+ validationResults.add(
+ isPrivateKeyPresent(extractedProperty, context)
+ && isPrivateKeyFormatCorrect(extractedProperty, context));
+ }
+ }
+ return !validationResults.contains(false);
+
+ }
+
+ private boolean isPrivateKeyPresent(SshUriProperties sshUriProperties, ConstraintValidatorContext context) {
+ if (!hasText(sshUriProperties.getPrivateKey())) {
+ context.buildConstraintViolationWithTemplate(
+ format("Property '%shostKey' must be set when '%shostKeyAlgorithm' is specified", GIT_PROPERTY_PREFIX, GIT_PROPERTY_PREFIX))
+ .addConstraintViolation();
+ return false;
+ }
+ return true;
+ }
+
+ private boolean isPrivateKeyFormatCorrect(SshUriProperties sshUriProperties, ConstraintValidatorContext context) {
+ try {
+ KeyPair.load(new JSch(), sshUriProperties.getPrivateKey().getBytes(), null);
+ return true;
+ } catch (JSchException e) {
+ context.buildConstraintViolationWithTemplate(
+ format("Property '%sprivateKey' contains is not a valid private key", GIT_PROPERTY_PREFIX))
+ .addConstraintViolation();
+ return false;
+ }
+ }
+}
diff --git a/spring-cloud-config-server/src/main/java/org/springframework/cloud/config/server/ssh/PropertyBasedSshSessionFactory.java b/spring-cloud-config-server/src/main/java/org/springframework/cloud/config/server/ssh/PropertyBasedSshSessionFactory.java
index 93493a43..20a4d701 100644
--- a/spring-cloud-config-server/src/main/java/org/springframework/cloud/config/server/ssh/PropertyBasedSshSessionFactory.java
+++ b/spring-cloud-config-server/src/main/java/org/springframework/cloud/config/server/ssh/PropertyBasedSshSessionFactory.java
@@ -15,6 +15,8 @@
*/
package org.springframework.cloud.config.server.ssh;
+import java.util.Map;
+
import com.jcraft.jsch.HostKey;
import com.jcraft.jsch.JSch;
import com.jcraft.jsch.JSchException;
@@ -24,9 +26,6 @@ import org.eclipse.jgit.transport.OpenSshConfig.Host;
import org.eclipse.jgit.util.Base64;
import org.eclipse.jgit.util.FS;
-import java.util.Map;
-
-
/**
* In a cloud environment local SSH config files such as `.known_hosts` may not be suitable for providing
* configuration settings due to ephemeral filesystems. This flag enables SSH config to be provided as application
@@ -36,6 +35,10 @@ import java.util.Map;
*/
public class PropertyBasedSshSessionFactory extends JschConfigSessionFactory {
+ private static final String STRICT_HOST_KEY_CHECKING = "StrictHostKeyChecking";
+ private static final String YES_OPTION = "yes";
+ private static final String NO_OPTION = "no";
+ private static final String SERVER_HOST_KEY = "server_host_key";
private final Map sshKeysByHostname;
private final JSch jSch;
@@ -49,12 +52,12 @@ public class PropertyBasedSshSessionFactory extends JschConfigSessionFactory {
SshUriProperties sshProperties = sshKeysByHostname.get(hc.getHostName());
String hostKeyAlgorithm = sshProperties.getHostKeyAlgorithm();
if (hostKeyAlgorithm != null) {
- session.setConfig("server_host_key", hostKeyAlgorithm);
+ session.setConfig(SERVER_HOST_KEY, hostKeyAlgorithm);
}
if (sshProperties.getHostKey() == null || !sshProperties.isStrictHostKeyChecking()) {
- session.setConfig("StrictHostKeyChecking", "no");
+ session.setConfig(STRICT_HOST_KEY_CHECKING, NO_OPTION);
} else {
- session.setConfig("StrictHostKeyChecking", "yes");
+ session.setConfig(STRICT_HOST_KEY_CHECKING, YES_OPTION);
}
}
diff --git a/spring-cloud-config-server/src/main/java/org/springframework/cloud/config/server/ssh/SshPropertyValidator.java b/spring-cloud-config-server/src/main/java/org/springframework/cloud/config/server/ssh/SshPropertyValidator.java
index 011effe7..b289587c 100644
--- a/spring-cloud-config-server/src/main/java/org/springframework/cloud/config/server/ssh/SshPropertyValidator.java
+++ b/spring-cloud-config-server/src/main/java/org/springframework/cloud/config/server/ssh/SshPropertyValidator.java
@@ -16,18 +16,16 @@
package org.springframework.cloud.config.server.ssh;
-import com.jcraft.jsch.JSch;
-import com.jcraft.jsch.JSchException;
-import com.jcraft.jsch.KeyPair;
-import org.springframework.beans.factory.annotation.Autowired;
+import java.net.URISyntaxException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+import org.eclipse.jgit.transport.URIish;
+
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.stereotype.Component;
-import org.springframework.util.Assert;
-import javax.annotation.PostConstruct;
-import java.util.*;
-
-import static java.lang.String.format;
import static org.springframework.util.StringUtils.hasText;
/**
@@ -39,72 +37,31 @@ import static org.springframework.util.StringUtils.hasText;
@EnableConfigurationProperties(SshUriProperties.class)
public class SshPropertyValidator {
- private final SshUriProperties sshUriProperties;
- private final JSch jsch = new JSch();
- private static final Set VALID_HOST_KEY_ALGORITHMS = new LinkedHashSet<>(Arrays.asList(
- "ssh-dss","ssh-rsa","ecdsa-sha2-nistp256","ecdsa-sha2-nistp384","ecdsa-sha2-nistp521"));
- private static final String GIT_PROPERTY_PREFIX = "spring.cloud.config.server.git.";
+ protected static boolean isSshUri(Object uri) {
+ if(uri != null) {
+ try {
+ URIish urIish = new URIish(uri.toString());
+ String scheme = urIish.getScheme();
+ if(scheme == null && hasText(urIish.getHost()) && hasText(urIish.getUser())) {
+ //JGit returns null if using SCP URI but user and host will be populated
+ return true;
+ }
+ return scheme != null && !scheme.matches("^(http|https)$");
- @Autowired
- public SshPropertyValidator(SshUriProperties sshUriProperties) {
- this.sshUriProperties = sshUriProperties;
- }
-
- static boolean isSshUri(Object uri) {
- return uri != null && (uri.toString().startsWith("ssh") || uri.toString().startsWith("git"));
+ } catch (URISyntaxException e) {
+ return false;
+ }
+ }
+ return false;
}
- @PostConstruct
- public void validateSshConfigurationProperties() {
+ protected List extractRepoProperties(SshUriProperties sshUriProperties) {
List allRepoProperties = new ArrayList<>();
allRepoProperties.add(sshUriProperties);
Map repos = sshUriProperties.getRepos();
if (repos != null) {
allRepoProperties.addAll(repos.values());
}
- for (SshUriProperties repoProperties : allRepoProperties) {
- if(isSshUri(repoProperties.getUri()) && sshUriProperties.isIgnoreLocalSshSettings()){
- validatePrivateKeyPresent();
- validatePrivateKeyFormat();
- validateAlgorithmSpecifiedWhenHostKeySet();
- validateHostKeySpecifiedWhenAlgorithmSet();
- validateHostKeyAlgorithmSupported();
- }
- }
+ return allRepoProperties;
}
-
- protected void validatePrivateKeyFormat() {
- try {
- KeyPair.load(jsch, sshUriProperties.getPrivateKey().getBytes(), null);
- } catch (JSchException e) {
- throw new IllegalStateException(format("Property '%sprivateKey' contains an invalid value", GIT_PROPERTY_PREFIX));
- }
- }
-
- protected void validateHostKeyAlgorithmSupported() {
- if (hasText(sshUriProperties.getHostKeyAlgorithm())) {
- Assert.state(VALID_HOST_KEY_ALGORITHMS.contains(sshUriProperties.getHostKeyAlgorithm()),
- format("Property '%shostKeyAlgorithm' must be one of %s", GIT_PROPERTY_PREFIX, VALID_HOST_KEY_ALGORITHMS));
- }
- }
-
- protected void validatePrivateKeyPresent() {
- Assert.state(sshUriProperties.getPrivateKey() != null,
- format("Property '%sprivateKey' must be set when '%signoreLocalSshSettings' is set to 'true'", GIT_PROPERTY_PREFIX, GIT_PROPERTY_PREFIX));
- }
-
- protected void validateHostKeySpecifiedWhenAlgorithmSet() {
- if (hasText(sshUriProperties.getHostKeyAlgorithm())) {
- Assert.state(hasText(sshUriProperties.getHostKey()),
- format("Property '%shostKey' must be set when 'hostKeyAlgorithm' is specified", GIT_PROPERTY_PREFIX));
- }
- }
-
- protected void validateAlgorithmSpecifiedWhenHostKeySet() {
- if (hasText(sshUriProperties.getHostKey())) {
- Assert.state(hasText(sshUriProperties.getHostKeyAlgorithm()),
- format("Property '%shostKeyAlgorithm' must be set when 'hostKey' is specified", GIT_PROPERTY_PREFIX));
- }
- }
-
}
diff --git a/spring-cloud-config-server/src/main/java/org/springframework/cloud/config/server/ssh/SshUriProperties.java b/spring-cloud-config-server/src/main/java/org/springframework/cloud/config/server/ssh/SshUriProperties.java
index 8d036d5a..5c8124d9 100644
--- a/spring-cloud-config-server/src/main/java/org/springframework/cloud/config/server/ssh/SshUriProperties.java
+++ b/spring-cloud-config-server/src/main/java/org/springframework/cloud/config/server/ssh/SshUriProperties.java
@@ -15,12 +15,11 @@
*/
package org.springframework.cloud.config.server.ssh;
-import org.springframework.boot.context.properties.ConfigurationProperties;
-import org.springframework.web.util.UriComponentsBuilder;
-
import java.util.HashMap;
import java.util.Map;
-import java.util.Objects;
+
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.validation.annotation.Validated;
/**
* Data container for property based SSH config
@@ -28,25 +27,25 @@ import java.util.Objects;
* @author Ollie Hughes
*/
@ConfigurationProperties("spring.cloud.config.server.git")
+@Validated
+@PrivateKeyIsValid
+@HostKeyAndAlgoBothExist
+@HostKeyAlgoSupported
public class SshUriProperties {
+ private String privateKey;
private String uri;
private String hostKeyAlgorithm;
private String hostKey;
- private String privateKey;
- private String username;
- private String password;
private boolean ignoreLocalSshSettings;
private boolean strictHostKeyChecking = true;
private Map repos = new HashMap<>();
- public SshUriProperties(String uri, String hostKeyAlgorithm, String hostKey, String privateKey, String username, String password, boolean ignoreLocalSshSettings, boolean strictHostKeyChecking, Map repos) {
+ public SshUriProperties(String uri, String hostKeyAlgorithm, String hostKey, String privateKey, boolean ignoreLocalSshSettings, boolean strictHostKeyChecking, Map repos) {
this.uri = uri;
this.hostKeyAlgorithm = hostKeyAlgorithm;
this.hostKey = hostKey;
this.privateKey = privateKey;
- this.username = username;
- this.password = password;
this.ignoreLocalSshSettings = ignoreLocalSshSettings;
this.strictHostKeyChecking = strictHostKeyChecking;
this.repos = repos;
@@ -59,28 +58,6 @@ public class SshUriProperties {
return new SshUriPropertiesBuilder();
}
- public boolean isSshUri() {
- return uri != null && !uri.startsWith("http");
- }
-
- public String getHostname() {
- if (getUri() == null) {
- return null;
- }
-
- if (getUri().matches("^[a-z]+://.*")) {
- return UriComponentsBuilder.fromUriString(uri).build().getHost();
- }
- else if (getUri().indexOf('@') < getUri().indexOf(':')) {
- return getUri().substring(getUri().indexOf('@') + 1, uri.indexOf(':'));
- }
- else if (getUri().startsWith("ssh:") && getUri().indexOf('@') > 0) {
- String postAt = getUri().substring(getUri().indexOf('@') + 1);
- return postAt.substring(0, postAt.indexOf(":"));
- }
- else return null;
- }
-
public String getUri() {
return this.uri;
}
@@ -97,14 +74,6 @@ public class SshUriProperties {
return this.privateKey;
}
- public String getUsername() {
- return this.username;
- }
-
- public String getPassword() {
- return this.password;
- }
-
public boolean isIgnoreLocalSshSettings() {
return this.ignoreLocalSshSettings;
}
@@ -133,14 +102,6 @@ public class SshUriProperties {
this.privateKey = privateKey;
}
- public void setUsername(String username) {
- this.username = username;
- }
-
- public void setPassword(String password) {
- this.password = password;
- }
-
public void setIgnoreLocalSshSettings(boolean ignoreLocalSshSettings) {
this.ignoreLocalSshSettings = ignoreLocalSshSettings;
}
@@ -153,32 +114,12 @@ public class SshUriProperties {
this.repos = repos;
}
- @Override
- public int hashCode() {
- return Objects.hash(uri, hostKeyAlgorithm, hostKey, privateKey, username, password, ignoreLocalSshSettings, strictHostKeyChecking);
- }
-
- @Override
- public boolean equals(Object obj) {
- if (this == obj) {
- return true;
- }
- if (obj == null || getClass() != obj.getClass()) {
- return false;
- }
- final SshUriProperties other = (SshUriProperties) obj;
- return Objects.equals(this.uri, other.uri)
- && Objects.equals(this.hostKeyAlgorithm, other.hostKeyAlgorithm)
- && Objects.equals(this.hostKey, other.hostKey)
- && Objects.equals(this.privateKey, other.privateKey)
- && Objects.equals(this.username, other.username)
- && Objects.equals(this.password, other.password)
- && Objects.equals(this.ignoreLocalSshSettings, other.ignoreLocalSshSettings)
- && Objects.equals(this.strictHostKeyChecking, other.strictHostKeyChecking);
+ public void addRepo(String repoName, SshUriProperties properties) {
+ this.repos.put(repoName, properties);
}
public String toString() {
- return "org.springframework.cloud.config.server.ssh.SshUriProperties(uri=" + this.getUri() + " hostKeyAlgorithm=" + this.getHostKeyAlgorithm() + ", hostKey=" + this.getHostKey() + ", privateKey=" + this.getPrivateKey() + ", username=" + this.getUsername() + ", password=" + this.getPassword() + ", ignoreLocalSshSettings=" + this.isIgnoreLocalSshSettings() + ", strictHostKeyChecking=" + this.isStrictHostKeyChecking() + ", repos=" + this.getRepos() + ")";
+ return "org.springframework.cloud.config.server.ssh.SshUriProperties(uri=" + this.getUri() + " hostKeyAlgorithm=" + this.getHostKeyAlgorithm() + ", hostKey=" + this.getHostKey() + ", privateKey=" + this.getPrivateKey() + ", ignoreLocalSshSettings=" + this.isIgnoreLocalSshSettings() + ", strictHostKeyChecking=" + this.isStrictHostKeyChecking() + ", repos=" + this.getRepos() + ")";
}
public static class SshUriPropertiesBuilder {
@@ -186,8 +127,6 @@ public class SshUriProperties {
private String hostKeyAlgorithm;
private String hostKey;
private String privateKey;
- private String username;
- private String password;
private boolean ignoreLocalSshSettings;
private boolean strictHostKeyChecking = true;
private Map repos;
@@ -215,16 +154,6 @@ public class SshUriProperties {
return this;
}
- public SshUriProperties.SshUriPropertiesBuilder username(String username) {
- this.username = username;
- return this;
- }
-
- public SshUriProperties.SshUriPropertiesBuilder password(String password) {
- this.password = password;
- return this;
- }
-
public SshUriProperties.SshUriPropertiesBuilder ignoreLocalSshSettings(boolean ignoreLocalSshSettings) {
this.ignoreLocalSshSettings = ignoreLocalSshSettings;
return this;
@@ -241,11 +170,11 @@ public class SshUriProperties {
}
public SshUriProperties build() {
- return new SshUriProperties(uri, hostKeyAlgorithm, hostKey, privateKey, username, password, ignoreLocalSshSettings, strictHostKeyChecking, repos);
+ return new SshUriProperties(uri, hostKeyAlgorithm, hostKey, privateKey, ignoreLocalSshSettings, strictHostKeyChecking, repos);
}
public String toString() {
- return "org.springframework.cloud.config.server.ssh.SshUriProperties.SshUriPropertiesBuilder(uri=" + this.uri + "hostKeyAlgorithm=" + this.hostKeyAlgorithm + ", hostKey=" + this.hostKey + ", privateKey=" + this.privateKey + ", username=" + this.username + ", password=" + this.password + ", ignoreLocalSshSettings=" + this.ignoreLocalSshSettings + ", strictHostKeyChecking=" + this.strictHostKeyChecking + ", repos=" + this.repos + ")";
+ return "org.springframework.cloud.config.server.ssh.SshUriProperties.SshUriPropertiesBuilder(uri=" + this.uri + "hostKeyAlgorithm=" + this.hostKeyAlgorithm + ", hostKey=" + this.hostKey + ", privateKey=" + this.privateKey + ", ignoreLocalSshSettings=" + this.ignoreLocalSshSettings + ", strictHostKeyChecking=" + this.strictHostKeyChecking + ", repos=" + this.repos + ")";
}
}
}
diff --git a/spring-cloud-config-server/src/main/java/org/springframework/cloud/config/server/ssh/SshUriPropertyProcessor.java b/spring-cloud-config-server/src/main/java/org/springframework/cloud/config/server/ssh/SshUriPropertyProcessor.java
index 791dcda9..ca004475 100644
--- a/spring-cloud-config-server/src/main/java/org/springframework/cloud/config/server/ssh/SshUriPropertyProcessor.java
+++ b/spring-cloud-config-server/src/main/java/org/springframework/cloud/config/server/ssh/SshUriPropertyProcessor.java
@@ -15,11 +15,13 @@
*/
package org.springframework.cloud.config.server.ssh;
-import org.springframework.web.util.UriComponentsBuilder;
+import java.net.URISyntaxException;
import java.util.HashMap;
import java.util.Map;
+import org.eclipse.jgit.transport.URIish;
+
import static org.springframework.cloud.config.server.ssh.SshPropertyValidator.isSshUri;
/**
@@ -57,20 +59,12 @@ public class SshUriPropertyProcessor {
return sshUriPropertyMap;
}
- private String getHostname(String uri) {
- if (uri == null) {
+ protected static String getHostname(String uri) {
+ try {
+ URIish urIish = new URIish(uri);
+ return urIish.getHost();
+ } catch (URISyntaxException e) {
return null;
}
- else if (uri.matches("^[a-z]+://.*")) {
- return UriComponentsBuilder.fromUriString(uri).build().getHost();
- }
- else if (uri.indexOf('@') < uri.indexOf(':')) {
- return uri.substring(uri.indexOf('@') + 1, uri.indexOf(':'));
- }
- else if (uri.startsWith("ssh:") && uri.indexOf('@') > 0) {
- String postAt = uri.substring(uri.indexOf('@') + 1);
- return postAt.substring(0, postAt.indexOf(":"));
- }
- else return null;
}
}
diff --git a/spring-cloud-config-server/src/main/resources/configserver.yml b/spring-cloud-config-server/src/main/resources/configserver.yml
index 176cc464..ee3218a8 100644
--- a/spring-cloud-config-server/src/main/resources/configserver.yml
+++ b/spring-cloud-config-server/src/main/resources/configserver.yml
@@ -18,4 +18,3 @@ server:
port: 8888
management:
context_path: /admin
-
\ No newline at end of file
diff --git a/spring-cloud-config-server/src/test/java/org/springframework/cloud/config/server/config/TransportConfigurationTest.java b/spring-cloud-config-server/src/test/java/org/springframework/cloud/config/server/config/TransportConfigurationTest.java
new file mode 100644
index 00000000..649eab13
--- /dev/null
+++ b/spring-cloud-config-server/src/test/java/org/springframework/cloud/config/server/config/TransportConfigurationTest.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.cloud.config.server.config;
+
+import org.eclipse.jgit.api.TransportConfigCallback;
+import org.junit.Test;
+import org.springframework.cloud.config.server.ssh.SshUriProperties;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.is;
+import static org.hamcrest.Matchers.instanceOf;
+/**
+* @author Ollie Hughes
+*/
+public class TransportConfigurationTest {
+ @Test
+ public void propertiesBasedSshTransportCallbackCreated() throws Exception {
+ SshUriProperties ignoreLocalSettings = SshUriProperties.builder()
+ .uri("user@gitrepo.com:proj/repo")
+ .ignoreLocalSshSettings(true)
+ .build();
+ TransportConfiguration transportConfiguration = new TransportConfiguration();
+ TransportConfigCallback transportConfigCallback = transportConfiguration.propertiesBasedSshTransportCallback(ignoreLocalSettings);
+ assertThat(transportConfigCallback, is(instanceOf(TransportConfiguration.PropertiesBasedSshTransportConfigCallback.class)));
+ }
+
+ @Test
+ public void fileBasedSshTransportCallbackCreated() throws Exception {
+ SshUriProperties dontIgnoreLocalSettings = SshUriProperties.builder()
+ .uri("user@gitrepo.com:proj/repo")
+ .ignoreLocalSshSettings(false)
+ .build();
+
+ TransportConfiguration transportConfiguration = new TransportConfiguration();
+ TransportConfigCallback transportConfigCallback = transportConfiguration.propertiesBasedSshTransportCallback(dontIgnoreLocalSettings);
+ assertThat(transportConfigCallback, is(instanceOf(TransportConfiguration.FileBasedSshTransportConfigCallback.class)));
+
+ }
+
+}
\ No newline at end of file
diff --git a/spring-cloud-config-server/src/test/java/org/springframework/cloud/config/server/ssh/PropertyBasedSshSessionFactoryTest.java b/spring-cloud-config-server/src/test/java/org/springframework/cloud/config/server/ssh/PropertyBasedSshSessionFactoryTest.java
index fbcb3461..2836886c 100644
--- a/spring-cloud-config-server/src/test/java/org/springframework/cloud/config/server/ssh/PropertyBasedSshSessionFactoryTest.java
+++ b/spring-cloud-config-server/src/test/java/org/springframework/cloud/config/server/ssh/PropertyBasedSshSessionFactoryTest.java
@@ -23,7 +23,6 @@ import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
-import org.mockito.Mockito;
import org.mockito.runners.MockitoJUnitRunner;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
@@ -113,7 +112,7 @@ public class PropertyBasedSshSessionFactoryTest {
.build();
setupSessionFactory(sshKey);
- factory.createSession(hc, null, sshKey.getHostname(), 22, null);
+ factory.createSession(hc, null, SshUriPropertyProcessor.getHostname(sshKey.getUri()), 22, null);
verify(jSch).addIdentity("gitlab.example.local", PRIVATE_KEY.getBytes(), null, null);
}
@@ -126,7 +125,7 @@ public class PropertyBasedSshSessionFactoryTest {
.build();
setupSessionFactory(sshKey);
- factory.createSession(hc, null, sshKey.getHostname(), 22, null);
+ factory.createSession(hc, null, SshUriPropertyProcessor.getHostname(sshKey.getUri()), 22, null);
ArgumentCaptor captor = ArgumentCaptor.forClass(HostKey.class);
verify(hostKeyRepository).add(captor.capture(), any(UserInfo.class));
HostKey hostKey = captor.getValue();
@@ -136,9 +135,9 @@ public class PropertyBasedSshSessionFactoryTest {
private void setupSessionFactory(SshUriProperties sshKey) {
Map sshKeysByHostname = new HashMap<>();
- sshKeysByHostname.put(sshKey.getHostname(), sshKey);
+ sshKeysByHostname.put(SshUriPropertyProcessor.getHostname(sshKey.getUri()), sshKey);
factory = new PropertyBasedSshSessionFactory(sshKeysByHostname, jSch) ;
- when(hc.getHostName()).thenReturn(sshKey.getHostname());
+ when(hc.getHostName()).thenReturn(SshUriPropertyProcessor.getHostname(sshKey.getUri()));
when(jSch.getHostKeyRepository()).thenReturn(hostKeyRepository);
}
diff --git a/spring-cloud-config-server/src/test/java/org/springframework/cloud/config/server/ssh/SshPropertyValidatorTest.java b/spring-cloud-config-server/src/test/java/org/springframework/cloud/config/server/ssh/SshPropertyValidatorTest.java
index 3fe69c98..7ce36ba6 100644
--- a/spring-cloud-config-server/src/test/java/org/springframework/cloud/config/server/ssh/SshPropertyValidatorTest.java
+++ b/spring-cloud-config-server/src/test/java/org/springframework/cloud/config/server/ssh/SshPropertyValidatorTest.java
@@ -16,9 +16,17 @@
package org.springframework.cloud.config.server.ssh;
+import org.junit.BeforeClass;
import org.junit.Test;
-import static org.mockito.Mockito.*;
+import javax.validation.ConstraintViolation;
+import javax.validation.Validation;
+import javax.validation.Validator;
+import javax.validation.ValidatorFactory;
+import java.util.Set;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.hasSize;
/**
* Unit tests for property based SSH config validators
@@ -58,6 +66,13 @@ public class SshPropertyValidatorTest {
"-----END RSA PRIVATE KEY-----";
private static final String VALID_HOST_KEY = "AAAAB3NzaC1yc2EAAAADAQABAAABAQDg6/W/5cbk/npvzpae7ZEa54F4rkwh2V3NiuqVZ5hWr+8O4/6SmrS7yBvRHAFeAJNb0LOCjE/7tjd1fqUx+QU1ATCtwkOhuwG8Ubzkx23mMZlrwEvx7XEfBoLN7Lw9fXjWDtTTgFB1AxCQ2pGGiNG0QCwyA4HViDHVU+ibwkRlzuDJG0tnp5Qpo3DXkHwFNdqWNfVrIZ6q2xbyeoJjKjnR215T0ehmuWFmKqG+uMNe/LQ6IOiK0F5+gr7rgPxNLAYYqyhraAnBeHn5gapsSzYJmFpoAHWvN7OUwHcJ88D9qUkKi4VKxYiuK69u3z825Xj2cLTfj9JiHCfV8cTo9GL";
+ private static Validator validator;
+
+ @BeforeClass
+ public static void setUpValidator() {
+ ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
+ validator = factory.getValidator();
+ }
@Test
public void supportedParametersSuccesful() throws Exception {
@@ -69,16 +84,12 @@ public class SshPropertyValidatorTest {
.hostKeyAlgorithm("ssh-rsa")
.build();
- SshPropertyValidator sshPropertyValidator = spy(new SshPropertyValidator(validSettings));
- sshPropertyValidator.validateSshConfigurationProperties();
- verify(sshPropertyValidator, times(1)).validatePrivateKeyFormat();
- verify(sshPropertyValidator, times(1)).validateAlgorithmSpecifiedWhenHostKeySet();
- verify(sshPropertyValidator, times(1)).validatePrivateKeyPresent();
- verify(sshPropertyValidator, times(1)).validateHostKeyAlgorithmSupported();
- verify(sshPropertyValidator, times(1)).validateHostKeySpecifiedWhenAlgorithmSet();
+ Set> constraintViolations = validator.validate(validSettings);
+ assertThat(constraintViolations, hasSize(0));
+
}
- @Test(expected = IllegalStateException.class)
+ @Test
public void invalidPrivateKeyFails() throws Exception {
SshUriProperties invalidKey = SshUriProperties.builder()
@@ -87,12 +98,12 @@ public class SshPropertyValidatorTest {
.privateKey("invalid_key")
.build();
- SshPropertyValidator sshPropertyValidator = new SshPropertyValidator(invalidKey);
- sshPropertyValidator.validateSshConfigurationProperties();
+ Set> constraintViolations = validator.validate(invalidKey);
+ assertThat(constraintViolations, hasSize(1));
}
- @Test(expected = IllegalStateException.class)
+ @Test
public void missingPrivateKeyFails() throws Exception {
SshUriProperties missingKey = SshUriProperties.builder()
@@ -100,51 +111,51 @@ public class SshPropertyValidatorTest {
.ignoreLocalSshSettings(true)
.build();
- SshPropertyValidator sshPropertyValidator = new SshPropertyValidator(missingKey);
- sshPropertyValidator.validateSshConfigurationProperties();
+ Set> constraintViolations = validator.validate(missingKey);
+ assertThat(constraintViolations, hasSize(1));
}
- @Test(expected = IllegalStateException.class)
+ @Test
public void hostKeyWithMissingAlgoFails() throws Exception {
SshUriProperties missingAlgo = SshUriProperties.builder()
.uri(SSH_URI)
.ignoreLocalSshSettings(true)
- .privateKey("invalid_key")
+ .privateKey(VALID_PRIVATE_KEY)
.hostKey("some_host")
.build();
- SshPropertyValidator sshPropertyValidator = new SshPropertyValidator(missingAlgo);
- sshPropertyValidator.validateSshConfigurationProperties();
+ Set> constraintViolations = validator.validate(missingAlgo);
+ assertThat(constraintViolations, hasSize(1));
}
- @Test(expected = IllegalStateException.class)
+ @Test
public void algoWithMissingHostKeyFails() throws Exception {
SshUriProperties missingHostKey = SshUriProperties.builder()
.uri(SSH_URI)
.ignoreLocalSshSettings(true)
- .privateKey("invalid_key")
- .hostKeyAlgorithm("some_host_algo")
+ .privateKey(VALID_PRIVATE_KEY)
+ .hostKeyAlgorithm("ssh-rsa")
.build();
- SshPropertyValidator sshPropertyValidator = new SshPropertyValidator(missingHostKey);
- sshPropertyValidator.validateSshConfigurationProperties();
+ Set> constraintViolations = validator.validate(missingHostKey);
+ assertThat(constraintViolations, hasSize(1));
}
- @Test(expected = IllegalStateException.class)
+ @Test
public void unsupportedAlgoFails() throws Exception {
SshUriProperties unsupportedAlgo = SshUriProperties.builder()
.uri(SSH_URI)
.ignoreLocalSshSettings(true)
- .privateKey("invalid_key")
+ .privateKey(VALID_PRIVATE_KEY)
.hostKey("some_host_key")
.hostKeyAlgorithm("unsupported")
.build();
- SshPropertyValidator sshPropertyValidator = new SshPropertyValidator(unsupportedAlgo);
- sshPropertyValidator.validateSshConfigurationProperties();
+ Set> constraintViolations = validator.validate(unsupportedAlgo);
+ assertThat(constraintViolations, hasSize(1));
}
@Test
@@ -156,13 +167,9 @@ public class SshPropertyValidatorTest {
.privateKey("invalid_key")
.build());
- SshPropertyValidator sshPropertyValidator = spy(new SshPropertyValidator(useLocal));
- sshPropertyValidator.validateSshConfigurationProperties();
- verify(sshPropertyValidator, times(0)).validatePrivateKeyFormat();
- verify(sshPropertyValidator, times(0)).validateAlgorithmSpecifiedWhenHostKeySet();
- verify(sshPropertyValidator, times(0)).validatePrivateKeyPresent();
- verify(sshPropertyValidator, times(0)).validateHostKeyAlgorithmSupported();
- verify(sshPropertyValidator, times(0)).validateHostKeySpecifiedWhenAlgorithmSet();
+ Set> constraintViolations = validator.validate(useLocal);
+ assertThat(constraintViolations, hasSize(0));
+
}
@Test
@@ -174,12 +181,8 @@ public class SshPropertyValidatorTest {
.privateKey("invalid_key")
.build());
- SshPropertyValidator sshPropertyValidator = spy(new SshPropertyValidator(httpsUri));
- sshPropertyValidator.validateSshConfigurationProperties();
- verify(sshPropertyValidator, times(0)).validatePrivateKeyFormat();
- verify(sshPropertyValidator, times(0)).validateAlgorithmSpecifiedWhenHostKeySet();
- verify(sshPropertyValidator, times(0)).validatePrivateKeyPresent();
- verify(sshPropertyValidator, times(0)).validateHostKeyAlgorithmSupported();
- verify(sshPropertyValidator, times(0)).validateHostKeySpecifiedWhenAlgorithmSet();
+ Set> constraintViolations = validator.validate(httpsUri);
+ assertThat(constraintViolations, hasSize(0));
+
}
}
\ No newline at end of file
diff --git a/spring-cloud-config-server/src/test/java/org/springframework/cloud/config/server/ssh/SshUriPropertyProcessorTest.java b/spring-cloud-config-server/src/test/java/org/springframework/cloud/config/server/ssh/SshUriPropertyProcessorTest.java
index cc3457b0..3051abf2 100644
--- a/spring-cloud-config-server/src/test/java/org/springframework/cloud/config/server/ssh/SshUriPropertyProcessorTest.java
+++ b/spring-cloud-config-server/src/test/java/org/springframework/cloud/config/server/ssh/SshUriPropertyProcessorTest.java
@@ -36,11 +36,14 @@ public class SshUriPropertyProcessorTest {
private static final String PRIVATE_KEY1 = "privateKey";
private static final String HOST_KEY1 = "hostKey";
private static final String ALGO1 = "ssh-rsa";
- private static final String URI1 = "git@gitlab.test.local:wtran/my-repo";
- private static final String HOST1 = "gitlab.test.local";
+ private static final String URI1 = "ollie@gitlab1.test.local:project/my-repo";
+ private static final String HOST1 = "gitlab1.test.local";
private static final String PRIVATE_KEY2 = "privateKey2";
- private static final String URI2 = "git@gitlab2.test.local:wtran/my-repo";
+ private static final String URI2 = "ssh://git@gitlab2.test.local/wtran/my-repo";
private static final String HOST2 = "gitlab2.test.local";
+ private static final String PRIVATE_KEY3 = "privateKey3";
+ private static final String URI3 = "git+ssh://git@gitlab3.test.local/wtran/my-repo";
+ private static final String HOST3 = "gitlab3.test.local";
@After
public void cleanup() {
@@ -64,27 +67,34 @@ public class SshUriPropertyProcessorTest {
addRepoProperties(sshUriProperties, SshUriProperties.builder()
.uri(URI2)
.privateKey(PRIVATE_KEY2)
- .build());
+ .build(), "repo2");
+ addRepoProperties(sshUriProperties, SshUriProperties.builder()
+ .uri(URI3)
+ .privateKey(PRIVATE_KEY3)
+ .build(), "repo3");
SshUriPropertyProcessor sshUriPropertyProcessor = new SshUriPropertyProcessor(sshUriProperties);
Map sshKeysByHostname = sshUriPropertyProcessor.getSshKeysByHostname();
+ assertThat(sshKeysByHostname.values(), hasSize(3));
- SshUriProperties sshKey = sshKeysByHostname.get(HOST1);
- assertMainRepo(sshKey);
+ SshUriProperties sshKey1 = sshKeysByHostname.get(HOST1);
+ assertMainRepo(sshKey1);
- sshKey = sshKeysByHostname.get(HOST2);
+ SshUriProperties sshKey2 = sshKeysByHostname.get(HOST2);
- assertThat(sshKeysByHostname.values(), hasSize(2));
+ assertThat(SshUriPropertyProcessor.getHostname(sshKey2.getUri()), is(equalTo(HOST2)));
+ assertThat(sshKey2.getHostKeyAlgorithm(), is(nullValue()));
+ assertThat(sshKey2.getHostKey(), is(nullValue()));
+ assertThat(sshKey2.getPrivateKey(), is(equalTo(PRIVATE_KEY2)));
- assertThat(sshKey.getHostname(), is(equalTo(HOST2)));
+ SshUriProperties sshKey3 = sshKeysByHostname.get(HOST3);
- assertThat(sshKey.getHostKeyAlgorithm(), is(nullValue()));
-
- assertThat(sshKey.getHostKey(), is(nullValue()));
-
- assertThat(sshKey.getPrivateKey(), is(equalTo(PRIVATE_KEY2)));
+ assertThat(SshUriPropertyProcessor.getHostname(sshKey3.getUri()), is(equalTo(HOST3)));
+ assertThat(sshKey3.getHostKeyAlgorithm(), is(nullValue()));
+ assertThat(sshKey3.getHostKey(), is(nullValue()));
+ assertThat(sshKey3.getPrivateKey(), is(equalTo(PRIVATE_KEY3)));
}
@Test
@@ -94,7 +104,7 @@ public class SshUriPropertyProcessorTest {
.privateKey(PRIVATE_KEY1)
.hostKey(HOST_KEY1)
.hostKeyAlgorithm(ALGO1)
- .build());
+ .build(), "repo2");
SshUriPropertyProcessor sshUriPropertyProcessor = new SshUriPropertyProcessor(sshUriProperties);
Map sshKeysByHostname = sshUriPropertyProcessor.getSshKeysByHostname();
@@ -106,12 +116,26 @@ public class SshUriPropertyProcessorTest {
}
@Test
- public void testNoSshUriPropertiess() {
+ public void testNoSshUriProperties() {
SshUriPropertyProcessor sshUriPropertyProcessor = new SshUriPropertyProcessor(new SshUriProperties());
Map sshKeysByHostname = sshUriPropertyProcessor.getSshKeysByHostname();
assertThat(sshKeysByHostname.values(), hasSize(0));
}
+ @Test
+ public void testInvalidUriDoesNotAddEntry() {
+ SshUriPropertyProcessor sshUriPropertyProcessor = new SshUriPropertyProcessor(SshUriProperties.builder().uri("invalid_uri").build());
+ Map sshKeysByHostname = sshUriPropertyProcessor.getSshKeysByHostname();
+ assertThat(sshKeysByHostname.values(), hasSize(0));
+ }
+
+ @Test
+ public void testHttpsUriDoesNotAddEntry() {
+ SshUriPropertyProcessor sshUriPropertyProcessor = new SshUriPropertyProcessor(SshUriProperties.builder().uri("https://user@github.com/proj/repo.git").build());
+ Map sshKeysByHostname = sshUriPropertyProcessor.getSshKeysByHostname();
+ assertThat(sshKeysByHostname.values(), hasSize(0));
+ }
+
private SshUriProperties mainRepoPropertiesFixture() {
return SshUriProperties.builder()
@@ -122,14 +146,20 @@ public class SshUriPropertyProcessorTest {
.build();
}
- private void addRepoProperties(SshUriProperties mainRepoProperties, SshUriProperties repoProperties) {
- Map repos = new HashMap<>();
- repos.put("repo2", repoProperties);
- mainRepoProperties.setRepos(repos);
+ private void addRepoProperties(SshUriProperties mainRepoProperties, SshUriProperties repoProperties, String repoName) {
+ if (mainRepoProperties.getRepos() == null) {
+ Map repos = new HashMap<>();
+ repos.put(repoName, repoProperties);
+ mainRepoProperties.setRepos(repos);
+ }
+ else {
+ mainRepoProperties.addRepo(repoName, repoProperties);
+ }
}
private void assertMainRepo(SshUriProperties sshKey) {
- assertThat(sshKey.getHostname(), is(equalTo(HOST1)));
+ assertThat(sshKey, is(notNullValue()));
+ assertThat(SshUriPropertyProcessor.getHostname(sshKey.getUri()), is(equalTo(HOST1)));
assertThat(sshKey.getHostKeyAlgorithm(), is(equalTo(ALGO1)));
assertThat(sshKey.getHostKey(), is(equalTo(HOST_KEY1)));
assertThat(sshKey.getPrivateKey(), is(equalTo(PRIVATE_KEY1)));