diff --git a/credentials/pom.xml b/credentials/pom.xml
index 48a97db60..e4547d6a6 100644
--- a/credentials/pom.xml
+++ b/credentials/pom.xml
@@ -4,7 +4,7 @@
com.google.auth
google-auth-library-parent
- 1.15.0
+ 1.16.0
../pom.xml
diff --git a/oauth2_http/java/com/google/auth/oauth2/DefaultPKCEProvider.java b/oauth2_http/java/com/google/auth/oauth2/DefaultPKCEProvider.java
new file mode 100644
index 000000000..d4671dbe2
--- /dev/null
+++ b/oauth2_http/java/com/google/auth/oauth2/DefaultPKCEProvider.java
@@ -0,0 +1,109 @@
+/*
+ * Copyright 2023, Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package com.google.auth.oauth2;
+
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.security.SecureRandom;
+import java.util.Base64;
+
+/**
+ * Implements PKCE using only the Java standard library. See https://www.rfc-editor.org/rfc/rfc7636.
+ *
+ * https://developers.google.com/identity/protocols/oauth2/native-app#step1-code-verifier.
+ */
+public class DefaultPKCEProvider implements PKCEProvider {
+ private String codeVerifier;
+ private CodeChallenge codeChallenge;
+ private static final int MAX_CODE_VERIFIER_LENGTH = 127;
+
+ private String createCodeVerifier() {
+ SecureRandom sr = new SecureRandom();
+ byte[] code = new byte[MAX_CODE_VERIFIER_LENGTH];
+ sr.nextBytes(code);
+ return Base64.getUrlEncoder().encodeToString(code);
+ }
+
+ private CodeChallenge createCodeChallenge(String codeVerifier) {
+ return new DefaultPKCEProvider.CodeChallenge(codeVerifier);
+ }
+
+ public DefaultPKCEProvider() {
+ this.codeVerifier = createCodeVerifier();
+ this.codeChallenge = createCodeChallenge(this.codeVerifier);
+ }
+
+ @Override
+ public String getCodeVerifier() {
+ return codeVerifier;
+ }
+
+ @Override
+ public String getCodeChallenge() {
+ return codeChallenge.getCodeChallenge();
+ }
+
+ @Override
+ public String getCodeChallengeMethod() {
+ return codeChallenge.getCodeChallengeMethod();
+ }
+
+ /** Class representing the Code Challenge derived from a Code Verifier string. */
+ private class CodeChallenge {
+ private String codeChallenge;
+ private String codeChallengeMethod;
+
+ CodeChallenge(String codeVerifier) {
+ try {
+ byte[] bytes = codeVerifier.getBytes();
+ MessageDigest md = MessageDigest.getInstance("SHA-256");
+ md.update(bytes);
+
+ byte[] digest = md.digest();
+
+ this.codeChallenge = Base64.getUrlEncoder().encodeToString(digest);
+ this.codeChallengeMethod = "S256";
+ } catch (NoSuchAlgorithmException e) {
+ this.codeChallenge = codeVerifier;
+ this.codeChallengeMethod = "plain";
+ }
+ }
+
+ public String getCodeChallenge() {
+ return codeChallenge;
+ }
+
+ public String getCodeChallengeMethod() {
+ return codeChallengeMethod;
+ }
+ }
+}
diff --git a/oauth2_http/java/com/google/auth/oauth2/ExternalAccountCredentials.java b/oauth2_http/java/com/google/auth/oauth2/ExternalAccountCredentials.java
index 0ec33935c..0140d0881 100644
--- a/oauth2_http/java/com/google/auth/oauth2/ExternalAccountCredentials.java
+++ b/oauth2_http/java/com/google/auth/oauth2/ExternalAccountCredentials.java
@@ -54,7 +54,6 @@
import java.util.Locale;
import java.util.Map;
import java.util.concurrent.Executor;
-import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.annotation.Nullable;
@@ -589,37 +588,20 @@ public boolean isWorkforcePoolConfiguration() {
}
static void validateTokenUrl(String tokenUrl) {
- List patterns = new ArrayList<>();
- patterns.add(Pattern.compile("^[^\\.\\s\\/\\\\]+\\.sts\\.googleapis\\.com$"));
- patterns.add(Pattern.compile("^sts\\.googleapis\\.com$"));
- patterns.add(Pattern.compile("^sts\\.[^\\.\\s\\/\\\\]+\\.googleapis\\.com$"));
- patterns.add(Pattern.compile("^[^\\.\\s\\/\\\\]+\\-sts\\.googleapis\\.com$"));
- patterns.add(Pattern.compile("^sts\\-[^\\.\\s\\/\\\\]+\\.p\\.googleapis\\.com$"));
-
- if (!isValidUrl(patterns, tokenUrl)) {
+ if (!isValidUrl(tokenUrl)) {
throw new IllegalArgumentException("The provided token URL is invalid.");
}
}
static void validateServiceAccountImpersonationInfoUrl(String serviceAccountImpersonationUrl) {
- List patterns = new ArrayList<>();
- patterns.add(Pattern.compile("^[^\\.\\s\\/\\\\]+\\.iamcredentials\\.googleapis\\.com$"));
- patterns.add(Pattern.compile("^iamcredentials\\.googleapis\\.com$"));
- patterns.add(Pattern.compile("^iamcredentials\\.[^\\.\\s\\/\\\\]+\\.googleapis\\.com$"));
- patterns.add(Pattern.compile("^[^\\.\\s\\/\\\\]+\\-iamcredentials\\.googleapis\\.com$"));
- patterns.add(Pattern.compile("^iamcredentials-[^\\.\\s\\/\\\\]+\\.p\\.googleapis\\.com$"));
-
- if (!isValidUrl(patterns, serviceAccountImpersonationUrl)) {
+ if (!isValidUrl(serviceAccountImpersonationUrl)) {
throw new IllegalArgumentException(
"The provided service account impersonation URL is invalid.");
}
}
- /**
- * Returns true if the provided URL's scheme is HTTPS and the host comforms to at least one of the
- * provided patterns.
- */
- private static boolean isValidUrl(List patterns, String url) {
+ /** Returns true if the provided URL's scheme is valid and is HTTPS. */
+ private static boolean isValidUrl(String url) {
URI uri;
try {
@@ -635,13 +617,7 @@ private static boolean isValidUrl(List patterns, String url) {
return false;
}
- for (Pattern pattern : patterns) {
- Matcher match = pattern.matcher(uri.getHost().toLowerCase(Locale.US));
- if (match.matches()) {
- return true;
- }
- }
- return false;
+ return true;
}
/**
diff --git a/oauth2_http/java/com/google/auth/oauth2/PKCEProvider.java b/oauth2_http/java/com/google/auth/oauth2/PKCEProvider.java
new file mode 100644
index 000000000..4800dd1cd
--- /dev/null
+++ b/oauth2_http/java/com/google/auth/oauth2/PKCEProvider.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2023, Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package com.google.auth.oauth2;
+
+public interface PKCEProvider {
+ /**
+ * Get the code_challenge parameter used in PKCE.
+ *
+ * @return The code_challenge String.
+ */
+ String getCodeChallenge();
+
+ /**
+ * Get the code_challenge_method parameter used in PKCE.
+ *
+ * Currently possible values are: S256,plain
+ *
+ * @return The code_challenge_method String.
+ */
+ String getCodeChallengeMethod();
+ /**
+ * Get the code_verifier parameter used in PKCE.
+ *
+ * @return The code_verifier String.
+ */
+ String getCodeVerifier();
+}
diff --git a/oauth2_http/java/com/google/auth/oauth2/ServiceAccountCredentials.java b/oauth2_http/java/com/google/auth/oauth2/ServiceAccountCredentials.java
index 479041ead..c6c95a71c 100644
--- a/oauth2_http/java/com/google/auth/oauth2/ServiceAccountCredentials.java
+++ b/oauth2_http/java/com/google/auth/oauth2/ServiceAccountCredentials.java
@@ -110,6 +110,8 @@ public class ServiceAccountCredentials extends GoogleCredentials
private transient HttpTransportFactory transportFactory;
+ private transient JwtCredentials selfSignedJwtCredentialsWithScope = null;
+
/**
* Internal constructor
*
@@ -704,6 +706,11 @@ public boolean getUseJwtAccessWithScope() {
return useJwtAccessWithScope;
}
+ @VisibleForTesting
+ JwtCredentials getSelfSignedJwtCredentialsWithScope() {
+ return selfSignedJwtCredentialsWithScope;
+ }
+
@Override
public String getAccount() {
return getClientEmail();
@@ -935,8 +942,11 @@ public Map> getRequestMetadata(URI uri) throws IOException
// Otherwise, use self signed JWT with uri as the audience.
JwtCredentials jwtCredentials;
if (!createScopedRequired() && useJwtAccessWithScope) {
- // Create JWT credentials with the scopes.
- jwtCredentials = createSelfSignedJwtCredentials(null);
+ // Create selfSignedJwtCredentialsWithScope when needed and reuse it for better performance.
+ if (selfSignedJwtCredentialsWithScope == null) {
+ selfSignedJwtCredentialsWithScope = createSelfSignedJwtCredentials(null);
+ }
+ jwtCredentials = selfSignedJwtCredentialsWithScope;
} else {
// Create JWT credentials with the uri as audience.
jwtCredentials = createSelfSignedJwtCredentials(uri);
diff --git a/oauth2_http/java/com/google/auth/oauth2/UserAuthorizer.java b/oauth2_http/java/com/google/auth/oauth2/UserAuthorizer.java
index c152b8b44..29a8284d5 100644
--- a/oauth2_http/java/com/google/auth/oauth2/UserAuthorizer.java
+++ b/oauth2_http/java/com/google/auth/oauth2/UserAuthorizer.java
@@ -67,6 +67,7 @@ public class UserAuthorizer {
private final HttpTransportFactory transportFactory;
private final URI tokenServerUri;
private final URI userAuthUri;
+ private final PKCEProvider pkce;
/**
* Constructor with all parameters.
@@ -79,6 +80,7 @@ public class UserAuthorizer {
* tokens.
* @param tokenServerUri URI of the end point that provides tokens
* @param userAuthUri URI of the Web UI for user consent
+ * @param pkce PKCE implementation
*/
private UserAuthorizer(
ClientId clientId,
@@ -87,7 +89,8 @@ private UserAuthorizer(
URI callbackUri,
HttpTransportFactory transportFactory,
URI tokenServerUri,
- URI userAuthUri) {
+ URI userAuthUri,
+ PKCEProvider pkce) {
this.clientId = Preconditions.checkNotNull(clientId);
this.scopes = ImmutableList.copyOf(Preconditions.checkNotNull(scopes));
this.callbackUri = (callbackUri == null) ? DEFAULT_CALLBACK_URI : callbackUri;
@@ -96,6 +99,7 @@ private UserAuthorizer(
this.tokenServerUri = (tokenServerUri == null) ? OAuth2Utils.TOKEN_SERVER_URI : tokenServerUri;
this.userAuthUri = (userAuthUri == null) ? OAuth2Utils.USER_AUTH_URI : userAuthUri;
this.tokenStore = (tokenStore == null) ? new MemoryTokensStorage() : tokenStore;
+ this.pkce = pkce;
}
/**
@@ -181,6 +185,10 @@ public URL getAuthorizationUrl(String userId, String state, URI baseUri) {
url.put("login_hint", userId);
}
url.put("include_granted_scopes", true);
+ if (pkce != null) {
+ url.put("code_challenge", pkce.getCodeChallenge());
+ url.put("code_challenge_method", pkce.getCodeChallengeMethod());
+ }
return url.toURL();
}
@@ -248,6 +256,11 @@ public UserCredentials getCredentialsFromCode(String code, URI baseUri) throws I
tokenData.put("client_secret", clientId.getClientSecret());
tokenData.put("redirect_uri", resolvedCallbackUri);
tokenData.put("grant_type", "authorization_code");
+
+ if (pkce != null) {
+ tokenData.put("code_verifier", pkce.getCodeVerifier());
+ }
+
UrlEncodedContent tokenContent = new UrlEncodedContent(tokenData);
HttpRequestFactory requestFactory = transportFactory.create().createRequestFactory();
HttpRequest tokenRequest =
@@ -430,6 +443,7 @@ public static class Builder {
private URI userAuthUri;
private Collection scopes;
private HttpTransportFactory transportFactory;
+ private PKCEProvider pkce;
protected Builder() {}
@@ -441,6 +455,7 @@ protected Builder(UserAuthorizer authorizer) {
this.tokenStore = authorizer.tokenStore;
this.callbackUri = authorizer.callbackUri;
this.userAuthUri = authorizer.userAuthUri;
+ this.pkce = new DefaultPKCEProvider();
}
public Builder setClientId(ClientId clientId) {
@@ -478,6 +493,20 @@ public Builder setHttpTransportFactory(HttpTransportFactory transportFactory) {
return this;
}
+ public Builder setPKCEProvider(PKCEProvider pkce) {
+ if (pkce != null) {
+ if (pkce.getCodeChallenge() == null
+ || pkce.getCodeVerifier() == null
+ || pkce.getCodeChallengeMethod() == null) {
+
+ throw new IllegalArgumentException(
+ "PKCE provider contained null implementations. PKCE object must implement all PKCEProvider methods.");
+ }
+ }
+ this.pkce = pkce;
+ return this;
+ }
+
public ClientId getClientId() {
return clientId;
}
@@ -506,9 +535,20 @@ public HttpTransportFactory getHttpTransportFactory() {
return transportFactory;
}
+ public PKCEProvider getPKCEProvider() {
+ return pkce;
+ }
+
public UserAuthorizer build() {
return new UserAuthorizer(
- clientId, scopes, tokenStore, callbackUri, transportFactory, tokenServerUri, userAuthUri);
+ clientId,
+ scopes,
+ tokenStore,
+ callbackUri,
+ transportFactory,
+ tokenServerUri,
+ userAuthUri,
+ pkce);
}
}
}
diff --git a/oauth2_http/javatests/com/google/auth/oauth2/DefaultPKCEProviderTest.java b/oauth2_http/javatests/com/google/auth/oauth2/DefaultPKCEProviderTest.java
new file mode 100644
index 000000000..e56739aad
--- /dev/null
+++ b/oauth2_http/javatests/com/google/auth/oauth2/DefaultPKCEProviderTest.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2023, Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package com.google.auth.oauth2;
+
+import static org.junit.Assert.assertEquals;
+
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.util.Base64;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+@RunWith(JUnit4.class)
+public final class DefaultPKCEProviderTest {
+ @Test
+ public void testPkceExpected() throws NoSuchAlgorithmException {
+ PKCEProvider pkce = new DefaultPKCEProvider();
+
+ byte[] bytes = pkce.getCodeVerifier().getBytes();
+ MessageDigest md = MessageDigest.getInstance("SHA-256");
+ md.update(bytes);
+
+ byte[] digest = md.digest();
+
+ String expectedCodeChallenge = Base64.getUrlEncoder().encodeToString(digest);
+ String expectedCodeChallengeMethod = "S256";
+
+ assertEquals(pkce.getCodeChallenge(), expectedCodeChallenge);
+ assertEquals(pkce.getCodeChallengeMethod(), expectedCodeChallengeMethod);
+ }
+}
diff --git a/oauth2_http/javatests/com/google/auth/oauth2/ExternalAccountCredentialsTest.java b/oauth2_http/javatests/com/google/auth/oauth2/ExternalAccountCredentialsTest.java
index d8f5b30e4..2350af89d 100644
--- a/oauth2_http/javatests/com/google/auth/oauth2/ExternalAccountCredentialsTest.java
+++ b/oauth2_http/javatests/com/google/auth/oauth2/ExternalAccountCredentialsTest.java
@@ -980,34 +980,14 @@ public void validateTokenUrl_validUrls() {
public void validateTokenUrl_invalidUrls() {
List invalidUrls =
Arrays.asList(
- "https://iamcredentials.googleapis.com",
"sts.googleapis.com",
"https://",
"http://sts.googleapis.com",
- "https://st.s.googleapis.com",
"https://us-eas\\t-1.sts.googleapis.com",
"https:/us-east-1.sts.googleapis.com",
- "https://US-WE/ST-1-sts.googleapis.com",
- "https://sts-us-east-1.googleapis.com",
- "https://sts-US-WEST-1.googleapis.com",
"testhttps://us-east-1.sts.googleapis.com",
- "https://us-east-1.sts.googleapis.comevil.com",
- "https://us-east-1.us-east-1.sts.googleapis.com",
- "https://us-ea.s.t.sts.googleapis.com",
- "https://sts.googleapis.comevil.com",
"hhttps://us-east-1.sts.googleapis.com",
- "https://us- -1.sts.googleapis.com",
- "https://-sts.googleapis.com",
- "https://us-east-1.sts.googleapis.com.evil.com",
- "https://sts.pgoogleapis.com",
- "https://p.googleapis.com",
- "https://sts.p.com",
- "http://sts.p.googleapis.com",
- "https://xyz-sts.p.googleapis.com",
- "https://sts-xyz.123.p.googleapis.com",
- "https://sts-xyz.p1.googleapis.com",
- "https://sts-xyz.p.foo.com",
- "https://sts-xyz.p.foo.googleapis.com");
+ "https://us- -1.sts.googleapis.com");
for (String url : invalidUrls) {
try {
@@ -1046,34 +1026,14 @@ public void validateServiceAccountImpersonationUrls_validUrls() {
public void validateServiceAccountImpersonationUrls_invalidUrls() {
List invalidUrls =
Arrays.asList(
- "https://sts.googleapis.com",
"iamcredentials.googleapis.com",
"https://",
"http://iamcredentials.googleapis.com",
- "https://iamcre.dentials.googleapis.com",
+ "https:/iamcredentials.googleapis.com",
"https://us-eas\t-1.iamcredentials.googleapis.com",
- "https:/us-east-1.iamcredentials.googleapis.com",
- "https://US-WE/ST-1-iamcredentials.googleapis.com",
- "https://iamcredentials-us-east-1.googleapis.com",
- "https://iamcredentials-US-WEST-1.googleapis.com",
"testhttps://us-east-1.iamcredentials.googleapis.com",
- "https://us-east-1.iamcredentials.googleapis.comevil.com",
- "https://us-east-1.us-east-1.iamcredentials.googleapis.com",
- "https://us-ea.s.t.iamcredentials.googleapis.com",
- "https://iamcredentials.googleapis.comevil.com",
"hhttps://us-east-1.iamcredentials.googleapis.com",
- "https://us- -1.iamcredentials.googleapis.com",
- "https://-iamcredentials.googleapis.com",
- "https://us-east-1.iamcredentials.googleapis.com.evil.com",
- "https://iamcredentials.pgoogleapis.com",
- "https://p.googleapis.com",
- "https://iamcredentials.p.com",
- "http://iamcredentials.p.googleapis.com",
- "https://xyz-iamcredentials.p.googleapis.com",
- "https://iamcredentials-xyz.123.p.googleapis.com",
- "https://iamcredentials-xyz.p1.googleapis.com",
- "https://iamcredentials-xyz.p.foo.com",
- "https://iamcredentials-xyz.p.foo.googleapis.com");
+ "https://us- -1.iamcredentials.googleapis.com");
for (String url : invalidUrls) {
try {
diff --git a/oauth2_http/javatests/com/google/auth/oauth2/ServiceAccountCredentialsTest.java b/oauth2_http/javatests/com/google/auth/oauth2/ServiceAccountCredentialsTest.java
index 14eb16b92..f3b3f0983 100644
--- a/oauth2_http/javatests/com/google/auth/oauth2/ServiceAccountCredentialsTest.java
+++ b/oauth2_http/javatests/com/google/auth/oauth2/ServiceAccountCredentialsTest.java
@@ -1465,6 +1465,7 @@ public void getRequestMetadata_selfSignedJWT_withScopes() throws IOException {
.build();
Map> metadata = credentials.getRequestMetadata(CALL_URI);
+ assertNotNull(((ServiceAccountCredentials) credentials).getSelfSignedJwtCredentialsWithScope());
verifyJwtAccess(metadata, "dummy.scope");
}
@@ -1518,6 +1519,7 @@ public void getRequestMetadata_selfSignedJWT_withAudience() throws IOException {
.build();
Map> metadata = credentials.getRequestMetadata(CALL_URI);
+ assertNull(((ServiceAccountCredentials) credentials).getSelfSignedJwtCredentialsWithScope());
verifyJwtAccess(metadata, null);
}
diff --git a/oauth2_http/javatests/com/google/auth/oauth2/UserAuthorizerTest.java b/oauth2_http/javatests/com/google/auth/oauth2/UserAuthorizerTest.java
index 822fcbe12..7f444330f 100644
--- a/oauth2_http/javatests/com/google/auth/oauth2/UserAuthorizerTest.java
+++ b/oauth2_http/javatests/com/google/auth/oauth2/UserAuthorizerTest.java
@@ -72,6 +72,7 @@ public class UserAuthorizerTest {
private static final URI CALLBACK_URI = URI.create("/testcallback");
private static final String CODE = "thisistheend";
private static final URI BASE_URI = URI.create("http://example.com/foo");
+ private static final PKCEProvider pkce = new DefaultPKCEProvider();
@Test
public void constructorMinimum() {
@@ -148,6 +149,7 @@ public void getAuthorizationUrl() throws IOException {
.setScopes(DUMMY_SCOPES)
.setCallbackUri(CALLBACK_URI)
.setUserAuthUri(AUTH_URI)
+ .setPKCEProvider(pkce)
.build();
URL authorizationUrl = authorizer.getAuthorizationUrl(USER_ID, CUSTOM_STATE, BASE_URI);
@@ -164,6 +166,8 @@ public void getAuthorizationUrl() throws IOException {
assertEquals(CLIENT_ID_VALUE, parameters.get("client_id"));
assertEquals(DUMMY_SCOPE, parameters.get("scope"));
assertEquals("code", parameters.get("response_type"));
+ assertEquals(pkce.getCodeChallenge(), parameters.get("code_challenge"));
+ assertEquals(pkce.getCodeChallengeMethod(), parameters.get("code_challenge_method"));
}
@Test
@@ -471,4 +475,91 @@ public void revokeAuthorization_revokesAndClears() throws IOException {
UserCredentials credentials2 = authorizer.getCredentials(USER_ID);
assertNull(credentials2);
}
+
+ @Test(expected = IllegalArgumentException.class)
+ public void nullCodeVerifierPKCEProvider() {
+ PKCEProvider pkce =
+ new PKCEProvider() {
+ @Override
+ public String getCodeVerifier() {
+ return null;
+ }
+
+ @Override
+ public String getCodeChallengeMethod() {
+ return "dummy string";
+ }
+
+ @Override
+ public String getCodeChallenge() {
+ return "dummy string";
+ }
+ };
+
+ UserAuthorizer authorizer =
+ UserAuthorizer.newBuilder()
+ .setClientId(CLIENT_ID)
+ .setScopes(DUMMY_SCOPES)
+ .setTokenStore(new MemoryTokensStorage())
+ .setPKCEProvider(pkce)
+ .build();
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void nullCodeChallengePKCEProvider() {
+ PKCEProvider pkce =
+ new PKCEProvider() {
+ @Override
+ public String getCodeVerifier() {
+ return "dummy string";
+ }
+
+ @Override
+ public String getCodeChallengeMethod() {
+ return "dummy string";
+ }
+
+ @Override
+ public String getCodeChallenge() {
+ return null;
+ }
+ };
+
+ UserAuthorizer authorizer =
+ UserAuthorizer.newBuilder()
+ .setClientId(CLIENT_ID)
+ .setScopes(DUMMY_SCOPES)
+ .setTokenStore(new MemoryTokensStorage())
+ .setPKCEProvider(pkce)
+ .build();
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void nullCodeChallengeMethodPKCEProvider() {
+ PKCEProvider pkce =
+ new PKCEProvider() {
+ @Override
+ public String getCodeVerifier() {
+ return "dummy string";
+ }
+
+ @Override
+ public String getCodeChallengeMethod() {
+ return null;
+ }
+
+ @Override
+ public String getCodeChallenge() {
+ return "dummy string";
+ }
+ };
+
+ UserAuthorizer authorizer =
+ UserAuthorizer.newBuilder()
+ .setClientId(CLIENT_ID)
+ .setScopes(DUMMY_SCOPES)
+ .setTokenStore(new MemoryTokensStorage())
+ .setPKCEProvider(pkce)
+ .build();
+ }
}
diff --git a/oauth2_http/pom.xml b/oauth2_http/pom.xml
index be57457b1..576309e7d 100644
--- a/oauth2_http/pom.xml
+++ b/oauth2_http/pom.xml
@@ -1,11 +1,13 @@
-
+
4.0.0
com.google.auth
google-auth-library-parent
- 1.15.0
+ 1.16.0
../pom.xml
@@ -19,8 +21,73 @@
+
+
+
+ native
+
+
+ org.junit.vintage
+ junit-vintage-engine
+ 5.9.1
+ test
+
+
+ org.graalvm.buildtools
+ junit-platform-native
+ 0.9.19
+ test
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-surefire-plugin
+
+ 2.22.2
+
+
+
+
+ **/IT*.java
+ **/functional/*.java
+
+
+
+
+ org.graalvm.buildtools
+ native-maven-plugin
+ 0.9.19
+ true
+
+
+ test-native
+
+ test
+
+ test
+
+
+
+
+ --no-fallback
+ --no-server
+
+
+
+
+
+
+
+
java
+
+
+ resources
+
+
javatests
@@ -44,7 +111,8 @@
org.apache.maven.plugins
maven-dependency-plugin
- com.google.auto.value:auto-value
+ com.google.auto.value:auto-value
+
@@ -151,7 +219,7 @@
org.mockito
mockito-core
- 4.9.0
+ 4.11.0
test
diff --git a/oauth2_http/resources/META-INF/native-image/com.google.auth/google-auth-library-oauth2-http/reflect-config.json b/oauth2_http/resources/META-INF/native-image/com.google.auth/google-auth-library-oauth2-http/reflect-config.json
new file mode 100644
index 000000000..f2732db41
--- /dev/null
+++ b/oauth2_http/resources/META-INF/native-image/com.google.auth/google-auth-library-oauth2-http/reflect-config.json
@@ -0,0 +1,780 @@
+[
+ {
+ "name": "[B"
+ },
+ {
+ "name": "[Ljava.lang.String;"
+ },
+ {
+ "name": "[Lsun.security.pkcs.SignerInfo;"
+ },
+ {
+ "name": "com.google.api.client.http.GenericUrl",
+ "allDeclaredFields": true
+ },
+ {
+ "name": "com.google.api.client.http.HttpHeaders",
+ "allDeclaredFields": true,
+ "queryAllDeclaredMethods": true,
+ "methods": [
+ {
+ "name": "setAccept",
+ "parameterTypes": [
+ "java.lang.String"
+ ]
+ },
+ {
+ "name": "setAcceptEncoding",
+ "parameterTypes": [
+ "java.lang.String"
+ ]
+ },
+ {
+ "name": "setAge",
+ "parameterTypes": [
+ "java.lang.Long"
+ ]
+ },
+ {
+ "name": "setAuthenticate",
+ "parameterTypes": [
+ "java.lang.String"
+ ]
+ },
+ {
+ "name": "setAuthorization",
+ "parameterTypes": [
+ "java.lang.String"
+ ]
+ },
+ {
+ "name": "setAuthorization",
+ "parameterTypes": [
+ "java.util.List"
+ ]
+ },
+ {
+ "name": "setCacheControl",
+ "parameterTypes": [
+ "java.lang.String"
+ ]
+ },
+ {
+ "name": "setContentEncoding",
+ "parameterTypes": [
+ "java.lang.String"
+ ]
+ },
+ {
+ "name": "setContentLength",
+ "parameterTypes": [
+ "java.lang.Long"
+ ]
+ },
+ {
+ "name": "setContentMD5",
+ "parameterTypes": [
+ "java.lang.String"
+ ]
+ },
+ {
+ "name": "setContentRange",
+ "parameterTypes": [
+ "java.lang.String"
+ ]
+ },
+ {
+ "name": "setContentType",
+ "parameterTypes": [
+ "java.lang.String"
+ ]
+ },
+ {
+ "name": "setCookie",
+ "parameterTypes": [
+ "java.lang.String"
+ ]
+ },
+ {
+ "name": "setDate",
+ "parameterTypes": [
+ "java.lang.String"
+ ]
+ },
+ {
+ "name": "setETag",
+ "parameterTypes": [
+ "java.lang.String"
+ ]
+ },
+ {
+ "name": "setExpires",
+ "parameterTypes": [
+ "java.lang.String"
+ ]
+ },
+ {
+ "name": "setIfMatch",
+ "parameterTypes": [
+ "java.lang.String"
+ ]
+ },
+ {
+ "name": "setIfModifiedSince",
+ "parameterTypes": [
+ "java.lang.String"
+ ]
+ },
+ {
+ "name": "setIfNoneMatch",
+ "parameterTypes": [
+ "java.lang.String"
+ ]
+ },
+ {
+ "name": "setIfRange",
+ "parameterTypes": [
+ "java.lang.String"
+ ]
+ },
+ {
+ "name": "setIfUnmodifiedSince",
+ "parameterTypes": [
+ "java.lang.String"
+ ]
+ },
+ {
+ "name": "setLastModified",
+ "parameterTypes": [
+ "java.lang.String"
+ ]
+ },
+ {
+ "name": "setLocation",
+ "parameterTypes": [
+ "java.lang.String"
+ ]
+ },
+ {
+ "name": "setMimeVersion",
+ "parameterTypes": [
+ "java.lang.String"
+ ]
+ },
+ {
+ "name": "setRange",
+ "parameterTypes": [
+ "java.lang.String"
+ ]
+ },
+ {
+ "name": "setRetryAfter",
+ "parameterTypes": [
+ "java.lang.String"
+ ]
+ },
+ {
+ "name": "setUserAgent",
+ "parameterTypes": [
+ "java.lang.String"
+ ]
+ }
+ ]
+ },
+ {
+ "name": "com.google.api.client.json.GenericJson",
+ "allDeclaredFields": true,
+ "methods": [
+ {
+ "name": "",
+ "parameterTypes": []
+ }
+ ]
+ },
+ {
+ "name": "com.google.api.client.json.webtoken.JsonWebSignature$Header",
+ "allDeclaredFields": true,
+ "queryAllDeclaredMethods": true,
+ "methods": [
+ {
+ "name": "",
+ "parameterTypes": []
+ },
+ {
+ "name": "setAlgorithm",
+ "parameterTypes": [
+ "java.lang.String"
+ ]
+ },
+ {
+ "name": "setKeyId",
+ "parameterTypes": [
+ "java.lang.String"
+ ]
+ }
+ ]
+ },
+ {
+ "name": "com.google.api.client.json.webtoken.JsonWebToken$Header",
+ "allDeclaredFields": true,
+ "queryAllDeclaredMethods": true,
+ "methods": [
+ {
+ "name": "setType",
+ "parameterTypes": [
+ "java.lang.String"
+ ]
+ }
+ ]
+ },
+ {
+ "name": "com.google.api.client.json.webtoken.JsonWebToken$Payload",
+ "allDeclaredFields": true,
+ "queryAllDeclaredMethods": true,
+ "methods": [
+ {
+ "name": "",
+ "parameterTypes": []
+ },
+ {
+ "name": "setAudience",
+ "parameterTypes": [
+ "java.lang.Object"
+ ]
+ },
+ {
+ "name": "setExpirationTimeSeconds",
+ "parameterTypes": [
+ "java.lang.Long"
+ ]
+ },
+ {
+ "name": "setIssuedAtTimeSeconds",
+ "parameterTypes": [
+ "java.lang.Long"
+ ]
+ },
+ {
+ "name": "setIssuer",
+ "parameterTypes": [
+ "java.lang.String"
+ ]
+ },
+ {
+ "name": "setSubject",
+ "parameterTypes": [
+ "java.lang.String"
+ ]
+ }
+ ]
+ },
+ {
+ "name": "com.google.api.client.util.ArrayMap",
+ "allDeclaredFields": true
+ },
+ {
+ "name": "com.google.api.client.util.GenericData",
+ "allDeclaredFields": true,
+ "methods": [
+ {
+ "name": "",
+ "parameterTypes": []
+ }
+ ]
+ },
+ {
+ "name": "com.google.common.util.concurrent.AbstractFuture",
+ "fields": [
+ {
+ "name": "listeners"
+ },
+ {
+ "name": "value"
+ },
+ {
+ "name": "waiters"
+ }
+ ]
+ },
+ {
+ "name": "com.google.common.util.concurrent.AbstractFuture$Waiter",
+ "fields": [
+ {
+ "name": "next"
+ },
+ {
+ "name": "thread"
+ }
+ ]
+ },
+ {
+ "name": "com.sun.crypto.provider.AESCipher$General",
+ "methods": [
+ {
+ "name": "",
+ "parameterTypes": []
+ }
+ ]
+ },
+ {
+ "name": "com.sun.crypto.provider.DHParameters",
+ "methods": [
+ {
+ "name": "",
+ "parameterTypes": []
+ }
+ ]
+ },
+ {
+ "name": "com.sun.crypto.provider.HmacCore$HmacSHA256",
+ "methods": [
+ {
+ "name": "",
+ "parameterTypes": []
+ }
+ ]
+ },
+ {
+ "name": "com.sun.crypto.provider.HmacCore$HmacSHA384",
+ "methods": [
+ {
+ "name": "",
+ "parameterTypes": []
+ }
+ ]
+ },
+ {
+ "name": "com.sun.crypto.provider.TlsKeyMaterialGenerator",
+ "methods": [
+ {
+ "name": "",
+ "parameterTypes": []
+ }
+ ]
+ },
+ {
+ "name": "com.sun.crypto.provider.TlsMasterSecretGenerator",
+ "methods": [
+ {
+ "name": "",
+ "parameterTypes": []
+ }
+ ]
+ },
+ {
+ "name": "com.sun.crypto.provider.TlsPrfGenerator$V12",
+ "methods": [
+ {
+ "name": "",
+ "parameterTypes": []
+ }
+ ]
+ },
+ {
+ "name": "java.lang.Object",
+ "allDeclaredFields": true,
+ "queryAllDeclaredMethods": true
+ },
+ {
+ "name": "java.lang.String"
+ },
+ {
+ "name": "java.security.AlgorithmParametersSpi"
+ },
+ {
+ "name": "java.security.KeyStoreSpi"
+ },
+ {
+ "name": "java.security.MessageDigestSpi"
+ },
+ {
+ "name": "java.security.SecureRandomParameters"
+ },
+ {
+ "name": "java.security.interfaces.ECPrivateKey"
+ },
+ {
+ "name": "java.security.interfaces.ECPublicKey"
+ },
+ {
+ "name": "java.security.interfaces.RSAPrivateKey"
+ },
+ {
+ "name": "java.security.interfaces.RSAPublicKey"
+ },
+ {
+ "name": "java.util.AbstractMap",
+ "allDeclaredFields": true
+ },
+ {
+ "name": "java.util.Date"
+ },
+ {
+ "name": "javax.security.auth.x500.X500Principal",
+ "fields": [
+ {
+ "name": "thisX500Name"
+ }
+ ],
+ "methods": [
+ {
+ "name": "",
+ "parameterTypes": [
+ "sun.security.x509.X500Name"
+ ]
+ }
+ ]
+ },
+ {
+ "name": "sun.misc.Unsafe",
+ "allDeclaredFields": true
+ },
+ {
+ "name": "sun.security.pkcs12.PKCS12KeyStore",
+ "methods": [
+ {
+ "name": "",
+ "parameterTypes": []
+ }
+ ]
+ },
+ {
+ "name": "sun.security.pkcs12.PKCS12KeyStore$DualFormatPKCS12",
+ "methods": [
+ {
+ "name": "",
+ "parameterTypes": []
+ }
+ ]
+ },
+ {
+ "name": "sun.security.provider.DSA$SHA224withDSA",
+ "methods": [
+ {
+ "name": "",
+ "parameterTypes": []
+ }
+ ]
+ },
+ {
+ "name": "sun.security.provider.DSA$SHA256withDSA",
+ "methods": [
+ {
+ "name": "",
+ "parameterTypes": []
+ }
+ ]
+ },
+ {
+ "name": "sun.security.provider.JavaKeyStore$DualFormatJKS",
+ "methods": [
+ {
+ "name": "",
+ "parameterTypes": []
+ }
+ ]
+ },
+ {
+ "name": "sun.security.provider.JavaKeyStore$JKS",
+ "methods": [
+ {
+ "name": "",
+ "parameterTypes": []
+ }
+ ]
+ },
+ {
+ "name": "sun.security.provider.NativePRNG",
+ "methods": [
+ {
+ "name": "",
+ "parameterTypes": []
+ }
+ ]
+ },
+ {
+ "name": "sun.security.provider.SHA",
+ "methods": [
+ {
+ "name": "",
+ "parameterTypes": []
+ }
+ ]
+ },
+ {
+ "name": "sun.security.provider.SHA2$SHA224",
+ "methods": [
+ {
+ "name": "",
+ "parameterTypes": []
+ }
+ ]
+ },
+ {
+ "name": "sun.security.provider.SHA2$SHA256",
+ "methods": [
+ {
+ "name": "",
+ "parameterTypes": []
+ }
+ ]
+ },
+ {
+ "name": "sun.security.provider.SHA5$SHA384",
+ "methods": [
+ {
+ "name": "",
+ "parameterTypes": []
+ }
+ ]
+ },
+ {
+ "name": "sun.security.provider.SHA5$SHA512",
+ "methods": [
+ {
+ "name": "",
+ "parameterTypes": []
+ }
+ ]
+ },
+ {
+ "name": "sun.security.provider.X509Factory",
+ "methods": [
+ {
+ "name": "",
+ "parameterTypes": []
+ }
+ ]
+ },
+ {
+ "name": "sun.security.provider.certpath.PKIXCertPathValidator",
+ "methods": [
+ {
+ "name": "",
+ "parameterTypes": []
+ }
+ ]
+ },
+ {
+ "name": "sun.security.rsa.PSSParameters",
+ "methods": [
+ {
+ "name": "",
+ "parameterTypes": []
+ }
+ ]
+ },
+ {
+ "name": "sun.security.rsa.RSAKeyFactory$Legacy",
+ "methods": [
+ {
+ "name": "",
+ "parameterTypes": []
+ }
+ ]
+ },
+ {
+ "name": "sun.security.rsa.RSAPSSSignature",
+ "methods": [
+ {
+ "name": "",
+ "parameterTypes": []
+ }
+ ]
+ },
+ {
+ "name": "sun.security.rsa.RSASignature$SHA224withRSA",
+ "methods": [
+ {
+ "name": "",
+ "parameterTypes": []
+ }
+ ]
+ },
+ {
+ "name": "sun.security.rsa.RSASignature$SHA256withRSA",
+ "methods": [
+ {
+ "name": "",
+ "parameterTypes": []
+ }
+ ]
+ },
+ {
+ "name": "sun.security.ssl.KeyManagerFactoryImpl$SunX509",
+ "methods": [
+ {
+ "name": "",
+ "parameterTypes": []
+ }
+ ]
+ },
+ {
+ "name": "sun.security.ssl.SSLContextImpl$DefaultSSLContext",
+ "methods": [
+ {
+ "name": "",
+ "parameterTypes": []
+ }
+ ]
+ },
+ {
+ "name": "sun.security.ssl.TrustManagerFactoryImpl$PKIXFactory",
+ "methods": [
+ {
+ "name": "",
+ "parameterTypes": []
+ }
+ ]
+ },
+ {
+ "name": "sun.security.util.ObjectIdentifier"
+ },
+ {
+ "name": "sun.security.x509.AuthorityInfoAccessExtension",
+ "methods": [
+ {
+ "name": "",
+ "parameterTypes": [
+ "java.lang.Boolean",
+ "java.lang.Object"
+ ]
+ }
+ ]
+ },
+ {
+ "name": "sun.security.x509.AuthorityKeyIdentifierExtension",
+ "methods": [
+ {
+ "name": "",
+ "parameterTypes": [
+ "java.lang.Boolean",
+ "java.lang.Object"
+ ]
+ }
+ ]
+ },
+ {
+ "name": "sun.security.x509.BasicConstraintsExtension",
+ "methods": [
+ {
+ "name": "",
+ "parameterTypes": [
+ "java.lang.Boolean",
+ "java.lang.Object"
+ ]
+ }
+ ]
+ },
+ {
+ "name": "sun.security.x509.CRLDistributionPointsExtension",
+ "methods": [
+ {
+ "name": "",
+ "parameterTypes": [
+ "java.lang.Boolean",
+ "java.lang.Object"
+ ]
+ }
+ ]
+ },
+ {
+ "name": "sun.security.x509.CertificateExtensions"
+ },
+ {
+ "name": "sun.security.x509.CertificatePoliciesExtension",
+ "methods": [
+ {
+ "name": "",
+ "parameterTypes": [
+ "java.lang.Boolean",
+ "java.lang.Object"
+ ]
+ }
+ ]
+ },
+ {
+ "name": "sun.security.x509.ExtendedKeyUsageExtension",
+ "methods": [
+ {
+ "name": "",
+ "parameterTypes": [
+ "java.lang.Boolean",
+ "java.lang.Object"
+ ]
+ }
+ ]
+ },
+ {
+ "name": "sun.security.x509.IssuerAlternativeNameExtension",
+ "methods": [
+ {
+ "name": "",
+ "parameterTypes": [
+ "java.lang.Boolean",
+ "java.lang.Object"
+ ]
+ }
+ ]
+ },
+ {
+ "name": "sun.security.x509.KeyUsageExtension",
+ "methods": [
+ {
+ "name": "",
+ "parameterTypes": [
+ "java.lang.Boolean",
+ "java.lang.Object"
+ ]
+ }
+ ]
+ },
+ {
+ "name": "sun.security.x509.NetscapeCertTypeExtension",
+ "methods": [
+ {
+ "name": "",
+ "parameterTypes": [
+ "java.lang.Boolean",
+ "java.lang.Object"
+ ]
+ }
+ ]
+ },
+ {
+ "name": "sun.security.x509.PrivateKeyUsageExtension",
+ "methods": [
+ {
+ "name": "",
+ "parameterTypes": [
+ "java.lang.Boolean",
+ "java.lang.Object"
+ ]
+ }
+ ]
+ },
+ {
+ "name": "sun.security.x509.SubjectAlternativeNameExtension",
+ "methods": [
+ {
+ "name": "",
+ "parameterTypes": [
+ "java.lang.Boolean",
+ "java.lang.Object"
+ ]
+ }
+ ]
+ },
+ {
+ "name": "sun.security.x509.SubjectKeyIdentifierExtension",
+ "methods": [
+ {
+ "name": "",
+ "parameterTypes": [
+ "java.lang.Boolean",
+ "java.lang.Object"
+ ]
+ }
+ ]
+ }
+]
diff --git a/oauth2_http/resources/META-INF/native-image/native-image.properties b/oauth2_http/resources/META-INF/native-image/native-image.properties
new file mode 100644
index 000000000..c7a7fe4db
--- /dev/null
+++ b/oauth2_http/resources/META-INF/native-image/native-image.properties
@@ -0,0 +1 @@
+Args=--enable-url-protocols=https,http
diff --git a/owlbot.py b/owlbot.py
index c245dee99..610e82700 100644
--- a/owlbot.py
+++ b/owlbot.py
@@ -32,7 +32,10 @@
"samples/**",
".github/workflows/approve-readme.yaml",
".github/workflows/samples.yaml",
+ ".github/CODEOWNERS",
".kokoro/nightly/integration.cfg",
".kokoro/presubmit/integration.cfg",
+ ".kokoro/presubmit/graalvm-native.cfg",
+ ".kokoro/presubmit/graalvm-native-17.cfg"
]
)
diff --git a/pom.xml b/pom.xml
index 6cbd21677..43f05d384 100644
--- a/pom.xml
+++ b/pom.xml
@@ -1,13 +1,16 @@
-
+
4.0.0
com.google.auth
google-auth-library-parent
- 1.15.0
+ 1.16.0
pom
Google Auth Library for Java
Client libraries providing authentication and
- authorization to enable calling Google APIs.
+ authorization to enable calling Google APIs.
+