Merge branch '1.3.x'
This commit is contained in:
@@ -7,7 +7,9 @@
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-config</artifactId>
|
||||
<version>1.3.2.BUILD-SNAPSHOT</version>
|
||||
<relativePath>..</relativePath>
|
||||
</parent>
|
||||
|
||||
<packaging>pom</packaging>
|
||||
<name>Spring Cloud Config Docs</name>
|
||||
<description>Spring Cloud Docs</description>
|
||||
|
||||
@@ -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
|
||||
@@ -360,7 +360,77 @@ by the default credential provider chain. AWS EC2 instances may use
|
||||
http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/iam-roles-for-amazon-ec2.html[IAM Roles for EC2 Instances].
|
||||
|
||||
Note: The aws-java-sdk-core jar is an optional dependency. If the aws-java-sdk-core jar is not on your
|
||||
classpath, then the AWS Code Commit credential provider will not be created regardless of the git server URI.
|
||||
classpath, then the AWS Code Commit credential provider will not be created regardless of the git server URI.
|
||||
|
||||
===== Git SSH configuration using properties
|
||||
|
||||
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:
|
||||
|
||||
[source,yaml]
|
||||
----
|
||||
spring:
|
||||
cloud:
|
||||
config:
|
||||
server:
|
||||
git:
|
||||
uri: git@gitserver.com:team/repo1.git
|
||||
ignoreLocalSshSettings: true
|
||||
hostKey: someHostKey
|
||||
hostKeyAlgorithm: ssh-rsa
|
||||
privateKey: |
|
||||
-----BEGIN RSA PRIVATE KEY-----
|
||||
MIIEpgIBAAKCAQEAx4UbaDzY5xjW6hc9jwN0mX33XpTDVW9WqHp5AKaRbtAC3DqX
|
||||
IXFMPgw3K45jxRb93f8tv9vL3rD9CUG1Gv4FM+o7ds7FRES5RTjv2RT/JVNJCoqF
|
||||
ol8+ngLqRZCyBtQN7zYByWMRirPGoDUqdPYrj2yq+ObBBNhg5N+hOwKjjpzdj2Ud
|
||||
1l7R+wxIqmJo1IYyy16xS8WsjyQuyC0lL456qkd5BDZ0Ag8j2X9H9D5220Ln7s9i
|
||||
oezTipXipS7p7Jekf3Ywx6abJwOmB0rX79dV4qiNcGgzATnG1PkXxqt76VhcGa0W
|
||||
DDVHEEYGbSQ6hIGSh0I7BQun0aLRZojfE3gqHQIDAQABAoIBAQCZmGrk8BK6tXCd
|
||||
fY6yTiKxFzwb38IQP0ojIUWNrq0+9Xt+NsypviLHkXfXXCKKU4zUHeIGVRq5MN9b
|
||||
BO56/RrcQHHOoJdUWuOV2qMqJvPUtC0CpGkD+valhfD75MxoXU7s3FK7yjxy3rsG
|
||||
EmfA6tHV8/4a5umo5TqSd2YTm5B19AhRqiuUVI1wTB41DjULUGiMYrnYrhzQlVvj
|
||||
5MjnKTlYu3V8PoYDfv1GmxPPh6vlpafXEeEYN8VB97e5x3DGHjZ5UrurAmTLTdO8
|
||||
+AahyoKsIY612TkkQthJlt7FJAwnCGMgY6podzzvzICLFmmTXYiZ/28I4BX/mOSe
|
||||
pZVnfRixAoGBAO6Uiwt40/PKs53mCEWngslSCsh9oGAaLTf/XdvMns5VmuyyAyKG
|
||||
ti8Ol5wqBMi4GIUzjbgUvSUt+IowIrG3f5tN85wpjQ1UGVcpTnl5Qo9xaS1PFScQ
|
||||
xrtWZ9eNj2TsIAMp/svJsyGG3OibxfnuAIpSXNQiJPwRlW3irzpGgVx/AoGBANYW
|
||||
dnhshUcEHMJi3aXwR12OTDnaLoanVGLwLnkqLSYUZA7ZegpKq90UAuBdcEfgdpyi
|
||||
PhKpeaeIiAaNnFo8m9aoTKr+7I6/uMTlwrVnfrsVTZv3orxjwQV20YIBCVRKD1uX
|
||||
VhE0ozPZxwwKSPAFocpyWpGHGreGF1AIYBE9UBtjAoGBAI8bfPgJpyFyMiGBjO6z
|
||||
FwlJc/xlFqDusrcHL7abW5qq0L4v3R+FrJw3ZYufzLTVcKfdj6GelwJJO+8wBm+R
|
||||
gTKYJItEhT48duLIfTDyIpHGVm9+I1MGhh5zKuCqIhxIYr9jHloBB7kRm0rPvYY4
|
||||
VAykcNgyDvtAVODP+4m6JvhjAoGBALbtTqErKN47V0+JJpapLnF0KxGrqeGIjIRV
|
||||
cYA6V4WYGr7NeIfesecfOC356PyhgPfpcVyEztwlvwTKb3RzIT1TZN8fH4YBr6Ee
|
||||
KTbTjefRFhVUjQqnucAvfGi29f+9oE3Ei9f7wA+H35ocF6JvTYUsHNMIO/3gZ38N
|
||||
CPjyCMa9AoGBAMhsITNe3QcbsXAbdUR00dDsIFVROzyFJ2m40i4KCRM35bC/BIBs
|
||||
q0TY3we+ERB40U8Z2BvU61QuwaunJ2+uGadHo58VSVdggqAo0BSkH58innKKt96J
|
||||
69pcVH/4rmLbXdcmNYGm6iu+MlPQk4BUZknHSmVHIFdJ0EPupVaQ8RHT
|
||||
-----END RSA PRIVATE KEY-----
|
||||
|
||||
----
|
||||
|
||||
.SSH Configuration properties
|
||||
|===
|
||||
|Property Name |Remarks
|
||||
|
||||
|*ignoreLocalSshSettings*
|
||||
|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
|
||||
|
||||
|*hostKey*
|
||||
|Valid SSH host key. Must be set if `hostKeyAlgorithm` is also set
|
||||
|
||||
|*hostKeyAlgorithm*
|
||||
|One of `ssh-dss, ssh-rsa, ecdsa-sha2-nistp256, ecdsa-sha2-nistp384 ,ecdsa-sha2-nistp521`. Must be set if `hostKey` is also set
|
||||
|
||||
|*strictHostKeyChecking*
|
||||
|`true` or `false`. If false, ignore errors with host key
|
||||
|===
|
||||
|
||||
|
||||
===== Placeholders in Git Search Paths
|
||||
|
||||
|
||||
@@ -29,7 +29,7 @@ import org.springframework.context.annotation.Import;
|
||||
@ConditionalOnBean(ConfigServerConfiguration.Marker.class)
|
||||
@EnableConfigurationProperties(ConfigServerProperties.class)
|
||||
@Import({ EnvironmentRepositoryConfiguration.class, CompositeConfiguration.class, ResourceRepositoryConfiguration.class,
|
||||
ConfigServerEncryptionConfiguration.class, ConfigServerMvcConfiguration.class })
|
||||
ConfigServerEncryptionConfiguration.class, ConfigServerMvcConfiguration.class, TransportConfiguration.class })
|
||||
public class ConfigServerAutoConfiguration {
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,103 @@
|
||||
/*
|
||||
* 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 com.jcraft.jsch.JSch;
|
||||
import com.jcraft.jsch.Session;
|
||||
import org.eclipse.jgit.api.TransportConfigCallback;
|
||||
import org.eclipse.jgit.transport.*;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.cloud.config.server.ssh.PropertyBasedSshSessionFactory;
|
||||
import org.springframework.cloud.config.server.ssh.SshUriProperties;
|
||||
import org.springframework.cloud.config.server.ssh.SshUriPropertyProcessor;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
/**
|
||||
* Configure a callback to set up a property based SSH settings before running a transport command (such as clone or fetch)
|
||||
*
|
||||
* @author Ollie Hughes
|
||||
*/
|
||||
@Configuration
|
||||
@EnableConfigurationProperties(SshUriProperties.class)
|
||||
public class TransportConfiguration {
|
||||
|
||||
@ConditionalOnMissingBean(TransportConfigCallback.class)
|
||||
@Bean
|
||||
public TransportConfigCallback propertiesBasedSshTransportCallback(final SshUriProperties sshUriProperties) {
|
||||
if(sshUriProperties.isIgnoreLocalSshSettings()) {
|
||||
return new PropertiesBasedSshTransportConfigCallback(sshUriProperties);
|
||||
}
|
||||
else return new FileBasedSshTransportConfigCallback(sshUriProperties);
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure JGit transport command to use a SSH session factory that is configured using properties defined
|
||||
* in {@link SshUriProperties}
|
||||
*/
|
||||
public static class PropertiesBasedSshTransportConfigCallback implements TransportConfigCallback {
|
||||
|
||||
private SshUriProperties sshUriProperties;
|
||||
|
||||
public PropertiesBasedSshTransportConfigCallback(SshUriProperties sshUriProperties) {
|
||||
this.sshUriProperties = sshUriProperties;
|
||||
}
|
||||
|
||||
public SshUriProperties getSshUriProperties() {
|
||||
return sshUriProperties;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configure(Transport transport) {
|
||||
if (transport instanceof SshTransport) {
|
||||
SshTransport sshTransport = (SshTransport) transport;
|
||||
sshTransport.setSshSessionFactory(
|
||||
new PropertyBasedSshSessionFactory(
|
||||
new SshUriPropertyProcessor(sshUriProperties).getSshKeysByHostname(), new JSch()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure JGit transport command to use a default SSH session factory based on local machines SSH config.
|
||||
* Allow strict host key checking to be set.
|
||||
*/
|
||||
public static class FileBasedSshTransportConfigCallback implements TransportConfigCallback {
|
||||
|
||||
private SshUriProperties sshUriProperties;
|
||||
|
||||
public FileBasedSshTransportConfigCallback(SshUriProperties sshUriProperties) {
|
||||
this.sshUriProperties = sshUriProperties;
|
||||
}
|
||||
|
||||
public SshUriProperties getSshUriProperties() {
|
||||
return sshUriProperties;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configure(Transport transport) {
|
||||
SshSessionFactory.setInstance(new JschConfigSessionFactory() {
|
||||
@Override
|
||||
protected void configure(OpenSshConfig.Host hc, Session session) {
|
||||
session.setConfig("StrictHostKeyChecking",
|
||||
sshUriProperties.isStrictHostKeyChecking() ? "yes" : "no");
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -16,6 +16,8 @@
|
||||
|
||||
package org.springframework.cloud.config.server.environment;
|
||||
|
||||
import static org.springframework.util.StringUtils.hasText;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.HashSet;
|
||||
@@ -58,8 +60,6 @@ import org.springframework.util.StringUtils;
|
||||
|
||||
import com.jcraft.jsch.Session;
|
||||
|
||||
import static org.springframework.util.StringUtils.hasText;
|
||||
|
||||
/**
|
||||
* An {@link EnvironmentRepository} backed by a single git repository.
|
||||
*
|
||||
@@ -81,8 +81,6 @@ public class JGitEnvironmentRepository extends AbstractScmEnvironmentRepository
|
||||
*/
|
||||
private int timeout = 5;
|
||||
|
||||
private boolean initialized;
|
||||
|
||||
/**
|
||||
* Flag to indicate that the repository should be cloned on startup (not on demand).
|
||||
* Generally leads to slower startup but faster first query.
|
||||
@@ -108,6 +106,7 @@ public class JGitEnvironmentRepository extends AbstractScmEnvironmentRepository
|
||||
* changes and take from remote repository.
|
||||
*/
|
||||
private boolean forcePull;
|
||||
private boolean initialized;
|
||||
|
||||
public JGitEnvironmentRepository(ConfigurableEnvironment environment) {
|
||||
super(environment);
|
||||
@@ -187,7 +186,6 @@ public class JGitEnvironmentRepository extends AbstractScmEnvironmentRepository
|
||||
* Get the working directory ready.
|
||||
*/
|
||||
public String refresh(String label) {
|
||||
initialize();
|
||||
Git git = null;
|
||||
try {
|
||||
git = createGitClient();
|
||||
|
||||
@@ -0,0 +1,101 @@
|
||||
/*
|
||||
* Copyright 2017 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;
|
||||
|
||||
/**
|
||||
* @author Dave Syer
|
||||
*
|
||||
*/
|
||||
@Validated
|
||||
@PrivateKeyIsValid
|
||||
@HostKeyAndAlgoBothExist
|
||||
@HostKeyAlgoSupported
|
||||
public class BaseSshUriProperties {
|
||||
|
||||
private String privateKey;
|
||||
private String uri;
|
||||
private String hostKeyAlgorithm;
|
||||
private String hostKey;
|
||||
private boolean ignoreLocalSshSettings;
|
||||
private boolean strictHostKeyChecking = true;
|
||||
|
||||
public BaseSshUriProperties(String uri, String hostKeyAlgorithm, String hostKey, String privateKey, boolean ignoreLocalSshSettings, boolean strictHostKeyChecking) {
|
||||
this.uri = uri;
|
||||
this.hostKeyAlgorithm = hostKeyAlgorithm;
|
||||
this.hostKey = hostKey;
|
||||
this.privateKey = privateKey;
|
||||
this.ignoreLocalSshSettings = ignoreLocalSshSettings;
|
||||
this.strictHostKeyChecking = strictHostKeyChecking;
|
||||
}
|
||||
|
||||
public BaseSshUriProperties() {
|
||||
}
|
||||
|
||||
public String getUri() {
|
||||
return this.uri;
|
||||
}
|
||||
|
||||
public String getHostKeyAlgorithm() {
|
||||
return this.hostKeyAlgorithm;
|
||||
}
|
||||
|
||||
public String getHostKey() {
|
||||
return this.hostKey;
|
||||
}
|
||||
|
||||
public String getPrivateKey() {
|
||||
return this.privateKey;
|
||||
}
|
||||
|
||||
public boolean isIgnoreLocalSshSettings() {
|
||||
return this.ignoreLocalSshSettings;
|
||||
}
|
||||
|
||||
public boolean isStrictHostKeyChecking() {
|
||||
return this.strictHostKeyChecking;
|
||||
}
|
||||
|
||||
public void setUri(String uri) {
|
||||
this.uri = uri;
|
||||
}
|
||||
|
||||
public void setHostKeyAlgorithm(String hostKeyAlgorithm) {
|
||||
this.hostKeyAlgorithm = hostKeyAlgorithm;
|
||||
}
|
||||
|
||||
public void setHostKey(String hostKey) {
|
||||
this.hostKey = hostKey;
|
||||
}
|
||||
|
||||
public void setPrivateKey(String privateKey) {
|
||||
this.privateKey = privateKey;
|
||||
}
|
||||
|
||||
public void setIgnoreLocalSshSettings(boolean ignoreLocalSshSettings) {
|
||||
this.ignoreLocalSshSettings = ignoreLocalSshSettings;
|
||||
}
|
||||
|
||||
public void setStrictHostKeyChecking(boolean strictHostKeyChecking) {
|
||||
this.strictHostKeyChecking = strictHostKeyChecking;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
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() + ")";
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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 {};
|
||||
}
|
||||
@@ -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<HostKeyAlgoSupported, SshUriProperties> {
|
||||
private static final String GIT_PROPERTY_PREFIX = "spring.cloud.config.server.git.";
|
||||
private final SshPropertyValidator sshPropertyValidator = new SshPropertyValidator();
|
||||
private static final Set<String> 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<Boolean> validationResults = new HashSet<>();
|
||||
List<SshUri> extractedProperties = sshPropertyValidator.extractRepoProperties(sshUriProperties);
|
||||
|
||||
for (SshUri extractedProperty : extractedProperties) {
|
||||
if (sshUriProperties.isIgnoreLocalSshSettings() && isSshUri(extractedProperty.getUri())) {
|
||||
validationResults.add(isHostKeySpecifiedWhenAlgorithmSet(extractedProperty, context));
|
||||
}
|
||||
}
|
||||
return !validationResults.contains(false);
|
||||
}
|
||||
|
||||
private boolean isHostKeySpecifiedWhenAlgorithmSet(SshUri 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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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 {};
|
||||
}
|
||||
@@ -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<HostKeyAndAlgoBothExist, SshUriProperties> {
|
||||
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<Boolean> validationResults = new HashSet<>();
|
||||
List<SshUri> extractedProperties = sshPropertyValidator.extractRepoProperties(sshUriProperties);
|
||||
|
||||
for (SshUri extractedProperty : extractedProperties) {
|
||||
if (sshUriProperties.isIgnoreLocalSshSettings() && isSshUri(extractedProperty.getUri())) {
|
||||
validationResults.add(
|
||||
isAlgorithmSpecifiedWhenHostKeySet(extractedProperty, context)
|
||||
&& isHostKeySpecifiedWhenAlgorithmSet(extractedProperty, context));
|
||||
}
|
||||
}
|
||||
return !validationResults.contains(false);
|
||||
}
|
||||
|
||||
private boolean isHostKeySpecifiedWhenAlgorithmSet(SshUri 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(SshUri 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;
|
||||
}
|
||||
}
|
||||
@@ -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 {};
|
||||
}
|
||||
@@ -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<PrivateKeyIsValid, SshUriProperties> {
|
||||
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<Boolean> validationResults = new HashSet<>();
|
||||
List<SshUri> extractedProperties = sshPropertyValidator.extractRepoProperties(sshUriProperties);
|
||||
|
||||
for (SshUri extractedProperty : extractedProperties) {
|
||||
if (sshUriProperties.isIgnoreLocalSshSettings() && isSshUri(extractedProperty.getUri())) {
|
||||
validationResults.add(
|
||||
isPrivateKeyPresent(extractedProperty, context)
|
||||
&& isPrivateKeyFormatCorrect(extractedProperty, context));
|
||||
}
|
||||
}
|
||||
return !validationResults.contains(false);
|
||||
|
||||
}
|
||||
|
||||
private boolean isPrivateKeyPresent(SshUri 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(SshUri 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
* 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.Map;
|
||||
|
||||
import com.jcraft.jsch.HostKey;
|
||||
import com.jcraft.jsch.JSch;
|
||||
import com.jcraft.jsch.JSchException;
|
||||
import com.jcraft.jsch.Session;
|
||||
import org.eclipse.jgit.transport.JschConfigSessionFactory;
|
||||
import org.eclipse.jgit.transport.OpenSshConfig.Host;
|
||||
import org.eclipse.jgit.util.Base64;
|
||||
import org.eclipse.jgit.util.FS;
|
||||
|
||||
/**
|
||||
* 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
|
||||
* properties
|
||||
* @author William Tran
|
||||
* @author Ollie Hughes
|
||||
*/
|
||||
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<String, SshUri> sshKeysByHostname;
|
||||
private final JSch jSch;
|
||||
|
||||
public PropertyBasedSshSessionFactory(Map<String, SshUri> sshKeysByHostname, JSch jSch) {
|
||||
this.sshKeysByHostname = sshKeysByHostname;
|
||||
this.jSch = jSch;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configure(Host hc, Session session) {
|
||||
SshUri sshProperties = sshKeysByHostname.get(hc.getHostName());
|
||||
String hostKeyAlgorithm = sshProperties.getHostKeyAlgorithm();
|
||||
if (hostKeyAlgorithm != null) {
|
||||
session.setConfig(SERVER_HOST_KEY, hostKeyAlgorithm);
|
||||
}
|
||||
if (sshProperties.getHostKey() == null || !sshProperties.isStrictHostKeyChecking()) {
|
||||
session.setConfig(STRICT_HOST_KEY_CHECKING, NO_OPTION);
|
||||
} else {
|
||||
session.setConfig(STRICT_HOST_KEY_CHECKING, YES_OPTION);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Session createSession(Host hc, String user, String host, int port, FS fs) throws JSchException {
|
||||
if (sshKeysByHostname.containsKey(host)) {
|
||||
SshUri sshUriProperties = sshKeysByHostname.get(host);
|
||||
jSch.addIdentity(host, sshUriProperties.getPrivateKey().getBytes(), null, null);
|
||||
if (sshUriProperties.getHostKey() != null) {
|
||||
HostKey hostkey = new HostKey(host, Base64.decode(sshUriProperties.getHostKey()));
|
||||
jSch.getHostKeyRepository().add(hostkey, null);
|
||||
}
|
||||
return jSch.getSession(user, host, port);
|
||||
}
|
||||
throw new JSchException("no keys configured for hostname " + host);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* 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.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 static org.springframework.util.StringUtils.hasText;
|
||||
|
||||
/**
|
||||
* Validate SSH related properties
|
||||
*
|
||||
* @author Ollie Hughes
|
||||
*/
|
||||
@Component
|
||||
@EnableConfigurationProperties(SshUriProperties.class)
|
||||
public class SshPropertyValidator {
|
||||
|
||||
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)$");
|
||||
|
||||
} catch (URISyntaxException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
protected List<SshUri> extractRepoProperties(SshUriProperties sshUriProperties) {
|
||||
List<SshUri> allRepoProperties = new ArrayList<>();
|
||||
allRepoProperties.add(sshUriProperties);
|
||||
Map<String, SshUriProperties.SshUriNestedRepoProperties> repos = sshUriProperties.getRepos();
|
||||
if (repos != null) {
|
||||
allRepoProperties.addAll(repos.values());
|
||||
}
|
||||
return allRepoProperties;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,150 @@
|
||||
package org.springframework.cloud.config.server.ssh;
|
||||
|
||||
import org.springframework.cloud.config.server.ssh.SshUriProperties.SshUriNestedRepoProperties;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Base class that contains configuration properties for Git SSH properties
|
||||
*
|
||||
* @author Ollie Hughes
|
||||
*/
|
||||
public abstract class SshUri {
|
||||
private String privateKey;
|
||||
private String uri;
|
||||
private String hostKeyAlgorithm;
|
||||
private String hostKey;
|
||||
private boolean ignoreLocalSshSettings;
|
||||
private boolean strictHostKeyChecking = true;
|
||||
|
||||
public static SshUriPropertiesBuilder builder() {
|
||||
return new SshUriPropertiesBuilder();
|
||||
}
|
||||
|
||||
public String getUri() {
|
||||
return this.uri;
|
||||
}
|
||||
|
||||
public String getHostKeyAlgorithm() {
|
||||
return this.hostKeyAlgorithm;
|
||||
}
|
||||
|
||||
public String getHostKey() {
|
||||
return this.hostKey;
|
||||
}
|
||||
|
||||
public String getPrivateKey() {
|
||||
return this.privateKey;
|
||||
}
|
||||
|
||||
public boolean isIgnoreLocalSshSettings() {
|
||||
return this.ignoreLocalSshSettings;
|
||||
}
|
||||
|
||||
public boolean isStrictHostKeyChecking() {
|
||||
return this.strictHostKeyChecking;
|
||||
}
|
||||
|
||||
public void setUri(String uri) {
|
||||
this.uri = uri;
|
||||
}
|
||||
|
||||
public void setHostKeyAlgorithm(String hostKeyAlgorithm) {
|
||||
this.hostKeyAlgorithm = hostKeyAlgorithm;
|
||||
}
|
||||
|
||||
public void setHostKey(String hostKey) {
|
||||
this.hostKey = hostKey;
|
||||
}
|
||||
|
||||
public void setPrivateKey(String privateKey) {
|
||||
this.privateKey = privateKey;
|
||||
}
|
||||
|
||||
public void setIgnoreLocalSshSettings(boolean ignoreLocalSshSettings) {
|
||||
this.ignoreLocalSshSettings = ignoreLocalSshSettings;
|
||||
}
|
||||
|
||||
public void setStrictHostKeyChecking(boolean strictHostKeyChecking) {
|
||||
this.strictHostKeyChecking = strictHostKeyChecking;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
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() + ",)";
|
||||
}
|
||||
|
||||
public static class SshUriPropertiesBuilder {
|
||||
private String uri;
|
||||
private String hostKeyAlgorithm;
|
||||
private String hostKey;
|
||||
private String privateKey;
|
||||
private boolean ignoreLocalSshSettings;
|
||||
private boolean strictHostKeyChecking = true;
|
||||
private Map<String, SshUriNestedRepoProperties> repos = new LinkedHashMap<>();
|
||||
|
||||
SshUriPropertiesBuilder() {
|
||||
}
|
||||
|
||||
public SshUri.SshUriPropertiesBuilder uri(String uri) {
|
||||
this.uri = uri;
|
||||
return this;
|
||||
}
|
||||
|
||||
public SshUri.SshUriPropertiesBuilder hostKeyAlgorithm(String hostKeyAlgorithm) {
|
||||
this.hostKeyAlgorithm = hostKeyAlgorithm;
|
||||
return this;
|
||||
}
|
||||
|
||||
public SshUri.SshUriPropertiesBuilder hostKey(String hostKey) {
|
||||
this.hostKey = hostKey;
|
||||
return this;
|
||||
}
|
||||
|
||||
public SshUri.SshUriPropertiesBuilder privateKey(String privateKey) {
|
||||
this.privateKey = privateKey;
|
||||
return this;
|
||||
}
|
||||
|
||||
public SshUri.SshUriPropertiesBuilder ignoreLocalSshSettings(boolean ignoreLocalSshSettings) {
|
||||
this.ignoreLocalSshSettings = ignoreLocalSshSettings;
|
||||
return this;
|
||||
}
|
||||
|
||||
public SshUri.SshUriPropertiesBuilder strictHostKeyChecking(boolean strictHostKeyChecking) {
|
||||
this.strictHostKeyChecking = strictHostKeyChecking;
|
||||
return this;
|
||||
}
|
||||
|
||||
public SshUri.SshUriPropertiesBuilder repos(Map<String, SshUriNestedRepoProperties> repos) {
|
||||
this.repos = repos;
|
||||
return this;
|
||||
}
|
||||
|
||||
public SshUriProperties build() {
|
||||
SshUriProperties sshUriProperties = new SshUriProperties();
|
||||
sshUriProperties.setRepos(repos);
|
||||
build(sshUriProperties);
|
||||
return sshUriProperties;
|
||||
}
|
||||
|
||||
public SshUriNestedRepoProperties buildAsNestedRepo() {
|
||||
SshUriNestedRepoProperties sshUriNestedRepoProperties = new SshUriNestedRepoProperties();
|
||||
build(sshUriNestedRepoProperties);
|
||||
return sshUriNestedRepoProperties;
|
||||
}
|
||||
|
||||
private void build(SshUri sshUriNestedRepoProperties) {
|
||||
sshUriNestedRepoProperties.setUri(uri);
|
||||
sshUriNestedRepoProperties.setHostKeyAlgorithm(hostKeyAlgorithm);
|
||||
sshUriNestedRepoProperties.setHostKey(hostKey);
|
||||
sshUriNestedRepoProperties.setPrivateKey(privateKey);
|
||||
sshUriNestedRepoProperties.setIgnoreLocalSshSettings(ignoreLocalSshSettings);
|
||||
sshUriNestedRepoProperties.setStrictHostKeyChecking(strictHostKeyChecking);
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
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 + ")";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* 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.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
|
||||
/**
|
||||
* Data container for property based SSH config
|
||||
*
|
||||
* @author Ollie Hughes
|
||||
*/
|
||||
@ConfigurationProperties("spring.cloud.config.server.git")
|
||||
@Validated
|
||||
@PrivateKeyIsValid
|
||||
@HostKeyAndAlgoBothExist
|
||||
@HostKeyAlgoSupported
|
||||
public class SshUriProperties extends SshUri {
|
||||
|
||||
private Map<String, SshUriProperties.SshUriNestedRepoProperties> repos = new LinkedHashMap<>();
|
||||
|
||||
public Map<String, SshUriProperties.SshUriNestedRepoProperties> getRepos() {
|
||||
return this.repos;
|
||||
}
|
||||
|
||||
public void setRepos(Map<String, SshUriNestedRepoProperties> repos) {
|
||||
this.repos = repos;
|
||||
}
|
||||
|
||||
public void addRepo(String repoName, SshUriProperties.SshUriNestedRepoProperties properties) {
|
||||
this.repos.put(repoName, properties);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return super.toString() + "{repos=" + repos + "}";
|
||||
}
|
||||
|
||||
/**
|
||||
* Differentiate between sets of properties that are defined in nested Git repos.
|
||||
* This is to prevent boot from guarding against a potential infinite deserialization of nested properties.
|
||||
* This sub class differentiates from {@link SshUriProperties} as it does not contain the self mao
|
||||
*/
|
||||
public static class SshUriNestedRepoProperties extends SshUri {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
* 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.net.URISyntaxException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.eclipse.jgit.transport.URIish;
|
||||
import org.springframework.cloud.config.server.ssh.SshUriProperties.SshUriNestedRepoProperties;
|
||||
|
||||
import static org.springframework.cloud.config.server.ssh.SshPropertyValidator.isSshUri;
|
||||
|
||||
/**
|
||||
* Check if Git repo properties refer to an SSH based transport then filter and extract the properties
|
||||
* @author William Tran
|
||||
* @author Ollie Hughes
|
||||
*/
|
||||
public class SshUriPropertyProcessor {
|
||||
|
||||
private final SshUriProperties sshUriProperties;
|
||||
|
||||
public SshUriPropertyProcessor(SshUriProperties sshUriProperties) {
|
||||
this.sshUriProperties = sshUriProperties;
|
||||
}
|
||||
|
||||
public Map<String, SshUri> getSshKeysByHostname() {
|
||||
return extractNestedProperties(sshUriProperties);
|
||||
}
|
||||
|
||||
private Map<String, SshUri> extractNestedProperties(SshUriProperties uriProperties) {
|
||||
Map<String, SshUri> sshUriPropertyMap = new HashMap<>();
|
||||
String parentUri = uriProperties.getUri();
|
||||
if (isSshUri(parentUri) && getHostname(parentUri) != null) {
|
||||
sshUriPropertyMap.put(getHostname(parentUri), uriProperties);
|
||||
}
|
||||
Map<String, SshUriNestedRepoProperties> repos = uriProperties.getRepos();
|
||||
if(repos != null) {
|
||||
for (SshUriNestedRepoProperties repoProperties : repos.values()) {
|
||||
String repoUri = repoProperties.getUri();
|
||||
if (isSshUri(repoUri) && getHostname(repoUri) != null) {
|
||||
sshUriPropertyMap.put(getHostname(repoUri), repoProperties);
|
||||
}
|
||||
}
|
||||
}
|
||||
return sshUriPropertyMap;
|
||||
}
|
||||
|
||||
protected static String getHostname(String uri) {
|
||||
try {
|
||||
URIish urIish = new URIish(uri);
|
||||
return urIish.getHost();
|
||||
} catch (URISyntaxException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -18,4 +18,3 @@ server:
|
||||
port: 8888
|
||||
management:
|
||||
context_path: /admin
|
||||
|
||||
@@ -0,0 +1,229 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
import com.jcraft.jsch.Session;
|
||||
import org.eclipse.jgit.api.TransportConfigCallback;
|
||||
import org.eclipse.jgit.transport.JschConfigSessionFactory;
|
||||
import org.eclipse.jgit.transport.OpenSshConfig;
|
||||
import org.eclipse.jgit.transport.SshSessionFactory;
|
||||
import org.eclipse.jgit.util.FS;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.cloud.config.server.config.TransportConfiguration;
|
||||
import org.springframework.cloud.config.server.environment.MultipleJGitEnvironmentRepository;
|
||||
import org.springframework.cloud.config.server.ssh.SshPropertyValidator;
|
||||
import org.springframework.cloud.config.server.ssh.SshUriProperties;
|
||||
import org.springframework.test.context.ActiveProfiles;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
|
||||
import java.io.File;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import static junit.framework.TestCase.assertTrue;
|
||||
import static org.hamcrest.Matchers.*;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
/**
|
||||
* Integration tests for property based SSH config support
|
||||
* @author Ollie Hughes
|
||||
*/
|
||||
public class TransportConfigurationIntegrationTests {
|
||||
|
||||
@RunWith(SpringRunner.class)
|
||||
@SpringBootTest(classes = {ConfigServerApplication.class, TransportConfiguration.class, SshPropertyValidator.class},
|
||||
webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
|
||||
properties = {
|
||||
"spring.config.name:ssh/ssh-private-key-block",})
|
||||
@ActiveProfiles({"test", "git"})
|
||||
public static class PropertyBasedCallbackTest {
|
||||
|
||||
@Autowired
|
||||
private MultipleJGitEnvironmentRepository jGitEnvironmentRepository;
|
||||
|
||||
@Test
|
||||
public void propertyBasedTransportCallbackIsConfigured() throws Exception {
|
||||
TransportConfigCallback transportConfigCallback = jGitEnvironmentRepository.getTransportConfigCallback();
|
||||
assertThat(transportConfigCallback, is(instanceOf(TransportConfiguration.PropertiesBasedSshTransportConfigCallback.class)));
|
||||
}
|
||||
}
|
||||
|
||||
@RunWith(SpringRunner.class)
|
||||
@SpringBootTest(classes = {ConfigServerApplication.class, TransportConfiguration.class, SshPropertyValidator.class},
|
||||
webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
|
||||
properties = {
|
||||
"spring.config.name:ssh/ssh-private-key-newline"
|
||||
})
|
||||
@ActiveProfiles({"test", "git"})
|
||||
public static class PrivateKeyPropertyWithLineBreaks {
|
||||
|
||||
@Autowired
|
||||
private MultipleJGitEnvironmentRepository jGitEnvironmentRepository;
|
||||
|
||||
@Test
|
||||
public void privateKeyPropertyWithLineBreaks() throws Exception {
|
||||
TransportConfigCallback transportConfigCallback = jGitEnvironmentRepository.getTransportConfigCallback();
|
||||
assertThat(transportConfigCallback, is(instanceOf(TransportConfiguration.PropertiesBasedSshTransportConfigCallback.class)));
|
||||
|
||||
TransportConfiguration.PropertiesBasedSshTransportConfigCallback configCallback =
|
||||
(TransportConfiguration.PropertiesBasedSshTransportConfigCallback) transportConfigCallback;
|
||||
assertThat(configCallback.getSshUriProperties().getPrivateKey(), is(equalTo(TestProperties.TEST_PRIVATE_KEY_1)));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@RunWith(SpringRunner.class)
|
||||
@SpringBootTest(classes = {ConfigServerApplication.class, TransportConfiguration.class, SshPropertyValidator.class},
|
||||
webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
|
||||
properties = {
|
||||
"spring.config.name:ssh/ssh-nested-settings"
|
||||
})
|
||||
@ActiveProfiles({"test", "git"})
|
||||
public static class SshPropertiesWithinNestedRepo {
|
||||
|
||||
@Autowired
|
||||
private MultipleJGitEnvironmentRepository jGitEnvironmentRepository;
|
||||
|
||||
@Test
|
||||
public void sshPropertiesWithinNestedRepo() throws Exception {
|
||||
TransportConfigCallback transportConfigCallback = jGitEnvironmentRepository.getTransportConfigCallback();
|
||||
assertThat(transportConfigCallback, is(instanceOf(TransportConfiguration.PropertiesBasedSshTransportConfigCallback.class)));
|
||||
|
||||
TransportConfiguration.PropertiesBasedSshTransportConfigCallback configCallback =
|
||||
(TransportConfiguration.PropertiesBasedSshTransportConfigCallback) transportConfigCallback;
|
||||
SshUriProperties sshUriProperties = configCallback.getSshUriProperties();
|
||||
assertThat(sshUriProperties.getPrivateKey(), is(equalTo(TestProperties.TEST_PRIVATE_KEY_1)));
|
||||
|
||||
assertThat(sshUriProperties.getRepos().get("repo1"), is(notNullValue()));
|
||||
assertThat(sshUriProperties.getRepos().get("repo1").getPrivateKey(), is(equalTo(TestProperties.TEST_PRIVATE_KEY_2)));
|
||||
}
|
||||
}
|
||||
|
||||
@RunWith(SpringRunner.class)
|
||||
@SpringBootTest(classes = {ConfigServerApplication.class, TransportConfiguration.class, SshPropertyValidator.class},
|
||||
webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
|
||||
properties = {
|
||||
"spring.cloud.config.server.git.uri=git@gitserver.com:team/repo.git",
|
||||
"spring.cloud.config.server.git.ignoreLocalSshSettings=false",})
|
||||
@ActiveProfiles({"test", "git"})
|
||||
public static class FileBasedCallbackTest {
|
||||
|
||||
@Autowired
|
||||
private MultipleJGitEnvironmentRepository jGitEnvironmentRepository;
|
||||
|
||||
@Test
|
||||
public void fileBasedTransportCallbackIsConfigured() throws Exception {
|
||||
TransportConfigCallback transportConfigCallback = jGitEnvironmentRepository.getTransportConfigCallback();
|
||||
assertThat(transportConfigCallback, is(instanceOf(TransportConfiguration.FileBasedSshTransportConfigCallback.class)));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void strictHostKeyCheckShouldCheck() throws Exception {
|
||||
String uri = "git+ssh://git@somegitserver/somegitrepo";
|
||||
SshSessionFactory.setInstance(null);
|
||||
jGitEnvironmentRepository.setUri(uri);
|
||||
jGitEnvironmentRepository.setBasedir(new File("./mybasedir"));
|
||||
assertTrue(jGitEnvironmentRepository.isStrictHostKeyChecking());
|
||||
jGitEnvironmentRepository.setCloneOnStart(true);
|
||||
try {
|
||||
// this will throw but we don't care about connecting.
|
||||
jGitEnvironmentRepository.afterPropertiesSet();
|
||||
} catch (Exception e) {
|
||||
final OpenSshConfig.Host hc = OpenSshConfig.get(FS.detect()).lookup("github.com");
|
||||
JschConfigSessionFactory factory = (JschConfigSessionFactory) SshSessionFactory.getInstance();
|
||||
// There's no public method that can be used to inspect the ssh
|
||||
// configuration, so we'll reflect
|
||||
// the configure method to allow us to check that the config
|
||||
// property is set as expected.
|
||||
Method configure = factory.getClass().getDeclaredMethod("configure", OpenSshConfig.Host.class,
|
||||
Session.class);
|
||||
configure.setAccessible(true);
|
||||
Session session = mock(Session.class);
|
||||
ArgumentCaptor<String> keyCaptor = ArgumentCaptor.forClass(String.class);
|
||||
ArgumentCaptor<String> valueCaptor = ArgumentCaptor.forClass(String.class);
|
||||
configure.invoke(factory, hc, session);
|
||||
verify(session).setConfig(keyCaptor.capture(), valueCaptor.capture());
|
||||
configure.setAccessible(false);
|
||||
assertTrue("yes".equals(valueCaptor.getValue()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static class TestProperties {
|
||||
private static final String TEST_PRIVATE_KEY_1 = "-----BEGIN RSA PRIVATE KEY-----\n" +
|
||||
"MIIEpAIBAAKCAQEAoqyz6YaYMTr7L8GLPSQpAQXaM04gRx4CCsGK2kfLQdw4BlqI\n" +
|
||||
"yyxp38YcuZG9cUDBAxby+K2TKmwHaC1R61QTwbPuCRdIPrDwRz+FLoegm3iDLCmn\n" +
|
||||
"uP6rjZDneYsqfU1KSdrOwIbCnONfDdvYL/vnZC/o8DDMlk5Orw2SfHkT3pq0o8km\n" +
|
||||
"ayBwN4Sf3bpyWTY0oZcmNeSCCoIdE59k8Pa7/t9bwY9caLj05C3DEsjucc7Ei/Eq\n" +
|
||||
"TOyGyobtXwaya5CqKLUHes74Poz1aEP/yVFdUud91uezd8ZK1P1t5/ZKA3R6aHir\n" +
|
||||
"+diDJ2/GQ2tD511FW46yw+EtBUJTO6ADVv4UnQIDAQABAoIBAF+5qwEfX82QfKFk\n" +
|
||||
"jfADqFFexUDtl1biFKeJrpC2MKhn01wByH9uejrhFKQqW8UaKroLthyZ34DWIyGt\n" +
|
||||
"lDnHGv0gSVF2LuAdNLdobJGt49e4+c9yD61vxzm97Eh8mRs08SM2q/VlF35E2fmI\n" +
|
||||
"xdWusUImYzd8L9e+6tRd8zZl9UhG5vR5XIstKqxC6S0g79aAt0hasE4Gw1FKOf2V\n" +
|
||||
"4mlL15atjQSKCPdOicuyc4zpjAtU1A9AfF51iG8oOUuJebPW8tCftfOQxaeGFgMG\n" +
|
||||
"7M9aai1KzXR6M5IBAKEv31yBvz/SHTneP7oZXNLeC1GIR420PKybmeZdNK8BbEAu\n" +
|
||||
"3reKgm0CgYEA03Sx8JoF5UBsIvFPpP1fjSlTgKryM5EJR6KQtj5e4YfyxccJepN8\n" +
|
||||
"q4MrqDfNKleG/a1acEtDMhBNovU7Usp2QIP7zpAeioHBOhmE5WSieZGc3icOGWWq\n" +
|
||||
"mRkdulSONruqWKv76ZoluxftekE03bDhZDNlcCgmrslEKB/ufHd2oc8CgYEAxPFa\n" +
|
||||
"lKOdSeiYFV5CtvO8Ro8em6rGpSsVz4qkPxbeBqUDCb9KXHhq6YrhRxOIfQJKfT7M\n" +
|
||||
"ZFCn8ArJXKgOGu+KsvwIErFHF9g2jJMG4DOUTpkQgi2yveihFxcmz/AltyVXgrnv\n" +
|
||||
"ZWQbAerH77pdKKhNivLGgEv72GYawdYjYNjemdMCgYA2kEMmMahZyrDcp2YEzfit\n" +
|
||||
"BT/t0K6kzcUWPgWXcSqsiZcEn+J7RbmCzFskkhmX1nQX23adyV3yejB+X0dKisHO\n" +
|
||||
"zf/ZAmlPFkJVCqa3RquCMSfIT02dEhXeYZPBM/Zqeyxuqxpa4hLgX0FBLbhFiFHw\n" +
|
||||
"uC5xrXql2XuD2xF//peXEwKBgQC+pa28Cg7vRxxCQzduB9CQtWc55j3aEjVQ7bNF\n" +
|
||||
"54sS/5ZLT0Ra8677WZfuyDfuW9NkHvCZg4Ku2qJG8eCFrrGjxlrCTZ62tHVJ6+JS\n" +
|
||||
"E1xUIdRbUIWhVZrr0VufG6hG/P0T7Y6Tpi6G0pKtvMkF3LcD9TS3adboix8H2ZXx\n" +
|
||||
"4L7MRQKBgQC0OO3qqNXOjIVYWOoqXLybOY/Wqu9lxCAgGyCYaMcstnBI7W0MZTBr\n" +
|
||||
"/syluvGsaFc1sE7MMGOOzKi1tF4YvDmSnzA/R1nmaPguuD9fOA+w7Pwkv5vLvuJq\n" +
|
||||
"2U7EeNwxq1I1L3Ag6E7wH4BHLHd4TKaZR6agFkn8oomz71yZPGjuZQ==\n" +
|
||||
"-----END RSA PRIVATE KEY-----";
|
||||
|
||||
private static final String TEST_PRIVATE_KEY_2 = "-----BEGIN RSA PRIVATE KEY-----\n" +
|
||||
"MIIEpgIBAAKCAQEAx4UbaDzY5xjW6hc9jwN0mX33XpTDVW9WqHp5AKaRbtAC3DqX\n" +
|
||||
"IXFMPgw3K45jxRb93f8tv9vL3rD9CUG1Gv4FM+o7ds7FRES5RTjv2RT/JVNJCoqF\n" +
|
||||
"ol8+ngLqRZCyBtQN7zYByWMRirPGoDUqdPYrj2yq+ObBBNhg5N+hOwKjjpzdj2Ud\n" +
|
||||
"1l7R+wxIqmJo1IYyy16xS8WsjyQuyC0lL456qkd5BDZ0Ag8j2X9H9D5220Ln7s9i\n" +
|
||||
"oezTipXipS7p7Jekf3Ywx6abJwOmB0rX79dV4qiNcGgzATnG1PkXxqt76VhcGa0W\n" +
|
||||
"DDVHEEYGbSQ6hIGSh0I7BQun0aLRZojfE3gqHQIDAQABAoIBAQCZmGrk8BK6tXCd\n" +
|
||||
"fY6yTiKxFzwb38IQP0ojIUWNrq0+9Xt+NsypviLHkXfXXCKKU4zUHeIGVRq5MN9b\n" +
|
||||
"BO56/RrcQHHOoJdUWuOV2qMqJvPUtC0CpGkD+valhfD75MxoXU7s3FK7yjxy3rsG\n" +
|
||||
"EmfA6tHV8/4a5umo5TqSd2YTm5B19AhRqiuUVI1wTB41DjULUGiMYrnYrhzQlVvj\n" +
|
||||
"5MjnKTlYu3V8PoYDfv1GmxPPh6vlpafXEeEYN8VB97e5x3DGHjZ5UrurAmTLTdO8\n" +
|
||||
"+AahyoKsIY612TkkQthJlt7FJAwnCGMgY6podzzvzICLFmmTXYiZ/28I4BX/mOSe\n" +
|
||||
"pZVnfRixAoGBAO6Uiwt40/PKs53mCEWngslSCsh9oGAaLTf/XdvMns5VmuyyAyKG\n" +
|
||||
"ti8Ol5wqBMi4GIUzjbgUvSUt+IowIrG3f5tN85wpjQ1UGVcpTnl5Qo9xaS1PFScQ\n" +
|
||||
"xrtWZ9eNj2TsIAMp/svJsyGG3OibxfnuAIpSXNQiJPwRlW3irzpGgVx/AoGBANYW\n" +
|
||||
"dnhshUcEHMJi3aXwR12OTDnaLoanVGLwLnkqLSYUZA7ZegpKq90UAuBdcEfgdpyi\n" +
|
||||
"PhKpeaeIiAaNnFo8m9aoTKr+7I6/uMTlwrVnfrsVTZv3orxjwQV20YIBCVRKD1uX\n" +
|
||||
"VhE0ozPZxwwKSPAFocpyWpGHGreGF1AIYBE9UBtjAoGBAI8bfPgJpyFyMiGBjO6z\n" +
|
||||
"FwlJc/xlFqDusrcHL7abW5qq0L4v3R+FrJw3ZYufzLTVcKfdj6GelwJJO+8wBm+R\n" +
|
||||
"gTKYJItEhT48duLIfTDyIpHGVm9+I1MGhh5zKuCqIhxIYr9jHloBB7kRm0rPvYY4\n" +
|
||||
"VAykcNgyDvtAVODP+4m6JvhjAoGBALbtTqErKN47V0+JJpapLnF0KxGrqeGIjIRV\n" +
|
||||
"cYA6V4WYGr7NeIfesecfOC356PyhgPfpcVyEztwlvwTKb3RzIT1TZN8fH4YBr6Ee\n" +
|
||||
"KTbTjefRFhVUjQqnucAvfGi29f+9oE3Ei9f7wA+H35ocF6JvTYUsHNMIO/3gZ38N\n" +
|
||||
"CPjyCMa9AoGBAMhsITNe3QcbsXAbdUR00dDsIFVROzyFJ2m40i4KCRM35bC/BIBs\n" +
|
||||
"q0TY3we+ERB40U8Z2BvU61QuwaunJ2+uGadHo58VSVdggqAo0BSkH58innKKt96J\n" +
|
||||
"69pcVH/4rmLbXdcmNYGm6iu+MlPQk4BUZknHSmVHIFdJ0EPupVaQ8RHT\n" +
|
||||
"-----END RSA PRIVATE KEY-----\n";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* 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.SshUri;
|
||||
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 = SshUri.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 = SshUri.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)));
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -33,7 +33,6 @@ import static org.mockito.Mockito.when;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
@@ -60,19 +59,14 @@ import org.eclipse.jgit.lib.StoredConfig;
|
||||
import org.eclipse.jgit.transport.CredentialItem;
|
||||
import org.eclipse.jgit.transport.CredentialsProvider;
|
||||
import org.eclipse.jgit.transport.FetchResult;
|
||||
import org.eclipse.jgit.transport.JschConfigSessionFactory;
|
||||
import org.eclipse.jgit.transport.OpenSshConfig;
|
||||
import org.eclipse.jgit.transport.SshSessionFactory;
|
||||
import org.eclipse.jgit.transport.TrackingRefUpdate;
|
||||
import org.eclipse.jgit.transport.URIish;
|
||||
import org.eclipse.jgit.transport.UsernamePasswordCredentialsProvider;
|
||||
import org.eclipse.jgit.util.FS;
|
||||
import org.eclipse.jgit.util.FileUtils;
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.rules.ExpectedException;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.springframework.cloud.config.environment.Environment;
|
||||
import org.springframework.cloud.config.server.support.AwsCodeCommitCredentialProvider;
|
||||
import org.springframework.cloud.config.server.support.GitCredentialsProviderFactory;
|
||||
@@ -677,38 +671,6 @@ public class JGitEnvironmentRepositoryTests {
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void strictHostKeyCheckShouldCheck() throws Exception {
|
||||
String uri = "git+ssh://git@somegitserver/somegitrepo";
|
||||
SshSessionFactory.setInstance(null);
|
||||
JGitEnvironmentRepository envRepository = new JGitEnvironmentRepository(this.environment);
|
||||
envRepository.setUri(uri);
|
||||
envRepository.setBasedir(new File("./mybasedir"));
|
||||
assertTrue(envRepository.isStrictHostKeyChecking());
|
||||
envRepository.setCloneOnStart(true);
|
||||
try {
|
||||
// this will throw but we don't care about connecting.
|
||||
envRepository.afterPropertiesSet();
|
||||
} catch (Exception e) {
|
||||
final OpenSshConfig.Host hc = OpenSshConfig.get(FS.detect()).lookup("github.com");
|
||||
JschConfigSessionFactory factory = (JschConfigSessionFactory) SshSessionFactory.getInstance();
|
||||
// There's no public method that can be used to inspect the ssh
|
||||
// configuration, so we'll reflect
|
||||
// the configure method to allow us to check that the config
|
||||
// property is set as expected.
|
||||
Method configure = factory.getClass().getDeclaredMethod("configure", OpenSshConfig.Host.class,
|
||||
Session.class);
|
||||
configure.setAccessible(true);
|
||||
Session session = mock(Session.class);
|
||||
ArgumentCaptor<String> keyCaptor = ArgumentCaptor.forClass(String.class);
|
||||
ArgumentCaptor<String> valueCaptor = ArgumentCaptor.forClass(String.class);
|
||||
configure.invoke(factory, hc, session);
|
||||
verify(session).setConfig(keyCaptor.capture(), valueCaptor.capture());
|
||||
configure.setAccessible(false);
|
||||
assertTrue("yes".equals(valueCaptor.getValue()));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldPrintStacktraceIfDebugEnabled() throws Exception {
|
||||
final Log mockLogger = mock(Log.class);
|
||||
|
||||
@@ -0,0 +1,159 @@
|
||||
/*
|
||||
* 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 com.jcraft.jsch.*;
|
||||
import org.eclipse.jgit.transport.OpenSshConfig.Host;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.runners.MockitoJUnitRunner;
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
import org.springframework.core.io.Resource;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.mockito.Matchers.any;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.verifyNoMoreInteractions;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
/**
|
||||
* Unit tests for property based SSH config processor
|
||||
* @author William Tran
|
||||
* @author Ollie Hughes
|
||||
*/
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class PropertyBasedSshSessionFactoryTest {
|
||||
|
||||
private static final String HOST_KEY = "AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBMzCa0AcNbahUFjFYJHIilhJOhKFHuDOOuY+/HqV9kALftitwNYo6dQ+tC9IK5JVZCZfqKfDWVMxspcPDf9eMoE=";
|
||||
private static final String HOST_KEY_ALGORITHM = "ecdsa-sha2-nistp256";
|
||||
private static final String PRIVATE_KEY = getResourceAsString("/ssh/key");
|
||||
private PropertyBasedSshSessionFactory factory;
|
||||
@Mock
|
||||
private Host hc;
|
||||
@Mock
|
||||
private Session session;
|
||||
@Mock
|
||||
private JSch jSch;
|
||||
@Mock
|
||||
private HostKeyRepository hostKeyRepository;
|
||||
|
||||
@Test
|
||||
public void strictHostKeyCheckingIsOptional() {
|
||||
SshUri sshKey = new SshUriProperties.SshUriPropertiesBuilder()
|
||||
.uri("ssh://gitlab.example.local:3322/somerepo.git")
|
||||
.privateKey(PRIVATE_KEY)
|
||||
.build();
|
||||
setupSessionFactory(sshKey);
|
||||
|
||||
factory.configure(hc, session);
|
||||
|
||||
verify(session).setConfig("StrictHostKeyChecking", "no");
|
||||
verifyNoMoreInteractions(session);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void strictHostKeyCheckingIsUsed() {
|
||||
SshUri sshKey = new SshUriProperties.SshUriPropertiesBuilder()
|
||||
.uri("ssh://gitlab.example.local:3322/somerepo.git")
|
||||
.hostKey(HOST_KEY)
|
||||
.privateKey(PRIVATE_KEY)
|
||||
.build();
|
||||
setupSessionFactory(sshKey);
|
||||
|
||||
factory.configure(hc, session);
|
||||
|
||||
verify(session).setConfig("StrictHostKeyChecking", "yes");
|
||||
verifyNoMoreInteractions(session);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void hostKeyAlgorithmIsSpecified() {
|
||||
SshUri sshKey = new SshUriProperties.SshUriPropertiesBuilder()
|
||||
.uri("ssh://gitlab.example.local:3322/somerepo.git")
|
||||
.hostKeyAlgorithm(HOST_KEY_ALGORITHM)
|
||||
.hostKey(HOST_KEY)
|
||||
.privateKey(PRIVATE_KEY)
|
||||
.build();
|
||||
setupSessionFactory(sshKey);
|
||||
|
||||
factory.configure(hc, session);
|
||||
verify(session).setConfig("server_host_key", HOST_KEY_ALGORITHM);
|
||||
verify(session).setConfig("StrictHostKeyChecking", "yes");
|
||||
verifyNoMoreInteractions(session);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void privateKeyIsUsed() throws Exception {
|
||||
SshUri sshKey = new SshUriProperties.SshUriPropertiesBuilder()
|
||||
.uri("git@gitlab.example.local:someorg/somerepo.git")
|
||||
.privateKey(PRIVATE_KEY)
|
||||
.build();
|
||||
setupSessionFactory(sshKey);
|
||||
|
||||
factory.createSession(hc, null, SshUriPropertyProcessor.getHostname(sshKey.getUri()), 22, null);
|
||||
verify(jSch).addIdentity("gitlab.example.local", PRIVATE_KEY.getBytes(), null, null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void hostKeyIsUsed() throws Exception {
|
||||
SshUri sshKey = new SshUriProperties.SshUriPropertiesBuilder()
|
||||
.uri("git@gitlab.example.local:someorg/somerepo.git")
|
||||
.hostKey(HOST_KEY)
|
||||
.privateKey(PRIVATE_KEY)
|
||||
.build();
|
||||
setupSessionFactory(sshKey);
|
||||
|
||||
factory.createSession(hc, null, SshUriPropertyProcessor.getHostname(sshKey.getUri()), 22, null);
|
||||
ArgumentCaptor<HostKey> captor = ArgumentCaptor.forClass(HostKey.class);
|
||||
verify(hostKeyRepository).add(captor.capture(), any(UserInfo.class));
|
||||
HostKey hostKey = captor.getValue();
|
||||
Assert.assertEquals("gitlab.example.local", hostKey.getHost());
|
||||
Assert.assertEquals(HOST_KEY, hostKey.getKey());
|
||||
}
|
||||
|
||||
private void setupSessionFactory(SshUri sshKey) {
|
||||
Map<String, SshUri> sshKeysByHostname = new HashMap<>();
|
||||
sshKeysByHostname.put(SshUriPropertyProcessor.getHostname(sshKey.getUri()), sshKey);
|
||||
factory = new PropertyBasedSshSessionFactory(sshKeysByHostname, jSch) ;
|
||||
when(hc.getHostName()).thenReturn(SshUriPropertyProcessor.getHostname(sshKey.getUri()));
|
||||
when(jSch.getHostKeyRepository()).thenReturn(hostKeyRepository);
|
||||
}
|
||||
|
||||
public static String getResourceAsString(String path) {
|
||||
try {
|
||||
Resource resource = new ClassPathResource(path);
|
||||
try (BufferedReader br = new BufferedReader(new InputStreamReader(resource.getInputStream()))) {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
String line = "";
|
||||
while ((line = br.readLine()) != null) {
|
||||
builder.append(line).append('\n');
|
||||
}
|
||||
return builder.toString();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new IllegalStateException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,188 @@
|
||||
/*
|
||||
* 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.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
|
||||
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
|
||||
*
|
||||
* @author Ollie Hughes
|
||||
*/
|
||||
public class SshPropertyValidatorTest {
|
||||
|
||||
private static final String SSH_URI = "git@gitserver.com:team/repo1.git";
|
||||
|
||||
private static final String VALID_PRIVATE_KEY = "-----BEGIN RSA PRIVATE KEY-----\n" +
|
||||
"MIIEpAIBAAKCAQEAoqyz6YaYMTr7L8GLPSQpAQXaM04gRx4CCsGK2kfLQdw4BlqI\n" +
|
||||
"yyxp38YcuZG9cUDBAxby+K2TKmwHaC1R61QTwbPuCRdIPrDwRz+FLoegm3iDLCmn\n" +
|
||||
"uP6rjZDneYsqfU1KSdrOwIbCnONfDdvYL/vnZC/o8DDMlk5Orw2SfHkT3pq0o8km\n" +
|
||||
"ayBwN4Sf3bpyWTY0oZcmNeSCCoIdE59k8Pa7/t9bwY9caLj05C3DEsjucc7Ei/Eq\n" +
|
||||
"TOyGyobtXwaya5CqKLUHes74Poz1aEP/yVFdUud91uezd8ZK1P1t5/ZKA3R6aHir\n" +
|
||||
"+diDJ2/GQ2tD511FW46yw+EtBUJTO6ADVv4UnQIDAQABAoIBAF+5qwEfX82QfKFk\n" +
|
||||
"jfADqFFexUDtl1biFKeJrpC2MKhn01wByH9uejrhFKQqW8UaKroLthyZ34DWIyGt\n" +
|
||||
"lDnHGv0gSVF2LuAdNLdobJGt49e4+c9yD61vxzm97Eh8mRs08SM2q/VlF35E2fmI\n" +
|
||||
"xdWusUImYzd8L9e+6tRd8zZl9UhG5vR5XIstKqxC6S0g79aAt0hasE4Gw1FKOf2V\n" +
|
||||
"4mlL15atjQSKCPdOicuyc4zpjAtU1A9AfF51iG8oOUuJebPW8tCftfOQxaeGFgMG\n" +
|
||||
"7M9aai1KzXR6M5IBAKEv31yBvz/SHTneP7oZXNLeC1GIR420PKybmeZdNK8BbEAu\n" +
|
||||
"3reKgm0CgYEA03Sx8JoF5UBsIvFPpP1fjSlTgKryM5EJR6KQtj5e4YfyxccJepN8\n" +
|
||||
"q4MrqDfNKleG/a1acEtDMhBNovU7Usp2QIP7zpAeioHBOhmE5WSieZGc3icOGWWq\n" +
|
||||
"mRkdulSONruqWKv76ZoluxftekE03bDhZDNlcCgmrslEKB/ufHd2oc8CgYEAxPFa\n" +
|
||||
"lKOdSeiYFV5CtvO8Ro8em6rGpSsVz4qkPxbeBqUDCb9KXHhq6YrhRxOIfQJKfT7M\n" +
|
||||
"ZFCn8ArJXKgOGu+KsvwIErFHF9g2jJMG4DOUTpkQgi2yveihFxcmz/AltyVXgrnv\n" +
|
||||
"ZWQbAerH77pdKKhNivLGgEv72GYawdYjYNjemdMCgYA2kEMmMahZyrDcp2YEzfit\n" +
|
||||
"BT/t0K6kzcUWPgWXcSqsiZcEn+J7RbmCzFskkhmX1nQX23adyV3yejB+X0dKisHO\n" +
|
||||
"zf/ZAmlPFkJVCqa3RquCMSfIT02dEhXeYZPBM/Zqeyxuqxpa4hLgX0FBLbhFiFHw\n" +
|
||||
"uC5xrXql2XuD2xF//peXEwKBgQC+pa28Cg7vRxxCQzduB9CQtWc55j3aEjVQ7bNF\n" +
|
||||
"54sS/5ZLT0Ra8677WZfuyDfuW9NkHvCZg4Ku2qJG8eCFrrGjxlrCTZ62tHVJ6+JS\n" +
|
||||
"E1xUIdRbUIWhVZrr0VufG6hG/P0T7Y6Tpi6G0pKtvMkF3LcD9TS3adboix8H2ZXx\n" +
|
||||
"4L7MRQKBgQC0OO3qqNXOjIVYWOoqXLybOY/Wqu9lxCAgGyCYaMcstnBI7W0MZTBr\n" +
|
||||
"/syluvGsaFc1sE7MMGOOzKi1tF4YvDmSnzA/R1nmaPguuD9fOA+w7Pwkv5vLvuJq\n" +
|
||||
"2U7EeNwxq1I1L3Ag6E7wH4BHLHd4TKaZR6agFkn8oomz71yZPGjuZQ==\n" +
|
||||
"-----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 {
|
||||
SshUriProperties validSettings = SshUri.builder()
|
||||
.uri(SSH_URI)
|
||||
.ignoreLocalSshSettings(true)
|
||||
.privateKey(VALID_PRIVATE_KEY)
|
||||
.hostKey(VALID_HOST_KEY)
|
||||
.hostKeyAlgorithm("ssh-rsa")
|
||||
.build();
|
||||
|
||||
Set<ConstraintViolation<SshUriProperties>> constraintViolations = validator.validate(validSettings);
|
||||
assertThat(constraintViolations, hasSize(0));
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void invalidPrivateKeyFails() throws Exception {
|
||||
|
||||
SshUriProperties invalidKey = SshUri.builder()
|
||||
.uri(SSH_URI)
|
||||
.ignoreLocalSshSettings(true)
|
||||
.privateKey("invalid_key")
|
||||
.build();
|
||||
|
||||
Set<ConstraintViolation<SshUriProperties>> constraintViolations = validator.validate(invalidKey);
|
||||
assertThat(constraintViolations, hasSize(1));
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void missingPrivateKeyFails() throws Exception {
|
||||
|
||||
SshUriProperties missingKey = SshUri.builder()
|
||||
.uri(SSH_URI)
|
||||
.ignoreLocalSshSettings(true)
|
||||
.build();
|
||||
|
||||
Set<ConstraintViolation<SshUriProperties>> constraintViolations = validator.validate(missingKey);
|
||||
assertThat(constraintViolations, hasSize(1));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void hostKeyWithMissingAlgoFails() throws Exception {
|
||||
|
||||
SshUriProperties missingAlgo = SshUri.builder()
|
||||
.uri(SSH_URI)
|
||||
.ignoreLocalSshSettings(true)
|
||||
.privateKey(VALID_PRIVATE_KEY)
|
||||
.hostKey("some_host")
|
||||
.build();
|
||||
|
||||
Set<ConstraintViolation<SshUriProperties>> constraintViolations = validator.validate(missingAlgo);
|
||||
assertThat(constraintViolations, hasSize(1));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void algoWithMissingHostKeyFails() throws Exception {
|
||||
|
||||
SshUriProperties missingHostKey = SshUri.builder()
|
||||
.uri(SSH_URI)
|
||||
.ignoreLocalSshSettings(true)
|
||||
.privateKey(VALID_PRIVATE_KEY)
|
||||
.hostKeyAlgorithm("ssh-rsa")
|
||||
.build();
|
||||
|
||||
Set<ConstraintViolation<SshUriProperties>> constraintViolations = validator.validate(missingHostKey);
|
||||
assertThat(constraintViolations, hasSize(1));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void unsupportedAlgoFails() throws Exception {
|
||||
|
||||
SshUriProperties unsupportedAlgo = SshUri.builder()
|
||||
.uri(SSH_URI)
|
||||
.ignoreLocalSshSettings(true)
|
||||
.privateKey(VALID_PRIVATE_KEY)
|
||||
.hostKey("some_host_key")
|
||||
.hostKeyAlgorithm("unsupported")
|
||||
.build();
|
||||
|
||||
Set<ConstraintViolation<SshUriProperties>> constraintViolations = validator.validate(unsupportedAlgo);
|
||||
assertThat(constraintViolations, hasSize(1));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void validatorNotRunIfIgnoreLocalSettingsFalse() throws Exception {
|
||||
|
||||
SshUriProperties useLocal = (SshUri.builder()
|
||||
.uri(SSH_URI)
|
||||
.ignoreLocalSshSettings(false)
|
||||
.privateKey("invalid_key")
|
||||
.build());
|
||||
|
||||
Set<ConstraintViolation<SshUriProperties>> constraintViolations = validator.validate(useLocal);
|
||||
assertThat(constraintViolations, hasSize(0));
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void validatorNotRunIfHttpsUri() throws Exception {
|
||||
|
||||
SshUriProperties httpsUri = (SshUri.builder()
|
||||
.uri("https://somerepo.com/team/project.git")
|
||||
.ignoreLocalSshSettings(true)
|
||||
.privateKey("invalid_key")
|
||||
.build());
|
||||
|
||||
Set<ConstraintViolation<SshUriProperties>> constraintViolations = validator.validate(httpsUri);
|
||||
assertThat(constraintViolations, hasSize(0));
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,162 @@
|
||||
/*
|
||||
* 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.Map;
|
||||
import org.eclipse.jgit.transport.SshSessionFactory;
|
||||
import org.junit.After;
|
||||
import org.junit.Test;
|
||||
import org.springframework.cloud.config.server.ssh.SshUriProperties.SshUriNestedRepoProperties;
|
||||
|
||||
|
||||
import static org.hamcrest.Matchers.*;
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
||||
/**
|
||||
* Unit tests for property based SSH config processor
|
||||
* @author William Tran
|
||||
* @author Ollie Hughes
|
||||
*/
|
||||
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 = "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 = "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() {
|
||||
SshSessionFactory.setInstance(null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSingleSshUriProperties() {
|
||||
SshUriPropertyProcessor sshUriPropertyProcessor = new SshUriPropertyProcessor(mainRepoPropertiesFixture());
|
||||
Map<String, SshUri> sshKeysByHostname = sshUriPropertyProcessor.getSshKeysByHostname();
|
||||
|
||||
assertThat(sshKeysByHostname.values(), hasSize(1));
|
||||
|
||||
SshUri sshKey = sshKeysByHostname.get(HOST1);
|
||||
assertMainRepo(sshKey);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMultipleSshUriPropertiess() {
|
||||
SshUriProperties sshUriProperties = mainRepoPropertiesFixture();
|
||||
addRepoProperties(sshUriProperties, SshUri.builder()
|
||||
.uri(URI2)
|
||||
.privateKey(PRIVATE_KEY2)
|
||||
.buildAsNestedRepo(), "repo2");
|
||||
addRepoProperties(sshUriProperties, SshUri.builder()
|
||||
.uri(URI3)
|
||||
.privateKey(PRIVATE_KEY3)
|
||||
.buildAsNestedRepo(), "repo3");
|
||||
|
||||
SshUriPropertyProcessor sshUriPropertyProcessor = new SshUriPropertyProcessor(sshUriProperties);
|
||||
|
||||
Map<String, SshUri> sshKeysByHostname = sshUriPropertyProcessor.getSshKeysByHostname();
|
||||
|
||||
assertThat(sshKeysByHostname.values(), hasSize(3));
|
||||
|
||||
SshUri sshKey1 = sshKeysByHostname.get(HOST1);
|
||||
assertMainRepo(sshKey1);
|
||||
|
||||
SshUri sshKey2 = sshKeysByHostname.get(HOST2);
|
||||
|
||||
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)));
|
||||
|
||||
SshUri sshKey3 = sshKeysByHostname.get(HOST3);
|
||||
|
||||
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
|
||||
public void testSameHostnameDifferentKeysFirstOneWins() {
|
||||
SshUriProperties sshUriProperties = mainRepoPropertiesFixture();
|
||||
addRepoProperties(sshUriProperties, SshUri.builder().uri(URI1)
|
||||
.privateKey(PRIVATE_KEY1)
|
||||
.hostKey(HOST_KEY1)
|
||||
.hostKeyAlgorithm(ALGO1)
|
||||
.buildAsNestedRepo(), "repo2");
|
||||
|
||||
SshUriPropertyProcessor sshUriPropertyProcessor = new SshUriPropertyProcessor(sshUriProperties);
|
||||
Map<String, SshUri> sshKeysByHostname = sshUriPropertyProcessor.getSshKeysByHostname();
|
||||
|
||||
assertThat(sshKeysByHostname.values(), hasSize(1));
|
||||
|
||||
SshUri sshKey = sshKeysByHostname.get(HOST1);
|
||||
assertMainRepo(sshKey);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNoSshUriProperties() {
|
||||
SshUriPropertyProcessor sshUriPropertyProcessor = new SshUriPropertyProcessor(new SshUriProperties());
|
||||
Map<String, SshUri> sshKeysByHostname = sshUriPropertyProcessor.getSshKeysByHostname();
|
||||
assertThat(sshKeysByHostname.values(), hasSize(0));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInvalidUriDoesNotAddEntry() {
|
||||
SshUriPropertyProcessor sshUriPropertyProcessor = new SshUriPropertyProcessor(SshUri.builder().uri("invalid_uri").build());
|
||||
Map<String, SshUri> sshKeysByHostname = sshUriPropertyProcessor.getSshKeysByHostname();
|
||||
assertThat(sshKeysByHostname.values(), hasSize(0));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHttpsUriDoesNotAddEntry() {
|
||||
SshUriPropertyProcessor sshUriPropertyProcessor = new SshUriPropertyProcessor(SshUri.builder().uri("https://user@github.com/proj/repo.git").build());
|
||||
Map<String, SshUri> sshKeysByHostname = sshUriPropertyProcessor.getSshKeysByHostname();
|
||||
assertThat(sshKeysByHostname.values(), hasSize(0));
|
||||
}
|
||||
|
||||
private SshUriProperties mainRepoPropertiesFixture() {
|
||||
|
||||
return SshUri.builder()
|
||||
.uri(URI1)
|
||||
.hostKeyAlgorithm(ALGO1)
|
||||
.hostKey(HOST_KEY1)
|
||||
.privateKey(PRIVATE_KEY1)
|
||||
.build();
|
||||
}
|
||||
|
||||
private void addRepoProperties(SshUriProperties mainRepoProperties, SshUriNestedRepoProperties repoProperties, String repoName) {
|
||||
mainRepoProperties.addRepo(repoName, repoProperties);
|
||||
}
|
||||
|
||||
private void assertMainRepo(SshUri sshKey) {
|
||||
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)));
|
||||
}
|
||||
|
||||
}
|
||||
27
spring-cloud-config-server/src/test/resources/ssh/key
Normal file
27
spring-cloud-config-server/src/test/resources/ssh/key
Normal file
@@ -0,0 +1,27 @@
|
||||
-----BEGIN RSA PRIVATE KEY-----
|
||||
MIIEpAIBAAKCAQEAwQTXywKTzJEYXQ/LOR/hDciu4tJ1Av8zQQqi4ekL2hnOUzA0
|
||||
XecMmoYp31j3aWbT8RFNaUxFObfG7uGUWG21NlciqN7NtRkzTceygwBl25J9UEIo
|
||||
iSHkS2arMhSIQ/B5TIFmL8fucsMUzqZ0LFwd2NR5k+BL5Ip/g6Gp6NpY2lNlxG3W
|
||||
EaI/ee73vp8fJd9xge1o5Y/WFjCdP2TVfBuMTzswtjooakhQMg16c3YxcpK3Utbc
|
||||
J4gaPDAGSd9eu5YuxSnTyC4s+FMPsKF3zEu+kTb5iutiCvO4lFdvlhURN2WBecRt
|
||||
Am4nrMHEmLp3Yy440UTSOAzUUdxlfyltxvdOnQIDAQABAoIBABpQtbb4z/u44HB3
|
||||
ocZVAVLmxGkqNkfFUVCRyakxI6uFjyqqTMlsobxDhFvt/jVBjq20JTCw9FMtKhMR
|
||||
cC8qLeWNtaz+S19gYy08h6ryl/B6pVkW2/3uP/jDs51tTTKuC2uRzMPA51KAJEsU
|
||||
SIxvtqYEOdseXlp3Q3FHzilv82M4dKQCUXO/BbYV1jtgGHsJIJIcJhb8JIuXGScq
|
||||
krm+GrzXpejF8FjpEFJ+VRbh/wjbMqUD5/9KimtJ9tXK5MKaxZ2aerYVONrPIbRH
|
||||
Ij2tKS2o+cEBL9b0E2GHSGQyzs+g4+eTmsf56O8MWAoh5uib3pKXi84wxWi1ETQd
|
||||
+NIGuUECgYEA9VZuTCbJVEriqptZKw8BNn7xIlXkmABEWAmIlo8U4NodjP/WIyIB
|
||||
FtwYS4jUxfJhLdgs8mzb7O+EY6F+lusQBcAViRfk6a0VL9qrzYAY21d1X0hRtt4t
|
||||
NKixjQ1hESao/CQDOonsYIqolXlDsvYxDX0tWXkVjiXPVk71oPtaF80CgYEAyWhT
|
||||
j1v6XtFQT4KAQ10pQEbXBet9ae4M6WALAghdROMY60zX6XdXNGugycy3T9s9q712
|
||||
gxglhhhQO+RpEtaVOXvOzZv5aczrDqPwYOX1jJbIaOT4Iv2szjI518akRTef+ANW
|
||||
t+mETUBf+qYKhW91lfSmi5PUPrWBs5z8j9qcohECgYEA1XgfAKO/ClkeYNRLAexM
|
||||
Yd6Scg3KmXeh//hLoLVetUcT71usN2WfDQT1HsQwXwxHAlzWvxl5QvAlgYtDWo2t
|
||||
o1M/acogpDK1/K2IT4bmGfQ/bGjAsR0guHEQDGtXylSZNMshBA5+XoJHrceV4GHW
|
||||
zKXej7uLxeOgRLjvgOMzwQECgYAWSjJ9OiuyVK3zrritO+E12OExKYe+snbBWTy+
|
||||
o9hWqF94ow9+KhP/nC22R6696sCfgh9ckM6OUaCHkFbEm/T14KrZfHqU5/XXr/MJ
|
||||
dkm/nmxdl4GStcprI4ndRIGnm2lb1FrDjddziT1WCww9CkHUL7hC2EB0FDhffW9C
|
||||
KGqPUQKBgQCd85DH751a6EKN8dyKUyf3sP8BraTsc26DFk3q+vfhzSyJF4wxIVWa
|
||||
kmjx6kfGTu0+ED0UXWi5LnMSvne4rGU1j3rQyHs71t6JLVcFl8j5i8g/n91FA87C
|
||||
EIni0JgBvgbDNlM04mMFE6K0u5+Rt3Nx/yywW/w9nQUrzNio7MP+8w==
|
||||
-----END RSA PRIVATE KEY-----
|
||||
@@ -0,0 +1,41 @@
|
||||
spring:
|
||||
cloud:
|
||||
config:
|
||||
server:
|
||||
git:
|
||||
uri: git@gitserver.com:team/repo1.git
|
||||
ignoreLocalSshSettings: true
|
||||
privateKey: "-----BEGIN RSA PRIVATE KEY-----\nMIIEpAIBAAKCAQEAoqyz6YaYMTr7L8GLPSQpAQXaM04gRx4CCsGK2kfLQdw4BlqI\nyyxp38YcuZG9cUDBAxby+K2TKmwHaC1R61QTwbPuCRdIPrDwRz+FLoegm3iDLCmn\nuP6rjZDneYsqfU1KSdrOwIbCnONfDdvYL/vnZC/o8DDMlk5Orw2SfHkT3pq0o8km\nayBwN4Sf3bpyWTY0oZcmNeSCCoIdE59k8Pa7/t9bwY9caLj05C3DEsjucc7Ei/Eq\nTOyGyobtXwaya5CqKLUHes74Poz1aEP/yVFdUud91uezd8ZK1P1t5/ZKA3R6aHir\n+diDJ2/GQ2tD511FW46yw+EtBUJTO6ADVv4UnQIDAQABAoIBAF+5qwEfX82QfKFk\njfADqFFexUDtl1biFKeJrpC2MKhn01wByH9uejrhFKQqW8UaKroLthyZ34DWIyGt\nlDnHGv0gSVF2LuAdNLdobJGt49e4+c9yD61vxzm97Eh8mRs08SM2q/VlF35E2fmI\nxdWusUImYzd8L9e+6tRd8zZl9UhG5vR5XIstKqxC6S0g79aAt0hasE4Gw1FKOf2V\n4mlL15atjQSKCPdOicuyc4zpjAtU1A9AfF51iG8oOUuJebPW8tCftfOQxaeGFgMG\n7M9aai1KzXR6M5IBAKEv31yBvz/SHTneP7oZXNLeC1GIR420PKybmeZdNK8BbEAu\n3reKgm0CgYEA03Sx8JoF5UBsIvFPpP1fjSlTgKryM5EJR6KQtj5e4YfyxccJepN8\nq4MrqDfNKleG/a1acEtDMhBNovU7Usp2QIP7zpAeioHBOhmE5WSieZGc3icOGWWq\nmRkdulSONruqWKv76ZoluxftekE03bDhZDNlcCgmrslEKB/ufHd2oc8CgYEAxPFa\nlKOdSeiYFV5CtvO8Ro8em6rGpSsVz4qkPxbeBqUDCb9KXHhq6YrhRxOIfQJKfT7M\nZFCn8ArJXKgOGu+KsvwIErFHF9g2jJMG4DOUTpkQgi2yveihFxcmz/AltyVXgrnv\nZWQbAerH77pdKKhNivLGgEv72GYawdYjYNjemdMCgYA2kEMmMahZyrDcp2YEzfit\nBT/t0K6kzcUWPgWXcSqsiZcEn+J7RbmCzFskkhmX1nQX23adyV3yejB+X0dKisHO\nzf/ZAmlPFkJVCqa3RquCMSfIT02dEhXeYZPBM/Zqeyxuqxpa4hLgX0FBLbhFiFHw\nuC5xrXql2XuD2xF//peXEwKBgQC+pa28Cg7vRxxCQzduB9CQtWc55j3aEjVQ7bNF\n54sS/5ZLT0Ra8677WZfuyDfuW9NkHvCZg4Ku2qJG8eCFrrGjxlrCTZ62tHVJ6+JS\nE1xUIdRbUIWhVZrr0VufG6hG/P0T7Y6Tpi6G0pKtvMkF3LcD9TS3adboix8H2ZXx\n4L7MRQKBgQC0OO3qqNXOjIVYWOoqXLybOY/Wqu9lxCAgGyCYaMcstnBI7W0MZTBr\n/syluvGsaFc1sE7MMGOOzKi1tF4YvDmSnzA/R1nmaPguuD9fOA+w7Pwkv5vLvuJq\n2U7EeNwxq1I1L3Ag6E7wH4BHLHd4TKaZR6agFkn8oomz71yZPGjuZQ==\n-----END RSA PRIVATE KEY-----"
|
||||
repos:
|
||||
repo1:
|
||||
uri: git@gitserver.com:team/repo2.git
|
||||
hostKey: someHostKey
|
||||
hostKeyAlgorithm: ssh-rsa
|
||||
privateKey: |
|
||||
-----BEGIN RSA PRIVATE KEY-----
|
||||
MIIEpgIBAAKCAQEAx4UbaDzY5xjW6hc9jwN0mX33XpTDVW9WqHp5AKaRbtAC3DqX
|
||||
IXFMPgw3K45jxRb93f8tv9vL3rD9CUG1Gv4FM+o7ds7FRES5RTjv2RT/JVNJCoqF
|
||||
ol8+ngLqRZCyBtQN7zYByWMRirPGoDUqdPYrj2yq+ObBBNhg5N+hOwKjjpzdj2Ud
|
||||
1l7R+wxIqmJo1IYyy16xS8WsjyQuyC0lL456qkd5BDZ0Ag8j2X9H9D5220Ln7s9i
|
||||
oezTipXipS7p7Jekf3Ywx6abJwOmB0rX79dV4qiNcGgzATnG1PkXxqt76VhcGa0W
|
||||
DDVHEEYGbSQ6hIGSh0I7BQun0aLRZojfE3gqHQIDAQABAoIBAQCZmGrk8BK6tXCd
|
||||
fY6yTiKxFzwb38IQP0ojIUWNrq0+9Xt+NsypviLHkXfXXCKKU4zUHeIGVRq5MN9b
|
||||
BO56/RrcQHHOoJdUWuOV2qMqJvPUtC0CpGkD+valhfD75MxoXU7s3FK7yjxy3rsG
|
||||
EmfA6tHV8/4a5umo5TqSd2YTm5B19AhRqiuUVI1wTB41DjULUGiMYrnYrhzQlVvj
|
||||
5MjnKTlYu3V8PoYDfv1GmxPPh6vlpafXEeEYN8VB97e5x3DGHjZ5UrurAmTLTdO8
|
||||
+AahyoKsIY612TkkQthJlt7FJAwnCGMgY6podzzvzICLFmmTXYiZ/28I4BX/mOSe
|
||||
pZVnfRixAoGBAO6Uiwt40/PKs53mCEWngslSCsh9oGAaLTf/XdvMns5VmuyyAyKG
|
||||
ti8Ol5wqBMi4GIUzjbgUvSUt+IowIrG3f5tN85wpjQ1UGVcpTnl5Qo9xaS1PFScQ
|
||||
xrtWZ9eNj2TsIAMp/svJsyGG3OibxfnuAIpSXNQiJPwRlW3irzpGgVx/AoGBANYW
|
||||
dnhshUcEHMJi3aXwR12OTDnaLoanVGLwLnkqLSYUZA7ZegpKq90UAuBdcEfgdpyi
|
||||
PhKpeaeIiAaNnFo8m9aoTKr+7I6/uMTlwrVnfrsVTZv3orxjwQV20YIBCVRKD1uX
|
||||
VhE0ozPZxwwKSPAFocpyWpGHGreGF1AIYBE9UBtjAoGBAI8bfPgJpyFyMiGBjO6z
|
||||
FwlJc/xlFqDusrcHL7abW5qq0L4v3R+FrJw3ZYufzLTVcKfdj6GelwJJO+8wBm+R
|
||||
gTKYJItEhT48duLIfTDyIpHGVm9+I1MGhh5zKuCqIhxIYr9jHloBB7kRm0rPvYY4
|
||||
VAykcNgyDvtAVODP+4m6JvhjAoGBALbtTqErKN47V0+JJpapLnF0KxGrqeGIjIRV
|
||||
cYA6V4WYGr7NeIfesecfOC356PyhgPfpcVyEztwlvwTKb3RzIT1TZN8fH4YBr6Ee
|
||||
KTbTjefRFhVUjQqnucAvfGi29f+9oE3Ei9f7wA+H35ocF6JvTYUsHNMIO/3gZ38N
|
||||
CPjyCMa9AoGBAMhsITNe3QcbsXAbdUR00dDsIFVROzyFJ2m40i4KCRM35bC/BIBs
|
||||
q0TY3we+ERB40U8Z2BvU61QuwaunJ2+uGadHo58VSVdggqAo0BSkH58innKKt96J
|
||||
69pcVH/4rmLbXdcmNYGm6iu+MlPQk4BUZknHSmVHIFdJ0EPupVaQ8RHT
|
||||
-----END RSA PRIVATE KEY-----
|
||||
@@ -0,0 +1,35 @@
|
||||
spring:
|
||||
cloud:
|
||||
config:
|
||||
server:
|
||||
git:
|
||||
uri: git@gitserver.com:team/repo.git
|
||||
ignoreLocalSshSettings: true
|
||||
privateKey: |
|
||||
-----BEGIN RSA PRIVATE KEY-----
|
||||
MIIEpAIBAAKCAQEAoqyz6YaYMTr7L8GLPSQpAQXaM04gRx4CCsGK2kfLQdw4BlqI
|
||||
yyxp38YcuZG9cUDBAxby+K2TKmwHaC1Wf1QTwbPuCRdIPrDwRz+FLoegm3iDLCmn
|
||||
uP6rjZDneYsqfU1sSdrOwIbCnONfDdvYL/vnZC/o8DDMlk5Orw2SfHkT3pq0o8km
|
||||
ayBwN4Sf3bpyWTY0oZcmNeSCCoIdE59k8Pa7/t9bwY9caLj05C3DEsjucc7Ei/Eq
|
||||
TOyGyobtXwaya5CqKLUHes74Poz1aEP/yVFdUud91uezd8ZK1P1t5/ZKA3R6aHir
|
||||
+diDJ2/GQ2tD511FW46yw+EtBUJTO6ADVv4UnQIDAQABAoIBAF+5qwEfX82QfKFk
|
||||
jfADqFFexUDtl1biFKeJrpC2MKhn01wByH9uejrhFKQqW8UaKroLthyZ34DWIyGt
|
||||
lDnHGv0gSVF2LuAdNLdobJGt49e4+c9yD61vxzm97Eh8mRs08SM2q/VlF35E2fmI
|
||||
xdWusUImYzd8L9e+6tRd8zZl9UhG5vR5XIstKqxC6S0g79aAt0hasE4Gw1FKOf2V
|
||||
4mlL15atjQSKCPdOicuyc4zpjAtU1A9AfF51iG8oOUuJebPW8tCftfOQxaeGFgMG
|
||||
7M9aai1KzXR6M5IBAKEv31yBvz/SHTneP7oZXNLeC1GIR420PKybmeZdNK8BbEAu
|
||||
3reKgm0CgYEA03Sx8JgF5UBsIvFPpP1fjSlTgKryM5EJR6KQtj5e4YfyxccJepN8
|
||||
q4MrqDfNKleG/a1acEtDMhBNovU7Usp2QIP7zpAeioHBOhmE5WSieZGc3icOGWWq
|
||||
mRkdulSONruqWKv76ZoluxftekE03bDhZDNlcCgmrslEKB/ufHd2oc8CgYEAxPFa
|
||||
lKOdSeiYFV5CtvO8Ro8em6rGpSsVz4qkPxbeBqUDCb9KXHhq6YrhRxOIfQJKfT7M
|
||||
ZFCn8ArJXKgOGu+KsvwIErFHF9g2jJMG4DOUTpkQgi2yveihFxcmz/AltyVXgrnv
|
||||
ZWQbAerH77pdKKhNivLGgEv72GYawdYjYNjemdMCgYA2kEMmMahZyrDcp2YEzfit
|
||||
BT/t0K6kzcUWPgWXcSqsiZcEn+J7RbmCzFskkhmX1nQX23adyV3yejB+X0dKisHO
|
||||
zf/ZAmlPFkJVCqa3RquCMSfIT02dEhXeYZPBM/Zqeyxuqxpa4hLgX0FBLbhFiFHw
|
||||
uC5xrXql2XuD2xF//peXEwKBgQC+pa28Cg7vRxxCQzduB9CQtWc55j3aEjVQ7bNF
|
||||
54sS/5ZLT0Ra8677WZfuyDfuW9NkHvCZg4Ku2qJG8eCFrrGjxlrCTZ62tHVJ6+JS
|
||||
E1xUIdRbUIWhVZrr0VufG6hG/P0T7Y6Tpi6G0pKtvMkF3LcD9TS3adboix8H2ZXx
|
||||
4L7MRQKBgQC0OO3qqNXOjIVYWOoqXLybOY/Wqu9lxCAgGyCYaMcstnBI7W0MZTBr
|
||||
/syluvGsaFc1sE7MMGOOzKi1tF4YvDmSnzA/R1nmaPguuD9fOA+w7Pwkv5vLvuJq
|
||||
2U7EeNwxq1I1L3Ag6E7wH4BHLHd4TKaZR6agFkn8oomz71yZPGjuZQ==
|
||||
-----END RSA PRIVATE KEY-----
|
||||
@@ -0,0 +1,10 @@
|
||||
spring:
|
||||
cloud:
|
||||
config:
|
||||
server:
|
||||
git:
|
||||
uri: git@gitserver.com:team/repo.git
|
||||
ignoreLocalSshSettings: true
|
||||
privateKey: "-----BEGIN RSA PRIVATE KEY-----\nMIIEpAIBAAKCAQEAoqyz6YaYMTr7L8GLPSQpAQXaM04gRx4CCsGK2kfLQdw4BlqI\nyyxp38YcuZG9cUDBAxby+K2TKmwHaC1R61QTwbPuCRdIPrDwRz+FLoegm3iDLCmn\nuP6rjZDneYsqfU1KSdrOwIbCnONfDdvYL/vnZC/o8DDMlk5Orw2SfHkT3pq0o8km\nayBwN4Sf3bpyWTY0oZcmNeSCCoIdE59k8Pa7/t9bwY9caLj05C3DEsjucc7Ei/Eq\nTOyGyobtXwaya5CqKLUHes74Poz1aEP/yVFdUud91uezd8ZK1P1t5/ZKA3R6aHir\n+diDJ2/GQ2tD511FW46yw+EtBUJTO6ADVv4UnQIDAQABAoIBAF+5qwEfX82QfKFk\njfADqFFexUDtl1biFKeJrpC2MKhn01wByH9uejrhFKQqW8UaKroLthyZ34DWIyGt\nlDnHGv0gSVF2LuAdNLdobJGt49e4+c9yD61vxzm97Eh8mRs08SM2q/VlF35E2fmI\nxdWusUImYzd8L9e+6tRd8zZl9UhG5vR5XIstKqxC6S0g79aAt0hasE4Gw1FKOf2V\n4mlL15atjQSKCPdOicuyc4zpjAtU1A9AfF51iG8oOUuJebPW8tCftfOQxaeGFgMG\n7M9aai1KzXR6M5IBAKEv31yBvz/SHTneP7oZXNLeC1GIR420PKybmeZdNK8BbEAu\n3reKgm0CgYEA03Sx8JoF5UBsIvFPpP1fjSlTgKryM5EJR6KQtj5e4YfyxccJepN8\nq4MrqDfNKleG/a1acEtDMhBNovU7Usp2QIP7zpAeioHBOhmE5WSieZGc3icOGWWq\nmRkdulSONruqWKv76ZoluxftekE03bDhZDNlcCgmrslEKB/ufHd2oc8CgYEAxPFa\nlKOdSeiYFV5CtvO8Ro8em6rGpSsVz4qkPxbeBqUDCb9KXHhq6YrhRxOIfQJKfT7M\nZFCn8ArJXKgOGu+KsvwIErFHF9g2jJMG4DOUTpkQgi2yveihFxcmz/AltyVXgrnv\nZWQbAerH77pdKKhNivLGgEv72GYawdYjYNjemdMCgYA2kEMmMahZyrDcp2YEzfit\nBT/t0K6kzcUWPgWXcSqsiZcEn+J7RbmCzFskkhmX1nQX23adyV3yejB+X0dKisHO\nzf/ZAmlPFkJVCqa3RquCMSfIT02dEhXeYZPBM/Zqeyxuqxpa4hLgX0FBLbhFiFHw\nuC5xrXql2XuD2xF//peXEwKBgQC+pa28Cg7vRxxCQzduB9CQtWc55j3aEjVQ7bNF\n54sS/5ZLT0Ra8677WZfuyDfuW9NkHvCZg4Ku2qJG8eCFrrGjxlrCTZ62tHVJ6+JS\nE1xUIdRbUIWhVZrr0VufG6hG/P0T7Y6Tpi6G0pKtvMkF3LcD9TS3adboix8H2ZXx\n4L7MRQKBgQC0OO3qqNXOjIVYWOoqXLybOY/Wqu9lxCAgGyCYaMcstnBI7W0MZTBr\n/syluvGsaFc1sE7MMGOOzKi1tF4YvDmSnzA/R1nmaPguuD9fOA+w7Pwkv5vLvuJq\n2U7EeNwxq1I1L3Ag6E7wH4BHLHd4TKaZR6agFkn8oomz71yZPGjuZQ==\n-----END RSA PRIVATE KEY-----"
|
||||
hostKey: somekey
|
||||
hostKeyAlgorithm: ssh-rsa
|
||||
Reference in New Issue
Block a user