@@ -53,7 +56,8 @@
scm:git:https://github.com/googleapis/google-auth-library-java.git
- scm:git:https://github.com/googleapis/google-auth-library-java.git
+ scm:git:https://github.com/googleapis/google-auth-library-java.git
+
https://github.com/googleapis/google-auth-library-java
@@ -478,7 +482,7 @@
${project.artifactId}
- 7
+ 7
@@ -490,12 +494,12 @@
com.microsoft.doclet.DocFxDoclet
false
-
+
${env.KOKORO_GFILE_DIR}/${docletName}.jar
- -outputpath ${outputpath}
- -projectname ${projectname}
- -excludeclasses ${excludeclasses}:
+ -outputpath ${outputpath}
+ -projectname ${projectname}
+ -excludeclasses ${excludeclasses}:
-excludepackages ${excludePackages}:
none
@@ -507,7 +511,7 @@
false
-
+
From 5bf606bb8f6d863b44e87587eebf51eaeea4a0ae Mon Sep 17 00:00:00 2001
From: Carl Lundin <108372512+clundin25@users.noreply.github.com>
Date: Mon, 6 Feb 2023 15:42:37 -0800
Subject: [PATCH 06/14] feat: Add PKCE to 3LO exchange. (#1146)
* feat: Add PKCE to 3LO exchange.
---
.../auth/oauth2/DefaultPKCEProvider.java | 103 ++++++++++++++++++
.../com/google/auth/oauth2/PKCEProvider.java | 56 ++++++++++
.../google/auth/oauth2/UserAuthorizer.java | 44 +++++++-
.../auth/oauth2/DefaultPKCEProviderTest.java | 61 +++++++++++
.../auth/oauth2/UserAuthorizerTest.java | 33 ++++++
5 files changed, 295 insertions(+), 2 deletions(-)
create mode 100644 oauth2_http/java/com/google/auth/oauth2/DefaultPKCEProvider.java
create mode 100644 oauth2_http/java/com/google/auth/oauth2/PKCEProvider.java
create mode 100644 oauth2_http/javatests/com/google/auth/oauth2/DefaultPKCEProviderTest.java
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..c114383ff
--- /dev/null
+++ b/oauth2_http/java/com/google/auth/oauth2/DefaultPKCEProvider.java
@@ -0,0 +1,103 @@
+/*
+ * 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;
+
+public class DefaultPKCEProvider implements PKCEProvider {
+ private String codeVerifier;
+ private CodeChallenge codeChallenge;
+ private static final int MAX_CODE_VERIFIER_LENGTH = 127;
+
+ 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;
+ }
+ }
+
+ 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();
+ }
+}
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/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/UserAuthorizerTest.java b/oauth2_http/javatests/com/google/auth/oauth2/UserAuthorizerTest.java
index 822fcbe12..60dd8f464 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,33 @@ public void revokeAuthorization_revokesAndClears() throws IOException {
UserCredentials credentials2 = authorizer.getCredentials(USER_ID);
assertNull(credentials2);
}
+
+ @Test(expected = IllegalArgumentException.class)
+ public void illegalPKCEProvider() {
+ PKCEProvider pkce =
+ new PKCEProvider() {
+ @Override
+ public String getCodeVerifier() {
+ return null;
+ }
+
+ @Override
+ public String getCodeChallengeMethod() {
+ return null;
+ }
+
+ @Override
+ public String getCodeChallenge() {
+ return null;
+ }
+ };
+
+ UserAuthorizer authorizer =
+ UserAuthorizer.newBuilder()
+ .setClientId(CLIENT_ID)
+ .setScopes(DUMMY_SCOPES)
+ .setTokenStore(new MemoryTokensStorage())
+ .setPKCEProvider(pkce)
+ .build();
+ }
}
From 35495b1207ffe11712ee996d3e305449752fb87c Mon Sep 17 00:00:00 2001
From: aeitzman <12433791+aeitzman@users.noreply.github.com>
Date: Sat, 11 Feb 2023 12:30:21 -0800
Subject: [PATCH 07/14] fix: Removed url pattern validation for google urls in
external account credential configurations (#1150)
* fix: Removed url pattern validation for google urls, added readme change to explain risk.
* fix: formatting
---
README.md | 7 +++
.../oauth2/ExternalAccountCredentials.java | 34 ++------------
.../ExternalAccountCredentialsTest.java | 46 ++-----------------
3 files changed, 15 insertions(+), 72 deletions(-)
diff --git a/README.md b/README.md
index e4e233807..dcf695426 100644
--- a/README.md
+++ b/README.md
@@ -728,6 +728,13 @@ ExternalAccountCredentials credentials =
ExternalAccountCredentials.fromStream(new FileInputStream("/path/to/credentials.json"));
```
+##### Security Considerations
+Note that this library does not perform any validation on the token_url, token_info_url,
+or service_account_impersonation_url fields of the credential configuration.
+It is not recommended to use a credential configuration that you did not
+generate with the gcloud CLI unless you verify that the URL fields point to a
+googleapis.com domain.
+
### Downscoping with Credential Access Boundaries
[Downscoping with Credential Access Boundaries](https://cloud.google.com/iam/docs/downscoping-short-lived-credentials)
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/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 {
From 154c1279b3ec96cc34a3225e5e78800ccdda927c Mon Sep 17 00:00:00 2001
From: Carl Lundin <108372512+clundin25@users.noreply.github.com>
Date: Mon, 13 Feb 2023 15:41:00 -0800
Subject: [PATCH 08/14] fix: Java doc for DefaultPKCEProvider.java (#1148)
* fix: Java doc for DefaultPKCEProvider.java
---
.../auth/oauth2/DefaultPKCEProvider.java | 64 ++++++++++---------
.../auth/oauth2/UserAuthorizerTest.java | 62 +++++++++++++++++-
2 files changed, 95 insertions(+), 31 deletions(-)
diff --git a/oauth2_http/java/com/google/auth/oauth2/DefaultPKCEProvider.java b/oauth2_http/java/com/google/auth/oauth2/DefaultPKCEProvider.java
index c114383ff..d4671dbe2 100644
--- a/oauth2_http/java/com/google/auth/oauth2/DefaultPKCEProvider.java
+++ b/oauth2_http/java/com/google/auth/oauth2/DefaultPKCEProvider.java
@@ -36,40 +36,16 @@
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 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;
- }
- }
-
private String createCodeVerifier() {
SecureRandom sr = new SecureRandom();
byte[] code = new byte[MAX_CODE_VERIFIER_LENGTH];
@@ -100,4 +76,34 @@ public String getCodeChallenge() {
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/javatests/com/google/auth/oauth2/UserAuthorizerTest.java b/oauth2_http/javatests/com/google/auth/oauth2/UserAuthorizerTest.java
index 60dd8f464..7f444330f 100644
--- a/oauth2_http/javatests/com/google/auth/oauth2/UserAuthorizerTest.java
+++ b/oauth2_http/javatests/com/google/auth/oauth2/UserAuthorizerTest.java
@@ -477,7 +477,7 @@ public void revokeAuthorization_revokesAndClears() throws IOException {
}
@Test(expected = IllegalArgumentException.class)
- public void illegalPKCEProvider() {
+ public void nullCodeVerifierPKCEProvider() {
PKCEProvider pkce =
new PKCEProvider() {
@Override
@@ -487,7 +487,36 @@ public String getCodeVerifier() {
@Override
public String getCodeChallengeMethod() {
- return null;
+ 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
@@ -504,4 +533,33 @@ public String getCodeChallenge() {
.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();
+ }
}
From eaaa8e89cf69d1e0d581443121f315854d52c75f Mon Sep 17 00:00:00 2001
From: arithmetic1728 <58957152+arithmetic1728@users.noreply.github.com>
Date: Tue, 14 Feb 2023 10:28:18 -0800
Subject: [PATCH 09/14] fix: create and reuse self signed jwt creds for better
performance (#1154)
* fix: create and reuse self signed jwt creds for better performance
* only create jwt cred when needed
---
.../auth/oauth2/ServiceAccountCredentials.java | 14 ++++++++++++--
.../auth/oauth2/ServiceAccountCredentialsTest.java | 2 ++
2 files changed, 14 insertions(+), 2 deletions(-)
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/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);
}
From ed57d315e058d20abf9870110d8b560924fcaebc Mon Sep 17 00:00:00 2001
From: Mend Renovate
Date: Tue, 14 Feb 2023 23:06:54 +0000
Subject: [PATCH 10/14] chore(deps): update dependency
org.apache.maven.plugins:maven-dependency-plugin to v3.5.0 (#1106)
Co-authored-by: Timur Sadykov
---
pom.xml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/pom.xml b/pom.xml
index bff0730c9..056c5ca9c 100644
--- a/pom.xml
+++ b/pom.xml
@@ -206,7 +206,7 @@
org.apache.maven.plugins
maven-dependency-plugin
- 3.3.0
+ 3.5.0
com.coveo
From b177ec7f6007bc55319705420109303ac91c4c10 Mon Sep 17 00:00:00 2001
From: Mend Renovate
Date: Tue, 14 Feb 2023 23:16:20 +0000
Subject: [PATCH 11/14] chore(deps): update dependency
com.google.cloud:google-iam-admin to v3.5.0 (#1118)
Co-authored-by: Timur Sadykov
---
samples/snippets/pom.xml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/samples/snippets/pom.xml b/samples/snippets/pom.xml
index 09f07fcda..332870f84 100644
--- a/samples/snippets/pom.xml
+++ b/samples/snippets/pom.xml
@@ -50,7 +50,7 @@
com.google.cloud
google-iam-admin
- 3.1.0
+ 3.5.0
From cbd7e8c744455c629185516f3319e513bf7715a0 Mon Sep 17 00:00:00 2001
From: Mend Renovate
Date: Tue, 14 Feb 2023 23:19:07 +0000
Subject: [PATCH 12/14] chore(deps): update dependency
com.google.cloud:libraries-bom to v26.8.0 (#1121)
Co-authored-by: Timur Sadykov
---
samples/snippets/pom.xml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/samples/snippets/pom.xml b/samples/snippets/pom.xml
index 332870f84..db1da8a40 100644
--- a/samples/snippets/pom.xml
+++ b/samples/snippets/pom.xml
@@ -30,7 +30,7 @@
com.google.cloud
libraries-bom
- 26.1.5
+ 26.8.0
pom
import
From 7d7375fd4e1aa10c3efc4ce367f25b0e23d0d29f Mon Sep 17 00:00:00 2001
From: Mend Renovate
Date: Wed, 15 Feb 2023 03:10:05 +0000
Subject: [PATCH 13/14] chore(deps): update dependency org.mockito:mockito-core
to v4.11.0 (#1120)
Co-authored-by: Timur Sadykov
---
oauth2_http/pom.xml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/oauth2_http/pom.xml b/oauth2_http/pom.xml
index ba7aa81e5..e1f14194c 100644
--- a/oauth2_http/pom.xml
+++ b/oauth2_http/pom.xml
@@ -219,7 +219,7 @@
org.mockito
mockito-core
- 4.9.0
+ 4.11.0
test
From ebf2b6b1f22bb07bea3814427590c89fe227644c Mon Sep 17 00:00:00 2001
From: "release-please[bot]"
<55107282+release-please[bot]@users.noreply.github.com>
Date: Wed, 15 Feb 2023 03:14:22 +0000
Subject: [PATCH 14/14] chore(main): release 1.16.0 (#1139)
:robot: I have created a release *beep* *boop*
---
## [1.16.0](https://togithub.com/googleapis/google-auth-library-java/compare/v1.15.0...v1.16.0) (2023-02-15)
### Features
* Add PKCE to 3LO exchange. ([#1146](https://togithub.com/googleapis/google-auth-library-java/issues/1146)) ([5bf606b](https://togithub.com/googleapis/google-auth-library-java/commit/5bf606bb8f6d863b44e87587eebf51eaeea4a0ae))
### Bug Fixes
* Create and reuse self signed jwt creds for better performance ([#1154](https://togithub.com/googleapis/google-auth-library-java/issues/1154)) ([eaaa8e8](https://togithub.com/googleapis/google-auth-library-java/commit/eaaa8e89cf69d1e0d581443121f315854d52c75f))
* Java doc for DefaultPKCEProvider.java ([#1148](https://togithub.com/googleapis/google-auth-library-java/issues/1148)) ([154c127](https://togithub.com/googleapis/google-auth-library-java/commit/154c1279b3ec96cc34a3225e5e78800ccdda927c))
* Removed url pattern validation for google urls in external account credential configurations ([#1150](https://togithub.com/googleapis/google-auth-library-java/issues/1150)) ([35495b1](https://togithub.com/googleapis/google-auth-library-java/commit/35495b1207ffe11712ee996d3e305449752fb87c))
### Documentation
* Clarified Maven artifact for HTTP-based clients ([#1136](https://togithub.com/googleapis/google-auth-library-java/issues/1136)) ([b49fc13](https://togithub.com/googleapis/google-auth-library-java/commit/b49fc13b10d0e326c7296e2aad7a50ea03e774f5))
---
This PR was generated with [Release Please](https://togithub.com/googleapis/release-please). See [documentation](https://togithub.com/googleapis/release-please#release-please).
---
CHANGELOG.md | 19 +++++++++++++++++++
appengine/pom.xml | 2 +-
bom/pom.xml | 2 +-
credentials/pom.xml | 2 +-
oauth2_http/pom.xml | 2 +-
pom.xml | 2 +-
versions.txt | 12 ++++++------
7 files changed, 30 insertions(+), 11 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 61f02473c..5ef1e7d4d 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,24 @@
# Changelog
+## [1.16.0](https://github.com/googleapis/google-auth-library-java/compare/v1.15.0...v1.16.0) (2023-02-15)
+
+
+### Features
+
+* Add PKCE to 3LO exchange. ([#1146](https://github.com/googleapis/google-auth-library-java/issues/1146)) ([5bf606b](https://github.com/googleapis/google-auth-library-java/commit/5bf606bb8f6d863b44e87587eebf51eaeea4a0ae))
+
+
+### Bug Fixes
+
+* Create and reuse self signed jwt creds for better performance ([#1154](https://github.com/googleapis/google-auth-library-java/issues/1154)) ([eaaa8e8](https://github.com/googleapis/google-auth-library-java/commit/eaaa8e89cf69d1e0d581443121f315854d52c75f))
+* Java doc for DefaultPKCEProvider.java ([#1148](https://github.com/googleapis/google-auth-library-java/issues/1148)) ([154c127](https://github.com/googleapis/google-auth-library-java/commit/154c1279b3ec96cc34a3225e5e78800ccdda927c))
+* Removed url pattern validation for google urls in external account credential configurations ([#1150](https://github.com/googleapis/google-auth-library-java/issues/1150)) ([35495b1](https://github.com/googleapis/google-auth-library-java/commit/35495b1207ffe11712ee996d3e305449752fb87c))
+
+
+### Documentation
+
+* Clarified Maven artifact for HTTP-based clients ([#1136](https://github.com/googleapis/google-auth-library-java/issues/1136)) ([b49fc13](https://github.com/googleapis/google-auth-library-java/commit/b49fc13b10d0e326c7296e2aad7a50ea03e774f5))
+
## [1.15.0](https://github.com/googleapis/google-auth-library-java/compare/v1.14.0...v1.15.0) (2023-01-25)
diff --git a/appengine/pom.xml b/appengine/pom.xml
index edb4f479f..ead41136a 100644
--- a/appengine/pom.xml
+++ b/appengine/pom.xml
@@ -5,7 +5,7 @@
com.google.auth
google-auth-library-parent
- 1.15.1-SNAPSHOT
+ 1.16.0
../pom.xml
diff --git a/bom/pom.xml b/bom/pom.xml
index f0b28564e..2efc12a30 100644
--- a/bom/pom.xml
+++ b/bom/pom.xml
@@ -3,7 +3,7 @@
4.0.0
com.google.auth
google-auth-library-bom
- 1.15.1-SNAPSHOT
+ 1.16.0
pom
Google Auth Library for Java BOM
diff --git a/credentials/pom.xml b/credentials/pom.xml
index 2cfc4ebcf..e4547d6a6 100644
--- a/credentials/pom.xml
+++ b/credentials/pom.xml
@@ -4,7 +4,7 @@
com.google.auth
google-auth-library-parent
- 1.15.1-SNAPSHOT
+ 1.16.0
../pom.xml
diff --git a/oauth2_http/pom.xml b/oauth2_http/pom.xml
index e1f14194c..576309e7d 100644
--- a/oauth2_http/pom.xml
+++ b/oauth2_http/pom.xml
@@ -7,7 +7,7 @@
com.google.auth
google-auth-library-parent
- 1.15.1-SNAPSHOT
+ 1.16.0
../pom.xml
diff --git a/pom.xml b/pom.xml
index 056c5ca9c..43f05d384 100644
--- a/pom.xml
+++ b/pom.xml
@@ -5,7 +5,7 @@
4.0.0
com.google.auth
google-auth-library-parent
- 1.15.1-SNAPSHOT
+ 1.16.0
pom
Google Auth Library for Java
Client libraries providing authentication and
diff --git a/versions.txt b/versions.txt
index 1ee93fcd4..d1e798829 100644
--- a/versions.txt
+++ b/versions.txt
@@ -1,9 +1,9 @@
# Format:
# module:released-version:current-version
-google-auth-library:1.15.0:1.15.1-SNAPSHOT
-google-auth-library-bom:1.15.0:1.15.1-SNAPSHOT
-google-auth-library-parent:1.15.0:1.15.1-SNAPSHOT
-google-auth-library-appengine:1.15.0:1.15.1-SNAPSHOT
-google-auth-library-credentials:1.15.0:1.15.1-SNAPSHOT
-google-auth-library-oauth2-http:1.15.0:1.15.1-SNAPSHOT
+google-auth-library:1.16.0:1.16.0
+google-auth-library-bom:1.16.0:1.16.0
+google-auth-library-parent:1.16.0:1.16.0
+google-auth-library-appengine:1.16.0:1.16.0
+google-auth-library-credentials:1.16.0:1.16.0
+google-auth-library-oauth2-http:1.16.0:1.16.0