Skip to content

Commit 0d39b43

Browse files
authored
feat: Provide HttpTransport support for google certificates with apache HTTP client v5 (#2497) (#2503)
provide new GoogleApache5HttpTransport that returns HttpTransport with google certificates using apache HTTP client v5
1 parent b3df1f6 commit 0d39b43

File tree

11 files changed

+521
-7
lines changed

11 files changed

+521
-7
lines changed

docs/component-modules.md

+9
Original file line numberDiff line numberDiff line change
@@ -55,4 +55,13 @@ XML extensions to the Google API Client Library for Java
5555
(`google-api-client-xml`). This module depends on `google-api-client` and
5656
`google-http-client-xml`.
5757

58+
## google-api-client-apache-v5
59+
60+
Provides Apache extension to the Google HTTP Client Library for Java (`google-api-client-apache-v5`) that
61+
returns an implementation of `HttpTransport` based on the Apache HTTP Client (v5) with Google certificates loaded in
62+
truststore. This module depends on `google-http-client`.
63+
64+
Please note this is the preferred Apache extension to be used, over the GoogleApacheHttpTransport included
65+
in `google-api-client` module. The previous google transport utilizes the EOL Apache HTTP Client v4.
66+
5867
[protobuf]: https://developers.google.com/protocol-buffers/docs/overview

google-api-client-apache-v5/pom.xml

+177
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,177 @@
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+
<artifactId>google-api-client-apache-v5</artifactId>
12+
<name>Apache extensions to the Google APIs Client Library for Java</name>
13+
<build>
14+
<plugins>
15+
<plugin>
16+
<groupId>org.apache.maven.plugins</groupId>
17+
<artifactId>maven-resources-plugin</artifactId>
18+
<executions>
19+
<execution>
20+
<goals>
21+
<goal>resources</goal>
22+
</goals>
23+
</execution>
24+
</executions>
25+
</plugin>
26+
<plugin>
27+
<artifactId>maven-javadoc-plugin</artifactId>
28+
<configuration>
29+
<links>
30+
<link>https://docs.oracle.com/javase/8/docs/api/</link>
31+
<link>https://cloud.google.com/appengine/docs/standard/java/javadoc/</link>
32+
<link>https://googleapis.dev/java/google-http-client/${project.http.version}/</link>
33+
<link>https://googleapis.dev/java/google-oauth-client/${project.oauth.version}/</link>
34+
</links>
35+
<doctitle>${project.name} ${project.version}</doctitle>
36+
<windowtitle>${project.artifactId} ${project.version}</windowtitle>
37+
</configuration>
38+
</plugin>
39+
<plugin>
40+
<artifactId>maven-jar-plugin</artifactId>
41+
<configuration>
42+
<archive>
43+
<manifestFile>${project.build.outputDirectory}/META-INF/MANIFEST.MF</manifestFile>
44+
<manifest>
45+
<addDefaultImplementationEntries>true</addDefaultImplementationEntries>
46+
</manifest>
47+
<manifestEntries>
48+
<Automatic-Module-Name>google.api.client</Automatic-Module-Name>
49+
</manifestEntries>
50+
<manifestFile>${project.build.outputDirectory}/META-INF/MANIFEST.MF</manifestFile>
51+
</archive>
52+
</configuration>
53+
</plugin>
54+
<plugin>
55+
<groupId>org.apache.felix</groupId>
56+
<artifactId>maven-bundle-plugin</artifactId>
57+
<version>5.1.9</version>
58+
<executions>
59+
<execution>
60+
<id>bundle-manifest</id>
61+
<phase>process-classes</phase>
62+
<goals>
63+
<goal>manifest</goal>
64+
</goals>
65+
</execution>
66+
</executions>
67+
<configuration>
68+
<instructions>
69+
<Bundle-DocURL>https://developers.google.com/api-client-library/java/</Bundle-DocURL>
70+
<Bundle-Description>Google HTTP transport wrapper for the Apache 5 Http Client.
71+
</Bundle-Description>
72+
<Bundle-SymbolicName>com.google.api.client.googleapis.apache</Bundle-SymbolicName>
73+
</instructions>
74+
</configuration>
75+
</plugin>
76+
<plugin>
77+
<artifactId>maven-source-plugin</artifactId>
78+
<executions>
79+
<execution>
80+
<id>source-jar</id>
81+
<goals>
82+
<goal>jar</goal>
83+
</goals>
84+
</execution>
85+
</executions>
86+
</plugin>
87+
<plugin>
88+
<groupId>org.apache.maven.plugins</groupId>
89+
<artifactId>maven-checkstyle-plugin</artifactId>
90+
<executions>
91+
<execution>
92+
<id>validate-google-style</id>
93+
<phase>validate</phase>
94+
<goals>
95+
<goal>check</goal>
96+
</goals>
97+
<configuration>
98+
<configLocation>google_checks.xml</configLocation>
99+
<suppressionsLocation>src/checkstyle/checkstyle-suppressions.xml</suppressionsLocation>
100+
<includeTestSourceDirectory>true</includeTestSourceDirectory>
101+
<failOnViolation>true</failOnViolation>
102+
<violationSeverity>warning</violationSeverity>
103+
</configuration>
104+
</execution>
105+
</executions>
106+
</plugin>
107+
</plugins>
108+
109+
<resources>
110+
<resource>
111+
<directory>src/main/resources</directory>
112+
</resource>
113+
<resource>
114+
<directory>src/main/properties</directory>
115+
<filtering>true</filtering>
116+
</resource>
117+
</resources>
118+
</build>
119+
<dependencies>
120+
<dependency>
121+
<groupId>junit</groupId>
122+
<artifactId>junit</artifactId>
123+
<scope>test</scope>
124+
</dependency>
125+
<dependency>
126+
<groupId>com.google.api-client</groupId>
127+
<artifactId>google-api-client</artifactId>
128+
<exclusions>
129+
<exclusion>
130+
<groupId>org.apache.httpcomponents</groupId>
131+
<artifactId>httpcore</artifactId>
132+
</exclusion>
133+
<exclusion>
134+
<groupId>org.apache.httpcomponents</groupId>
135+
<artifactId>httpclient</artifactId>
136+
</exclusion>
137+
</exclusions>
138+
</dependency>
139+
<dependency>
140+
<groupId>com.google.http-client</groupId>
141+
<artifactId>google-http-client-apache-v5</artifactId>
142+
</dependency>
143+
<dependency>
144+
<groupId>com.google.guava</groupId>
145+
<artifactId>guava</artifactId>
146+
</dependency>
147+
<dependency>
148+
<groupId>org.apache.httpcomponents.client5</groupId>
149+
<artifactId>httpclient5</artifactId>
150+
</dependency>
151+
<dependency>
152+
<groupId>org.apache.httpcomponents.core5</groupId>
153+
<artifactId>httpcore5</artifactId>
154+
</dependency>
155+
<dependency>
156+
<groupId>com.google.http-client</groupId>
157+
<artifactId>google-http-client</artifactId>
158+
<exclusions>
159+
<exclusion>
160+
<groupId>org.apache.httpcomponents</groupId>
161+
<artifactId>httpcore</artifactId>
162+
</exclusion>
163+
<exclusion>
164+
<groupId>org.apache.httpcomponents</groupId>
165+
<artifactId>httpclient</artifactId>
166+
</exclusion>
167+
</exclusions>
168+
</dependency>
169+
<dependency>
170+
<groupId>com.google.api-client</groupId>
171+
<artifactId>google-api-client</artifactId>
172+
<type>test-jar</type>
173+
<scope>test</scope>
174+
<version> ${project.version}</version>
175+
</dependency>
176+
</dependencies>
177+
</project>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<?xml version="1.0"?>
2+
<!DOCTYPE suppressions PUBLIC
3+
"-//Checkstyle//DTD SuppressionFilter Configuration 1.2//EN"
4+
"https://checkstyle.org/dtds/suppressions_1_2.dtd">
5+
<suppressions>
6+
<!-- Test checkstyle suppressions -->
7+
<suppress checks="MissingJavadocType" files=".*Test.java"/>
8+
<suppress checks="AbbreviationAsWordInName" files=".*Test.java"/>
9+
<suppress checks="VariableDeclarationUsageDistance" files=".*Test.java"/>
10+
</suppressions>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,148 @@
1+
/*
2+
* Copyright 2024 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.api.client.util.SslUtils;
23+
import com.google.common.annotations.Beta;
24+
import com.google.common.annotations.VisibleForTesting;
25+
import java.io.IOException;
26+
import java.net.ProxySelector;
27+
import java.security.GeneralSecurityException;
28+
import java.security.KeyStore;
29+
import java.util.concurrent.TimeUnit;
30+
import javax.net.ssl.SSLContext;
31+
import org.apache.hc.client5.http.config.ConnectionConfig;
32+
import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
33+
import org.apache.hc.client5.http.impl.classic.HttpClients;
34+
import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManager;
35+
import org.apache.hc.client5.http.impl.routing.SystemDefaultRoutePlanner;
36+
import org.apache.hc.client5.http.socket.ConnectionSocketFactory;
37+
import org.apache.hc.client5.http.socket.LayeredConnectionSocketFactory;
38+
import org.apache.hc.client5.http.socket.PlainConnectionSocketFactory;
39+
import org.apache.hc.client5.http.ssl.SSLConnectionSocketFactory;
40+
import org.apache.hc.core5.http.config.Registry;
41+
import org.apache.hc.core5.http.config.RegistryBuilder;
42+
43+
/**
44+
* Utilities for Google APIs based on {@link Apache5HttpTransport}.
45+
*
46+
* @since 2.6.1
47+
*/
48+
public final class GoogleApache5HttpTransport {
49+
50+
/**
51+
* Returns a new instance of {@link Apache5HttpTransport} that uses {@link
52+
* GoogleUtils#getCertificateTrustStore()} for the trusted certificates. If
53+
* `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to "true", and the default
54+
* client certificate key store from {@link Utils#loadDefaultMtlsKeyStore()} is not null, then the
55+
* transport uses the default client certificate and is mutual TLS.
56+
*/
57+
public static Apache5HttpTransport newTrustedTransport()
58+
throws GeneralSecurityException, IOException {
59+
return newTrustedTransport(MtlsUtils.getDefaultMtlsProvider());
60+
}
61+
62+
/**
63+
* {@link Beta} <br>
64+
* Returns a new instance of {@link Apache5HttpTransport} that uses {@link
65+
* GoogleUtils#getCertificateTrustStore()} for the trusted certificates. mtlsProvider can be used
66+
* to configure mutual TLS for the transport.
67+
*
68+
* @param mtlsProvider MtlsProvider to configure mutual TLS for the transport
69+
*/
70+
@Beta
71+
public static Apache5HttpTransport newTrustedTransport(MtlsProvider mtlsProvider)
72+
throws GeneralSecurityException, IOException {
73+
74+
SocketFactoryRegistryHandler handler = new SocketFactoryRegistryHandler(mtlsProvider);
75+
76+
PoolingHttpClientConnectionManager connectionManager =
77+
new PoolingHttpClientConnectionManager(handler.getSocketFactoryRegistry());
78+
connectionManager.setMaxTotal(200);
79+
connectionManager.setDefaultMaxPerRoute(20);
80+
connectionManager.setDefaultConnectionConfig(
81+
ConnectionConfig.custom()
82+
.setTimeToLive(-1, TimeUnit.MILLISECONDS)
83+
.setValidateAfterInactivity(-1L, TimeUnit.MILLISECONDS)
84+
.build());
85+
86+
CloseableHttpClient client =
87+
HttpClients.custom()
88+
.useSystemProperties()
89+
.setConnectionManager(connectionManager)
90+
.setRoutePlanner(new SystemDefaultRoutePlanner(ProxySelector.getDefault()))
91+
.disableRedirectHandling()
92+
.disableAutomaticRetries()
93+
.build();
94+
95+
return new Apache5HttpTransport(client, handler.isMtls());
96+
}
97+
98+
@VisibleForTesting
99+
static class SocketFactoryRegistryHandler {
100+
private final Registry<ConnectionSocketFactory> socketFactoryRegistry;
101+
private final boolean isMtls;
102+
103+
public SocketFactoryRegistryHandler(MtlsProvider mtlsProvider)
104+
throws GeneralSecurityException, IOException {
105+
KeyStore mtlsKeyStore = null;
106+
String mtlsKeyStorePassword = null;
107+
if (mtlsProvider.useMtlsClientCertificate()) {
108+
mtlsKeyStore = mtlsProvider.getKeyStore();
109+
mtlsKeyStorePassword = mtlsProvider.getKeyStorePassword();
110+
}
111+
112+
// Use the included trust store
113+
KeyStore trustStore = GoogleUtils.getCertificateTrustStore();
114+
SSLContext sslContext = SslUtils.getTlsSslContext();
115+
116+
if (mtlsKeyStore != null && mtlsKeyStorePassword != null) {
117+
this.isMtls = true;
118+
SslUtils.initSslContext(
119+
sslContext,
120+
trustStore,
121+
SslUtils.getPkixTrustManagerFactory(),
122+
mtlsKeyStore,
123+
mtlsKeyStorePassword,
124+
SslUtils.getDefaultKeyManagerFactory());
125+
} else {
126+
this.isMtls = false;
127+
SslUtils.initSslContext(sslContext, trustStore, SslUtils.getPkixTrustManagerFactory());
128+
}
129+
LayeredConnectionSocketFactory socketFactory = new SSLConnectionSocketFactory(sslContext);
130+
131+
this.socketFactoryRegistry =
132+
RegistryBuilder.<ConnectionSocketFactory>create()
133+
.register("http", PlainConnectionSocketFactory.getSocketFactory())
134+
.register("https", socketFactory)
135+
.build();
136+
}
137+
138+
public Registry<ConnectionSocketFactory> getSocketFactoryRegistry() {
139+
return this.socketFactoryRegistry;
140+
}
141+
142+
public boolean isMtls() {
143+
return this.isMtls;
144+
}
145+
}
146+
147+
private GoogleApache5HttpTransport() {}
148+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
/*
2+
* Copyright 2024 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 2.6.1
19+
*/
20+
package com.google.api.client.googleapis.apache.v5;

0 commit comments

Comments
 (0)