Use JGit URIish to parse SSH URIs

Use JSR-303 cross field validation for `SshUriProperties`
Rebase with 1.3.x Dalston
This commit is contained in:
Ollie Hughes
2017-07-12 17:41:04 +01:00
parent acee8a1b10
commit 67cdfab7fa
19 changed files with 572 additions and 250 deletions

View File

@@ -6,7 +6,7 @@
<parent>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-config</artifactId>
<version>1.4.0.BUILD-SNAPSHOT</version>
<version>1.3.2.BUILD-SNAPSHOT</version>
<relativePath>..</relativePath>
</parent>

View File

@@ -151,8 +151,8 @@ This repository implementation maps the `{label}` parameter of the
HTTP resource to a git label (commit id, branch name or tag). If the
git branch or tag name contains a slash ("/") then the label in the
HTTP URL should be specified with the special string "(\_)" instead (to
avoid ambiguity with other URL paths). For example, if the label is
`foo/bar`, replacing the slash would result in a label that looks like
avoid ambiguity with other URL paths). For example, if the label is
`foo/bar`, replacing the slash would result in a label that looks like
`foo(_)bar`. Be careful with the brackets in
the URL if you are using a command line client like curl (e.g. escape
them from the shell with quotes '').
@@ -351,7 +351,7 @@ https://git-codecommit.${AWS_REGION}.amazonaws.com/${repopath}.
If you provide a username and password with an AWS CodeCommit URI, then these must be
the http://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSGettingStartedGuide/AWSCredentials.html[AWS accessKeyId and secretAccessKey]
to be used to access the repository. If you do not specify a username and password,
then the accessKeyId and secretAccessKey will be retrieved using the
then the accessKeyId and secretAccessKey will be retrieved using the
http://docs.aws.amazon.com/sdk-for-java/v1/developer-guide/credentials.html[AWS Default Credential Provider Chain].
If your Git URI matches the CodeCommit URI pattern (above) then you must provide
@@ -364,7 +364,7 @@ classpath, then the AWS Code Commit credential provider will not be created rega
===== Git SSH configuration using properties
By default, Spring Cloud Config Server uses SSH configuration files such as `~/.ssh/known_hosts` and `/etc/ssh/ssh_config` when connecting to Git repositories using an SSH URI.
By default, the JGit library used by Spring Cloud Config Server uses SSH configuration files such as `~/.ssh/known_hosts` and `/etc/ssh/ssh_config` when connecting to Git repositories using an SSH URI.
In cloud environments such as Cloud Foundry, the local filesystem may be ephemeral or not easily accessible. For cases such as these, SSH configuration can be set using
Java properties. In order to activate property based SSH configuration, the property `spring.cloud.config.server.git.ignoreLocalSshSettings` must be set to `true`.
Example:
@@ -416,7 +416,7 @@ Example:
|Property Name |Remarks
|*ignoreLocalSshSettings*
|If true, use property based SSH config instead of file based
|If true, use property based SSH config instead of file based. Must be set at as `spring.cloud.config.server.git.ignoreLocalSshSettings`, *not* inside a repository definition.
|*privateKey*
|Valid SSH private key. Must be set if `ignoreLocalSshSettings` is true and Git URI is SSH format

View File

@@ -64,10 +64,12 @@ public class TransportConfiguration {
@Override
public void configure(Transport transport) {
SshTransport sshTransport = (SshTransport) transport;
sshTransport.setSshSessionFactory(
new PropertyBasedSshSessionFactory(
new SshUriPropertyProcessor(sshUriProperties).getSshKeysByHostname(), new JSch()));
if (transport instanceof SshTransport) {
SshTransport sshTransport = (SshTransport) transport;
sshTransport.setSshSessionFactory(
new PropertyBasedSshSessionFactory(
new SshUriPropertyProcessor(sshUriProperties).getSshKeysByHostname(), new JSch()));
}
}
}

View File

@@ -21,6 +21,7 @@ import java.io.IOException;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.eclipse.jgit.api.CheckoutCommand;
import org.eclipse.jgit.api.CloneCommand;
import org.eclipse.jgit.api.CreateBranchCommand.SetupUpstreamMode;

View File

@@ -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 {};
}

View File

@@ -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<SshUriProperties> extractedProperties = sshPropertyValidator.extractRepoProperties(sshUriProperties);
for (SshUriProperties extractedProperty : extractedProperties) {
if (sshUriProperties.isIgnoreLocalSshSettings() && isSshUri(extractedProperty.getUri())) {
validationResults.add(isHostKeySpecifiedWhenAlgorithmSet(extractedProperty, context));
}
}
return !validationResults.contains(false);
}
private boolean isHostKeySpecifiedWhenAlgorithmSet(SshUriProperties sshUriProperties, ConstraintValidatorContext context) {
if (hasText(sshUriProperties.getHostKeyAlgorithm())
&& !VALID_HOST_KEY_ALGORITHMS.contains(sshUriProperties.getHostKeyAlgorithm())) {
context.buildConstraintViolationWithTemplate(
format("Property '%shostKeyAlgorithm' must be one of %s", GIT_PROPERTY_PREFIX, VALID_HOST_KEY_ALGORITHMS))
.addConstraintViolation();
return false;
}
return true;
}
}

View File

@@ -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 {};
}

View File

@@ -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<SshUriProperties> extractedProperties = sshPropertyValidator.extractRepoProperties(sshUriProperties);
for (SshUriProperties extractedProperty : extractedProperties) {
if (sshUriProperties.isIgnoreLocalSshSettings() && isSshUri(extractedProperty.getUri())) {
validationResults.add(
isAlgorithmSpecifiedWhenHostKeySet(extractedProperty, context)
&& isHostKeySpecifiedWhenAlgorithmSet(extractedProperty, context));
}
}
return !validationResults.contains(false);
}
private boolean isHostKeySpecifiedWhenAlgorithmSet(SshUriProperties sshUriProperties, ConstraintValidatorContext context) {
if (hasText(sshUriProperties.getHostKeyAlgorithm()) && !hasText(sshUriProperties.getHostKey())) {
context.disableDefaultConstraintViolation();
context.buildConstraintViolationWithTemplate(
format("Property '%shostKey' must be set when '%shostKeyAlgorithm' is specified", GIT_PROPERTY_PREFIX, GIT_PROPERTY_PREFIX))
.addConstraintViolation();
return false;
}
return true;
}
private boolean isAlgorithmSpecifiedWhenHostKeySet(SshUriProperties sshUriProperties, ConstraintValidatorContext context) {
if (hasText(sshUriProperties.getHostKey()) && !hasText(sshUriProperties.getHostKeyAlgorithm())) {
context.disableDefaultConstraintViolation();
context.buildConstraintViolationWithTemplate(
format("Property '%shostKeyAlgorithm' must be set when '%shostKey' is specified", GIT_PROPERTY_PREFIX, GIT_PROPERTY_PREFIX))
.addConstraintViolation();
return false;
}
return true;
}
}

View File

@@ -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 {};
}

View File

@@ -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<SshUriProperties> extractedProperties = sshPropertyValidator.extractRepoProperties(sshUriProperties);
for (SshUriProperties extractedProperty : extractedProperties) {
if (sshUriProperties.isIgnoreLocalSshSettings() && isSshUri(extractedProperty.getUri())) {
validationResults.add(
isPrivateKeyPresent(extractedProperty, context)
&& isPrivateKeyFormatCorrect(extractedProperty, context));
}
}
return !validationResults.contains(false);
}
private boolean isPrivateKeyPresent(SshUriProperties sshUriProperties, ConstraintValidatorContext context) {
if (!hasText(sshUriProperties.getPrivateKey())) {
context.buildConstraintViolationWithTemplate(
format("Property '%shostKey' must be set when '%shostKeyAlgorithm' is specified", GIT_PROPERTY_PREFIX, GIT_PROPERTY_PREFIX))
.addConstraintViolation();
return false;
}
return true;
}
private boolean isPrivateKeyFormatCorrect(SshUriProperties sshUriProperties, ConstraintValidatorContext context) {
try {
KeyPair.load(new JSch(), sshUriProperties.getPrivateKey().getBytes(), null);
return true;
} catch (JSchException e) {
context.buildConstraintViolationWithTemplate(
format("Property '%sprivateKey' contains is not a valid private key", GIT_PROPERTY_PREFIX))
.addConstraintViolation();
return false;
}
}
}

View File

@@ -15,6 +15,8 @@
*/
package org.springframework.cloud.config.server.ssh;
import java.util.Map;
import com.jcraft.jsch.HostKey;
import com.jcraft.jsch.JSch;
import com.jcraft.jsch.JSchException;
@@ -24,9 +26,6 @@ import org.eclipse.jgit.transport.OpenSshConfig.Host;
import org.eclipse.jgit.util.Base64;
import org.eclipse.jgit.util.FS;
import java.util.Map;
/**
* In a cloud environment local SSH config files such as `.known_hosts` may not be suitable for providing
* configuration settings due to ephemeral filesystems. This flag enables SSH config to be provided as application
@@ -36,6 +35,10 @@ import java.util.Map;
*/
public class PropertyBasedSshSessionFactory extends JschConfigSessionFactory {
private static final String STRICT_HOST_KEY_CHECKING = "StrictHostKeyChecking";
private static final String YES_OPTION = "yes";
private static final String NO_OPTION = "no";
private static final String SERVER_HOST_KEY = "server_host_key";
private final Map<String, SshUriProperties> sshKeysByHostname;
private final JSch jSch;
@@ -49,12 +52,12 @@ public class PropertyBasedSshSessionFactory extends JschConfigSessionFactory {
SshUriProperties sshProperties = sshKeysByHostname.get(hc.getHostName());
String hostKeyAlgorithm = sshProperties.getHostKeyAlgorithm();
if (hostKeyAlgorithm != null) {
session.setConfig("server_host_key", hostKeyAlgorithm);
session.setConfig(SERVER_HOST_KEY, hostKeyAlgorithm);
}
if (sshProperties.getHostKey() == null || !sshProperties.isStrictHostKeyChecking()) {
session.setConfig("StrictHostKeyChecking", "no");
session.setConfig(STRICT_HOST_KEY_CHECKING, NO_OPTION);
} else {
session.setConfig("StrictHostKeyChecking", "yes");
session.setConfig(STRICT_HOST_KEY_CHECKING, YES_OPTION);
}
}

View File

@@ -16,18 +16,16 @@
package org.springframework.cloud.config.server.ssh;
import com.jcraft.jsch.JSch;
import com.jcraft.jsch.JSchException;
import com.jcraft.jsch.KeyPair;
import org.springframework.beans.factory.annotation.Autowired;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import org.eclipse.jgit.transport.URIish;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;
import javax.annotation.PostConstruct;
import java.util.*;
import static java.lang.String.format;
import static org.springframework.util.StringUtils.hasText;
/**
@@ -39,72 +37,31 @@ import static org.springframework.util.StringUtils.hasText;
@EnableConfigurationProperties(SshUriProperties.class)
public class SshPropertyValidator {
private final SshUriProperties sshUriProperties;
private final JSch jsch = new JSch();
private static final Set<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.";
protected static boolean isSshUri(Object uri) {
if(uri != null) {
try {
URIish urIish = new URIish(uri.toString());
String scheme = urIish.getScheme();
if(scheme == null && hasText(urIish.getHost()) && hasText(urIish.getUser())) {
//JGit returns null if using SCP URI but user and host will be populated
return true;
}
return scheme != null && !scheme.matches("^(http|https)$");
@Autowired
public SshPropertyValidator(SshUriProperties sshUriProperties) {
this.sshUriProperties = sshUriProperties;
}
static boolean isSshUri(Object uri) {
return uri != null && (uri.toString().startsWith("ssh") || uri.toString().startsWith("git"));
} catch (URISyntaxException e) {
return false;
}
}
return false;
}
@PostConstruct
public void validateSshConfigurationProperties() {
protected List<SshUriProperties> extractRepoProperties(SshUriProperties sshUriProperties) {
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();
}
}
return allRepoProperties;
}
protected void validatePrivateKeyFormat() {
try {
KeyPair.load(jsch, sshUriProperties.getPrivateKey().getBytes(), null);
} catch (JSchException e) {
throw new IllegalStateException(format("Property '%sprivateKey' contains an invalid value", GIT_PROPERTY_PREFIX));
}
}
protected void validateHostKeyAlgorithmSupported() {
if (hasText(sshUriProperties.getHostKeyAlgorithm())) {
Assert.state(VALID_HOST_KEY_ALGORITHMS.contains(sshUriProperties.getHostKeyAlgorithm()),
format("Property '%shostKeyAlgorithm' must be one of %s", GIT_PROPERTY_PREFIX, VALID_HOST_KEY_ALGORITHMS));
}
}
protected void validatePrivateKeyPresent() {
Assert.state(sshUriProperties.getPrivateKey() != null,
format("Property '%sprivateKey' must be set when '%signoreLocalSshSettings' is set to 'true'", GIT_PROPERTY_PREFIX, GIT_PROPERTY_PREFIX));
}
protected void validateHostKeySpecifiedWhenAlgorithmSet() {
if (hasText(sshUriProperties.getHostKeyAlgorithm())) {
Assert.state(hasText(sshUriProperties.getHostKey()),
format("Property '%shostKey' must be set when 'hostKeyAlgorithm' is specified", GIT_PROPERTY_PREFIX));
}
}
protected void validateAlgorithmSpecifiedWhenHostKeySet() {
if (hasText(sshUriProperties.getHostKey())) {
Assert.state(hasText(sshUriProperties.getHostKeyAlgorithm()),
format("Property '%shostKeyAlgorithm' must be set when 'hostKey' is specified", GIT_PROPERTY_PREFIX));
}
}
}

View File

@@ -15,12 +15,11 @@
*/
package org.springframework.cloud.config.server.ssh;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.web.util.UriComponentsBuilder;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.validation.annotation.Validated;
/**
* Data container for property based SSH config
@@ -28,25 +27,25 @@ import java.util.Objects;
* @author Ollie Hughes
*/
@ConfigurationProperties("spring.cloud.config.server.git")
@Validated
@PrivateKeyIsValid
@HostKeyAndAlgoBothExist
@HostKeyAlgoSupported
public class SshUriProperties {
private String privateKey;
private String uri;
private String hostKeyAlgorithm;
private String hostKey;
private String privateKey;
private String username;
private String password;
private boolean ignoreLocalSshSettings;
private boolean strictHostKeyChecking = true;
private Map<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) {
public SshUriProperties(String uri, String hostKeyAlgorithm, String hostKey, String privateKey, 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;
@@ -59,28 +58,6 @@ public class SshUriProperties {
return new SshUriPropertiesBuilder();
}
public boolean isSshUri() {
return uri != null && !uri.startsWith("http");
}
public String getHostname() {
if (getUri() == null) {
return null;
}
if (getUri().matches("^[a-z]+://.*")) {
return UriComponentsBuilder.fromUriString(uri).build().getHost();
}
else if (getUri().indexOf('@') < getUri().indexOf(':')) {
return getUri().substring(getUri().indexOf('@') + 1, uri.indexOf(':'));
}
else if (getUri().startsWith("ssh:") && getUri().indexOf('@') > 0) {
String postAt = getUri().substring(getUri().indexOf('@') + 1);
return postAt.substring(0, postAt.indexOf(":"));
}
else return null;
}
public String getUri() {
return this.uri;
}
@@ -97,14 +74,6 @@ public class SshUriProperties {
return this.privateKey;
}
public String getUsername() {
return this.username;
}
public String getPassword() {
return this.password;
}
public boolean isIgnoreLocalSshSettings() {
return this.ignoreLocalSshSettings;
}
@@ -133,14 +102,6 @@ public class SshUriProperties {
this.privateKey = privateKey;
}
public void setUsername(String username) {
this.username = username;
}
public void setPassword(String password) {
this.password = password;
}
public void setIgnoreLocalSshSettings(boolean ignoreLocalSshSettings) {
this.ignoreLocalSshSettings = ignoreLocalSshSettings;
}
@@ -153,32 +114,12 @@ public class SshUriProperties {
this.repos = repos;
}
@Override
public int hashCode() {
return Objects.hash(uri, hostKeyAlgorithm, hostKey, privateKey, username, password, ignoreLocalSshSettings, strictHostKeyChecking);
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null || getClass() != obj.getClass()) {
return false;
}
final SshUriProperties other = (SshUriProperties) obj;
return Objects.equals(this.uri, other.uri)
&& Objects.equals(this.hostKeyAlgorithm, other.hostKeyAlgorithm)
&& Objects.equals(this.hostKey, other.hostKey)
&& Objects.equals(this.privateKey, other.privateKey)
&& Objects.equals(this.username, other.username)
&& Objects.equals(this.password, other.password)
&& Objects.equals(this.ignoreLocalSshSettings, other.ignoreLocalSshSettings)
&& Objects.equals(this.strictHostKeyChecking, other.strictHostKeyChecking);
public void addRepo(String repoName, SshUriProperties properties) {
this.repos.put(repoName, properties);
}
public String toString() {
return "org.springframework.cloud.config.server.ssh.SshUriProperties(uri=" + this.getUri() + " hostKeyAlgorithm=" + this.getHostKeyAlgorithm() + ", hostKey=" + this.getHostKey() + ", privateKey=" + this.getPrivateKey() + ", username=" + this.getUsername() + ", password=" + this.getPassword() + ", ignoreLocalSshSettings=" + this.isIgnoreLocalSshSettings() + ", strictHostKeyChecking=" + this.isStrictHostKeyChecking() + ", repos=" + this.getRepos() + ")";
return "org.springframework.cloud.config.server.ssh.SshUriProperties(uri=" + this.getUri() + " hostKeyAlgorithm=" + this.getHostKeyAlgorithm() + ", hostKey=" + this.getHostKey() + ", privateKey=" + this.getPrivateKey() + ", ignoreLocalSshSettings=" + this.isIgnoreLocalSshSettings() + ", strictHostKeyChecking=" + this.isStrictHostKeyChecking() + ", repos=" + this.getRepos() + ")";
}
public static class SshUriPropertiesBuilder {
@@ -186,8 +127,6 @@ public class SshUriProperties {
private String hostKeyAlgorithm;
private String hostKey;
private String privateKey;
private String username;
private String password;
private boolean ignoreLocalSshSettings;
private boolean strictHostKeyChecking = true;
private Map<String, SshUriProperties> repos;
@@ -215,16 +154,6 @@ public class SshUriProperties {
return this;
}
public SshUriProperties.SshUriPropertiesBuilder username(String username) {
this.username = username;
return this;
}
public SshUriProperties.SshUriPropertiesBuilder password(String password) {
this.password = password;
return this;
}
public SshUriProperties.SshUriPropertiesBuilder ignoreLocalSshSettings(boolean ignoreLocalSshSettings) {
this.ignoreLocalSshSettings = ignoreLocalSshSettings;
return this;
@@ -241,11 +170,11 @@ public class SshUriProperties {
}
public SshUriProperties build() {
return new SshUriProperties(uri, hostKeyAlgorithm, hostKey, privateKey, username, password, ignoreLocalSshSettings, strictHostKeyChecking, repos);
return new SshUriProperties(uri, hostKeyAlgorithm, hostKey, privateKey, ignoreLocalSshSettings, strictHostKeyChecking, repos);
}
public String toString() {
return "org.springframework.cloud.config.server.ssh.SshUriProperties.SshUriPropertiesBuilder(uri=" + this.uri + "hostKeyAlgorithm=" + this.hostKeyAlgorithm + ", hostKey=" + this.hostKey + ", privateKey=" + this.privateKey + ", username=" + this.username + ", password=" + this.password + ", ignoreLocalSshSettings=" + this.ignoreLocalSshSettings + ", strictHostKeyChecking=" + this.strictHostKeyChecking + ", repos=" + this.repos + ")";
return "org.springframework.cloud.config.server.ssh.SshUriProperties.SshUriPropertiesBuilder(uri=" + this.uri + "hostKeyAlgorithm=" + this.hostKeyAlgorithm + ", hostKey=" + this.hostKey + ", privateKey=" + this.privateKey + ", ignoreLocalSshSettings=" + this.ignoreLocalSshSettings + ", strictHostKeyChecking=" + this.strictHostKeyChecking + ", repos=" + this.repos + ")";
}
}
}

View File

@@ -15,11 +15,13 @@
*/
package org.springframework.cloud.config.server.ssh;
import org.springframework.web.util.UriComponentsBuilder;
import java.net.URISyntaxException;
import java.util.HashMap;
import java.util.Map;
import org.eclipse.jgit.transport.URIish;
import static org.springframework.cloud.config.server.ssh.SshPropertyValidator.isSshUri;
/**
@@ -57,20 +59,12 @@ public class SshUriPropertyProcessor {
return sshUriPropertyMap;
}
private String getHostname(String uri) {
if (uri == null) {
protected static String getHostname(String uri) {
try {
URIish urIish = new URIish(uri);
return urIish.getHost();
} catch (URISyntaxException e) {
return null;
}
else if (uri.matches("^[a-z]+://.*")) {
return UriComponentsBuilder.fromUriString(uri).build().getHost();
}
else if (uri.indexOf('@') < uri.indexOf(':')) {
return uri.substring(uri.indexOf('@') + 1, uri.indexOf(':'));
}
else if (uri.startsWith("ssh:") && uri.indexOf('@') > 0) {
String postAt = uri.substring(uri.indexOf('@') + 1);
return postAt.substring(0, postAt.indexOf(":"));
}
else return null;
}
}

View File

@@ -18,4 +18,3 @@ server:
port: 8888
management:
context_path: /admin

View File

@@ -0,0 +1,54 @@
/*
* Copyright 2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.cloud.config.server.config;
import org.eclipse.jgit.api.TransportConfigCallback;
import org.junit.Test;
import org.springframework.cloud.config.server.ssh.SshUriProperties;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.instanceOf;
/**
* @author Ollie Hughes
*/
public class TransportConfigurationTest {
@Test
public void propertiesBasedSshTransportCallbackCreated() throws Exception {
SshUriProperties ignoreLocalSettings = SshUriProperties.builder()
.uri("user@gitrepo.com:proj/repo")
.ignoreLocalSshSettings(true)
.build();
TransportConfiguration transportConfiguration = new TransportConfiguration();
TransportConfigCallback transportConfigCallback = transportConfiguration.propertiesBasedSshTransportCallback(ignoreLocalSettings);
assertThat(transportConfigCallback, is(instanceOf(TransportConfiguration.PropertiesBasedSshTransportConfigCallback.class)));
}
@Test
public void fileBasedSshTransportCallbackCreated() throws Exception {
SshUriProperties dontIgnoreLocalSettings = SshUriProperties.builder()
.uri("user@gitrepo.com:proj/repo")
.ignoreLocalSshSettings(false)
.build();
TransportConfiguration transportConfiguration = new TransportConfiguration();
TransportConfigCallback transportConfigCallback = transportConfiguration.propertiesBasedSshTransportCallback(dontIgnoreLocalSettings);
assertThat(transportConfigCallback, is(instanceOf(TransportConfiguration.FileBasedSshTransportConfigCallback.class)));
}
}

View File

@@ -23,7 +23,6 @@ import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.runners.MockitoJUnitRunner;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
@@ -113,7 +112,7 @@ public class PropertyBasedSshSessionFactoryTest {
.build();
setupSessionFactory(sshKey);
factory.createSession(hc, null, sshKey.getHostname(), 22, null);
factory.createSession(hc, null, SshUriPropertyProcessor.getHostname(sshKey.getUri()), 22, null);
verify(jSch).addIdentity("gitlab.example.local", PRIVATE_KEY.getBytes(), null, null);
}
@@ -126,7 +125,7 @@ public class PropertyBasedSshSessionFactoryTest {
.build();
setupSessionFactory(sshKey);
factory.createSession(hc, null, sshKey.getHostname(), 22, null);
factory.createSession(hc, null, SshUriPropertyProcessor.getHostname(sshKey.getUri()), 22, null);
ArgumentCaptor<HostKey> captor = ArgumentCaptor.forClass(HostKey.class);
verify(hostKeyRepository).add(captor.capture(), any(UserInfo.class));
HostKey hostKey = captor.getValue();
@@ -136,9 +135,9 @@ public class PropertyBasedSshSessionFactoryTest {
private void setupSessionFactory(SshUriProperties sshKey) {
Map<String, SshUriProperties> sshKeysByHostname = new HashMap<>();
sshKeysByHostname.put(sshKey.getHostname(), sshKey);
sshKeysByHostname.put(SshUriPropertyProcessor.getHostname(sshKey.getUri()), sshKey);
factory = new PropertyBasedSshSessionFactory(sshKeysByHostname, jSch) ;
when(hc.getHostName()).thenReturn(sshKey.getHostname());
when(hc.getHostName()).thenReturn(SshUriPropertyProcessor.getHostname(sshKey.getUri()));
when(jSch.getHostKeyRepository()).thenReturn(hostKeyRepository);
}

View File

@@ -16,9 +16,17 @@
package org.springframework.cloud.config.server.ssh;
import org.junit.BeforeClass;
import org.junit.Test;
import static org.mockito.Mockito.*;
import javax.validation.ConstraintViolation;
import javax.validation.Validation;
import javax.validation.Validator;
import javax.validation.ValidatorFactory;
import java.util.Set;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.hasSize;
/**
* Unit tests for property based SSH config validators
@@ -58,6 +66,13 @@ public class SshPropertyValidatorTest {
"-----END RSA PRIVATE KEY-----";
private static final String VALID_HOST_KEY = "AAAAB3NzaC1yc2EAAAADAQABAAABAQDg6/W/5cbk/npvzpae7ZEa54F4rkwh2V3NiuqVZ5hWr+8O4/6SmrS7yBvRHAFeAJNb0LOCjE/7tjd1fqUx+QU1ATCtwkOhuwG8Ubzkx23mMZlrwEvx7XEfBoLN7Lw9fXjWDtTTgFB1AxCQ2pGGiNG0QCwyA4HViDHVU+ibwkRlzuDJG0tnp5Qpo3DXkHwFNdqWNfVrIZ6q2xbyeoJjKjnR215T0ehmuWFmKqG+uMNe/LQ6IOiK0F5+gr7rgPxNLAYYqyhraAnBeHn5gapsSzYJmFpoAHWvN7OUwHcJ88D9qUkKi4VKxYiuK69u3z825Xj2cLTfj9JiHCfV8cTo9GL";
private static Validator validator;
@BeforeClass
public static void setUpValidator() {
ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
validator = factory.getValidator();
}
@Test
public void supportedParametersSuccesful() throws Exception {
@@ -69,16 +84,12 @@ public class SshPropertyValidatorTest {
.hostKeyAlgorithm("ssh-rsa")
.build();
SshPropertyValidator sshPropertyValidator = spy(new SshPropertyValidator(validSettings));
sshPropertyValidator.validateSshConfigurationProperties();
verify(sshPropertyValidator, times(1)).validatePrivateKeyFormat();
verify(sshPropertyValidator, times(1)).validateAlgorithmSpecifiedWhenHostKeySet();
verify(sshPropertyValidator, times(1)).validatePrivateKeyPresent();
verify(sshPropertyValidator, times(1)).validateHostKeyAlgorithmSupported();
verify(sshPropertyValidator, times(1)).validateHostKeySpecifiedWhenAlgorithmSet();
Set<ConstraintViolation<SshUriProperties>> constraintViolations = validator.validate(validSettings);
assertThat(constraintViolations, hasSize(0));
}
@Test(expected = IllegalStateException.class)
@Test
public void invalidPrivateKeyFails() throws Exception {
SshUriProperties invalidKey = SshUriProperties.builder()
@@ -87,12 +98,12 @@ public class SshPropertyValidatorTest {
.privateKey("invalid_key")
.build();
SshPropertyValidator sshPropertyValidator = new SshPropertyValidator(invalidKey);
sshPropertyValidator.validateSshConfigurationProperties();
Set<ConstraintViolation<SshUriProperties>> constraintViolations = validator.validate(invalidKey);
assertThat(constraintViolations, hasSize(1));
}
@Test(expected = IllegalStateException.class)
@Test
public void missingPrivateKeyFails() throws Exception {
SshUriProperties missingKey = SshUriProperties.builder()
@@ -100,51 +111,51 @@ public class SshPropertyValidatorTest {
.ignoreLocalSshSettings(true)
.build();
SshPropertyValidator sshPropertyValidator = new SshPropertyValidator(missingKey);
sshPropertyValidator.validateSshConfigurationProperties();
Set<ConstraintViolation<SshUriProperties>> constraintViolations = validator.validate(missingKey);
assertThat(constraintViolations, hasSize(1));
}
@Test(expected = IllegalStateException.class)
@Test
public void hostKeyWithMissingAlgoFails() throws Exception {
SshUriProperties missingAlgo = SshUriProperties.builder()
.uri(SSH_URI)
.ignoreLocalSshSettings(true)
.privateKey("invalid_key")
.privateKey(VALID_PRIVATE_KEY)
.hostKey("some_host")
.build();
SshPropertyValidator sshPropertyValidator = new SshPropertyValidator(missingAlgo);
sshPropertyValidator.validateSshConfigurationProperties();
Set<ConstraintViolation<SshUriProperties>> constraintViolations = validator.validate(missingAlgo);
assertThat(constraintViolations, hasSize(1));
}
@Test(expected = IllegalStateException.class)
@Test
public void algoWithMissingHostKeyFails() throws Exception {
SshUriProperties missingHostKey = SshUriProperties.builder()
.uri(SSH_URI)
.ignoreLocalSshSettings(true)
.privateKey("invalid_key")
.hostKeyAlgorithm("some_host_algo")
.privateKey(VALID_PRIVATE_KEY)
.hostKeyAlgorithm("ssh-rsa")
.build();
SshPropertyValidator sshPropertyValidator = new SshPropertyValidator(missingHostKey);
sshPropertyValidator.validateSshConfigurationProperties();
Set<ConstraintViolation<SshUriProperties>> constraintViolations = validator.validate(missingHostKey);
assertThat(constraintViolations, hasSize(1));
}
@Test(expected = IllegalStateException.class)
@Test
public void unsupportedAlgoFails() throws Exception {
SshUriProperties unsupportedAlgo = SshUriProperties.builder()
.uri(SSH_URI)
.ignoreLocalSshSettings(true)
.privateKey("invalid_key")
.privateKey(VALID_PRIVATE_KEY)
.hostKey("some_host_key")
.hostKeyAlgorithm("unsupported")
.build();
SshPropertyValidator sshPropertyValidator = new SshPropertyValidator(unsupportedAlgo);
sshPropertyValidator.validateSshConfigurationProperties();
Set<ConstraintViolation<SshUriProperties>> constraintViolations = validator.validate(unsupportedAlgo);
assertThat(constraintViolations, hasSize(1));
}
@Test
@@ -156,13 +167,9 @@ public class SshPropertyValidatorTest {
.privateKey("invalid_key")
.build());
SshPropertyValidator sshPropertyValidator = spy(new SshPropertyValidator(useLocal));
sshPropertyValidator.validateSshConfigurationProperties();
verify(sshPropertyValidator, times(0)).validatePrivateKeyFormat();
verify(sshPropertyValidator, times(0)).validateAlgorithmSpecifiedWhenHostKeySet();
verify(sshPropertyValidator, times(0)).validatePrivateKeyPresent();
verify(sshPropertyValidator, times(0)).validateHostKeyAlgorithmSupported();
verify(sshPropertyValidator, times(0)).validateHostKeySpecifiedWhenAlgorithmSet();
Set<ConstraintViolation<SshUriProperties>> constraintViolations = validator.validate(useLocal);
assertThat(constraintViolations, hasSize(0));
}
@Test
@@ -174,12 +181,8 @@ public class SshPropertyValidatorTest {
.privateKey("invalid_key")
.build());
SshPropertyValidator sshPropertyValidator = spy(new SshPropertyValidator(httpsUri));
sshPropertyValidator.validateSshConfigurationProperties();
verify(sshPropertyValidator, times(0)).validatePrivateKeyFormat();
verify(sshPropertyValidator, times(0)).validateAlgorithmSpecifiedWhenHostKeySet();
verify(sshPropertyValidator, times(0)).validatePrivateKeyPresent();
verify(sshPropertyValidator, times(0)).validateHostKeyAlgorithmSupported();
verify(sshPropertyValidator, times(0)).validateHostKeySpecifiedWhenAlgorithmSet();
Set<ConstraintViolation<SshUriProperties>> constraintViolations = validator.validate(httpsUri);
assertThat(constraintViolations, hasSize(0));
}
}

View File

@@ -36,11 +36,14 @@ public class SshUriPropertyProcessorTest {
private static final String PRIVATE_KEY1 = "privateKey";
private static final String HOST_KEY1 = "hostKey";
private static final String ALGO1 = "ssh-rsa";
private static final String URI1 = "git@gitlab.test.local:wtran/my-repo";
private static final String HOST1 = "gitlab.test.local";
private static final String URI1 = "ollie@gitlab1.test.local:project/my-repo";
private static final String HOST1 = "gitlab1.test.local";
private static final String PRIVATE_KEY2 = "privateKey2";
private static final String URI2 = "git@gitlab2.test.local:wtran/my-repo";
private static final String URI2 = "ssh://git@gitlab2.test.local/wtran/my-repo";
private static final String HOST2 = "gitlab2.test.local";
private static final String PRIVATE_KEY3 = "privateKey3";
private static final String URI3 = "git+ssh://git@gitlab3.test.local/wtran/my-repo";
private static final String HOST3 = "gitlab3.test.local";
@After
public void cleanup() {
@@ -64,27 +67,34 @@ public class SshUriPropertyProcessorTest {
addRepoProperties(sshUriProperties, SshUriProperties.builder()
.uri(URI2)
.privateKey(PRIVATE_KEY2)
.build());
.build(), "repo2");
addRepoProperties(sshUriProperties, SshUriProperties.builder()
.uri(URI3)
.privateKey(PRIVATE_KEY3)
.build(), "repo3");
SshUriPropertyProcessor sshUriPropertyProcessor = new SshUriPropertyProcessor(sshUriProperties);
Map<String, SshUriProperties> sshKeysByHostname = sshUriPropertyProcessor.getSshKeysByHostname();
assertThat(sshKeysByHostname.values(), hasSize(3));
SshUriProperties sshKey = sshKeysByHostname.get(HOST1);
assertMainRepo(sshKey);
SshUriProperties sshKey1 = sshKeysByHostname.get(HOST1);
assertMainRepo(sshKey1);
sshKey = sshKeysByHostname.get(HOST2);
SshUriProperties sshKey2 = sshKeysByHostname.get(HOST2);
assertThat(sshKeysByHostname.values(), hasSize(2));
assertThat(SshUriPropertyProcessor.getHostname(sshKey2.getUri()), is(equalTo(HOST2)));
assertThat(sshKey2.getHostKeyAlgorithm(), is(nullValue()));
assertThat(sshKey2.getHostKey(), is(nullValue()));
assertThat(sshKey2.getPrivateKey(), is(equalTo(PRIVATE_KEY2)));
assertThat(sshKey.getHostname(), is(equalTo(HOST2)));
SshUriProperties sshKey3 = sshKeysByHostname.get(HOST3);
assertThat(sshKey.getHostKeyAlgorithm(), is(nullValue()));
assertThat(sshKey.getHostKey(), is(nullValue()));
assertThat(sshKey.getPrivateKey(), is(equalTo(PRIVATE_KEY2)));
assertThat(SshUriPropertyProcessor.getHostname(sshKey3.getUri()), is(equalTo(HOST3)));
assertThat(sshKey3.getHostKeyAlgorithm(), is(nullValue()));
assertThat(sshKey3.getHostKey(), is(nullValue()));
assertThat(sshKey3.getPrivateKey(), is(equalTo(PRIVATE_KEY3)));
}
@Test
@@ -94,7 +104,7 @@ public class SshUriPropertyProcessorTest {
.privateKey(PRIVATE_KEY1)
.hostKey(HOST_KEY1)
.hostKeyAlgorithm(ALGO1)
.build());
.build(), "repo2");
SshUriPropertyProcessor sshUriPropertyProcessor = new SshUriPropertyProcessor(sshUriProperties);
Map<String, SshUriProperties> sshKeysByHostname = sshUriPropertyProcessor.getSshKeysByHostname();
@@ -106,12 +116,26 @@ public class SshUriPropertyProcessorTest {
}
@Test
public void testNoSshUriPropertiess() {
public void testNoSshUriProperties() {
SshUriPropertyProcessor sshUriPropertyProcessor = new SshUriPropertyProcessor(new SshUriProperties());
Map<String, SshUriProperties> sshKeysByHostname = sshUriPropertyProcessor.getSshKeysByHostname();
assertThat(sshKeysByHostname.values(), hasSize(0));
}
@Test
public void testInvalidUriDoesNotAddEntry() {
SshUriPropertyProcessor sshUriPropertyProcessor = new SshUriPropertyProcessor(SshUriProperties.builder().uri("invalid_uri").build());
Map<String, SshUriProperties> sshKeysByHostname = sshUriPropertyProcessor.getSshKeysByHostname();
assertThat(sshKeysByHostname.values(), hasSize(0));
}
@Test
public void testHttpsUriDoesNotAddEntry() {
SshUriPropertyProcessor sshUriPropertyProcessor = new SshUriPropertyProcessor(SshUriProperties.builder().uri("https://user@github.com/proj/repo.git").build());
Map<String, SshUriProperties> sshKeysByHostname = sshUriPropertyProcessor.getSshKeysByHostname();
assertThat(sshKeysByHostname.values(), hasSize(0));
}
private SshUriProperties mainRepoPropertiesFixture() {
return SshUriProperties.builder()
@@ -122,14 +146,20 @@ public class SshUriPropertyProcessorTest {
.build();
}
private void addRepoProperties(SshUriProperties mainRepoProperties, SshUriProperties repoProperties) {
Map<String, SshUriProperties> repos = new HashMap<>();
repos.put("repo2", repoProperties);
mainRepoProperties.setRepos(repos);
private void addRepoProperties(SshUriProperties mainRepoProperties, SshUriProperties repoProperties, String repoName) {
if (mainRepoProperties.getRepos() == null) {
Map<String, SshUriProperties> repos = new HashMap<>();
repos.put(repoName, repoProperties);
mainRepoProperties.setRepos(repos);
}
else {
mainRepoProperties.addRepo(repoName, repoProperties);
}
}
private void assertMainRepo(SshUriProperties sshKey) {
assertThat(sshKey.getHostname(), is(equalTo(HOST1)));
assertThat(sshKey, is(notNullValue()));
assertThat(SshUriPropertyProcessor.getHostname(sshKey.getUri()), is(equalTo(HOST1)));
assertThat(sshKey.getHostKeyAlgorithm(), is(equalTo(ALGO1)));
assertThat(sshKey.getHostKey(), is(equalTo(HOST_KEY1)));
assertThat(sshKey.getPrivateKey(), is(equalTo(PRIVATE_KEY1)));