Skip to content

Commit cafe781

Browse files
committed
provide HttpTransport support for google certificates with apache HTTP client v5
1 parent b3df1f6 commit cafe781

File tree

8 files changed

+484
-8
lines changed

8 files changed

+484
-8
lines changed
Lines changed: 201 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,201 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<project xmlns="http://maven.apache.org/POM/4.0.0"
3+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
5+
<modelVersion>4.0.0</modelVersion>
6+
<parent>
7+
<groupId>com.google.api-client</groupId>
8+
<artifactId>google-api-client-parent</artifactId>
9+
<version>2.6.1-SNAPSHOT</version>
10+
</parent>
11+
12+
<artifactId>google-api-client-apache-v5</artifactId>
13+
14+
<name>Apache extensions to the Google APIs Client Library for Java</name>
15+
<build>
16+
<extensions>
17+
<extension>
18+
<groupId>kr.motd.maven</groupId>
19+
<artifactId>os-maven-plugin</artifactId>
20+
<version>1.7.1</version>
21+
</extension>
22+
</extensions>
23+
<plugins>
24+
<plugin>
25+
<groupId>org.apache.maven.plugins</groupId>
26+
<artifactId>maven-resources-plugin</artifactId>
27+
<executions>
28+
<execution>
29+
<goals>
30+
<goal>resources</goal>
31+
</goals>
32+
</execution>
33+
</executions>
34+
</plugin>
35+
<plugin>
36+
<artifactId>maven-javadoc-plugin</artifactId>
37+
<configuration>
38+
<links>
39+
<link>https://docs.oracle.com/javase/7/docs/api/</link>
40+
<link>https://cloud.google.com/appengine/docs/standard/java/javadoc/</link>
41+
<link>https://googleapis.dev/java/google-http-client/${project.http.version}/</link>
42+
<link>https://googleapis.dev/java/google-oauth-client/${project.oauth.version}/</link>
43+
</links>
44+
<doctitle>${project.name} ${project.version}</doctitle>
45+
<windowtitle>${project.artifactId} ${project.version}</windowtitle>
46+
</configuration>
47+
</plugin>
48+
<plugin>
49+
<artifactId>maven-jar-plugin</artifactId>
50+
<configuration>
51+
<archive>
52+
<manifestFile>${project.build.outputDirectory}/META-INF/MANIFEST.MF</manifestFile>
53+
<manifest>
54+
<addDefaultImplementationEntries>true</addDefaultImplementationEntries>
55+
</manifest>
56+
<manifestEntries>
57+
<Automatic-Module-Name>google.api.client</Automatic-Module-Name>
58+
</manifestEntries>
59+
<manifestFile>${project.build.outputDirectory}/META-INF/MANIFEST.MF</manifestFile>
60+
</archive>
61+
</configuration>
62+
</plugin>
63+
<plugin>
64+
<groupId>org.apache.felix</groupId>
65+
<artifactId>maven-bundle-plugin</artifactId>
66+
<version>5.1.9</version>
67+
<executions>
68+
<execution>
69+
<id>bundle-manifest</id>
70+
<phase>process-classes</phase>
71+
<goals>
72+
<goal>manifest</goal>
73+
</goals>
74+
</execution>
75+
</executions>
76+
<configuration>
77+
<instructions>
78+
<Bundle-DocURL>https://developers.google.com/api-client-library/java/</Bundle-DocURL>
79+
<Bundle-Description>Google HTTP transport wrapper for the Apache Http Client.</Bundle-Description>
80+
<Bundle-SymbolicName>com.google.api.client.googleapis.apache</Bundle-SymbolicName>
81+
</instructions>
82+
</configuration>
83+
</plugin>
84+
<plugin>
85+
<artifactId>maven-source-plugin</artifactId>
86+
<executions>
87+
<execution>
88+
<id>source-jar</id>
89+
<goals>
90+
<goal>jar</goal>
91+
</goals>
92+
</execution>
93+
</executions>
94+
</plugin>
95+
96+
<plugin>
97+
<groupId>org.apache.maven.plugins</groupId>
98+
<artifactId>maven-dependency-plugin</artifactId>
99+
<configuration>
100+
<usedDependencies>commons-codec:commons-codec</usedDependencies>
101+
</configuration>
102+
</plugin>
103+
<plugin>
104+
<groupId>org.apache.maven.plugins</groupId>
105+
<artifactId>maven-surefire-plugin</artifactId>
106+
<configuration>
107+
<!-- These tests require an Env Var to be set. Use -PenvVarTest to ONLY run these tests -->
108+
<test>!AbstractGoogleClientTest#testGoogleClientBuilder_noCustomUniverseDomain_universeDomainEnvVar+testGoogleClientBuilder_customUniverseDomain_universeDomainEnvVar</test>
109+
</configuration>
110+
</plugin>
111+
</plugins>
112+
113+
<resources>
114+
<resource>
115+
<directory>src/main/resources</directory>
116+
</resource>
117+
<resource>
118+
<directory>src/main/properties</directory>
119+
<filtering>true</filtering>
120+
</resource>
121+
</resources>
122+
</build>
123+
<dependencies>
124+
<dependency>
125+
<groupId>junit</groupId>
126+
<artifactId>junit</artifactId>
127+
<scope>test</scope>
128+
</dependency>
129+
<dependency>
130+
<!-- google-api-client itself does not touch commons-codec. Its
131+
httpclient's dependency. For security advisories in commons-codec, it
132+
declares a newer commons-codec than the one declared by httpclient. -->
133+
<groupId>commons-codec</groupId>
134+
<artifactId>commons-codec</artifactId>
135+
</dependency>
136+
137+
<dependency>
138+
<groupId>com.google.api-client</groupId>
139+
<artifactId>google-api-client</artifactId>
140+
<exclusions>
141+
<exclusion>
142+
<groupId>org.apache.httpcomponents</groupId>
143+
<artifactId>httpcore</artifactId>
144+
</exclusion>
145+
<exclusion>
146+
<groupId>org.apache.httpcomponents</groupId>
147+
<artifactId>httpclient</artifactId>
148+
</exclusion>
149+
</exclusions>
150+
</dependency>
151+
<dependency>
152+
<groupId>com.google.http-client</groupId>
153+
<artifactId>google-http-client-apache-v5</artifactId>
154+
<version>1.44.3-SNAPSHOT</version>
155+
</dependency>
156+
<dependency>
157+
<groupId>org.apache.httpcomponents.client5</groupId>
158+
<artifactId>httpclient5</artifactId>
159+
<version>5.3.1</version>
160+
</dependency>
161+
<dependency>
162+
<groupId>org.apache.httpcomponents.core5</groupId>
163+
<artifactId>httpcore5-h2</artifactId>
164+
<version>5.2.4</version>
165+
</dependency>
166+
<dependency>
167+
<groupId>com.google.http-client</groupId>
168+
<artifactId>google-http-client</artifactId>
169+
<exclusions>
170+
<exclusion>
171+
<groupId>org.apache.httpcomponents</groupId>
172+
<artifactId>httpcore</artifactId>
173+
</exclusion>
174+
<exclusion>
175+
<groupId>org.apache.httpcomponents</groupId>
176+
<artifactId>httpclient</artifactId>
177+
</exclusion>
178+
</exclusions>
179+
</dependency>
180+
<dependency>
181+
<groupId>junit</groupId>
182+
<artifactId>junit</artifactId>
183+
<scope>test</scope>
184+
</dependency>
185+
<dependency>
186+
<groupId>org.mockito</groupId>
187+
<artifactId>mockito-core</artifactId>
188+
<scope>test</scope>
189+
</dependency>
190+
<dependency>
191+
<groupId>com.google.api-client</groupId>
192+
<artifactId>google-api-client</artifactId>
193+
<type>test-jar</type>
194+
<scope>test</scope>
195+
<version>2.6.1-SNAPSHOT</version>
196+
</dependency>
197+
198+
</dependencies>
199+
200+
201+
</project>
Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
/*
2+
* Copyright 2020 Google LLC
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
5+
* in compliance with the License. You may obtain a copy of the License at
6+
*
7+
* http://www.apache.org/licenses/LICENSE-2.0
8+
*
9+
* Unless required by applicable law or agreed to in writing, software distributed under the License
10+
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
11+
* or implied. See the License for the specific language governing permissions and limitations under
12+
* the License.
13+
*/
14+
15+
package com.google.api.client.googleapis.apache.v5;
16+
17+
import com.google.api.client.googleapis.GoogleUtils;
18+
import com.google.api.client.googleapis.mtls.MtlsProvider;
19+
import com.google.api.client.googleapis.mtls.MtlsUtils;
20+
import com.google.api.client.googleapis.util.Utils;
21+
import com.google.api.client.http.apache.v5.Apache5HttpTransport;
22+
import com.google.common.annotations.Beta;
23+
import com.google.api.client.util.SslUtils;
24+
import com.google.common.annotations.VisibleForTesting;
25+
import org.apache.hc.client5.http.config.ConnectionConfig;
26+
import org.apache.hc.client5.http.impl.classic.HttpClients;
27+
import org.apache.hc.client5.http.socket.LayeredConnectionSocketFactory;
28+
import org.apache.hc.client5.http.socket.PlainConnectionSocketFactory;
29+
import org.apache.hc.client5.http.ssl.SSLConnectionSocketFactory;
30+
import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
31+
import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManager;
32+
import org.apache.hc.client5.http.impl.routing.SystemDefaultRoutePlanner;
33+
import org.apache.hc.client5.http.socket.ConnectionSocketFactory;
34+
import org.apache.hc.core5.http.config.Registry;
35+
import org.apache.hc.core5.http.config.RegistryBuilder;
36+
37+
import javax.net.ssl.SSLContext;
38+
import java.io.IOException;
39+
import java.net.ProxySelector;
40+
import java.security.GeneralSecurityException;
41+
import java.security.KeyStore;
42+
import java.util.concurrent.TimeUnit;
43+
44+
/**
45+
* Utilities for Google APIs based on {@link ApacheHttpTransport}.
46+
*
47+
* @since 1.31
48+
*/
49+
public final class GoogleApache5HttpTransport {
50+
51+
/**
52+
* Returns a new instance of {@link ApacheHttpTransport} that uses {@link
53+
* GoogleUtils#getCertificateTrustStore()} for the trusted certificates. If
54+
* `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to "true", and the default
55+
* client certificate key store from {@link Utils#loadDefaultMtlsKeyStore()} is not null, then the
56+
* transport uses the default client certificate and is mutual TLS.
57+
*/
58+
public static Apache5HttpTransport newTrustedTransport()
59+
throws GeneralSecurityException, IOException {
60+
return newTrustedTransport(MtlsUtils.getDefaultMtlsProvider());
61+
}
62+
63+
/**
64+
* {@link Beta} <br>
65+
* Returns a new instance of {@link ApacheHttpTransport} that uses {@link
66+
* GoogleUtils#getCertificateTrustStore()} for the trusted certificates. mtlsProvider can be used
67+
* to configure mutual TLS for the transport.
68+
*
69+
* @param mtlsProvider MtlsProvider to configure mutual TLS for the transport
70+
*/
71+
@Beta
72+
public static Apache5HttpTransport newTrustedTransport(MtlsProvider mtlsProvider)
73+
throws GeneralSecurityException, IOException {
74+
75+
SocketFactoryRegistryHandler handler = new SocketFactoryRegistryHandler(mtlsProvider);
76+
77+
PoolingHttpClientConnectionManager connectionManager =
78+
new PoolingHttpClientConnectionManager(handler.getSocketFactoryRegistry());
79+
connectionManager.setMaxTotal(200);
80+
connectionManager.setDefaultMaxPerRoute(20);
81+
connectionManager.setDefaultConnectionConfig(
82+
ConnectionConfig.custom()
83+
.setTimeToLive(-1, TimeUnit.MILLISECONDS)
84+
.setValidateAfterInactivity(-1L, TimeUnit.MILLISECONDS)
85+
.build());
86+
87+
CloseableHttpClient client =
88+
HttpClients.custom()
89+
.useSystemProperties()
90+
.setConnectionManager(connectionManager)
91+
.setRoutePlanner(new SystemDefaultRoutePlanner(ProxySelector.getDefault()))
92+
.disableRedirectHandling()
93+
.disableAutomaticRetries()
94+
.build();
95+
96+
return new Apache5HttpTransport(client, handler.isMtls());
97+
}
98+
99+
@VisibleForTesting
100+
static class SocketFactoryRegistryHandler {
101+
private final Registry<ConnectionSocketFactory> socketFactoryRegistry;
102+
private final boolean isMtls;
103+
104+
public SocketFactoryRegistryHandler(MtlsProvider mtlsProvider)
105+
throws GeneralSecurityException, IOException {
106+
KeyStore mtlsKeyStore = null;
107+
String mtlsKeyStorePassword = null;
108+
if (mtlsProvider.useMtlsClientCertificate()) {
109+
mtlsKeyStore = mtlsProvider.getKeyStore();
110+
mtlsKeyStorePassword = mtlsProvider.getKeyStorePassword();
111+
}
112+
113+
// Use the included trust store
114+
KeyStore trustStore = GoogleUtils.getCertificateTrustStore();
115+
SSLContext sslContext = SslUtils.getTlsSslContext();
116+
117+
if (mtlsKeyStore != null && mtlsKeyStorePassword != null) {
118+
this.isMtls = true;
119+
SslUtils.initSslContext(
120+
sslContext,
121+
trustStore,
122+
SslUtils.getPkixTrustManagerFactory(),
123+
mtlsKeyStore,
124+
mtlsKeyStorePassword,
125+
SslUtils.getDefaultKeyManagerFactory());
126+
} else {
127+
this.isMtls = false;
128+
SslUtils.initSslContext(sslContext, trustStore, SslUtils.getPkixTrustManagerFactory());
129+
}
130+
LayeredConnectionSocketFactory socketFactory = new SSLConnectionSocketFactory(sslContext);
131+
132+
this.socketFactoryRegistry =
133+
RegistryBuilder.<ConnectionSocketFactory>create()
134+
.register("http", PlainConnectionSocketFactory.getSocketFactory())
135+
.register("https", socketFactory)
136+
.build();
137+
}
138+
139+
public Registry<ConnectionSocketFactory> getSocketFactoryRegistry() {
140+
return this.socketFactoryRegistry;
141+
}
142+
143+
public boolean isMtls() {
144+
return this.isMtls;
145+
}
146+
}
147+
148+
private GoogleApache5HttpTransport() {}
149+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
/*
2+
* Copyright 2020 Google LLC
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
5+
* in compliance with the License. You may obtain a copy of the License at
6+
*
7+
* http://www.apache.org/licenses/LICENSE-2.0
8+
*
9+
* Unless required by applicable law or agreed to in writing, software distributed under the License
10+
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
11+
* or implied. See the License for the specific language governing permissions and limitations under
12+
* the License.
13+
*/
14+
15+
/**
16+
* Google APIs support based on the Apache HTTP Client v5.
17+
*
18+
* @since 1.31
19+
*/
20+
package com.google.api.client.googleapis.apache.v5;

0 commit comments

Comments
 (0)