Support Google Cloud Source repositories (#1278)
* Extract transport configuration to TransportConfigCallbackFactory * Authenticate against Google Cloud Source repositories Fixes gh-1260
This commit is contained in:
committed by
Ryan Baxter
parent
3c0348ca62
commit
79bea06f3e
@@ -334,6 +334,17 @@ AWS EC2 instances may use https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ia
|
||||
NOTE: The `aws-java-sdk-core` jar is an optional dependency.
|
||||
If the `aws-java-sdk-core` jar is not on your classpath, the AWS Code Commit credential provider is not created, regardless of the git server URI.
|
||||
|
||||
===== Authentication with Google Cloud Source
|
||||
|
||||
Spring Cloud Config Server also supports authenticating against https://cloud.google.com/source-repositories/[Google Cloud Source] repositories.
|
||||
|
||||
If your Git URI uses the `http` or `https` protocol and the domain name is `source.developers.google.com`, the Google Cloud Source credentials provider will be used. A Google Cloud Source repository URI has the format `https://source.developers.google.com/p/${GCP_PROJECT}/r/${REPO}`. To obtain the URI for your repository, click on "Clone" in the Google Cloud Source UI, and select "Manually generated credentials". Do not generate any credentials, simply copy the displayed URI.
|
||||
|
||||
The Google Cloud Source credentials provider will use Google Cloud Platform application default credentials. See https://cloud.google.com/sdk/gcloud/reference/auth/application-default/login[Google Cloud SDK documentation] on how to create application default credentials for a system. This approach will work for user accounts in dev environments and for service accounts in production environments.
|
||||
|
||||
NOTE: `com.google.auth:google-auth-library-oauth2-http` is an optional dependency.
|
||||
If the `google-auth-library-oauth2-http` jar is not on your classpath, the Google Cloud Source credential provider is not created, regardless of the git server URI.
|
||||
|
||||
===== Git SSH configuration using properties
|
||||
|
||||
By default, the JGit library used by Spring Cloud Config Server uses SSH configuration files such as `~/.ssh/known_hosts` and `/etc/ssh/ssh_config` when connecting to Git repositories by using an SSH URI.
|
||||
|
||||
5
pom.xml
5
pom.xml
@@ -70,6 +70,11 @@
|
||||
<artifactId>aws-java-sdk-core</artifactId>
|
||||
<version>1.11.52</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.google.auth</groupId>
|
||||
<artifactId>google-auth-library-oauth2-http</artifactId>
|
||||
<version>0.15.0</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</dependencyManagement>
|
||||
<profiles>
|
||||
|
||||
@@ -85,6 +85,11 @@
|
||||
<artifactId>spring-boot-autoconfigure-processor</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.google.auth</groupId>
|
||||
<artifactId>google-auth-library-oauth2-http</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.h2database</groupId>
|
||||
<artifactId>h2</artifactId>
|
||||
|
||||
@@ -64,6 +64,8 @@ import org.springframework.cloud.config.server.environment.SvnKitEnvironmentRepo
|
||||
import org.springframework.cloud.config.server.environment.VaultEnvironmentProperties;
|
||||
import org.springframework.cloud.config.server.environment.VaultEnvironmentRepository;
|
||||
import org.springframework.cloud.config.server.environment.VaultEnvironmentRepositoryFactory;
|
||||
import org.springframework.cloud.config.server.support.GoogleCloudSourceSupport;
|
||||
import org.springframework.cloud.config.server.support.TransportConfigCallbackFactory;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
@@ -91,7 +93,8 @@ import org.springframework.jdbc.core.JdbcTemplate;
|
||||
VaultRepositoryConfiguration.class, CredhubConfiguration.class,
|
||||
CredhubRepositoryConfiguration.class, SvnRepositoryConfiguration.class,
|
||||
NativeRepositoryConfiguration.class, GitRepositoryConfiguration.class,
|
||||
RedisRepositoryConfiguration.class, DefaultRepositoryConfiguration.class })
|
||||
RedisRepositoryConfiguration.class, GoogleCloudSourceConfiguration.class,
|
||||
DefaultRepositoryConfiguration.class })
|
||||
public class EnvironmentRepositoryConfiguration {
|
||||
|
||||
@Bean
|
||||
@@ -137,9 +140,13 @@ public class EnvironmentRepositoryConfiguration {
|
||||
public MultipleJGitEnvironmentRepositoryFactory gitEnvironmentRepositoryFactory(
|
||||
ConfigurableEnvironment environment, ConfigServerProperties server,
|
||||
Optional<ConfigurableHttpConnectionFactory> jgitHttpConnectionFactory,
|
||||
Optional<TransportConfigCallback> customTransportConfigCallback) {
|
||||
Optional<TransportConfigCallback> customTransportConfigCallback,
|
||||
Optional<GoogleCloudSourceSupport> googleCloudSourceSupport) {
|
||||
final TransportConfigCallbackFactory transportConfigCallbackFactory = new TransportConfigCallbackFactory(
|
||||
customTransportConfigCallback.orElse(null),
|
||||
googleCloudSourceSupport.orElse(null));
|
||||
return new MultipleJGitEnvironmentRepositoryFactory(environment, server,
|
||||
jgitHttpConnectionFactory, customTransportConfigCallback);
|
||||
jgitHttpConnectionFactory, transportConfigCallbackFactory);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright 2013-2019 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
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.config.server.config;
|
||||
|
||||
import com.google.auth.oauth2.GoogleCredentials;
|
||||
import org.eclipse.jgit.api.TransportConfigCallback;
|
||||
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.cloud.config.server.support.GoogleCloudSourceSupport;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
/**
|
||||
* Adds Google Cloud Source OAuth2 support, if
|
||||
* com.google.auth:google-auth-library-oauth2-http library is on classpath.
|
||||
*
|
||||
* @author Eduard Wirch
|
||||
*/
|
||||
@Configuration
|
||||
@ConditionalOnClass({ GoogleCredentials.class, TransportConfigCallback.class })
|
||||
public class GoogleCloudSourceConfiguration {
|
||||
|
||||
@Bean
|
||||
public GoogleCloudSourceSupport createGoogleCloudSourceSupport() {
|
||||
return new GoogleCloudSourceSupport();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -18,12 +18,10 @@ package org.springframework.cloud.config.server.environment;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
import org.eclipse.jgit.api.TransportConfigCallback;
|
||||
import org.eclipse.jgit.transport.HttpTransport;
|
||||
|
||||
import org.springframework.cloud.config.server.config.ConfigServerProperties;
|
||||
import org.springframework.cloud.config.server.ssh.FileBasedSshTransportConfigCallback;
|
||||
import org.springframework.cloud.config.server.ssh.PropertiesBasedSshTransportConfigCallback;
|
||||
import org.springframework.cloud.config.server.support.TransportConfigCallbackFactory;
|
||||
import org.springframework.core.env.ConfigurableEnvironment;
|
||||
|
||||
/**
|
||||
@@ -38,23 +36,23 @@ public class MultipleJGitEnvironmentRepositoryFactory implements
|
||||
|
||||
private Optional<ConfigurableHttpConnectionFactory> connectionFactory;
|
||||
|
||||
private Optional<TransportConfigCallback> customTransportConfigCallback;
|
||||
private final TransportConfigCallbackFactory transportConfigCallbackFactory;
|
||||
|
||||
@Deprecated
|
||||
public MultipleJGitEnvironmentRepositoryFactory(ConfigurableEnvironment environment,
|
||||
ConfigServerProperties server,
|
||||
Optional<TransportConfigCallback> customTransportConfigCallback) {
|
||||
this(environment, server, Optional.empty(), customTransportConfigCallback);
|
||||
TransportConfigCallbackFactory transportConfigCallbackFactory) {
|
||||
this(environment, server, Optional.empty(), transportConfigCallbackFactory);
|
||||
}
|
||||
|
||||
public MultipleJGitEnvironmentRepositoryFactory(ConfigurableEnvironment environment,
|
||||
ConfigServerProperties server,
|
||||
Optional<ConfigurableHttpConnectionFactory> connectionFactory,
|
||||
Optional<TransportConfigCallback> customTransportConfigCallback) {
|
||||
TransportConfigCallbackFactory transportConfigCallbackFactory) {
|
||||
this.environment = environment;
|
||||
this.server = server;
|
||||
this.connectionFactory = connectionFactory;
|
||||
this.customTransportConfigCallback = customTransportConfigCallback;
|
||||
this.transportConfigCallbackFactory = transportConfigCallbackFactory;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -67,21 +65,12 @@ public class MultipleJGitEnvironmentRepositoryFactory implements
|
||||
|
||||
MultipleJGitEnvironmentRepository repository = new MultipleJGitEnvironmentRepository(
|
||||
this.environment, environmentProperties);
|
||||
repository.setTransportConfigCallback(this.customTransportConfigCallback
|
||||
.orElse(buildTransportConfigCallback(environmentProperties)));
|
||||
repository.setTransportConfigCallback(
|
||||
transportConfigCallbackFactory.build(environmentProperties));
|
||||
if (this.server.getDefaultLabel() != null) {
|
||||
repository.setDefaultLabel(this.server.getDefaultLabel());
|
||||
}
|
||||
return repository;
|
||||
}
|
||||
|
||||
private TransportConfigCallback buildTransportConfigCallback(
|
||||
MultipleJGitEnvironmentProperties gitEnvironmentProperties) {
|
||||
if (gitEnvironmentProperties.isIgnoreLocalSshSettings()) {
|
||||
return new PropertiesBasedSshTransportConfigCallback(
|
||||
gitEnvironmentProperties);
|
||||
}
|
||||
return new FileBasedSshTransportConfigCallback(gitEnvironmentProperties);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,144 @@
|
||||
/*
|
||||
* Copyright 2013-2019 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
|
||||
*
|
||||
* https://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.support;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URISyntaxException;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Objects;
|
||||
|
||||
import com.google.auth.oauth2.GoogleCredentials;
|
||||
import org.eclipse.jgit.api.TransportConfigCallback;
|
||||
import org.eclipse.jgit.transport.Transport;
|
||||
import org.eclipse.jgit.transport.TransportHttp;
|
||||
import org.eclipse.jgit.transport.URIish;
|
||||
|
||||
import static java.util.stream.Collectors.toMap;
|
||||
|
||||
/**
|
||||
* Provides credentials for Google Cloud Source repositories by adding a
|
||||
* {@code Authenticate} http header.
|
||||
* <p/>
|
||||
* It does so by acting as a transport configurer. If a transport instance targets a
|
||||
* Google Cloud Source repository, this implementation retrieves Google Cloud application
|
||||
* default credentials and adds them as a http header.
|
||||
*
|
||||
* @author Eduard Wirch
|
||||
* @see <a href=
|
||||
* "https://cloud.google.com/sdk/gcloud/reference/auth/application-default/login"> gcloud
|
||||
* auth application-default login</a>
|
||||
*/
|
||||
public final class GoogleCloudSourceSupport {
|
||||
|
||||
boolean canHandle(String uri) {
|
||||
try {
|
||||
return GCSTransportConfigCallback.canHandle(new URIish(uri));
|
||||
}
|
||||
catch (URISyntaxException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// This detour via GCSTransportConfigCallback was necessary because:
|
||||
// - we want the Google Cloud credentials provider to be a bean, so we can use
|
||||
// @ConditionalOnClass to conditionally disable support, if required classes
|
||||
// are not on the class path.
|
||||
// - We cannot make a class implementing TransportConfigCallback a bean,
|
||||
// because Spring would populate customTransportConfigCallback with this bean
|
||||
// (see JGitFactoryConfig.gitEnvironmentRepositoryFactory()), and report a
|
||||
// conflict whenever there is a real "custom" TransportConfigCallback
|
||||
// implementation in the Spring context.
|
||||
// This is why GoogleCloudSourceSupport is the optional bean, which can provide
|
||||
// the TransportConfigCallback on request.
|
||||
TransportConfigCallback createTransportConfigCallback() {
|
||||
return new GCSTransportConfigCallback(
|
||||
new ApplicationDefaultCredentialsProvider());
|
||||
}
|
||||
|
||||
TransportConfigCallback createTransportConfigCallback(
|
||||
CredentialsProvider credentialsProvider) {
|
||||
return new GCSTransportConfigCallback(credentialsProvider);
|
||||
}
|
||||
|
||||
private static final class GCSTransportConfigCallback
|
||||
implements TransportConfigCallback {
|
||||
|
||||
private static final String GOOGLE_CLOUD_SOURCE_HOST = "source.developers.google.com";
|
||||
|
||||
private final CredentialsProvider credentialsProvider;
|
||||
|
||||
private GCSTransportConfigCallback(CredentialsProvider credentialsProvider) {
|
||||
this.credentialsProvider = credentialsProvider;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configure(Transport transport) {
|
||||
if (transport instanceof TransportHttp && canHandle(transport.getURI())) {
|
||||
addHeaders((TransportHttp) transport,
|
||||
credentialsProvider.getAuthorizationHeaders());
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean canHandle(URIish uri) {
|
||||
return isHttpScheme(uri) && isGoogleCloudSourceHost(uri);
|
||||
}
|
||||
|
||||
private static boolean isHttpScheme(URIish uri) {
|
||||
final String scheme = uri.getScheme();
|
||||
return Objects.equals(scheme, "http") || Objects.equals(scheme, "https");
|
||||
}
|
||||
|
||||
private static boolean isGoogleCloudSourceHost(URIish uri) {
|
||||
return Objects.equals(uri.getHost(), GOOGLE_CLOUD_SOURCE_HOST);
|
||||
}
|
||||
|
||||
private void addHeaders(TransportHttp transport, Map<String, String> headers) {
|
||||
transport.setAdditionalHeaders(headers);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
interface CredentialsProvider {
|
||||
|
||||
Map<String, String> getAuthorizationHeaders();
|
||||
|
||||
}
|
||||
|
||||
private static class ApplicationDefaultCredentialsProvider
|
||||
implements CredentialsProvider {
|
||||
|
||||
@Override
|
||||
public Map<String, String> getAuthorizationHeaders() {
|
||||
try {
|
||||
return GoogleCredentials.getApplicationDefault().getRequestMetadata()
|
||||
.entrySet().stream()
|
||||
.collect(toMap(Entry::getKey, this::joinValues));
|
||||
}
|
||||
catch (IOException ex) {
|
||||
throw new IllegalStateException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
private String joinValues(Entry<?, List<String>> entry) {
|
||||
return String.join(", ", entry.getValue());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
* Copyright 2013-2019 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
|
||||
*
|
||||
* https://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.support;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import org.eclipse.jgit.api.TransportConfigCallback;
|
||||
|
||||
import org.springframework.cloud.config.server.environment.MultipleJGitEnvironmentProperties;
|
||||
import org.springframework.cloud.config.server.ssh.FileBasedSshTransportConfigCallback;
|
||||
import org.springframework.cloud.config.server.ssh.PropertiesBasedSshTransportConfigCallback;
|
||||
|
||||
public class TransportConfigCallbackFactory {
|
||||
|
||||
@Nullable
|
||||
private final TransportConfigCallback customTransportConfigCallback;
|
||||
|
||||
@Nullable
|
||||
private final GoogleCloudSourceSupport googleCloudSourceSupport;
|
||||
|
||||
public TransportConfigCallbackFactory(
|
||||
TransportConfigCallback customTransportConfigCallback,
|
||||
GoogleCloudSourceSupport googleCloudSourceSupport) {
|
||||
|
||||
this.customTransportConfigCallback = customTransportConfigCallback;
|
||||
this.googleCloudSourceSupport = googleCloudSourceSupport;
|
||||
}
|
||||
|
||||
public TransportConfigCallback build(
|
||||
MultipleJGitEnvironmentProperties environmentProperties) {
|
||||
|
||||
// customTransportConfigCallback has the highest priority. If someone put
|
||||
// a TransportConfigCallback bean in to the Spring context, we use it for
|
||||
// all repositories.
|
||||
if (customTransportConfigCallback != null) {
|
||||
return customTransportConfigCallback;
|
||||
}
|
||||
|
||||
// If the currently configured repository is a Google Cloud Source repository
|
||||
// we use GoogleCloudSourceSupport.
|
||||
if (googleCloudSourceSupport != null) {
|
||||
final String uri = environmentProperties.getUri();
|
||||
if (googleCloudSourceSupport.canHandle(uri)) {
|
||||
return googleCloudSourceSupport.createTransportConfigCallback();
|
||||
}
|
||||
}
|
||||
|
||||
// Otherwise - legacy behaviour - use SshTransportConfigCallback for all
|
||||
// repositories.
|
||||
return buildSshTransportConfigCallback(environmentProperties);
|
||||
}
|
||||
|
||||
private TransportConfigCallback buildSshTransportConfigCallback(
|
||||
MultipleJGitEnvironmentProperties gitEnvironmentProperties) {
|
||||
|
||||
if (gitEnvironmentProperties.isIgnoreLocalSshSettings()) {
|
||||
return new PropertiesBasedSshTransportConfigCallback(
|
||||
gitEnvironmentProperties);
|
||||
}
|
||||
return new FileBasedSshTransportConfigCallback(gitEnvironmentProperties);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -114,4 +114,23 @@ public class CompositeClasspathTests {
|
||||
|
||||
}
|
||||
|
||||
@RunWith(ModifiedClassPathRunner.class)
|
||||
@ClassPathExclusions("google-auth-library-oauth2-http-*.jar")
|
||||
public static class GoogleAuthTests {
|
||||
|
||||
@Test
|
||||
public void contextLoads() {
|
||||
new WebApplicationContextRunner()
|
||||
.withUserConfiguration(ConfigServerApplication.class)
|
||||
.withPropertyValues("spring.profiles.active:test,composite",
|
||||
"spring.jmx.enabled=false", "spring.config.name:configserver",
|
||||
"spring.cloud.config.server.composite[0].uri:https://source.developers.google.com",
|
||||
"spring.cloud.config.server.composite[0].type:git")
|
||||
.run(context -> {
|
||||
CompositeUtils.getCompositeTypeList(context.getEnvironment());
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,161 @@
|
||||
/*
|
||||
* Copyright 2013-2019 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
|
||||
*
|
||||
* https://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.support;
|
||||
|
||||
import java.net.URISyntaxException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.eclipse.jgit.api.TransportConfigCallback;
|
||||
import org.eclipse.jgit.transport.SshTransport;
|
||||
import org.eclipse.jgit.transport.Transport;
|
||||
import org.eclipse.jgit.transport.TransportHttp;
|
||||
import org.eclipse.jgit.transport.URIish;
|
||||
import org.junit.Test;
|
||||
import org.mockito.Mockito;
|
||||
|
||||
import org.springframework.cloud.config.server.support.GoogleCloudSourceSupport.CredentialsProvider;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.ArgumentMatchers.anyMap;
|
||||
import static org.mockito.Mockito.atMost;
|
||||
import static org.mockito.Mockito.doAnswer;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.verifyNoMoreInteractions;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
/**
|
||||
* @author Eduard Wirch
|
||||
*/
|
||||
public class GoogleCloudSourceSupportTests {
|
||||
|
||||
private static final String HTTPS_GOOGLE_CLOUD_SOURCE_REPO = "https://source.developers.google.com/r/somerepo";
|
||||
|
||||
private static final String HTTP_GOOGLE_CLOUD_SOURCE_REPO = "http://source.developers.google.com/r/somerepo";
|
||||
|
||||
private static final String SSH_GOOGLE_CLOUD_SOURCE_REPO = "ssh://source.developers.google.com/r/somerepo";
|
||||
|
||||
private static final String HTTPS_OTHER_REPO = "https://somehub.com/r/somerepo";
|
||||
|
||||
@Test
|
||||
public void verifySetsAuthHeadersForHttpsGCSRepo() throws URISyntaxException {
|
||||
Map<String, String> authHeaders = createAuthHeaders();
|
||||
TransportConfigCallback callback = transportConfigCallbackWith(authHeaders);
|
||||
|
||||
TransportHttp transport = mockTransportHttp(HTTPS_GOOGLE_CLOUD_SOURCE_REPO);
|
||||
Map<String, String> actualHeaders = recordSetHeaders(transport);
|
||||
|
||||
callback.configure(transport);
|
||||
|
||||
assertThat(actualHeaders).containsAllEntriesOf(authHeaders);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void verifySetsAuthHeadersForHttpGCSRepo() throws URISyntaxException {
|
||||
Map<String, String> authHeaders = createAuthHeaders();
|
||||
TransportConfigCallback callback = transportConfigCallbackWith(authHeaders);
|
||||
|
||||
TransportHttp transport = mockTransportHttp(HTTP_GOOGLE_CLOUD_SOURCE_REPO);
|
||||
Map<String, String> actualHeaders = recordSetHeaders(transport);
|
||||
|
||||
callback.configure(transport);
|
||||
|
||||
assertThat(actualHeaders).containsAllEntriesOf(authHeaders);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void verifyDoesNothingForSshGCSRepo() throws URISyntaxException {
|
||||
TransportConfigCallback callback = transportConfigCallbackWith(
|
||||
createAuthHeaders());
|
||||
TransportHttp transport = mockTransportHttp(SSH_GOOGLE_CLOUD_SOURCE_REPO);
|
||||
|
||||
callback.configure(transport);
|
||||
|
||||
verifyOnlyValidInteraction(transport);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void verifyDoesNothingForHttpsOtherRepo() throws URISyntaxException {
|
||||
TransportConfigCallback callback = transportConfigCallbackWith(
|
||||
createAuthHeaders());
|
||||
TransportHttp transport = mockTransportHttp(HTTPS_OTHER_REPO);
|
||||
|
||||
callback.configure(transport);
|
||||
|
||||
verifyOnlyValidInteraction(transport);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void verifyDoesNothingForNonHttpTransports() throws URISyntaxException {
|
||||
TransportConfigCallback callback = transportConfigCallbackWith(
|
||||
createAuthHeaders());
|
||||
Transport transport = mockSshTransport(SSH_GOOGLE_CLOUD_SOURCE_REPO);
|
||||
|
||||
callback.configure(transport);
|
||||
|
||||
verifyOnlyValidInteraction(transport);
|
||||
}
|
||||
|
||||
private void verifyOnlyValidInteraction(Transport transport) {
|
||||
// Actually, we don't care how often getURI() was invoked, simply "allow"
|
||||
// invocation of getURI(), so verifyNoMoreInteractions() won't complain
|
||||
// about getURI().
|
||||
verify(transport, atMost(10000)).getURI();
|
||||
|
||||
verifyNoMoreInteractions(transport);
|
||||
}
|
||||
|
||||
private Map<String, String> createAuthHeaders() {
|
||||
Map<String, String> headers = new HashMap<>();
|
||||
headers.put("WWW-Authorization", "user:password");
|
||||
return headers;
|
||||
}
|
||||
|
||||
private Map<String, String> recordSetHeaders(TransportHttp transport) {
|
||||
Map<String, String> headers = new HashMap<>();
|
||||
doAnswer(invocation -> {
|
||||
headers.putAll(invocation.getArgument(0));
|
||||
return null;
|
||||
}).when(transport).setAdditionalHeaders(anyMap());
|
||||
return headers;
|
||||
}
|
||||
|
||||
private TransportHttp mockTransportHttp(String uri) throws URISyntaxException {
|
||||
TransportHttp transport = Mockito.mock(TransportHttp.class);
|
||||
|
||||
when(transport.getURI()).thenReturn(new URIish(uri));
|
||||
|
||||
return transport;
|
||||
}
|
||||
|
||||
@SuppressWarnings("SameParameterValue")
|
||||
private Transport mockSshTransport(String uri) throws URISyntaxException {
|
||||
Transport transport = Mockito.mock(SshTransport.class);
|
||||
|
||||
when(transport.getURI()).thenReturn(new URIish(uri));
|
||||
|
||||
return transport;
|
||||
}
|
||||
|
||||
private TransportConfigCallback transportConfigCallbackWith(
|
||||
Map<String, String> authHeaders) {
|
||||
CredentialsProvider credentialsProvider = () -> authHeaders;
|
||||
return new GoogleCloudSourceSupport()
|
||||
.createTransportConfigCallback(credentialsProvider);
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user