Git SSH configuration using properties
By default, Spring Cloud Config Server uses SSH configuration files such as ~/.ssh/known_hosts and /etc/ssh/ssh_config when connecting to Git repositories using an SSH URI. 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
This commit is contained in:
@@ -6,8 +6,10 @@
|
||||
<parent>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-config</artifactId>
|
||||
<version>1.3.2.BUILD-SNAPSHOT</version>
|
||||
<version>1.4.0.BUILD-SNAPSHOT</version>
|
||||
<relativePath>..</relativePath>
|
||||
</parent>
|
||||
|
||||
<packaging>pom</packaging>
|
||||
<name>Spring Cloud Config Docs</name>
|
||||
<description>Spring Cloud Docs</description>
|
||||
|
||||
@@ -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, 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
|
||||
|
||||
|*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,101 @@
|
||||
/*
|
||||
* 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) {
|
||||
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");
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -21,7 +21,6 @@ import java.io.IOException;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.eclipse.jgit.api.CheckoutCommand;
|
||||
import org.eclipse.jgit.api.CloneCommand;
|
||||
import org.eclipse.jgit.api.CreateBranchCommand.SetupUpstreamMode;
|
||||
@@ -43,9 +42,6 @@ import org.eclipse.jgit.errors.NoRemoteRepositoryException;
|
||||
import org.eclipse.jgit.lib.Ref;
|
||||
import org.eclipse.jgit.transport.CredentialsProvider;
|
||||
import org.eclipse.jgit.transport.FetchResult;
|
||||
import org.eclipse.jgit.transport.JschConfigSessionFactory;
|
||||
import org.eclipse.jgit.transport.OpenSshConfig.Host;
|
||||
import org.eclipse.jgit.transport.SshSessionFactory;
|
||||
import org.eclipse.jgit.transport.TagOpt;
|
||||
import org.eclipse.jgit.transport.UsernamePasswordCredentialsProvider;
|
||||
import org.eclipse.jgit.util.FileUtils;
|
||||
@@ -56,8 +52,6 @@ import org.springframework.core.io.UrlResource;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import com.jcraft.jsch.Session;
|
||||
|
||||
import static org.springframework.util.StringUtils.hasText;
|
||||
|
||||
/**
|
||||
@@ -81,8 +75,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.
|
||||
@@ -174,7 +166,6 @@ public class JGitEnvironmentRepository extends AbstractScmEnvironmentRepository
|
||||
@Override
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
Assert.state(getUri() != null, "You need to configure a uri for the git repository");
|
||||
initialize();
|
||||
if (this.cloneOnStart) {
|
||||
initClonedRepository();
|
||||
}
|
||||
@@ -184,7 +175,6 @@ public class JGitEnvironmentRepository extends AbstractScmEnvironmentRepository
|
||||
* Get the working directory ready.
|
||||
*/
|
||||
public String refresh(String label) {
|
||||
initialize();
|
||||
Git git = null;
|
||||
try {
|
||||
git = createGitClient();
|
||||
@@ -422,18 +412,6 @@ public class JGitEnvironmentRepository extends AbstractScmEnvironmentRepository
|
||||
}
|
||||
}
|
||||
|
||||
private void initialize() {
|
||||
if (!this.initialized) {
|
||||
SshSessionFactory.setInstance(new JschConfigSessionFactory() {
|
||||
@Override
|
||||
protected void configure(Host hc, Session session) {
|
||||
session.setConfig("StrictHostKeyChecking", isStrictHostKeyChecking() ? "yes" : "no");
|
||||
}
|
||||
});
|
||||
this.initialized = true;
|
||||
}
|
||||
}
|
||||
|
||||
private void configureCommand(TransportCommand<?, ?> command) {
|
||||
command.setTimeout(this.timeout);
|
||||
if (this.transportConfigCallback != null) {
|
||||
|
||||
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* 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.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;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
|
||||
/**
|
||||
* In a cloud environment local SSH config files such as `.known_hosts` may not be suitable for providing
|
||||
* configuration settings due to ephemeral filesystems. This flag enables SSH config to be provided as application
|
||||
* properties
|
||||
* @author William Tran
|
||||
* @author Ollie Hughes
|
||||
*/
|
||||
public class PropertyBasedSshSessionFactory extends JschConfigSessionFactory {
|
||||
|
||||
private final Map<String, SshUriProperties> sshKeysByHostname;
|
||||
private final JSch jSch;
|
||||
|
||||
public PropertyBasedSshSessionFactory(Map<String, SshUriProperties> sshKeysByHostname, JSch jSch) {
|
||||
this.sshKeysByHostname = sshKeysByHostname;
|
||||
this.jSch = jSch;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configure(Host hc, Session session) {
|
||||
SshUriProperties 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("StrictHostKeyChecking", "no");
|
||||
} else {
|
||||
session.setConfig("StrictHostKeyChecking", "yes");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Session createSession(Host hc, String user, String host, int port, FS fs) throws JSchException {
|
||||
if (sshKeysByHostname.containsKey(host)) {
|
||||
SshUriProperties 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,110 @@
|
||||
/*
|
||||
* 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.JSch;
|
||||
import com.jcraft.jsch.JSchException;
|
||||
import com.jcraft.jsch.KeyPair;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
import java.util.*;
|
||||
|
||||
import static java.lang.String.format;
|
||||
import static org.springframework.util.StringUtils.hasText;
|
||||
|
||||
/**
|
||||
* Validate SSH related properties
|
||||
*
|
||||
* @author Ollie Hughes
|
||||
*/
|
||||
@Component
|
||||
@EnableConfigurationProperties(SshUriProperties.class)
|
||||
public class SshPropertyValidator {
|
||||
|
||||
private final SshUriProperties sshUriProperties;
|
||||
private final JSch jsch = new JSch();
|
||||
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"));
|
||||
private static final String GIT_PROPERTY_PREFIX = "spring.cloud.config.server.git.";
|
||||
|
||||
@Autowired
|
||||
public SshPropertyValidator(SshUriProperties sshUriProperties) {
|
||||
this.sshUriProperties = sshUriProperties;
|
||||
}
|
||||
|
||||
static boolean isSshUri(Object uri) {
|
||||
return uri != null && (uri.toString().startsWith("ssh") || uri.toString().startsWith("git"));
|
||||
}
|
||||
|
||||
@PostConstruct
|
||||
public void validateSshConfigurationProperties() {
|
||||
List<SshUriProperties> allRepoProperties = new ArrayList<>();
|
||||
allRepoProperties.add(sshUriProperties);
|
||||
Map<String, SshUriProperties> repos = sshUriProperties.getRepos();
|
||||
if (repos != null) {
|
||||
allRepoProperties.addAll(repos.values());
|
||||
}
|
||||
for (SshUriProperties repoProperties : allRepoProperties) {
|
||||
if(isSshUri(repoProperties.getUri()) && sshUriProperties.isIgnoreLocalSshSettings()){
|
||||
validatePrivateKeyPresent();
|
||||
validatePrivateKeyFormat();
|
||||
validateAlgorithmSpecifiedWhenHostKeySet();
|
||||
validateHostKeySpecifiedWhenAlgorithmSet();
|
||||
validateHostKeyAlgorithmSupported();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void validatePrivateKeyFormat() {
|
||||
try {
|
||||
KeyPair.load(jsch, sshUriProperties.getPrivateKey().getBytes(), null);
|
||||
} catch (JSchException e) {
|
||||
throw new IllegalStateException(format("Property '%sprivateKey' contains an invalid value", GIT_PROPERTY_PREFIX));
|
||||
}
|
||||
}
|
||||
|
||||
protected void validateHostKeyAlgorithmSupported() {
|
||||
if (hasText(sshUriProperties.getHostKeyAlgorithm())) {
|
||||
Assert.state(VALID_HOST_KEY_ALGORITHMS.contains(sshUriProperties.getHostKeyAlgorithm()),
|
||||
format("Property '%shostKeyAlgorithm' must be one of %s", GIT_PROPERTY_PREFIX, VALID_HOST_KEY_ALGORITHMS));
|
||||
}
|
||||
}
|
||||
|
||||
protected void validatePrivateKeyPresent() {
|
||||
Assert.state(sshUriProperties.getPrivateKey() != null,
|
||||
format("Property '%sprivateKey' must be set when '%signoreLocalSshSettings' is set to 'true'", GIT_PROPERTY_PREFIX, GIT_PROPERTY_PREFIX));
|
||||
}
|
||||
|
||||
protected void validateHostKeySpecifiedWhenAlgorithmSet() {
|
||||
if (hasText(sshUriProperties.getHostKeyAlgorithm())) {
|
||||
Assert.state(hasText(sshUriProperties.getHostKey()),
|
||||
format("Property '%shostKey' must be set when 'hostKeyAlgorithm' is specified", GIT_PROPERTY_PREFIX));
|
||||
}
|
||||
}
|
||||
|
||||
protected void validateAlgorithmSpecifiedWhenHostKeySet() {
|
||||
if (hasText(sshUriProperties.getHostKey())) {
|
||||
Assert.state(hasText(sshUriProperties.getHostKeyAlgorithm()),
|
||||
format("Property '%shostKeyAlgorithm' must be set when 'hostKey' is specified", GIT_PROPERTY_PREFIX));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,251 @@
|
||||
/*
|
||||
* 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.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.web.util.UriComponentsBuilder;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Data container for property based SSH config
|
||||
*
|
||||
* @author Ollie Hughes
|
||||
*/
|
||||
@ConfigurationProperties("spring.cloud.config.server.git")
|
||||
public class SshUriProperties {
|
||||
private String uri;
|
||||
private String hostKeyAlgorithm;
|
||||
private String hostKey;
|
||||
private String privateKey;
|
||||
private String username;
|
||||
private String password;
|
||||
private boolean ignoreLocalSshSettings;
|
||||
private boolean strictHostKeyChecking = true;
|
||||
|
||||
private Map<String, SshUriProperties> repos = new HashMap<>();
|
||||
|
||||
public SshUriProperties(String uri, String hostKeyAlgorithm, String hostKey, String privateKey, String username, String password, boolean ignoreLocalSshSettings, boolean strictHostKeyChecking, Map<String, SshUriProperties> repos) {
|
||||
this.uri = uri;
|
||||
this.hostKeyAlgorithm = hostKeyAlgorithm;
|
||||
this.hostKey = hostKey;
|
||||
this.privateKey = privateKey;
|
||||
this.username = username;
|
||||
this.password = password;
|
||||
this.ignoreLocalSshSettings = ignoreLocalSshSettings;
|
||||
this.strictHostKeyChecking = strictHostKeyChecking;
|
||||
this.repos = repos;
|
||||
}
|
||||
|
||||
public SshUriProperties() {
|
||||
}
|
||||
|
||||
public static SshUriPropertiesBuilder builder() {
|
||||
return new SshUriPropertiesBuilder();
|
||||
}
|
||||
|
||||
public boolean isSshUri() {
|
||||
return uri != null && !uri.startsWith("http");
|
||||
}
|
||||
|
||||
public String getHostname() {
|
||||
if (getUri() == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (getUri().matches("^[a-z]+://.*")) {
|
||||
return UriComponentsBuilder.fromUriString(uri).build().getHost();
|
||||
}
|
||||
else if (getUri().indexOf('@') < getUri().indexOf(':')) {
|
||||
return getUri().substring(getUri().indexOf('@') + 1, uri.indexOf(':'));
|
||||
}
|
||||
else if (getUri().startsWith("ssh:") && getUri().indexOf('@') > 0) {
|
||||
String postAt = getUri().substring(getUri().indexOf('@') + 1);
|
||||
return postAt.substring(0, postAt.indexOf(":"));
|
||||
}
|
||||
else return null;
|
||||
}
|
||||
|
||||
public String getUri() {
|
||||
return this.uri;
|
||||
}
|
||||
|
||||
public String getHostKeyAlgorithm() {
|
||||
return this.hostKeyAlgorithm;
|
||||
}
|
||||
|
||||
public String getHostKey() {
|
||||
return this.hostKey;
|
||||
}
|
||||
|
||||
public String getPrivateKey() {
|
||||
return this.privateKey;
|
||||
}
|
||||
|
||||
public String getUsername() {
|
||||
return this.username;
|
||||
}
|
||||
|
||||
public String getPassword() {
|
||||
return this.password;
|
||||
}
|
||||
|
||||
public boolean isIgnoreLocalSshSettings() {
|
||||
return this.ignoreLocalSshSettings;
|
||||
}
|
||||
|
||||
public boolean isStrictHostKeyChecking() {
|
||||
return this.strictHostKeyChecking;
|
||||
}
|
||||
|
||||
public Map<String, SshUriProperties> getRepos() {
|
||||
return this.repos;
|
||||
}
|
||||
|
||||
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 setUsername(String username) {
|
||||
this.username = username;
|
||||
}
|
||||
|
||||
public void setPassword(String password) {
|
||||
this.password = password;
|
||||
}
|
||||
|
||||
public void setIgnoreLocalSshSettings(boolean ignoreLocalSshSettings) {
|
||||
this.ignoreLocalSshSettings = ignoreLocalSshSettings;
|
||||
}
|
||||
|
||||
public void setStrictHostKeyChecking(boolean strictHostKeyChecking) {
|
||||
this.strictHostKeyChecking = strictHostKeyChecking;
|
||||
}
|
||||
|
||||
public void setRepos(Map<String, SshUriProperties> repos) {
|
||||
this.repos = repos;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(uri, hostKeyAlgorithm, hostKey, privateKey, username, password, ignoreLocalSshSettings, strictHostKeyChecking);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (obj == null || getClass() != obj.getClass()) {
|
||||
return false;
|
||||
}
|
||||
final SshUriProperties other = (SshUriProperties) obj;
|
||||
return Objects.equals(this.uri, other.uri)
|
||||
&& Objects.equals(this.hostKeyAlgorithm, other.hostKeyAlgorithm)
|
||||
&& Objects.equals(this.hostKey, other.hostKey)
|
||||
&& Objects.equals(this.privateKey, other.privateKey)
|
||||
&& Objects.equals(this.username, other.username)
|
||||
&& Objects.equals(this.password, other.password)
|
||||
&& Objects.equals(this.ignoreLocalSshSettings, other.ignoreLocalSshSettings)
|
||||
&& Objects.equals(this.strictHostKeyChecking, other.strictHostKeyChecking);
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return "org.springframework.cloud.config.server.ssh.SshUriProperties(uri=" + this.getUri() + " hostKeyAlgorithm=" + this.getHostKeyAlgorithm() + ", hostKey=" + this.getHostKey() + ", privateKey=" + this.getPrivateKey() + ", username=" + this.getUsername() + ", password=" + this.getPassword() + ", ignoreLocalSshSettings=" + this.isIgnoreLocalSshSettings() + ", strictHostKeyChecking=" + this.isStrictHostKeyChecking() + ", repos=" + this.getRepos() + ")";
|
||||
}
|
||||
|
||||
public static class SshUriPropertiesBuilder {
|
||||
private String uri;
|
||||
private String hostKeyAlgorithm;
|
||||
private String hostKey;
|
||||
private String privateKey;
|
||||
private String username;
|
||||
private String password;
|
||||
private boolean ignoreLocalSshSettings;
|
||||
private boolean strictHostKeyChecking = true;
|
||||
private Map<String, SshUriProperties> repos;
|
||||
|
||||
SshUriPropertiesBuilder() {
|
||||
}
|
||||
|
||||
public SshUriProperties.SshUriPropertiesBuilder uri(String uri) {
|
||||
this.uri = uri;
|
||||
return this;
|
||||
}
|
||||
|
||||
public SshUriProperties.SshUriPropertiesBuilder hostKeyAlgorithm(String hostKeyAlgorithm) {
|
||||
this.hostKeyAlgorithm = hostKeyAlgorithm;
|
||||
return this;
|
||||
}
|
||||
|
||||
public SshUriProperties.SshUriPropertiesBuilder hostKey(String hostKey) {
|
||||
this.hostKey = hostKey;
|
||||
return this;
|
||||
}
|
||||
|
||||
public SshUriProperties.SshUriPropertiesBuilder privateKey(String privateKey) {
|
||||
this.privateKey = privateKey;
|
||||
return this;
|
||||
}
|
||||
|
||||
public SshUriProperties.SshUriPropertiesBuilder username(String username) {
|
||||
this.username = username;
|
||||
return this;
|
||||
}
|
||||
|
||||
public SshUriProperties.SshUriPropertiesBuilder password(String password) {
|
||||
this.password = password;
|
||||
return this;
|
||||
}
|
||||
|
||||
public SshUriProperties.SshUriPropertiesBuilder ignoreLocalSshSettings(boolean ignoreLocalSshSettings) {
|
||||
this.ignoreLocalSshSettings = ignoreLocalSshSettings;
|
||||
return this;
|
||||
}
|
||||
|
||||
public SshUriProperties.SshUriPropertiesBuilder strictHostKeyChecking(boolean strictHostKeyChecking) {
|
||||
this.strictHostKeyChecking = strictHostKeyChecking;
|
||||
return this;
|
||||
}
|
||||
|
||||
public SshUriProperties.SshUriPropertiesBuilder repos(Map<String, SshUriProperties> repos) {
|
||||
this.repos = repos;
|
||||
return this;
|
||||
}
|
||||
|
||||
public SshUriProperties build() {
|
||||
return new SshUriProperties(uri, hostKeyAlgorithm, hostKey, privateKey, username, password, ignoreLocalSshSettings, strictHostKeyChecking, repos);
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return "org.springframework.cloud.config.server.ssh.SshUriProperties.SshUriPropertiesBuilder(uri=" + this.uri + "hostKeyAlgorithm=" + this.hostKeyAlgorithm + ", hostKey=" + this.hostKey + ", privateKey=" + this.privateKey + ", username=" + this.username + ", password=" + this.password + ", ignoreLocalSshSettings=" + this.ignoreLocalSshSettings + ", strictHostKeyChecking=" + this.strictHostKeyChecking + ", repos=" + this.repos + ")";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
* 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.web.util.UriComponentsBuilder;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
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, SshUriProperties> getSshKeysByHostname() {
|
||||
return extractNestedProperties(sshUriProperties);
|
||||
}
|
||||
|
||||
private Map<String, SshUriProperties> extractNestedProperties(SshUriProperties uriProperties) {
|
||||
Map<String, SshUriProperties> sshUriPropertyMap = new HashMap<>();
|
||||
String parentUri = uriProperties.getUri();
|
||||
if (isSshUri(parentUri) && getHostname(parentUri) != null) {
|
||||
sshUriPropertyMap.put(getHostname(parentUri), uriProperties);
|
||||
}
|
||||
Map<String, SshUriProperties> repos = uriProperties.getRepos();
|
||||
if(repos != null) {
|
||||
for (SshUriProperties repoProperties : repos.values()) {
|
||||
String repoUri = repoProperties.getUri();
|
||||
if (isSshUri(repoUri) && getHostname(repoUri) != null) {
|
||||
sshUriPropertyMap.put(getHostname(repoUri), repoProperties);
|
||||
}
|
||||
}
|
||||
}
|
||||
return sshUriPropertyMap;
|
||||
}
|
||||
|
||||
private String getHostname(String uri) {
|
||||
if (uri == null) {
|
||||
return null;
|
||||
}
|
||||
else if (uri.matches("^[a-z]+://.*")) {
|
||||
return UriComponentsBuilder.fromUriString(uri).build().getHost();
|
||||
}
|
||||
else if (uri.indexOf('@') < uri.indexOf(':')) {
|
||||
return uri.substring(uri.indexOf('@') + 1, uri.indexOf(':'));
|
||||
}
|
||||
else if (uri.startsWith("ssh:") && uri.indexOf('@') > 0) {
|
||||
String postAt = uri.substring(uri.indexOf('@') + 1);
|
||||
return postAt.substring(0, postAt.indexOf(":"));
|
||||
}
|
||||
else return null;
|
||||
}
|
||||
}
|
||||
@@ -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";
|
||||
}
|
||||
}
|
||||
@@ -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,160 @@
|
||||
/*
|
||||
* 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.Mockito;
|
||||
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() {
|
||||
SshUriProperties 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() {
|
||||
SshUriProperties 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() {
|
||||
SshUriProperties 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 {
|
||||
SshUriProperties sshKey = new SshUriProperties.SshUriPropertiesBuilder()
|
||||
.uri("git@gitlab.example.local:someorg/somerepo.git")
|
||||
.privateKey(PRIVATE_KEY)
|
||||
.build();
|
||||
setupSessionFactory(sshKey);
|
||||
|
||||
factory.createSession(hc, null, sshKey.getHostname(), 22, null);
|
||||
verify(jSch).addIdentity("gitlab.example.local", PRIVATE_KEY.getBytes(), null, null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void hostKeyIsUsed() throws Exception {
|
||||
SshUriProperties 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, sshKey.getHostname(), 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(SshUriProperties sshKey) {
|
||||
Map<String, SshUriProperties> sshKeysByHostname = new HashMap<>();
|
||||
sshKeysByHostname.put(sshKey.getHostname(), sshKey);
|
||||
factory = new PropertyBasedSshSessionFactory(sshKeysByHostname, jSch) ;
|
||||
when(hc.getHostName()).thenReturn(sshKey.getHostname());
|
||||
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,185 @@
|
||||
/*
|
||||
* 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.Test;
|
||||
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
/**
|
||||
* 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";
|
||||
|
||||
@Test
|
||||
public void supportedParametersSuccesful() throws Exception {
|
||||
SshUriProperties validSettings = SshUriProperties.builder()
|
||||
.uri(SSH_URI)
|
||||
.ignoreLocalSshSettings(true)
|
||||
.privateKey(VALID_PRIVATE_KEY)
|
||||
.hostKey(VALID_HOST_KEY)
|
||||
.hostKeyAlgorithm("ssh-rsa")
|
||||
.build();
|
||||
|
||||
SshPropertyValidator sshPropertyValidator = spy(new SshPropertyValidator(validSettings));
|
||||
sshPropertyValidator.validateSshConfigurationProperties();
|
||||
verify(sshPropertyValidator, times(1)).validatePrivateKeyFormat();
|
||||
verify(sshPropertyValidator, times(1)).validateAlgorithmSpecifiedWhenHostKeySet();
|
||||
verify(sshPropertyValidator, times(1)).validatePrivateKeyPresent();
|
||||
verify(sshPropertyValidator, times(1)).validateHostKeyAlgorithmSupported();
|
||||
verify(sshPropertyValidator, times(1)).validateHostKeySpecifiedWhenAlgorithmSet();
|
||||
}
|
||||
|
||||
@Test(expected = IllegalStateException.class)
|
||||
public void invalidPrivateKeyFails() throws Exception {
|
||||
|
||||
SshUriProperties invalidKey = SshUriProperties.builder()
|
||||
.uri(SSH_URI)
|
||||
.ignoreLocalSshSettings(true)
|
||||
.privateKey("invalid_key")
|
||||
.build();
|
||||
|
||||
SshPropertyValidator sshPropertyValidator = new SshPropertyValidator(invalidKey);
|
||||
sshPropertyValidator.validateSshConfigurationProperties();
|
||||
|
||||
}
|
||||
|
||||
@Test(expected = IllegalStateException.class)
|
||||
public void missingPrivateKeyFails() throws Exception {
|
||||
|
||||
SshUriProperties missingKey = SshUriProperties.builder()
|
||||
.uri(SSH_URI)
|
||||
.ignoreLocalSshSettings(true)
|
||||
.build();
|
||||
|
||||
SshPropertyValidator sshPropertyValidator = new SshPropertyValidator(missingKey);
|
||||
sshPropertyValidator.validateSshConfigurationProperties();
|
||||
}
|
||||
|
||||
@Test(expected = IllegalStateException.class)
|
||||
public void hostKeyWithMissingAlgoFails() throws Exception {
|
||||
|
||||
SshUriProperties missingAlgo = SshUriProperties.builder()
|
||||
.uri(SSH_URI)
|
||||
.ignoreLocalSshSettings(true)
|
||||
.privateKey("invalid_key")
|
||||
.hostKey("some_host")
|
||||
.build();
|
||||
|
||||
SshPropertyValidator sshPropertyValidator = new SshPropertyValidator(missingAlgo);
|
||||
sshPropertyValidator.validateSshConfigurationProperties();
|
||||
}
|
||||
|
||||
@Test(expected = IllegalStateException.class)
|
||||
public void algoWithMissingHostKeyFails() throws Exception {
|
||||
|
||||
SshUriProperties missingHostKey = SshUriProperties.builder()
|
||||
.uri(SSH_URI)
|
||||
.ignoreLocalSshSettings(true)
|
||||
.privateKey("invalid_key")
|
||||
.hostKeyAlgorithm("some_host_algo")
|
||||
.build();
|
||||
|
||||
SshPropertyValidator sshPropertyValidator = new SshPropertyValidator(missingHostKey);
|
||||
sshPropertyValidator.validateSshConfigurationProperties();
|
||||
}
|
||||
|
||||
@Test(expected = IllegalStateException.class)
|
||||
public void unsupportedAlgoFails() throws Exception {
|
||||
|
||||
SshUriProperties unsupportedAlgo = SshUriProperties.builder()
|
||||
.uri(SSH_URI)
|
||||
.ignoreLocalSshSettings(true)
|
||||
.privateKey("invalid_key")
|
||||
.hostKey("some_host_key")
|
||||
.hostKeyAlgorithm("unsupported")
|
||||
.build();
|
||||
|
||||
SshPropertyValidator sshPropertyValidator = new SshPropertyValidator(unsupportedAlgo);
|
||||
sshPropertyValidator.validateSshConfigurationProperties();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void validatorNotRunIfIgnoreLocalSettingsFalse() throws Exception {
|
||||
|
||||
SshUriProperties useLocal = (SshUriProperties.builder()
|
||||
.uri(SSH_URI)
|
||||
.ignoreLocalSshSettings(false)
|
||||
.privateKey("invalid_key")
|
||||
.build());
|
||||
|
||||
SshPropertyValidator sshPropertyValidator = spy(new SshPropertyValidator(useLocal));
|
||||
sshPropertyValidator.validateSshConfigurationProperties();
|
||||
verify(sshPropertyValidator, times(0)).validatePrivateKeyFormat();
|
||||
verify(sshPropertyValidator, times(0)).validateAlgorithmSpecifiedWhenHostKeySet();
|
||||
verify(sshPropertyValidator, times(0)).validatePrivateKeyPresent();
|
||||
verify(sshPropertyValidator, times(0)).validateHostKeyAlgorithmSupported();
|
||||
verify(sshPropertyValidator, times(0)).validateHostKeySpecifiedWhenAlgorithmSet();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void validatorNotRunIfHttpsUri() throws Exception {
|
||||
|
||||
SshUriProperties httpsUri = (SshUriProperties.builder()
|
||||
.uri("https://somerepo.com/team/project.git")
|
||||
.ignoreLocalSshSettings(true)
|
||||
.privateKey("invalid_key")
|
||||
.build());
|
||||
|
||||
SshPropertyValidator sshPropertyValidator = spy(new SshPropertyValidator(httpsUri));
|
||||
sshPropertyValidator.validateSshConfigurationProperties();
|
||||
verify(sshPropertyValidator, times(0)).validatePrivateKeyFormat();
|
||||
verify(sshPropertyValidator, times(0)).validateAlgorithmSpecifiedWhenHostKeySet();
|
||||
verify(sshPropertyValidator, times(0)).validatePrivateKeyPresent();
|
||||
verify(sshPropertyValidator, times(0)).validateHostKeyAlgorithmSupported();
|
||||
verify(sshPropertyValidator, times(0)).validateHostKeySpecifiedWhenAlgorithmSet();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,138 @@
|
||||
/*
|
||||
* 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.eclipse.jgit.transport.SshSessionFactory;
|
||||
import org.junit.After;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
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 = "git@gitlab.test.local:wtran/my-repo";
|
||||
private static final String HOST1 = "gitlab.test.local";
|
||||
private static final String PRIVATE_KEY2 = "privateKey2";
|
||||
private static final String URI2 = "git@gitlab2.test.local:wtran/my-repo";
|
||||
private static final String HOST2 = "gitlab2.test.local";
|
||||
|
||||
@After
|
||||
public void cleanup() {
|
||||
SshSessionFactory.setInstance(null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSingleSshUriProperties() {
|
||||
SshUriPropertyProcessor sshUriPropertyProcessor = new SshUriPropertyProcessor(mainRepoPropertiesFixture());
|
||||
Map<String, SshUriProperties> sshKeysByHostname = sshUriPropertyProcessor.getSshKeysByHostname();
|
||||
|
||||
assertThat(sshKeysByHostname.values(), hasSize(1));
|
||||
|
||||
SshUriProperties sshKey = sshKeysByHostname.get(HOST1);
|
||||
assertMainRepo(sshKey);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMultipleSshUriPropertiess() {
|
||||
SshUriProperties sshUriProperties = mainRepoPropertiesFixture();
|
||||
addRepoProperties(sshUriProperties, SshUriProperties.builder()
|
||||
.uri(URI2)
|
||||
.privateKey(PRIVATE_KEY2)
|
||||
.build());
|
||||
|
||||
SshUriPropertyProcessor sshUriPropertyProcessor = new SshUriPropertyProcessor(sshUriProperties);
|
||||
|
||||
Map<String, SshUriProperties> sshKeysByHostname = sshUriPropertyProcessor.getSshKeysByHostname();
|
||||
|
||||
|
||||
SshUriProperties sshKey = sshKeysByHostname.get(HOST1);
|
||||
assertMainRepo(sshKey);
|
||||
|
||||
sshKey = sshKeysByHostname.get(HOST2);
|
||||
|
||||
assertThat(sshKeysByHostname.values(), hasSize(2));
|
||||
|
||||
assertThat(sshKey.getHostname(), is(equalTo(HOST2)));
|
||||
|
||||
assertThat(sshKey.getHostKeyAlgorithm(), is(nullValue()));
|
||||
|
||||
assertThat(sshKey.getHostKey(), is(nullValue()));
|
||||
|
||||
assertThat(sshKey.getPrivateKey(), is(equalTo(PRIVATE_KEY2)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSameHostnameDifferentKeysFirstOneWins() {
|
||||
SshUriProperties sshUriProperties = mainRepoPropertiesFixture();
|
||||
addRepoProperties(sshUriProperties, SshUriProperties.builder().uri(URI1)
|
||||
.privateKey(PRIVATE_KEY1)
|
||||
.hostKey(HOST_KEY1)
|
||||
.hostKeyAlgorithm(ALGO1)
|
||||
.build());
|
||||
|
||||
SshUriPropertyProcessor sshUriPropertyProcessor = new SshUriPropertyProcessor(sshUriProperties);
|
||||
Map<String, SshUriProperties> sshKeysByHostname = sshUriPropertyProcessor.getSshKeysByHostname();
|
||||
|
||||
assertThat(sshKeysByHostname.values(), hasSize(1));
|
||||
|
||||
SshUriProperties sshKey = sshKeysByHostname.get(HOST1);
|
||||
assertMainRepo(sshKey);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNoSshUriPropertiess() {
|
||||
SshUriPropertyProcessor sshUriPropertyProcessor = new SshUriPropertyProcessor(new SshUriProperties());
|
||||
Map<String, SshUriProperties> sshKeysByHostname = sshUriPropertyProcessor.getSshKeysByHostname();
|
||||
assertThat(sshKeysByHostname.values(), hasSize(0));
|
||||
}
|
||||
|
||||
private SshUriProperties mainRepoPropertiesFixture() {
|
||||
|
||||
return SshUriProperties.builder()
|
||||
.uri(URI1)
|
||||
.hostKeyAlgorithm(ALGO1)
|
||||
.hostKey(HOST_KEY1)
|
||||
.privateKey(PRIVATE_KEY1)
|
||||
.build();
|
||||
}
|
||||
|
||||
private void addRepoProperties(SshUriProperties mainRepoProperties, SshUriProperties repoProperties) {
|
||||
Map<String, SshUriProperties> repos = new HashMap<>();
|
||||
repos.put("repo2", repoProperties);
|
||||
mainRepoProperties.setRepos(repos);
|
||||
}
|
||||
|
||||
private void assertMainRepo(SshUriProperties sshKey) {
|
||||
assertThat(sshKey.getHostname(), 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