> publicKeyCache;
++
+ /** Seconds of time skew to accept when verifying time. */
+ private final long acceptableTimeSkewSeconds;
+
+@@ -82,11 +136,21 @@ public class IdTokenVerifier {
+ * @param builder builder
+ */
+ protected IdTokenVerifier(Builder builder) {
++ this.certificatesLocation = builder.certificatesLocation;
+ clock = builder.clock;
+ acceptableTimeSkewSeconds = builder.acceptableTimeSkewSeconds;
+ issuers = builder.issuers == null ? null : Collections.unmodifiableCollection(builder.issuers);
+ audience =
+ builder.audience == null ? null : Collections.unmodifiableCollection(builder.audience);
++ HttpTransportFactory transport =
++ builder.httpTransportFactory == null
++ ? new DefaultHttpTransportFactory()
++ : builder.httpTransportFactory;
++ this.publicKeyCache =
++ CacheBuilder.newBuilder()
++ .expireAfterWrite(1, TimeUnit.HOURS)
++ .build(new PublicKeyLoader(transport));
++ this.environment = builder.environment == null ? new Environment() : builder.environment;
+ }
+
+ /** Returns the clock. */
+@@ -133,13 +197,20 @@ public class IdTokenVerifier {
+ * It verifies:
+ *
+ *
+- * - The issuer is one of {@link #getIssuers()} by calling {@link
+- * IdToken#verifyIssuer(String)}.
+- * - The audience is one of {@link #getAudience()} by calling
+- * {@link IdToken#verifyAudience(Collection)}.
+- * - The current time against the issued at and expiration time, using the {@link #getClock()}
+- * and allowing for a time skew specified in {#link {@link #getAcceptableTimeSkewSeconds()} , by
+- * calling {@link IdToken#verifyTime(long, long)}.
++ * - The issuer is one of {@link #getIssuers()} by calling {@link
++ * IdToken#verifyIssuer(String)}.
++ * - The audience is one of {@link #getAudience()} by calling
++ * {@link IdToken#verifyAudience(Collection)}.
++ * - The current time against the issued at and expiration time, using the {@link #getClock()}
++ * and allowing for a time skew specified in {#link {@link #getAcceptableTimeSkewSeconds()} , by
++ * calling {@link IdToken#verifyTime(long, long)}.
++ * - This method verifies token signature per current OpenID Connect Spec:
++ * https://openid.net/specs/openid-connect-core-1_0.html#IDTokenValidation. By default,
++ * method gets a certificate from well-known location. A request to certificate location is
++ * performed using {@link com.google.api.client.http.javanet.NetHttpTransport} Both
++ * certificate location and transport implementation can be overridden via {@link Builder}
++ * not recommended: this check can be disabled with OAUTH_CLIENT_SKIP_SIGNATURE environment
++ * variable set to true.
+ *
+ *
+ *
+@@ -150,9 +221,74 @@ public class IdTokenVerifier {
+ * @return {@code true} if verified successfully or {@code false} if failed
+ */
+ public boolean verify(IdToken idToken) {
+- return (issuers == null || idToken.verifyIssuer(issuers))
+- && (audience == null || idToken.verifyAudience(audience))
+- && idToken.verifyTime(clock.currentTimeMillis(), acceptableTimeSkewSeconds);
++ boolean tokenFieldsValid =
++ (issuers == null || idToken.verifyIssuer(issuers))
++ && (audience == null || idToken.verifyAudience(audience))
++ && idToken.verifyTime(clock.currentTimeMillis(), acceptableTimeSkewSeconds);
++
++ if (!tokenFieldsValid) {
++ return false;
++ }
++
++ try {
++ return verifySignature(idToken);
++ } catch (VerificationException ex) {
++ LOGGER.log(
++ Level.SEVERE,
++ "id token signature verification failed. "
++ + "Please see docs for IdTokenVerifier for default settings and configuration options",
++ ex);
++ return false;
++ }
++ }
++
++ @VisibleForTesting
++ boolean verifySignature(IdToken idToken) throws VerificationException {
++ if (Boolean.parseBoolean(environment.getVariable(SKIP_SIGNATURE_ENV_VAR))) {
++ return true;
++ }
++
++ // Short-circuit signature types
++ if (!SUPPORTED_ALGORITHMS.contains(idToken.getHeader().getAlgorithm())) {
++ throw new VerificationException(
++ String.format(NOT_SUPPORTED_ALGORITHM, idToken.getHeader().getAlgorithm()));
++ }
++
++ PublicKey publicKeyToUse = null;
++ try {
++ String certificateLocation = getCertificateLocation(idToken.getHeader());
++ publicKeyToUse = publicKeyCache.get(certificateLocation).get(idToken.getHeader().getKeyId());
++ } catch (ExecutionException | UncheckedExecutionException e) {
++ throw new VerificationException(
++ "Error fetching PublicKey from certificate location " + certificatesLocation, e);
++ }
++
++ if (publicKeyToUse == null) {
++ throw new VerificationException(
++ "Could not find PublicKey for provided keyId: " + idToken.getHeader().getKeyId());
++ }
++
++ try {
++ if (idToken.verifySignature(publicKeyToUse)) {
++ return true;
++ }
++ throw new VerificationException("Invalid signature");
++ } catch (GeneralSecurityException e) {
++ throw new VerificationException("Error validating token", e);
++ }
++ }
++
++ private String getCertificateLocation(Header header) throws VerificationException {
++ if (certificatesLocation != null) return certificatesLocation;
++
++ switch (header.getAlgorithm()) {
++ case "RS256":
++ return FEDERATED_SIGNON_CERT_URL;
++ case "ES256":
++ return IAP_CERT_URL;
++ }
++
++ throw new VerificationException(String.format(NOT_SUPPORTED_ALGORITHM, header.getAlgorithm()));
+ }
+
+ /**
+@@ -171,6 +307,11 @@ public class IdTokenVerifier {
+ /** Clock. */
+ Clock clock = Clock.SYSTEM;
+
++ String certificatesLocation;
++
++ /** wrapper for environment variables */
++ Environment environment;
++
+ /** Seconds of time skew to accept when verifying time. */
+ long acceptableTimeSkewSeconds = DEFAULT_TIME_SKEW_SECONDS;
+
+@@ -180,6 +321,8 @@ public class IdTokenVerifier {
+ /** List of trusted audience client IDs or {@code null} to suppress the audience check. */
+ Collection audience;
+
++ HttpTransportFactory httpTransportFactory;
++
+ /** Builds a new instance of {@link IdTokenVerifier}. */
+ public IdTokenVerifier build() {
+ return new IdTokenVerifier(this);
+@@ -231,6 +374,18 @@ public class IdTokenVerifier {
+ }
+
+ /**
++ * Override the location URL that contains published public keys. Defaults to well-known Google
++ * locations.
++ *
++ * @param certificatesLocation URL to published public keys
++ * @return the builder
++ */
++ public Builder setCertificatesLocation(String certificatesLocation) {
++ this.certificatesLocation = certificatesLocation;
++ return this;
++ }
++
++ /**
+ * Returns the equivalent expected issuers or {@code null} if issuer check suppressed.
+ *
+ * @since 1.21.0
+@@ -303,5 +458,172 @@ public class IdTokenVerifier {
+ return this;
+ }
+
++ /** Returns an instance of the {@link Environment} */
++ final Environment getEnvironment() {
++ return environment;
++ }
++
++ /** Sets the environment. Used mostly for testing */
++ Builder setEnvironment(Environment environment) {
++ this.environment = environment;
++ return this;
++ }
++
++ /**
++ * Sets the HttpTransportFactory used for requesting public keys from the certificate URL. Used
++ * mostly for testing.
++ *
++ * @param httpTransportFactory the HttpTransportFactory used to build certificate URL requests
++ * @return the builder
++ */
++ public Builder setHttpTransportFactory(HttpTransportFactory httpTransportFactory) {
++ this.httpTransportFactory = httpTransportFactory;
++ return this;
++ }
++ }
++
++ /** Custom CacheLoader for mapping certificate urls to the contained public keys. */
++ static class PublicKeyLoader extends CacheLoader> {
++ private final HttpTransportFactory httpTransportFactory;
++
++ /**
++ * Data class used for deserializing a JSON Web Key Set (JWKS) from an external HTTP request.
++ */
++ public static class JsonWebKeySet extends GenericJson {
++ @Key public List keys;
++ }
++
++ /** Data class used for deserializing a single JSON Web Key. */
++ public static class JsonWebKey {
++ @Key public String alg;
++
++ @Key public String crv;
++
++ @Key public String kid;
++
++ @Key public String kty;
++
++ @Key public String use;
++
++ @Key public String x;
++
++ @Key public String y;
++
++ @Key public String e;
++
++ @Key public String n;
++ }
++
++ PublicKeyLoader(HttpTransportFactory httpTransportFactory) {
++ super();
++ this.httpTransportFactory = httpTransportFactory;
++ }
++
++ @Override
++ public Map load(String certificateUrl) throws Exception {
++ HttpTransport httpTransport = httpTransportFactory.create();
++ JsonWebKeySet jwks;
++ try {
++ HttpRequest request =
++ httpTransport
++ .createRequestFactory()
++ .buildGetRequest(new GenericUrl(certificateUrl))
++ .setParser(GsonFactory.getDefaultInstance().createJsonObjectParser());
++ HttpResponse response = request.execute();
++ jwks = response.parseAs(JsonWebKeySet.class);
++ } catch (IOException io) {
++ LOGGER.log(
++ Level.WARNING,
++ "Failed to get a certificate from certificate location " + certificateUrl,
++ io);
++ return ImmutableMap.of();
++ }
++
++ ImmutableMap.Builder keyCacheBuilder = new ImmutableMap.Builder<>();
++ if (jwks.keys == null) {
++ // Fall back to x509 formatted specification
++ for (String keyId : jwks.keySet()) {
++ String publicKeyPem = (String) jwks.get(keyId);
++ keyCacheBuilder.put(keyId, buildPublicKey(publicKeyPem));
++ }
++ } else {
++ for (JsonWebKey key : jwks.keys) {
++ try {
++ keyCacheBuilder.put(key.kid, buildPublicKey(key));
++ } catch (NoSuchAlgorithmException
++ | InvalidKeySpecException
++ | InvalidParameterSpecException ignored) {
++ LOGGER.log(Level.WARNING, "Failed to put a key into the cache", ignored);
++ }
++ }
++ }
++
++ return keyCacheBuilder.build();
++ }
++
++ private PublicKey buildPublicKey(JsonWebKey key)
++ throws NoSuchAlgorithmException, InvalidParameterSpecException, InvalidKeySpecException {
++ if ("ES256".equals(key.alg)) {
++ return buildEs256PublicKey(key);
++ } else if ("RS256".equals((key.alg))) {
++ return buildRs256PublicKey(key);
++ } else {
++ return null;
++ }
++ }
++
++ private PublicKey buildPublicKey(String publicPem)
++ throws CertificateException, UnsupportedEncodingException {
++ return CertificateFactory.getInstance("X.509")
++ .generateCertificate(new ByteArrayInputStream(publicPem.getBytes("UTF-8")))
++ .getPublicKey();
++ }
++
++ private PublicKey buildRs256PublicKey(JsonWebKey key)
++ throws NoSuchAlgorithmException, InvalidKeySpecException {
++ com.google.common.base.Preconditions.checkArgument("RSA".equals(key.kty));
++ com.google.common.base.Preconditions.checkNotNull(key.e);
++ com.google.common.base.Preconditions.checkNotNull(key.n);
++
++ BigInteger modulus = new BigInteger(1, Base64.decodeBase64(key.n));
++ BigInteger exponent = new BigInteger(1, Base64.decodeBase64(key.e));
++
++ RSAPublicKeySpec spec = new RSAPublicKeySpec(modulus, exponent);
++ KeyFactory factory = KeyFactory.getInstance("RSA");
++ return factory.generatePublic(spec);
++ }
++
++ private PublicKey buildEs256PublicKey(JsonWebKey key)
++ throws NoSuchAlgorithmException, InvalidParameterSpecException, InvalidKeySpecException {
++ com.google.common.base.Preconditions.checkArgument("EC".equals(key.kty));
++ com.google.common.base.Preconditions.checkArgument("P-256".equals(key.crv));
++
++ BigInteger x = new BigInteger(1, Base64.decodeBase64(key.x));
++ BigInteger y = new BigInteger(1, Base64.decodeBase64(key.y));
++ ECPoint pubPoint = new ECPoint(x, y);
++ AlgorithmParameters parameters = AlgorithmParameters.getInstance("EC");
++ parameters.init(new ECGenParameterSpec("secp256r1"));
++ ECParameterSpec ecParameters = parameters.getParameterSpec(ECParameterSpec.class);
++ ECPublicKeySpec pubSpec = new ECPublicKeySpec(pubPoint, ecParameters);
++ KeyFactory kf = KeyFactory.getInstance("EC");
++ return kf.generatePublic(pubSpec);
++ }
++ }
++
++ /** Custom exception for wrapping all verification errors. */
++ static class VerificationException extends Exception {
++ public VerificationException(String message) {
++ super(message);
++ }
++
++ public VerificationException(String message, Throwable cause) {
++ super(message, cause);
++ }
++ }
++
++ static class DefaultHttpTransportFactory implements HttpTransportFactory {
++ public HttpTransport create() {
++ return HTTP_TRANSPORT;
++ }
+ }
+ }
+Index: google-oauth-java-client-1.22.0/google-oauth-client/src/test/java/com/google/api/client/auth/openidconnect/IdTokenVerifierTest.java
+===================================================================
+--- google-oauth-java-client-1.22.0.orig/google-oauth-client/src/test/java/com/google/api/client/auth/openidconnect/IdTokenVerifierTest.java
++++ google-oauth-java-client-1.22.0/google-oauth-client/src/test/java/com/google/api/client/auth/openidconnect/IdTokenVerifierTest.java
+@@ -15,15 +15,30 @@
+ package com.google.api.client.auth.openidconnect;
+
+ import com.google.api.client.auth.openidconnect.IdToken.Payload;
++import com.google.api.client.auth.openidconnect.IdTokenVerifier.VerificationException;
++import com.google.api.client.http.HttpTransport;
++import com.google.api.client.http.LowLevelHttpRequest;
++import com.google.api.client.http.LowLevelHttpResponse;
++import com.google.api.client.http.javanet.NetHttpTransport;
++import com.google.api.client.json.JsonFactory;
++import com.google.api.client.json.gson.GsonFactory;
+ import com.google.api.client.json.webtoken.JsonWebSignature.Header;
++import com.google.api.client.testing.http.MockHttpTransport;
++import com.google.api.client.testing.http.MockLowLevelHttpRequest;
++import com.google.api.client.testing.http.MockLowLevelHttpResponse;
+ import com.google.api.client.util.Clock;
+ import com.google.api.client.util.Lists;
+-
+-import junit.framework.TestCase;
+-
++import com.google.common.io.CharStreams;
++import java.io.IOException;
++import java.io.InputStream;
++import java.io.InputStreamReader;
++import java.io.Reader;
+ import java.util.Arrays;
+ import java.util.Collections;
++import java.util.HashMap;
+ import java.util.List;
++import java.util.Map;
++import junit.framework.TestCase;
+
+ /**
+ * Tests {@link IdTokenVerifier}.
+@@ -41,6 +56,25 @@ public class IdTokenVerifierTest extends
+ private static final String ISSUER2 = ISSUER + "2";
+ private static final String ISSUER3 = ISSUER + "3";
+
++ private static final String ES256_TOKEN =
++ "eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6Im1wZjBEQSJ9.eyJhdWQiOiIvcHJvamVjdHMvNjUyNTYyNzc2Nzk4L2FwcHMvY2xvdWQtc2FtcGxlcy10ZXN0cy1waHAtaWFwIiwiZW1haWwiOiJjaGluZ29yQGdvb2dsZS5jb20iLCJleHAiOjE1ODQwNDc2MTcsImdvb2dsZSI6eyJhY2Nlc3NfbGV2ZWxzIjpbImFjY2Vzc1BvbGljaWVzLzUxODU1MTI4MDkyNC9hY2Nlc3NMZXZlbHMvcmVjZW50U2VjdXJlQ29ubmVjdERhdGEiLCJhY2Nlc3NQb2xpY2llcy81MTg1NTEyODA5MjQvYWNjZXNzTGV2ZWxzL3Rlc3ROb09wIiwiYWNjZXNzUG9saWNpZXMvNTE4NTUxMjgwOTI0L2FjY2Vzc0xldmVscy9ldmFwb3JhdGlvblFhRGF0YUZ1bGx5VHJ1c3RlZCJdfSwiaGQiOiJnb29nbGUuY29tIiwiaWF0IjoxNTg0MDQ3MDE3LCJpc3MiOiJodHRwczovL2Nsb3VkLmdvb2dsZS5jb20vaWFwIiwic3ViIjoiYWNjb3VudHMuZ29vZ2xlLmNvbToxMTIxODE3MTI3NzEyMDE5NzI4OTEifQ.yKNtdFY5EKkRboYNexBdfugzLhC3VuGyFcuFYA8kgpxMqfyxa41zkML68hYKrWu2kOBTUW95UnbGpsIi_u1fiA";
++
++ private static final String FEDERATED_SIGNON_RS256_TOKEN =
++ "eyJhbGciOiJSUzI1NiIsImtpZCI6ImY5ZDk3YjRjYWU5MGJjZDc2YWViMjAwMjZmNmI3NzBjYWMyMjE3ODMiLCJ0eXAiOiJKV1QifQ.eyJhdWQiOiJodHRwczovL2V4YW1wbGUuY29tL3BhdGgiLCJhenAiOiJpbnRlZ3JhdGlvbi10ZXN0c0BjaGluZ29yLXRlc3QuaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJlbWFpbCI6ImludGVncmF0aW9uLXRlc3RzQGNoaW5nb3ItdGVzdC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsImVtYWlsX3ZlcmlmaWVkIjp0cnVlLCJleHAiOjE1ODc2Mjk4ODgsImlhdCI6MTU4NzYyNjI4OCwiaXNzIjoiaHR0cHM6Ly9hY2NvdW50cy5nb29nbGUuY29tIiwic3ViIjoiMTA0MDI5MjkyODUzMDk5OTc4MjkzIn0.Pj4KsJh7riU7ZIbPMcHcHWhasWEcbVjGP4yx_5E0iOpeDalTdri97E-o0dSSkuVX2FeBIgGUg_TNNgJ3YY97T737jT5DUYwdv6M51dDlLmmNqlu_P6toGCSRC8-Beu5gGmqS2Y82TmpHH9Vhoh5PsK7_rVHk8U6VrrVVKKTWm_IzTFhqX1oYKPdvfyaNLsXPbCt_NFE0C3DNmFkgVhRJu7LtzQQN-ghaqd3Ga3i6KH222OEI_PU4BUTvEiNOqRGoMlT_YOsyFN3XwqQ6jQGWhhkArL1z3CG2BVQjHTKpgVsRyy_H6WTZiju2Q-XWobgH-UPSZbyymV8-cFT9XKEtZQ";
++ private static final String LEGACY_FEDERATED_SIGNON_CERT_URL =
++ "https://www.googleapis.com/oauth2/v1/certs";
++
++ private static final String SERVICE_ACCOUNT_RS256_TOKEN =
++ "eyJhbGciOiJSUzI1NiIsImtpZCI6IjJlZjc3YjM4YTFiMDM3MDQ4NzA0MzkxNmFjYmYyN2Q3NGVkZDA4YjEiLCJ0eXAiOiJKV1QifQ.eyJhdWQiOiJodHRwczovL2V4YW1wbGUuY29tL2F1ZGllbmNlIiwiZXhwIjoxNTg3NjMwNTQzLCJpYXQiOjE1ODc2MjY5NDMsImlzcyI6InNvbWUgaXNzdWVyIiwic3ViIjoic29tZSBzdWJqZWN0In0.gGOQW0qQgs4jGUmCsgRV83RqsJLaEy89-ZOG6p1u0Y26FyY06b6Odgd7xXLsSTiiSnch62dl0Lfi9D0x2ByxvsGOCbovmBl2ZZ0zHr1wpc4N0XS9lMUq5RJQbonDibxXG4nC2zroDfvD0h7i-L8KMXeJb9pYwW7LkmrM_YwYfJnWnZ4bpcsDjojmPeUBlACg7tjjOgBFbyQZvUtaERJwSRlaWibvNjof7eCVfZChE0PwBpZc_cGqSqKXv544L4ttqdCnmONjqrTATXwC4gYxruevkjHfYI5ojcQmXoWDJJ0-_jzfyPE4MFFdCFgzLgnfIOwe5ve0MtquKuv2O0pgvg";
++ private static final String SERVICE_ACCOUNT_CERT_URL =
++ "https://www.googleapis.com/robot/v1/metadata/x509/integration-tests%40chingor-test.iam.gserviceaccount.com";
++
++ private static final List ALL_TOKENS =
++ Arrays.asList(ES256_TOKEN, FEDERATED_SIGNON_RS256_TOKEN, SERVICE_ACCOUNT_RS256_TOKEN);
++
++ static final JsonFactory JSON_FACTORY = GsonFactory.getDefaultInstance();
++ static final MockClock FIXED_CLOCK = new MockClock(1584047020000L);
++
+ private static IdToken newIdToken(String issuer, String audience) {
+ Payload payload = new Payload();
+ payload.setIssuer(issuer);
+@@ -56,8 +90,8 @@ public class IdTokenVerifierTest extends
+ assertEquals(Clock.SYSTEM, builder.getClock());
+ assertEquals(ISSUER, builder.getIssuer());
+ assertEquals(Collections.singleton(ISSUER), builder.getIssuers());
+- assertTrue(TRUSTED_CLIENT_IDS.equals(builder.getAudience()));
+- Clock clock = new MyClock();
++ assertEquals(TRUSTED_CLIENT_IDS, builder.getAudience());
++ Clock clock = new MockClock();
+ builder.setClock(clock);
+ assertEquals(clock, builder.getClock());
+ IdTokenVerifier verifier = builder.build();
+@@ -67,22 +101,22 @@ public class IdTokenVerifierTest extends
+ assertEquals(TRUSTED_CLIENT_IDS, Lists.newArrayList(verifier.getAudience()));
+ }
+
+- static class MyClock implements Clock {
+-
+- long timeMillis;
+-
+- public long currentTimeMillis() {
+- return timeMillis;
+- }
+- }
+-
+ public void testVerify() throws Exception {
+- MyClock clock = new MyClock();
+- IdTokenVerifier verifier = new IdTokenVerifier.Builder()
+- .setIssuers(Arrays.asList(ISSUER, ISSUER3))
+- .setAudience(Arrays.asList(CLIENT_ID)).setClock(clock).build();
++ MockClock clock = new MockClock();
++ MockEnvironment testEnvironment = new MockEnvironment();
++ testEnvironment.setVariable(IdTokenVerifier.SKIP_SIGNATURE_ENV_VAR, "true");
++ IdTokenVerifier verifier =
++ new IdTokenVerifier.Builder()
++ .setIssuers(Arrays.asList(ISSUER, ISSUER3))
++ .setAudience(Arrays.asList(CLIENT_ID))
++ .setClock(clock)
++ .setEnvironment(testEnvironment)
++ .build();
++
+ // verifier flexible doesn't check issuer and audience
+- IdTokenVerifier verifierFlexible = new IdTokenVerifier.Builder().setClock(clock).build();
++ IdTokenVerifier verifierFlexible =
++ new IdTokenVerifier.Builder().setClock(clock).setEnvironment(testEnvironment).build();
++
+ // issuer
+ clock.timeMillis = 1500000L;
+ IdToken idToken = newIdToken(ISSUER, CLIENT_ID);
+@@ -136,4 +170,165 @@ public class IdTokenVerifierTest extends
+ assertNull(verifier.getIssuers());
+ assertNull(verifier.getIssuer());
+ }
++
++ public void testVerifyEs256TokenPublicKeyMismatch() throws Exception {
++ // Mock HTTP requests
++ HttpTransportFactory httpTransportFactory =
++ new HttpTransportFactory() {
++ @Override
++ public HttpTransport create() {
++ return new MockHttpTransport() {
++ @Override
++ public LowLevelHttpRequest buildRequest(String method, String url)
++ throws IOException {
++ return new MockLowLevelHttpRequest() {
++ @Override
++ public LowLevelHttpResponse execute() throws IOException {
++ MockLowLevelHttpResponse response = new MockLowLevelHttpResponse();
++ response.setStatusCode(200);
++ response.setContentType("application/json");
++ response.setContent("");
++ return response;
++ }
++ };
++ }
++ };
++ }
++ };
++ IdTokenVerifier tokenVerifier =
++ new IdTokenVerifier.Builder()
++ .setClock(FIXED_CLOCK)
++ .setHttpTransportFactory(httpTransportFactory)
++ .build();
++
++ try {
++ tokenVerifier.verifySignature(IdToken.parse(JSON_FACTORY, ES256_TOKEN));
++ fail("Should have failed verification");
++ } catch (VerificationException ex) {
++ assertTrue(ex.getMessage().contains("Error fetching PublicKey"));
++ }
++ }
++
++ public void testVerifyEs256Token() throws VerificationException, IOException {
++ HttpTransportFactory httpTransportFactory =
++ mockTransport(
++ "https://www.gstatic.com/iap/verify/public_key-jwk",
++ readResourceAsString("iap_keys.json"));
++ IdTokenVerifier tokenVerifier =
++ new IdTokenVerifier.Builder()
++ .setClock(FIXED_CLOCK)
++ .setHttpTransportFactory(httpTransportFactory)
++ .build();
++ assertTrue(tokenVerifier.verify(IdToken.parse(JSON_FACTORY, ES256_TOKEN)));
++ }
++
++ public void testVerifyRs256Token() throws VerificationException, IOException {
++ HttpTransportFactory httpTransportFactory =
++ mockTransport(
++ "https://www.googleapis.com/oauth2/v3/certs",
++ readResourceAsString("federated_keys.json"));
++ MockClock clock = new MockClock(1587625988000L);
++ IdTokenVerifier tokenVerifier =
++ new IdTokenVerifier.Builder()
++ .setClock(clock)
++ .setHttpTransportFactory(httpTransportFactory)
++ .build();
++ assertTrue(tokenVerifier.verify(IdToken.parse(JSON_FACTORY, FEDERATED_SIGNON_RS256_TOKEN)));
++ }
++
++ public void testVerifyRs256TokenWithLegacyCertificateUrlFormat()
++ throws VerificationException, IOException {
++ HttpTransportFactory httpTransportFactory =
++ mockTransport(
++ LEGACY_FEDERATED_SIGNON_CERT_URL, readResourceAsString("legacy_federated_keys.json"));
++ MockClock clock = new MockClock(1587626288000L);
++ IdTokenVerifier tokenVerifier =
++ new IdTokenVerifier.Builder()
++ .setCertificatesLocation(LEGACY_FEDERATED_SIGNON_CERT_URL)
++ .setClock(clock)
++ .setHttpTransportFactory(httpTransportFactory)
++ .build();
++ assertTrue(tokenVerifier.verify(IdToken.parse(JSON_FACTORY, FEDERATED_SIGNON_RS256_TOKEN)));
++ }
++
++ public void testVerifyServiceAccountRs256Token() throws VerificationException, IOException {
++ MockClock clock = new MockClock(1587626643000L);
++ IdTokenVerifier tokenVerifier =
++ new IdTokenVerifier.Builder()
++ .setClock(clock)
++ .setCertificatesLocation(SERVICE_ACCOUNT_CERT_URL)
++ .setHttpTransportFactory(new DefaultHttpTransportFactory())
++ .build();
++ assertTrue(tokenVerifier.verify(IdToken.parse(JSON_FACTORY, SERVICE_ACCOUNT_RS256_TOKEN)));
++ }
++
++ static String readResourceAsString(String resourceName) throws IOException {
++ InputStream inputStream =
++ IdTokenVerifierTest.class.getClassLoader().getResourceAsStream(resourceName);
++ try (final Reader reader = new InputStreamReader(inputStream)) {
++ return CharStreams.toString(reader);
++ }
++ }
++
++ static HttpTransportFactory mockTransport(String url, String certificates) {
++ final String certificatesContent = certificates;
++ final String certificatesUrl = url;
++ return new HttpTransportFactory() {
++ @Override
++ public HttpTransport create() {
++ return new MockHttpTransport() {
++ @Override
++ public LowLevelHttpRequest buildRequest(String method, String url) throws IOException {
++ assertEquals(certificatesUrl, url);
++ return new MockLowLevelHttpRequest() {
++ @Override
++ public LowLevelHttpResponse execute() throws IOException {
++ MockLowLevelHttpResponse response = new MockLowLevelHttpResponse();
++ response.setStatusCode(200);
++ response.setContentType("application/json");
++ response.setContent(certificatesContent);
++ return response;
++ }
++ };
++ }
++ };
++ }
++ };
++ }
++
++ /** A mock implementation of {@link Clock} to set clock for testing */
++ static class MockClock implements Clock {
++ public MockClock() {}
++
++ public MockClock(long timeMillis) {
++ this.timeMillis = timeMillis;
++ }
++
++ long timeMillis;
++
++ public long currentTimeMillis() {
++ return timeMillis;
++ }
++ }
++
++ /** A default http transport factory for testing */
++ static class DefaultHttpTransportFactory implements HttpTransportFactory {
++ public HttpTransport create() {
++ return new NetHttpTransport();
++ }
++ }
++
++ /** A mock implementation of {@link Environment} to set environment variables for testing */
++ class MockEnvironment extends Environment {
++ private final Map variables = new HashMap<>();
++
++ @Override
++ public String getVariable(String name) {
++ return variables.get(name);
++ }
++
++ public void setVariable(String name, String value) {
++ variables.put(name, value);
++ }
++ }
+ }
+Index: google-oauth-java-client-1.22.0/google-oauth-client/src/test/resources/aws_security_credentials.json
+===================================================================
+--- /dev/null
++++ google-oauth-java-client-1.22.0/google-oauth-client/src/test/resources/aws_security_credentials.json
+@@ -0,0 +1,9 @@
++{
++ "Code" : "Success",
++ "LastUpdated" : "2020-08-11T19:33:07Z",
++ "Type" : "AWS-HMAC",
++ "AccessKeyId" : "ASIARD4OQDT6A77FR3CL",
++ "SecretAccessKey" : "Y8AfSaucF37G4PpvfguKZ3/l7Id4uocLXxX0+VTx",
++ "Token" : "IQoJb3JpZ2luX2VjEIz//////////wEaCXVzLWVhc3QtMiJGMEQCIH7MHX/Oy/OB8OlLQa9GrqU1B914+iMikqWQW7vPCKlgAiA/Lsv8Jcafn14owfxXn95FURZNKaaphj0ykpmS+Ki+CSq0AwhlEAAaDDA3NzA3MTM5MTk5NiIMx9sAeP1ovlMTMKLjKpEDwuJQg41/QUKx0laTZYjPlQvjwSqS3OB9P1KAXPWSLkliVMMqaHqelvMF/WO/glv3KwuTfQsavRNs3v5pcSEm4SPO3l7mCs7KrQUHwGP0neZhIKxEXy+Ls//1C/Bqt53NL+LSbaGv6RPHaX82laz2qElphg95aVLdYgIFY6JWV5fzyjgnhz0DQmy62/Vi8pNcM2/VnxeCQ8CC8dRDSt52ry2v+nc77vstuI9xV5k8mPtnaPoJDRANh0bjwY5Sdwkbp+mGRUJBAQRlNgHUJusefXQgVKBCiyJY4w3Csd8Bgj9IyDV+Azuy1jQqfFZWgP68LSz5bURyIjlWDQunO82stZ0BgplKKAa/KJHBPCp8Qi6i99uy7qh76FQAqgVTsnDuU6fGpHDcsDSGoCls2HgZjZFPeOj8mmRhFk1Xqvkbjuz8V1cJk54d3gIJvQt8gD2D6yJQZecnuGWd5K2e2HohvCc8Fc9kBl1300nUJPV+k4tr/A5R/0QfEKOZL1/k5lf1g9CREnrM8LVkGxCgdYMxLQow1uTL+QU67AHRRSp5PhhGX4Rek+01vdYSnJCMaPhSEgcLqDlQkhk6MPsyT91QMXcWmyO+cAZwUPwnRamFepuP4K8k2KVXs/LIJHLELwAZ0ekyaS7CptgOqS7uaSTFG3U+vzFZLEnGvWQ7y9IPNQZ+Dffgh4p3vF4J68y9049sI6Sr5d5wbKkcbm8hdCDHZcv4lnqohquPirLiFQ3q7B17V9krMPu3mz1cg4Ekgcrn/E09NTsxAqD8NcZ7C7ECom9r+X3zkDOxaajW6hu3Az8hGlyylDaMiFfRbBJpTIlxp7jfa7CxikNgNtEKLH9iCzvuSg2vhA==",
++ "Expiration" : "2020-08-11T07:35:49Z"
++}
+\ No newline at end of file
+Index: google-oauth-java-client-1.22.0/google-oauth-client/src/test/resources/client_secret.json
+===================================================================
+--- /dev/null
++++ google-oauth-java-client-1.22.0/google-oauth-client/src/test/resources/client_secret.json
+@@ -0,0 +1,16 @@
++{
++ "web": {
++ "client_id":"ya29.1.AADtN_UtlxN3PuGAxrN2XQnZTVRvDyVWnYq4I6dws",
++ "auth_uri":"https://accounts.google.com/o/oauth2/auth",
++ "token_uri":"https://accounts.google.com/o/oauth2/token",
++ "auth_provider_x509_cert_url":"https://www.googleapis.com/oauth2/v1/certs",
++ "client_secret":"jakuaL9YyieakhECKL2SwZcu",
++ "redirect_uris":[
++ "http://example.appspot.com/oauth2callback",
++ "http://localhost:8080/oauth2callback"
++ ],
++ "javascript_origins":[
++ "https://www.example.com"
++ ]
++ }
++}
+Index: google-oauth-java-client-1.22.0/google-oauth-client/src/test/resources/federated_keys.json
+===================================================================
+--- /dev/null
++++ google-oauth-java-client-1.22.0/google-oauth-client/src/test/resources/federated_keys.json
+@@ -0,0 +1,20 @@
++{
++ "keys": [
++ {
++ "kid": "f9d97b4cae90bcd76aeb20026f6b770cac221783",
++ "e": "AQAB",
++ "kty": "RSA",
++ "alg": "RS256",
++ "n": "ya_7gVJrvqFp5xfYPOco8gBLY38kQDlTlT6ueHtUtbTkRVE1X5tFmPqChnX7wWd2fK7MS4-nclYaGLL7IvJtN9tjrD0h_3_HvnrRZTaVyS-yfWqCQDRq_0VW1LBEygwYRqbO2T0lOocTY-5qUosDvJfe-o-lQYMH7qtDAyiq9XprVzKYTfS545BTECXi0he9ikJl5Q_RAP1BZoaip8F0xX5Y_60G90VyXFWuy16nm5ASW8fwqzdn1lL_ogiO1LirgBFFEXz_t4PwmjWzfQwkoKv4Ab_l9u2FdAoKtFH2CwKaGB8hatIK3bOAJJgRebeU3w6Ah3gxRfi8HWPHbAGjtw",
++ "use": "sig"
++ },
++ {
++ "kid": "28b741e8de984a47159f19e6d7783e9d4fa810db",
++ "e": "AQAB",
++ "kty": "RSA",
++ "alg": "RS256",
++ "n": "zc4ELn-9nLzCZb4PdXGVhtUtzwmQI8HZH8tOIEg9omx6CW-PZ5xtVQ5O5EBG2AA5_K-aOWvVEWyfeHe8WwZltM1cXu6QNdXbpVVYeZ0th9hm7ZflNz7h1PMM9lNXLJjokax5gxGskc8CsjhkwurEot1TD2zbGIQsOYoebQTvJ2AYxIjk77BU20nLplurge8jrK-V1G3zJlp0xIKqxjsfIFYm1Mp-HQhJzdMbjNEScs0dDT4rPxdA-wOVGix0wrPdIE1gM4GxZ7AlSZ7IcjuYMZIe6d6oAeKG0FG0avbtipAQglxTHM3UOge6PmThr_mmiI82oLqGutul-XYgy1S2NQ",
++ "use": "sig"
++ }
++ ]
++}
+\ No newline at end of file
+Index: google-oauth-java-client-1.22.0/google-oauth-client/src/test/resources/iap_keys.json
+===================================================================
+--- /dev/null
++++ google-oauth-java-client-1.22.0/google-oauth-client/src/test/resources/iap_keys.json
+@@ -0,0 +1,49 @@
++{
++ "keys" : [
++ {
++ "alg" : "ES256",
++ "crv" : "P-256",
++ "kid" : "2nMJtw",
++ "kty" : "EC",
++ "use" : "sig",
++ "x" : "9e1x7YRZg53A5zIJ0p2ZQ9yTrgPLGIf4ntOk-4O2R28",
++ "y" : "q8iDm7nsnpz1xPdrWBtTZSowzciS3O7bMYtFFJ8saYo"
++ },
++ {
++ "alg" : "ES256",
++ "crv" : "P-256",
++ "kid" : "LYyP2g",
++ "kty" : "EC",
++ "use" : "sig",
++ "x" : "SlXFFkJ3JxMsXyXNrqzE3ozl_0913PmNbccLLWfeQFU",
++ "y" : "GLSahrZfBErmMUcHP0MGaeVnJdBwquhrhQ8eP05NfCI"
++ },
++ {
++ "alg" : "ES256",
++ "crv" : "P-256",
++ "kid" : "mpf0DA",
++ "kty" : "EC",
++ "use" : "sig",
++ "x" : "fHEdeT3a6KaC1kbwov73ZwB_SiUHEyKQwUUtMCEn0aI",
++ "y" : "QWOjwPhInNuPlqjxLQyhveXpWqOFcQPhZ3t-koMNbZI"
++ },
++ {
++ "alg" : "ES256",
++ "crv" : "P-256",
++ "kid" : "b9vTLA",
++ "kty" : "EC",
++ "use" : "sig",
++ "x" : "qCByTAvci-jRAD7uQSEhTdOs8iA714IbcY2L--YzynI",
++ "y" : "WQY0uCoQyPSozWKGQ0anmFeOH5JNXiZa9i6SNqOcm7w"
++ },
++ {
++ "alg" : "ES256",
++ "crv" : "P-256",
++ "kid" : "0oeLcQ",
++ "kty" : "EC",
++ "use" : "sig",
++ "x" : "MdhRXGEoGJLtBjQEIjnYLPkeci9rXnca2TffkI0Kac0",
++ "y" : "9BoREHfX7g5OK8ELpA_4RcOnFCGSjfR4SGZpBo7juEY"
++ }
++ ]
++}
+\ No newline at end of file
+Index: google-oauth-java-client-1.22.0/google-oauth-client/src/test/resources/legacy_federated_keys.json
+===================================================================
+--- /dev/null
++++ google-oauth-java-client-1.22.0/google-oauth-client/src/test/resources/legacy_federated_keys.json
+@@ -0,0 +1,4 @@
++{
++ "f9d97b4cae90bcd76aeb20026f6b770cac221783": "-----BEGIN CERTIFICATE-----\nMIIDJjCCAg6gAwIBAgIILRTfnfU3e2gwDQYJKoZIhvcNAQEFBQAwNjE0MDIGA1UE\nAxMrZmVkZXJhdGVkLXNpZ25vbi5zeXN0ZW0uZ3NlcnZpY2VhY2NvdW50LmNvbTAe\nFw0yMDA0MTQwNDI5MzBaFw0yMDA0MzAxNjQ0MzBaMDYxNDAyBgNVBAMTK2ZlZGVy\nYXRlZC1zaWdub24uc3lzdGVtLmdzZXJ2aWNlYWNjb3VudC5jb20wggEiMA0GCSqG\nSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDJr/uBUmu+oWnnF9g85yjyAEtjfyRAOVOV\nPq54e1S1tORFUTVfm0WY+oKGdfvBZ3Z8rsxLj6dyVhoYsvsi8m0322OsPSH/f8e+\netFlNpXJL7J9aoJANGr/RVbUsETKDBhGps7ZPSU6hxNj7mpSiwO8l976j6VBgwfu\nq0MDKKr1emtXMphN9LnjkFMQJeLSF72KQmXlD9EA/UFmhqKnwXTFflj/rQb3RXJc\nVa7LXqebkBJbx/CrN2fWUv+iCI7UuKuAEUURfP+3g/CaNbN9DCSgq/gBv+X27YV0\nCgq0UfYLApoYHyFq0grds4AkmBF5t5TfDoCHeDFF+LwdY8dsAaO3AgMBAAGjODA2\nMAwGA1UdEwEB/wQCMAAwDgYDVR0PAQH/BAQDAgeAMBYGA1UdJQEB/wQMMAoGCCsG\nAQUFBwMCMA0GCSqGSIb3DQEBBQUAA4IBAQA1Wrx3XsIAAYOaycAkV2mZW1j+Vqxx\nSAeUyuhLoaJ7jntd7LqTuTr+qRnR/fH/CjTbPzngvCyVE6hjClh159YRpf4TJ4aL\nMJ97qDxc/f/pM/7yklIaHHOwqYU10plIyw+m0dnQutPqy1o/aDUytDznNmM6L3v+\ncot2bxyd2PtjGfa1hPNNnEnrZfS2Gc0qqR64RUWbsdLVVQB8MKcaNUqjk9o/1O4p\nNNk2D2VcofdaLPpwSmtzV8wEd4vfzI17qFSPi6gbTfydvxkejk0kdSyWUPw+1YC4\nv2o2rzwXub9hcP2zXyZvTGKPMAkZ8VKuzWuvfuSsTtgcPJ20GpIkin/j\n-----END CERTIFICATE-----\n",
++ "28b741e8de984a47159f19e6d7783e9d4fa810db": "-----BEGIN CERTIFICATE-----\nMIIDJjCCAg6gAwIBAgIIcog+uwMaMb8wDQYJKoZIhvcNAQEFBQAwNjE0MDIGA1UE\nAxMrZmVkZXJhdGVkLXNpZ25vbi5zeXN0ZW0uZ3NlcnZpY2VhY2NvdW50LmNvbTAe\nFw0yMDA0MjIwNDI5MzBaFw0yMDA1MDgxNjQ0MzBaMDYxNDAyBgNVBAMTK2ZlZGVy\nYXRlZC1zaWdub24uc3lzdGVtLmdzZXJ2aWNlYWNjb3VudC5jb20wggEiMA0GCSqG\nSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDNzgQuf72cvMJlvg91cZWG1S3PCZAjwdkf\ny04gSD2ibHoJb49nnG1VDk7kQEbYADn8r5o5a9URbJ94d7xbBmW0zVxe7pA11dul\nVVh5nS2H2Gbtl+U3PuHU8wz2U1csmOiRrHmDEayRzwKyOGTC6sSi3VMPbNsYhCw5\nih5tBO8nYBjEiOTvsFTbScumW6uB7yOsr5XUbfMmWnTEgqrGOx8gVibUyn4dCEnN\n0xuM0RJyzR0NPis/F0D7A5UaLHTCs90gTWAzgbFnsCVJnshyO5gxkh7p3qgB4obQ\nUbRq9u2KkBCCXFMczdQ6B7o+ZOGv+aaIjzaguoa626X5diDLVLY1AgMBAAGjODA2\nMAwGA1UdEwEB/wQCMAAwDgYDVR0PAQH/BAQDAgeAMBYGA1UdJQEB/wQMMAoGCCsG\nAQUFBwMCMA0GCSqGSIb3DQEBBQUAA4IBAQBEfCN7qgI2GJJAC99PDbafqC1EMBlv\nBT/7UiQdTuDV04+cQH9IpzROW7IZc/ILcqpF6KXUmj6j0sWO+hxKFY66TJKPcypK\n/ZMI58epwwVgGZyYU0BbAIZ9uvOgDfuveMildlMDMg1cJNp7WjBrEJ2DcGfC56wJ\nuKvqB1upxnfh+Ceg3ApU50k6Ld6+dbDDR0Vzt/wGZlZZ5Uj6AwDFe+5p9zEpWg61\nHeny/tSBfgZ19vP2h3ye9ZTK1OFRMNufj8iSzmlkbSqWuy82XVSBRKy5QslqXsYe\nU3gM3EVvXHA/Of3sROFpvznCXNr+Kn03wTv0ny6rnSgHQUzj7p9fydXY\n-----END CERTIFICATE-----\n"
++}
+\ No newline at end of file
+Index: google-oauth-java-client-1.22.0/google-oauth-client/src/test/resources/service_account_keys.json
+===================================================================
+--- /dev/null
++++ google-oauth-java-client-1.22.0/google-oauth-client/src/test/resources/service_account_keys.json
+@@ -0,0 +1,4 @@
++{
++ "a8611b6a9c0a0a8b940d0f915c326fd1605c8ac6": "-----BEGIN CERTIFICATE-----\nMIIDPDCCAiSgAwIBAgIIFJsPvyc/ZSUwDQYJKoZIhvcNAQEFBQAwQTE/MD0GA1UE\nAxM2aW50ZWdyYXRpb24tdGVzdHMuY2hpbmdvci10ZXN0LmlhbS5nc2VydmljZWFj\nY291bnQuY29tMB4XDTIwMDQwMjIyMjIxN1oXDTIyMDUwMTEzNTYxNVowQTE/MD0G\nA1UEAxM2aW50ZWdyYXRpb24tdGVzdHMuY2hpbmdvci10ZXN0LmlhbS5nc2Vydmlj\nZWFjY291bnQuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA6Yys\nP5LIa1rRxQY93FXIJDzq6Tai4VuetffJbltRtYbdwC5Vyl99O2zoVdRlg+iYXK5B\nb6kidjmWOf0kNimQ5FwYvu+xsm6w8vjL/XShkHEKiURszyCua8wvLeGVCiGBg/XU\nDOgYMjzRIH5fTuj3PTZk4sMj02ZCpCQEMQ6ogpLXjaLp3ZXtFhkuHyCxVYbTRr+k\nGU86JAg4XwD6AdC349v+8FEQD7YtJezUAAKEgXh9e5UeL5CpOo3Vsdv/yEVo00jh\nYuWzLM6Oxt55WAhiD29vKrm7VQPSr1XwwqpdyFL2BlmqyTlb3amwvc9qv2kojGvM\nSUqgS83dc0jFqtMvEQIDAQABozgwNjAMBgNVHRMBAf8EAjAAMA4GA1UdDwEB/wQE\nAwIHgDAWBgNVHSUBAf8EDDAKBggrBgEFBQcDAjANBgkqhkiG9w0BAQUFAAOCAQEA\nm3XUMKOtXdpw0oRjykLHdYzTHHFjQTMmhWD172rsxSzwpkFoErAC7bnmEvpcRU7D\nr4M+pE5VuDJ64J3lEpAh7W0zMXezPtGyWr39hVxL3vp3nh4CbCzzkUCfFvBOFFhm\nOI9qnjtMtaozoGi5zLs5jEaFmgR3wfij9KQjNGZJxAg0ZkwcSNb76qOCG1/vG5au\n4UuoIaq8WqSxMqBF/g+NrAE2PZhjNGnUwFPTre3SyR0otYDzJfmpL/tp5VDie8hM\nL5UZU/CmZk46+T9VbvnZ5mkPAjGiPumiptO5iliBOHPtPdn8VrP+aSQM1btHA094\n1HwfbFp7pZHBUn9COAP/1Q==\n-----END CERTIFICATE-----\n",
++ "2ef77b38a1b0370487043916acbf27d74edd08b1": "-----BEGIN CERTIFICATE-----\nMIIC+jCCAeKgAwIBAgIIIwRR4+AftjswDQYJKoZIhvcNAQEFBQAwIDEeMBwGA1UE\nAxMVMTA0MDI5MjkyODUzMDk5OTc4MjkzMB4XDTIwMDMwNDA1NTIyMloXDTMwMDMw\nMjA1NTIyMlowIDEeMBwGA1UEAxMVMTA0MDI5MjkyODUzMDk5OTc4MjkzMIIBIjAN\nBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAm4jAbNdDEDkG/36wP07lFKMTAnWy\nhtV/Vp4QFSIE456moU/HEmBwJX2wocPgvoxPat7FxUv7mwdgHq7+sczis4DrDIIY\n8XfZ+D98+X+rOfkS1WLXpO76REZE4JCUfkB3NKVMP0kfoCFPf2pafz1NJRrZczUw\nbSi/q1+KYHmbk8YS+Q7Iq7gW9dvQtWrsRH8dQIrToJfGH+rbSQyKUFN7skFOflw4\n/OSuT0wvD6z57JcRFtAD3zgeUuCPNRIbkPQC3vCLwWGLKSYWLJ3eM9PPW9bk+czf\nSxJOie7zRMToh4BchLO6ZQgshoEaBHbwdOTu8455skqlRJMU9SKwA6eqVQIDAQAB\nozgwNjAMBgNVHRMBAf8EAjAAMA4GA1UdDwEB/wQEAwIHgDAWBgNVHSUBAf8EDDAK\nBggrBgEFBQcDAjANBgkqhkiG9w0BAQUFAAOCAQEAXvt8M2GFK+5UHG0GclIqse8j\n+EgqXvDTkbeTxFP+onbA/RwKM+fzdYpDwrH1dQ6jJervmceewUTTMegfFzhF33GC\nxvjQfhs+yVOXQiBHosd93CgR19dMUYs/r1wuUpwqBGdW2S81ns3yreY72BHrikrl\nHNLD3aSJ6hq5CZ01EFpjTW10ndBdPhJRSWD2g8VI1lpd716HEmrXfPHX73KVkk5/\nWfvrMA1UK/Ag+TWQerKG3iQFUAPIUiyepdaG4uFWTBY9nzLPiC1cx3bVPVZ+5yul\nJN15hmAMd3qPgSbbeQ6JC72zXCfW3buBE2n9cGtRbZF1URJZ3NbvwRS5BD425g==\n-----END CERTIFICATE-----\n"
++}
+\ No newline at end of file
+
diff --git a/google-oauth-java-client.spec b/google-oauth-java-client.spec
index 2e0530fa369ca6bd83b0c3f00e51b1bf8e165753..2f20f7b121cbc83287f05429014226cee832b572 100644
--- a/google-oauth-java-client.spec
+++ b/google-oauth-java-client.spec
@@ -1,16 +1,20 @@
Name: google-oauth-java-client
Version: 1.22.0
-Release: 5
+Release: 6
Summary: Google OAuth Client Library for Java
License: ASL 2.0
URL: https://github.com/google/google-oauth-java-client
Source0: https://github.com/google/google-oauth-java-client/archive/%{version}/%{name}-%{version}.tar.gz
+Patch0: CVE-2021-22573.patch
BuildArch: noarch
BuildRequires: mvn(com.google.code.findbugs:jsr305) mvn(com.google.http-client:google-http-client)
BuildRequires: mvn(com.google.http-client:google-http-client-jdo)
BuildRequires: maven-local mvn(javax.jdo:jdo2-api) mvn(javax.servlet:javax.servlet-api)
BuildRequires: mvn(org.sonatype.oss:oss-parent:pom:)
+BuildRequires: mvn(com.google.http-client:google-http-client-gson)
+BuildRequires: java-11-openjdk-devel mvn(com.google.guava:guava)
+Requires: java-11-openjdk
Provides: google-oauth-java-client-java6 = %{version}-%{release}
Obsoletes: google-oauth-java-client-java6 < %{version}-%{release}
@@ -48,6 +52,7 @@ The google-oauth-java-client package contains related documents.
%pom_disable_module google-oauth-client-appengine
%pom_disable_module google-oauth-client-jetty
%pom_disable_module samples/dailymotion-cmdline-sample
+%pom_xpath_remove "pom:dependency[pom:artifactId ='guava-jdk5']/pom:scope" google-oauth-client
%pom_change_dep -r :guava-jdk5 :guava
%pom_change_dep -r :servlet-api :javax.servlet-api:3.1.0
%pom_remove_plugin -r :animal-sniffer-maven-plugin
@@ -57,12 +62,14 @@ The google-oauth-java-client package contains related documents.
%pom_remove_plugin -r :maven-deploy-plugin
%pom_remove_plugin -r :maven-source-plugin
%pom_remove_plugin -r :maven-release-plugin
+%pom_add_dep com.google.http-client:google-http-client-gson google-oauth-client
%pom_xpath_remove -r "pom:plugin[pom:artifactId ='maven-jar-plugin']/pom:executions"
%pom_remove_plugin org.datanucleus:maven-datanucleus-plugin google-oauth-client-servlet
%build
-%mvn_build -s --skip-tests
+export JAVA_HOME=%{_jvmdir}/java-11-openjdk
+%mvn_build -s -f -- -Dmaven.compiler.release=8
%install
%mvn_install
@@ -74,6 +81,9 @@ The google-oauth-java-client package contains related documents.
%doc LICENSE
%changelog
+* Mon Oct 13 2025 yaoxin <1024769339@qq.com> - 1.22.0-6
+- Fix CVE-2021-22573
+
* Wed Jan 27 2021 huanghaitao - 1.22.0-5
- Skip tests to drop datanuclues components