Skip to content

Commit 47ec152

Browse files
committed
Merge branch 'main' into mds-cred-token-req-param
2 parents ba11e8a + 08a5436 commit 47ec152

File tree

13 files changed

+617
-24
lines changed

13 files changed

+617
-24
lines changed

CHANGELOG.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,17 @@
11
# Changelog
22

3+
## [1.30.0](https://github.com/googleapis/google-auth-library-java/compare/v1.29.0...v1.30.0) (2024-11-08)
4+
5+
6+
### Features
7+
8+
* Support querying S2A Addresses from MDS ([#1400](https://github.com/googleapis/google-auth-library-java/issues/1400)) ([df06bd1](https://github.com/googleapis/google-auth-library-java/commit/df06bd1f94d03c4f8807c2adf42d25d29b731531))
9+
10+
11+
### Bug Fixes
12+
13+
* Make it explicit that there is a network call to MDS to get SecureSessionAgentConfig ([#1573](https://github.com/googleapis/google-auth-library-java/issues/1573)) ([18020fe](https://github.com/googleapis/google-auth-library-java/commit/18020fedb855742ee27b6558f5de58d3818c6b48))
14+
315
## [1.29.0](https://github.com/googleapis/google-auth-library-java/compare/v1.28.0...v1.29.0) (2024-10-22)
416

517

appengine/pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
<parent>
66
<groupId>com.google.auth</groupId>
77
<artifactId>google-auth-library-parent</artifactId>
8-
<version>1.29.1-SNAPSHOT</version><!-- {x-version-update:google-auth-library-parent:current} -->
8+
<version>1.30.1-SNAPSHOT</version><!-- {x-version-update:google-auth-library-parent:current} -->
99
<relativePath>../pom.xml</relativePath>
1010
</parent>
1111

bom/pom.xml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
<modelVersion>4.0.0</modelVersion>
44
<groupId>com.google.auth</groupId>
55
<artifactId>google-auth-library-bom</artifactId>
6-
<version>1.29.1-SNAPSHOT</version><!-- {x-version-update:google-auth-library-bom:current} -->
6+
<version>1.30.1-SNAPSHOT</version><!-- {x-version-update:google-auth-library-bom:current} -->
77
<packaging>pom</packaging>
88
<name>Google Auth Library for Java BOM</name>
99
<description>
@@ -83,7 +83,7 @@
8383
<plugin>
8484
<groupId>org.apache.maven.plugins</groupId>
8585
<artifactId>maven-javadoc-plugin</artifactId>
86-
<version>3.10.1</version>
86+
<version>3.11.1</version>
8787
<configuration>
8888
<skip>true</skip>
8989
</configuration>

credentials/pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
<parent>
55
<groupId>com.google.auth</groupId>
66
<artifactId>google-auth-library-parent</artifactId>
7-
<version>1.29.1-SNAPSHOT</version><!-- {x-version-update:google-auth-library-parent:current} -->
7+
<version>1.30.1-SNAPSHOT</version><!-- {x-version-update:google-auth-library-parent:current} -->
88
<relativePath>../pom.xml</relativePath>
99
</parent>
1010

Lines changed: 213 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,213 @@
1+
/*
2+
* Copyright 2024, Google Inc. All rights reserved.
3+
*
4+
* Redistribution and use in source and binary forms, with or without
5+
* modification, are permitted provided that the following conditions are
6+
* met:
7+
*
8+
* * Redistributions of source code must retain the above copyright
9+
* notice, this list of conditions and the following disclaimer.
10+
* * Redistributions in binary form must reproduce the above
11+
* copyright notice, this list of conditions and the following disclaimer
12+
* in the documentation and/or other materials provided with the
13+
* distribution.
14+
*
15+
* * Neither the name of Google Inc. nor the names of its
16+
* contributors may be used to endorse or promote products derived from
17+
* this software without specific prior written permission.
18+
*
19+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20+
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21+
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22+
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23+
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24+
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25+
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26+
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27+
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28+
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29+
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30+
*/
31+
package com.google.auth.oauth2;
32+
33+
import com.google.api.client.http.GenericUrl;
34+
import com.google.api.client.http.HttpBackOffIOExceptionHandler;
35+
import com.google.api.client.http.HttpBackOffUnsuccessfulResponseHandler;
36+
import com.google.api.client.http.HttpRequest;
37+
import com.google.api.client.http.HttpResponse;
38+
import com.google.api.client.json.JsonObjectParser;
39+
import com.google.api.client.util.ExponentialBackOff;
40+
import com.google.api.client.util.GenericData;
41+
import com.google.auth.http.HttpTransportFactory;
42+
import com.google.common.collect.Iterables;
43+
import com.google.errorprone.annotations.CanIgnoreReturnValue;
44+
import java.io.IOException;
45+
import java.io.InputStream;
46+
import java.util.Arrays;
47+
import java.util.HashSet;
48+
import java.util.ServiceLoader;
49+
import java.util.Set;
50+
import javax.annotation.concurrent.ThreadSafe;
51+
52+
/**
53+
* Utilities to fetch the S2A (Secure Session Agent) address from the mTLS configuration.
54+
*
55+
* <p>mTLS configuration is queried from the MDS MTLS Autoconfiguration endpoint. See
56+
* https://google.aip.dev/auth/4115 for details.
57+
*
58+
* <p>This is an experimental utility.
59+
*/
60+
@ThreadSafe
61+
public class SecureSessionAgent {
62+
static final String S2A_PLAINTEXT_ADDRESS_JSON_KEY = "plaintext_address";
63+
static final String S2A_MTLS_ADDRESS_JSON_KEY = "mtls_address";
64+
static final String S2A_CONFIG_ENDPOINT_POSTFIX =
65+
"/computeMetadata/v1/instance/platform-security/auto-mtls-configuration";
66+
67+
static final String METADATA_FLAVOR = "Metadata-Flavor";
68+
static final String GOOGLE = "Google";
69+
private static final Set<Integer> RETRYABLE_STATUS_CODES =
70+
new HashSet<>(Arrays.asList(500, 502, 503));
71+
private static final String PARSE_ERROR_S2A = "Error parsing S2A Config from MDS JSON response.";
72+
private static final String MDS_MTLS_ENDPOINT =
73+
ComputeEngineCredentials.getMetadataServerUrl() + S2A_CONFIG_ENDPOINT_POSTFIX;
74+
75+
private transient HttpTransportFactory transportFactory;
76+
77+
SecureSessionAgent(SecureSessionAgent.Builder builder) {
78+
this.transportFactory = builder.getHttpTransportFactory();
79+
}
80+
81+
/**
82+
* This method makes a network call to MDS to get the {@link SecureSessionAgentConfig} which
83+
* contains the plaintext and mtls address to reach the S2A (Secure Session Agent).
84+
*
85+
* @return a SecureSessionAgentConfig.
86+
*/
87+
public SecureSessionAgentConfig getConfig() {
88+
return getSecureSessionAgentConfigFromMDS();
89+
}
90+
91+
/** @return default instance of SecureSessionAgent */
92+
public static SecureSessionAgent create() {
93+
return newBuilder().build();
94+
}
95+
96+
public static Builder newBuilder() {
97+
return new Builder();
98+
}
99+
100+
public static class Builder {
101+
private HttpTransportFactory transportFactory;
102+
103+
protected Builder() {}
104+
105+
@CanIgnoreReturnValue
106+
public Builder setHttpTransportFactory(HttpTransportFactory transportFactory) {
107+
this.transportFactory = transportFactory;
108+
return this;
109+
}
110+
111+
public HttpTransportFactory getHttpTransportFactory() {
112+
return this.transportFactory;
113+
}
114+
115+
public SecureSessionAgent build() {
116+
return new SecureSessionAgent(this);
117+
}
118+
}
119+
120+
/**
121+
* Queries the MDS mTLS Autoconfiguration endpoint and returns the {@link
122+
* SecureSessionAgentConfig}.
123+
*
124+
* <p>Returns {@link SecureSessionAgentConfig}. If S2A is not running, or if any error occurs when
125+
* making the request to MDS / processing the response, {@link SecureSessionAgentConfig} will be
126+
* populated with empty addresses.
127+
*
128+
* <p>Users are expected to try to fetch the mTLS-S2A address first (via {@link
129+
* getMtlsS2AAddress}). If it is empty or they have some problem loading the mTLS-MDS credentials,
130+
* they should then fallback to fetching the plaintext-S2A address (via {@link
131+
* getPlaintextS2AAddress}). If the plaintext-S2A address is empty it means that an error occurred
132+
* when talking to the MDS / processing the response or that S2A is not running in the
133+
* environment; in either case this indicates S2A shouldn't be used.
134+
*
135+
* @return the {@link SecureSessionAgentConfig}.
136+
*/
137+
private SecureSessionAgentConfig getSecureSessionAgentConfigFromMDS() {
138+
if (transportFactory == null) {
139+
transportFactory =
140+
Iterables.getFirst(
141+
ServiceLoader.load(HttpTransportFactory.class), OAuth2Utils.HTTP_TRANSPORT_FACTORY);
142+
}
143+
144+
HttpRequest request = null;
145+
GenericUrl genericUrl = new GenericUrl(MDS_MTLS_ENDPOINT);
146+
try {
147+
request = transportFactory.create().createRequestFactory().buildGetRequest(genericUrl);
148+
} catch (IOException ignore) {
149+
/*
150+
* Return empty addresses in {@link SecureSessionAgentConfig} if error building the GET request.
151+
*/
152+
return SecureSessionAgentConfig.createBuilder().build();
153+
}
154+
155+
request.setParser(new JsonObjectParser(OAuth2Utils.JSON_FACTORY));
156+
request.getHeaders().set(METADATA_FLAVOR, GOOGLE);
157+
request.setThrowExceptionOnExecuteError(false);
158+
request.setNumberOfRetries(OAuth2Utils.DEFAULT_NUMBER_OF_RETRIES);
159+
160+
ExponentialBackOff backoff =
161+
new ExponentialBackOff.Builder()
162+
.setInitialIntervalMillis(OAuth2Utils.INITIAL_RETRY_INTERVAL_MILLIS)
163+
.setRandomizationFactor(OAuth2Utils.RETRY_RANDOMIZATION_FACTOR)
164+
.setMultiplier(OAuth2Utils.RETRY_MULTIPLIER)
165+
.build();
166+
167+
// Retry on 5xx status codes.
168+
request.setUnsuccessfulResponseHandler(
169+
new HttpBackOffUnsuccessfulResponseHandler(backoff)
170+
.setBackOffRequired(
171+
response -> RETRYABLE_STATUS_CODES.contains(response.getStatusCode())));
172+
request.setIOExceptionHandler(new HttpBackOffIOExceptionHandler(backoff));
173+
174+
GenericData responseData = null;
175+
try {
176+
HttpResponse response = request.execute();
177+
InputStream content = response.getContent();
178+
if (content == null) {
179+
return SecureSessionAgentConfig.createBuilder().build();
180+
}
181+
responseData = response.parseAs(GenericData.class);
182+
} catch (IOException ignore) {
183+
/*
184+
* Return empty addresses in {@link SecureSessionAgentConfig} once all retries have been exhausted.
185+
*/
186+
return SecureSessionAgentConfig.createBuilder().build();
187+
}
188+
189+
String plaintextS2AAddress = "";
190+
String mtlsS2AAddress = "";
191+
try {
192+
plaintextS2AAddress =
193+
OAuth2Utils.validateString(responseData, S2A_PLAINTEXT_ADDRESS_JSON_KEY, PARSE_ERROR_S2A);
194+
} catch (IOException ignore) {
195+
/*
196+
* Do not throw error because of parsing error, just leave the address as empty in {@link SecureSessionAgentConfig}.
197+
*/
198+
}
199+
try {
200+
mtlsS2AAddress =
201+
OAuth2Utils.validateString(responseData, S2A_MTLS_ADDRESS_JSON_KEY, PARSE_ERROR_S2A);
202+
} catch (IOException ignore) {
203+
/*
204+
* Do not throw error because of parsing error, just leave the address as empty in {@link SecureSessionAgentConfig}.
205+
*/
206+
}
207+
208+
return SecureSessionAgentConfig.createBuilder()
209+
.setPlaintextAddress(plaintextS2AAddress)
210+
.setMtlsAddress(mtlsS2AAddress)
211+
.build();
212+
}
213+
}
Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
/*
2+
* Copyright 2024, Google Inc. All rights reserved.
3+
*
4+
* Redistribution and use in source and binary forms, with or without
5+
* modification, are permitted provided that the following conditions are
6+
* met:
7+
*
8+
* * Redistributions of source code must retain the above copyright
9+
* notice, this list of conditions and the following disclaimer.
10+
* * Redistributions in binary form must reproduce the above
11+
* copyright notice, this list of conditions and the following disclaimer
12+
* in the documentation and/or other materials provided with the
13+
* distribution.
14+
*
15+
* * Neither the name of Google Inc. nor the names of its
16+
* contributors may be used to endorse or promote products derived from
17+
* this software without specific prior written permission.
18+
*
19+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20+
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21+
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22+
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23+
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24+
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25+
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26+
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27+
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28+
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29+
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30+
*/
31+
package com.google.auth.oauth2;
32+
33+
import com.google.errorprone.annotations.CanIgnoreReturnValue;
34+
35+
/** Holds an mTLS configuration (consists of address of S2A) retrieved from the Metadata Server. */
36+
public class SecureSessionAgentConfig {
37+
// plaintextAddress is the plaintext address to reach the S2A.
38+
private final String plaintextAddress;
39+
40+
// mtlsAddress is the mTLS address to reach the S2A.
41+
private final String mtlsAddress;
42+
43+
public static Builder createBuilder() {
44+
return new Builder();
45+
}
46+
47+
/** @return the plaintext S2A Address. */
48+
public String getPlaintextAddress() {
49+
return plaintextAddress;
50+
}
51+
52+
/** @return the mTLS S2A Address. */
53+
public String getMtlsAddress() {
54+
return mtlsAddress;
55+
}
56+
57+
public static final class Builder {
58+
// plaintextAddress is the plaintext address to reach the S2A.
59+
private String plaintextAddress;
60+
61+
// mtlsAddress is the mTLS address to reach the S2A.
62+
private String mtlsAddress;
63+
64+
Builder() {
65+
plaintextAddress = "";
66+
mtlsAddress = "";
67+
}
68+
69+
@CanIgnoreReturnValue
70+
public Builder setPlaintextAddress(String plaintextAddress) {
71+
/*
72+
* No validation / format check is necessary here. It is up to the client which consumes this address
73+
* to return error if there is a problem connecting to S2A at that address.
74+
*/
75+
this.plaintextAddress = plaintextAddress;
76+
return this;
77+
}
78+
79+
@CanIgnoreReturnValue
80+
public Builder setMtlsAddress(String mtlsAddress) {
81+
/*
82+
* No validation / format check is necessary here. It is up to the client which consumes this address
83+
* to return error if there is a problem connecting to S2A at that address.
84+
*/
85+
this.mtlsAddress = mtlsAddress;
86+
return this;
87+
}
88+
89+
public SecureSessionAgentConfig build() {
90+
return new SecureSessionAgentConfig(plaintextAddress, mtlsAddress);
91+
}
92+
}
93+
94+
private SecureSessionAgentConfig(String plaintextAddress, String mtlsAddress) {
95+
this.plaintextAddress = plaintextAddress;
96+
this.mtlsAddress = mtlsAddress;
97+
}
98+
}

0 commit comments

Comments
 (0)