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:
@@ -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>
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright 2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.cloud.config.server.ssh;
|
||||
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
|
||||
import javax.validation.Constraint;
|
||||
import javax.validation.Payload;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Beans annotated with {@link HostKeyAlgoSupported} and {@link Validated} will have the constraints applied.
|
||||
*
|
||||
* @author Ollie Hughes
|
||||
**/
|
||||
@Constraint(validatedBy = HostKeyAlgoSupportedValidator.class)
|
||||
@Target(ElementType.TYPE)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface HostKeyAlgoSupported {
|
||||
String message() default "{HostKeyAlgoSupported.message}";
|
||||
Class<?>[] groups() default {};
|
||||
Class<? extends Payload>[] payload() default {};
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
* Copyright 2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.cloud.config.server.ssh;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import javax.validation.ConstraintValidator;
|
||||
import javax.validation.ConstraintValidatorContext;
|
||||
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
|
||||
import static java.lang.String.format;
|
||||
import static org.springframework.cloud.config.server.ssh.SshPropertyValidator.isSshUri;
|
||||
import static org.springframework.util.StringUtils.hasText;
|
||||
|
||||
/**
|
||||
* JSR-303 Cross Field validator that ensures that a {@link SshUriProperties} bean for the constraints:
|
||||
* - If host key algo is supported
|
||||
*
|
||||
* Beans annotated with {@link HostKeyAlgoSupported} and {@link Validated} will have the constraints applied.
|
||||
*
|
||||
* @author Ollie Hughes
|
||||
*/
|
||||
public class HostKeyAlgoSupportedValidator implements ConstraintValidator<HostKeyAlgoSupported, SshUriProperties> {
|
||||
private static final String GIT_PROPERTY_PREFIX = "spring.cloud.config.server.git.";
|
||||
private final SshPropertyValidator sshPropertyValidator = new SshPropertyValidator();
|
||||
private static final Set<String> VALID_HOST_KEY_ALGORITHMS = new LinkedHashSet<>(Arrays.asList(
|
||||
"ssh-dss","ssh-rsa","ecdsa-sha2-nistp256","ecdsa-sha2-nistp384","ecdsa-sha2-nistp521"));
|
||||
|
||||
@Override
|
||||
public void initialize(HostKeyAlgoSupported constrainAnnotation) {
|
||||
//No special initialization of validator required
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isValid(SshUriProperties sshUriProperties, ConstraintValidatorContext context) {
|
||||
context.disableDefaultConstraintViolation();
|
||||
Set<Boolean> validationResults = new HashSet<>();
|
||||
List<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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright 2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.cloud.config.server.ssh;
|
||||
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
|
||||
import javax.validation.Constraint;
|
||||
import javax.validation.Payload;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Beans annotated with {@link HostKeyAndAlgoBothExist} and {@link Validated} will have the constraints applied.
|
||||
* @author Ollie Hughes
|
||||
*/
|
||||
@Constraint(validatedBy = HostKeyAndAlgoBothExistValidator.class)
|
||||
@Target(ElementType.TYPE)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface HostKeyAndAlgoBothExist {
|
||||
String message() default "{HostKeyAndAlgoBothExist.message}";
|
||||
Class<?>[] groups() default {};
|
||||
Class<? extends Payload>[] payload() default {};
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
* Copyright 2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.cloud.config.server.ssh;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import javax.validation.ConstraintValidator;
|
||||
import javax.validation.ConstraintValidatorContext;
|
||||
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
|
||||
import static java.lang.String.format;
|
||||
import static org.springframework.cloud.config.server.ssh.SshPropertyValidator.isSshUri;
|
||||
import static org.springframework.util.StringUtils.hasText;
|
||||
|
||||
/**
|
||||
* JSR-303 Cross Field validator that ensures that a {@link SshUriProperties} bean for the constraints:
|
||||
* - If host key is set then host key algo must also be set
|
||||
* - If host key algo is set then host key must also be set
|
||||
*
|
||||
* Beans annotated with {@link HostKeyAndAlgoBothExist} and {@link Validated} will have the constraints applied.
|
||||
*
|
||||
* @author Ollie Hughes
|
||||
*/
|
||||
public class HostKeyAndAlgoBothExistValidator implements ConstraintValidator<HostKeyAndAlgoBothExist, SshUriProperties> {
|
||||
private static final String GIT_PROPERTY_PREFIX = "spring.cloud.config.server.git.";
|
||||
private final SshPropertyValidator sshPropertyValidator = new SshPropertyValidator();
|
||||
|
||||
@Override
|
||||
public void initialize(HostKeyAndAlgoBothExist constrainAnnotation) {
|
||||
//No special initialization of validator required
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isValid(SshUriProperties sshUriProperties, ConstraintValidatorContext context) {
|
||||
Set<Boolean> validationResults = new HashSet<>();
|
||||
List<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;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package org.springframework.cloud.config.server.ssh;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
import javax.validation.Constraint;
|
||||
import javax.validation.Payload;
|
||||
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
|
||||
/**
|
||||
* Beans annotated with {@link PrivateKeyValidator} and {@link Validated} will have the constraints applied.
|
||||
*
|
||||
* @author Ollie Hughes
|
||||
*/
|
||||
@Constraint(validatedBy = PrivateKeyValidator.class)
|
||||
@Target(ElementType.TYPE)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface PrivateKeyIsValid {
|
||||
String message() default "{PrivateKeyIsValid.message}";
|
||||
Class<?>[] groups() default {};
|
||||
Class<? extends Payload>[] payload() default {};
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
/*
|
||||
* Copyright 2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.cloud.config.server.ssh;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import javax.validation.ConstraintValidator;
|
||||
import javax.validation.ConstraintValidatorContext;
|
||||
|
||||
import com.jcraft.jsch.JSch;
|
||||
import com.jcraft.jsch.JSchException;
|
||||
import com.jcraft.jsch.KeyPair;
|
||||
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
|
||||
import static java.lang.String.format;
|
||||
import static org.springframework.cloud.config.server.ssh.SshPropertyValidator.isSshUri;
|
||||
import static org.springframework.util.StringUtils.hasText;
|
||||
|
||||
/**
|
||||
* JSR-303 Cross Field validator that ensures that a {@link SshUriProperties} bean for the constraints:
|
||||
* - Private key is present and can be correctly parsed using {@link com.jcraft.jsch.KeyPair}
|
||||
*
|
||||
* Beans annotated with {@link PrivateKeyValidator} and {@link Validated} will have the constraints applied.
|
||||
*
|
||||
* @author Ollie Hughes
|
||||
*/
|
||||
public class PrivateKeyValidator implements ConstraintValidator<PrivateKeyIsValid, SshUriProperties> {
|
||||
private static final String GIT_PROPERTY_PREFIX = "spring.cloud.config.server.git.";
|
||||
private final SshPropertyValidator sshPropertyValidator = new SshPropertyValidator();
|
||||
|
||||
@Override
|
||||
public void initialize(PrivateKeyIsValid constrainAnnotation) {
|
||||
//No special initialization of validator required
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isValid(SshUriProperties sshUriProperties, ConstraintValidatorContext context) {
|
||||
context.disableDefaultConstraintViolation();
|
||||
Set<Boolean> validationResults = new HashSet<>();
|
||||
List<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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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 + ")";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,4 +18,3 @@ server:
|
||||
port: 8888
|
||||
management:
|
||||
context_path: /admin
|
||||
|
||||
@@ -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)));
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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));
|
||||
|
||||
}
|
||||
}
|
||||
@@ -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)));
|
||||
|
||||
Reference in New Issue
Block a user