From 4f8f79c601c54c66aa1a7a34be01af03e24079cf Mon Sep 17 00:00:00 2001 From: "release-please[bot]" <55107282+release-please[bot]@users.noreply.github.com> Date: Thu, 25 Feb 2021 22:18:18 +0000 Subject: [PATCH 1/9] chore(master): release 0.24.2-SNAPSHOT (#583) :robot: I have created a release \*beep\* \*boop\* --- ### Updating meta-information for bleeding-edge SNAPSHOT release. --- This PR was generated with [Release Please](https://github.com/googleapis/release-please). See [documentation](https://github.com/googleapis/release-please#release-please). --- appengine/pom.xml | 2 +- bom/pom.xml | 2 +- credentials/pom.xml | 2 +- oauth2_http/pom.xml | 2 +- pom.xml | 2 +- versions.txt | 12 ++++++------ 6 files changed, 11 insertions(+), 11 deletions(-) diff --git a/appengine/pom.xml b/appengine/pom.xml index db0a45519..08783d9fa 100644 --- a/appengine/pom.xml +++ b/appengine/pom.xml @@ -5,7 +5,7 @@ com.google.auth google-auth-library-parent - 0.24.1 + 0.24.2-SNAPSHOT ../pom.xml diff --git a/bom/pom.xml b/bom/pom.xml index daffccd04..1ce5a1ab8 100644 --- a/bom/pom.xml +++ b/bom/pom.xml @@ -3,7 +3,7 @@ 4.0.0 com.google.auth google-auth-library-bom - 0.24.1 + 0.24.2-SNAPSHOT pom Google Auth Library for Java BOM diff --git a/credentials/pom.xml b/credentials/pom.xml index d40022109..116ccb564 100644 --- a/credentials/pom.xml +++ b/credentials/pom.xml @@ -4,7 +4,7 @@ com.google.auth google-auth-library-parent - 0.24.1 + 0.24.2-SNAPSHOT ../pom.xml diff --git a/oauth2_http/pom.xml b/oauth2_http/pom.xml index b7faf489b..c49af043b 100644 --- a/oauth2_http/pom.xml +++ b/oauth2_http/pom.xml @@ -5,7 +5,7 @@ com.google.auth google-auth-library-parent - 0.24.1 + 0.24.2-SNAPSHOT ../pom.xml diff --git a/pom.xml b/pom.xml index b669df2ca..463559818 100644 --- a/pom.xml +++ b/pom.xml @@ -3,7 +3,7 @@ 4.0.0 com.google.auth google-auth-library-parent - 0.24.1 + 0.24.2-SNAPSHOT pom Google Auth Library for Java Client libraries providing authentication and diff --git a/versions.txt b/versions.txt index 722ed622b..1af3a5727 100644 --- a/versions.txt +++ b/versions.txt @@ -1,9 +1,9 @@ # Format: # module:released-version:current-version -google-auth-library:0.24.1:0.24.1 -google-auth-library-bom:0.24.1:0.24.1 -google-auth-library-parent:0.24.1:0.24.1 -google-auth-library-appengine:0.24.1:0.24.1 -google-auth-library-credentials:0.24.1:0.24.1 -google-auth-library-oauth2-http:0.24.1:0.24.1 +google-auth-library:0.24.1:0.24.2-SNAPSHOT +google-auth-library-bom:0.24.1:0.24.2-SNAPSHOT +google-auth-library-parent:0.24.1:0.24.2-SNAPSHOT +google-auth-library-appengine:0.24.1:0.24.2-SNAPSHOT +google-auth-library-credentials:0.24.1:0.24.2-SNAPSHOT +google-auth-library-oauth2-http:0.24.1:0.24.2-SNAPSHOT From 9246b5cff42dd24e45b2bff4fc803ea9c1cfa33c Mon Sep 17 00:00:00 2001 From: Yoshi Automation Bot Date: Tue, 2 Mar 2021 15:28:10 -0800 Subject: [PATCH 2/9] chore: remove docLava v2 doc generation (#587) This PR was generated using Autosynth. :rainbow: Synth log will be available here: https://source.cloud.google.com/results/invocations/dd48a04e-1b79-4cf2-bbe1-c31ca37cdd54/targets - [ ] To automatically regenerate this PR, check this box. Source-Link: https://github.com/googleapis/synthtool/commit/21da7d9fa02f6916d9f87cf4072b3547b5c72eb5 --- .kokoro/release/publish_javadoc.cfg | 8 +------- .kokoro/release/publish_javadoc.sh | 19 ------------------- synth.metadata | 4 ++-- 3 files changed, 3 insertions(+), 28 deletions(-) diff --git a/.kokoro/release/publish_javadoc.cfg b/.kokoro/release/publish_javadoc.cfg index 713676594..49b734164 100644 --- a/.kokoro/release/publish_javadoc.cfg +++ b/.kokoro/release/publish_javadoc.cfg @@ -7,12 +7,6 @@ env_vars: { value: "docs-staging" } -# cloud-rad staging -env_vars: { - key: "STAGING_BUCKET_V2" - value: "docs-staging-v2-staging" -} - env_vars: { key: "TRAMPOLINE_BUILD_FILE" value: "github/google-auth-library-java/.kokoro/release/publish_javadoc.sh" @@ -26,4 +20,4 @@ before_action { keyname: "docuploader_service_account" } } -} \ No newline at end of file +} diff --git a/.kokoro/release/publish_javadoc.sh b/.kokoro/release/publish_javadoc.sh index ba83b7f23..b16006b35 100755 --- a/.kokoro/release/publish_javadoc.sh +++ b/.kokoro/release/publish_javadoc.sh @@ -56,22 +56,3 @@ python3 -m docuploader create-metadata \ python3 -m docuploader upload . \ --credentials ${CREDENTIALS} \ --staging-bucket ${STAGING_BUCKET} - -popd - -# V2 due to problems w/ the released javadoc plugin doclava, Java 8 is required. Beware of accidental updates. - -mvn clean site -B -q -Ddevsite.template="${KOKORO_GFILE_DIR}/java/" - -pushd target/devsite/reference - -# create metadata -python3 -m docuploader create-metadata \ - --name ${NAME} \ - --version ${VERSION} \ - --language java - -# upload docs to staging bucket -python3 -m docuploader upload . \ - --credentials ${CREDENTIALS} \ - --staging-bucket ${STAGING_BUCKET_V2} diff --git a/synth.metadata b/synth.metadata index e39ce6cd6..e09ecde4c 100644 --- a/synth.metadata +++ b/synth.metadata @@ -4,14 +4,14 @@ "git": { "name": ".", "remote": "https://github.com/googleapis/google-auth-library-java.git", - "sha": "61810306dc0e18500a4a6b2704e00842fbecd879" + "sha": "4f8f79c601c54c66aa1a7a34be01af03e24079cf" } }, { "git": { "name": "synthtool", "remote": "https://github.com/googleapis/synthtool.git", - "sha": "6946fd71ae9215b0e7ae188f5057df765ee6d7d2" + "sha": "21da7d9fa02f6916d9f87cf4072b3547b5c72eb5" } } ], From 7cd534c2d5aee2a77a7a8647999b50c31d1cc246 Mon Sep 17 00:00:00 2001 From: Yoshi Automation Bot Date: Thu, 4 Mar 2021 15:08:17 -0800 Subject: [PATCH 3/9] chore: copy README to docfx-yml dir (#588) This PR was generated using Autosynth. :rainbow: Synth log will be available here: https://source.cloud.google.com/results/invocations/69766c45-5159-4300-b6d1-f7a09f78f2ab/targets - [ ] To automatically regenerate this PR, check this box. Source-Link: https://github.com/googleapis/synthtool/commit/d0bdade9a962042dc0f770cf631086f3db59b5b0 --- .kokoro/release/publish_javadoc11.sh | 5 ++++- synth.metadata | 4 ++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/.kokoro/release/publish_javadoc11.sh b/.kokoro/release/publish_javadoc11.sh index 83beb9a06..e4096f3e7 100755 --- a/.kokoro/release/publish_javadoc11.sh +++ b/.kokoro/release/publish_javadoc11.sh @@ -40,6 +40,9 @@ export VERSION=$(grep ${NAME}: versions.txt | cut -d: -f3) # generate yml mvn clean site -B -q -P docFX +# copy README to docfx-yml dir and rename index.md +cp README.md target/docfx-yml/index.md + pushd target/docfx-yml # create metadata @@ -52,4 +55,4 @@ python3 -m docuploader create-metadata \ python3 -m docuploader upload . \ --credentials ${CREDENTIALS} \ --staging-bucket ${STAGING_BUCKET_V2} \ - --destination-prefix docfx- + --destination-prefix docfx diff --git a/synth.metadata b/synth.metadata index e09ecde4c..10a453652 100644 --- a/synth.metadata +++ b/synth.metadata @@ -4,14 +4,14 @@ "git": { "name": ".", "remote": "https://github.com/googleapis/google-auth-library-java.git", - "sha": "4f8f79c601c54c66aa1a7a34be01af03e24079cf" + "sha": "9246b5cff42dd24e45b2bff4fc803ea9c1cfa33c" } }, { "git": { "name": "synthtool", "remote": "https://github.com/googleapis/synthtool.git", - "sha": "21da7d9fa02f6916d9f87cf4072b3547b5c72eb5" + "sha": "d0bdade9a962042dc0f770cf631086f3db59b5b0" } } ], From 8653ef16b85af2d596fb75278a8ce3a2e9c56c75 Mon Sep 17 00:00:00 2001 From: WhiteSource Renovate Date: Tue, 9 Mar 2021 00:12:03 +0100 Subject: [PATCH 4/9] chore(deps): update dependency com.google.appengine:appengine-api-1.0-sdk to v1.9.86 (#561) [![WhiteSource Renovate](https://app.renovatebot.com/images/banner.svg)](https://renovatebot.com) This PR contains the following updates: | Package | Change | Age | Adoption | Passing | Confidence | |---|---|---|---|---|---| | com.google.appengine:appengine-api-1.0-sdk | `1.9.84` -> `1.9.86` | [![age](https://badges.renovateapi.com/packages/maven/com.google.appengine:appengine-api-1.0-sdk/1.9.86/age-slim)](https://docs.renovatebot.com/merge-confidence/) | [![adoption](https://badges.renovateapi.com/packages/maven/com.google.appengine:appengine-api-1.0-sdk/1.9.86/adoption-slim)](https://docs.renovatebot.com/merge-confidence/) | [![passing](https://badges.renovateapi.com/packages/maven/com.google.appengine:appengine-api-1.0-sdk/1.9.86/compatibility-slim/1.9.84)](https://docs.renovatebot.com/merge-confidence/) | [![confidence](https://badges.renovateapi.com/packages/maven/com.google.appengine:appengine-api-1.0-sdk/1.9.86/confidence-slim/1.9.84)](https://docs.renovatebot.com/merge-confidence/) | --- ### Renovate configuration :date: **Schedule**: At any time (no schedule defined). :vertical_traffic_light: **Automerge**: Disabled by config. Please merge this manually once you are satisfied. :recycle: **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox. :no_bell: **Ignore**: Close this PR and you won't be reminded about this update again. --- - [ ] If you want to rebase/retry this PR, check this box --- This PR has been generated by [WhiteSource Renovate](https://renovate.whitesourcesoftware.com). View repository job log [here](https://app.renovatebot.com/dashboard#github/googleapis/google-auth-library-java). --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 463559818..851f66642 100644 --- a/pom.xml +++ b/pom.xml @@ -62,7 +62,7 @@ 1.39.0 4.13.2 30.1-android - 1.9.84 + 1.9.86 1.7.4 3.0.2 false From a54ca74e33c9a05cf2b42b3d83ff613645f60ed0 Mon Sep 17 00:00:00 2001 From: WhiteSource Renovate Date: Tue, 9 Mar 2021 00:14:03 +0100 Subject: [PATCH 5/9] chore(deps): update dependency com.google.appengine:appengine to v1.9.86 (#560) [![WhiteSource Renovate](https://app.renovatebot.com/images/banner.svg)](https://renovatebot.com) This PR contains the following updates: | Package | Change | Age | Adoption | Passing | Confidence | |---|---|---|---|---|---| | [com.google.appengine:appengine](https://cloud.google.com/appengine/docs/standard/java/javadoc/) | `1.9.84` -> `1.9.86` | [![age](https://badges.renovateapi.com/packages/maven/com.google.appengine:appengine/1.9.86/age-slim)](https://docs.renovatebot.com/merge-confidence/) | [![adoption](https://badges.renovateapi.com/packages/maven/com.google.appengine:appengine/1.9.86/adoption-slim)](https://docs.renovatebot.com/merge-confidence/) | [![passing](https://badges.renovateapi.com/packages/maven/com.google.appengine:appengine/1.9.86/compatibility-slim/1.9.84)](https://docs.renovatebot.com/merge-confidence/) | [![confidence](https://badges.renovateapi.com/packages/maven/com.google.appengine:appengine/1.9.86/confidence-slim/1.9.84)](https://docs.renovatebot.com/merge-confidence/) | --- ### Renovate configuration :date: **Schedule**: At any time (no schedule defined). :vertical_traffic_light: **Automerge**: Disabled by config. Please merge this manually once you are satisfied. :recycle: **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox. :no_bell: **Ignore**: Close this PR and you won't be reminded about this update again. --- - [ ] If you want to rebase/retry this PR, check this box --- This PR has been generated by [WhiteSource Renovate](https://renovate.whitesourcesoftware.com). View repository job log [here](https://app.renovatebot.com/dashboard#github/googleapis/google-auth-library-java). From 497d4e739cf83876b77d1eda8c9618968cf8165a Mon Sep 17 00:00:00 2001 From: Yoshi Automation Bot Date: Wed, 10 Mar 2021 16:10:22 -0800 Subject: [PATCH 6/9] build(java): update autorelease title check in response to the new multi release branch changes (#589) This PR was generated using Autosynth. :rainbow: Synth log will be available here: https://source.cloud.google.com/results/invocations/8cc0a777-d7bc-4b36-bf33-b2f08ac29afb/targets - [ ] To automatically regenerate this PR, check this box. Source-Link: https://github.com/googleapis/synthtool/commit/0b064d767537e0675fc053e53fca473c5c701fb8 --- .github/workflows/auto-release.yaml | 4 ++-- synth.metadata | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/auto-release.yaml b/.github/workflows/auto-release.yaml index 7c8816a7d..9b4fd4d83 100644 --- a/.github/workflows/auto-release.yaml +++ b/.github/workflows/auto-release.yaml @@ -16,8 +16,8 @@ jobs: return; } - // only approve PRs like "chore(master): release " - if ( !context.payload.pull_request.title.startsWith("chore(master): release") ) { + // only approve PRs like "chore: release " + if ( !context.payload.pull_request.title.startsWith("chore: release") ) { return; } diff --git a/synth.metadata b/synth.metadata index 10a453652..e6795ee02 100644 --- a/synth.metadata +++ b/synth.metadata @@ -4,14 +4,14 @@ "git": { "name": ".", "remote": "https://github.com/googleapis/google-auth-library-java.git", - "sha": "9246b5cff42dd24e45b2bff4fc803ea9c1cfa33c" + "sha": "a54ca74e33c9a05cf2b42b3d83ff613645f60ed0" } }, { "git": { "name": "synthtool", "remote": "https://github.com/googleapis/synthtool.git", - "sha": "d0bdade9a962042dc0f770cf631086f3db59b5b0" + "sha": "0b064d767537e0675fc053e53fca473c5c701fb8" } } ], From efe103a2e688ca915ec9925a72c49bb2a1b3c3b5 Mon Sep 17 00:00:00 2001 From: arithmetic1728 <58957152+arithmetic1728@users.noreply.github.com> Date: Mon, 15 Mar 2021 23:18:29 -0700 Subject: [PATCH 7/9] feat: add self signed jwt support (#572) * feat: add self signed jwt support * update * chore: add more tests * update * update defaultscopes * update default scopes * update * update ComputeEngineCredentials * improve test coverage * update Co-authored-by: Brent Shaffer --- .../auth/oauth2/AppEngineCredentials.java | 30 ++- .../auth/oauth2/ComputeEngineCredentials.java | 23 +- .../oauth2/DefaultCredentialsProvider.java | 3 +- .../google/auth/oauth2/GoogleCredentials.java | 14 + .../oauth2/ServiceAccountCredentials.java | 247 ++++++++++++++++-- .../ServiceAccountJwtAccessCredentials.java | 21 +- .../auth/oauth2/AppEngineCredentialsTest.java | 30 ++- .../oauth2/ComputeEngineCredentialsTest.java | 25 ++ .../auth/oauth2/GoogleCredentialsTest.java | 6 + .../oauth2/ServiceAccountCredentialsTest.java | 167 +++++++++++- ...erviceAccountJwtAccessCredentialsTest.java | 16 +- 11 files changed, 537 insertions(+), 45 deletions(-) diff --git a/oauth2_http/java/com/google/auth/oauth2/AppEngineCredentials.java b/oauth2_http/java/com/google/auth/oauth2/AppEngineCredentials.java index baa2f6530..861adba16 100644 --- a/oauth2_http/java/com/google/auth/oauth2/AppEngineCredentials.java +++ b/oauth2_http/java/com/google/auth/oauth2/AppEngineCredentials.java @@ -79,18 +79,32 @@ class AppEngineCredentials extends GoogleCredentials implements ServiceAccountSi private transient Method getSignature; private transient String account; - AppEngineCredentials(Collection scopes) throws IOException { - this.scopes = scopes == null ? ImmutableSet.of() : ImmutableList.copyOf(scopes); + AppEngineCredentials(Collection scopes, Collection defaultScopes) + throws IOException { + // Use defaultScopes only when scopes don't exist. + if (scopes == null || scopes.isEmpty()) { + this.scopes = + defaultScopes == null ? ImmutableList.of() : ImmutableList.copyOf(defaultScopes); + } else { + this.scopes = ImmutableList.copyOf(scopes); + } this.scopesRequired = this.scopes.isEmpty(); init(); } - AppEngineCredentials(Collection scopes, AppEngineCredentials unscoped) { + AppEngineCredentials( + Collection scopes, Collection defaultScopes, AppEngineCredentials unscoped) { this.appIdentityService = unscoped.appIdentityService; this.getAccessToken = unscoped.getAccessToken; this.getAccessTokenResult = unscoped.getAccessTokenResult; this.getExpirationTime = unscoped.getExpirationTime; - this.scopes = scopes == null ? ImmutableSet.of() : ImmutableList.copyOf(scopes); + // Use defaultScopes only when scopes don't exist. + if (scopes == null || scopes.isEmpty()) { + this.scopes = + defaultScopes == null ? ImmutableSet.of() : ImmutableList.copyOf(defaultScopes); + } else { + this.scopes = ImmutableList.copyOf(scopes); + } this.scopesRequired = this.scopes.isEmpty(); } @@ -145,7 +159,13 @@ public boolean createScopedRequired() { @Override public GoogleCredentials createScoped(Collection scopes) { - return new AppEngineCredentials(scopes, this); + return new AppEngineCredentials(scopes, null, this); + } + + @Override + public GoogleCredentials createScoped( + Collection scopes, Collection defaultScopes) { + return new AppEngineCredentials(scopes, defaultScopes, this); } @Override diff --git a/oauth2_http/java/com/google/auth/oauth2/ComputeEngineCredentials.java b/oauth2_http/java/com/google/auth/oauth2/ComputeEngineCredentials.java index ede42cee9..01988d1f4 100644 --- a/oauth2_http/java/com/google/auth/oauth2/ComputeEngineCredentials.java +++ b/oauth2_http/java/com/google/auth/oauth2/ComputeEngineCredentials.java @@ -109,14 +109,22 @@ public class ComputeEngineCredentials extends GoogleCredentials * @param transportFactory HTTP transport factory, creates the transport used to get access * tokens. * @param scopes scope strings for the APIs to be called. May be null or an empty collection. + * @param defaultScopes default scope strings for the APIs to be called. May be null or an empty + * collection. Default scopes are ignored if scopes are provided. */ private ComputeEngineCredentials( - HttpTransportFactory transportFactory, Collection scopes) { + HttpTransportFactory transportFactory, + Collection scopes, + Collection defaultScopes) { this.transportFactory = firstNonNull( transportFactory, getFromServiceLoader(HttpTransportFactory.class, OAuth2Utils.HTTP_TRANSPORT_FACTORY)); this.transportFactoryClassName = this.transportFactory.getClass().getName(); + // Use defaultScopes only when scopes don't exist. + if (scopes == null || scopes.isEmpty()) { + scopes = defaultScopes; + } if (scopes == null) { this.scopes = ImmutableSet.of(); } else { @@ -129,7 +137,14 @@ private ComputeEngineCredentials( /** Clones the compute engine account with the specified scopes. */ @Override public GoogleCredentials createScoped(Collection newScopes) { - return new ComputeEngineCredentials(this.transportFactory, newScopes); + return new ComputeEngineCredentials(this.transportFactory, newScopes, null); + } + + /** Clones the compute engine account with the specified scopes. */ + @Override + public GoogleCredentials createScoped( + Collection newScopes, Collection newDefaultScopes) { + return new ComputeEngineCredentials(this.transportFactory, newScopes, newDefaultScopes); } /** @@ -138,7 +153,7 @@ public GoogleCredentials createScoped(Collection newScopes) { * @return new ComputeEngineCredentials */ public static ComputeEngineCredentials create() { - return new ComputeEngineCredentials(null, null); + return new ComputeEngineCredentials(null, null, null); } public final Collection getScopes() { @@ -465,7 +480,7 @@ public Collection getScopes() { } public ComputeEngineCredentials build() { - return new ComputeEngineCredentials(transportFactory, scopes); + return new ComputeEngineCredentials(transportFactory, scopes, null); } } } diff --git a/oauth2_http/java/com/google/auth/oauth2/DefaultCredentialsProvider.java b/oauth2_http/java/com/google/auth/oauth2/DefaultCredentialsProvider.java index 78ad73066..12fff6a37 100644 --- a/oauth2_http/java/com/google/auth/oauth2/DefaultCredentialsProvider.java +++ b/oauth2_http/java/com/google/auth/oauth2/DefaultCredentialsProvider.java @@ -301,7 +301,8 @@ private GoogleCredentials tryGetAppEngineCredential() throws IOException { if (!onAppEngine) { return null; } - return new AppEngineCredentials(Collections.emptyList()); + return new AppEngineCredentials( + Collections.emptyList(), Collections.emptyList()); } private final GoogleCredentials tryGetComputeCredentials(HttpTransportFactory transportFactory) { diff --git a/oauth2_http/java/com/google/auth/oauth2/GoogleCredentials.java b/oauth2_http/java/com/google/auth/oauth2/GoogleCredentials.java index 3e61e5d60..5a215322f 100644 --- a/oauth2_http/java/com/google/auth/oauth2/GoogleCredentials.java +++ b/oauth2_http/java/com/google/auth/oauth2/GoogleCredentials.java @@ -235,6 +235,20 @@ public GoogleCredentials createScoped(Collection scopes) { return this; } + /** + * If the credentials support scopes, creates a copy of the the identity with the specified scopes + * and default scopes; otherwise, returns the same instance. This is mainly used by client + * libraries. + * + * @param scopes Collection of scopes to request. + * @param defaultScopes Collection of default scopes to request. + * @return GoogleCredentials with requested scopes. + */ + public GoogleCredentials createScoped( + Collection scopes, Collection defaultScopes) { + return this; + } + /** * If the credentials support scopes, creates a copy of the the identity with the specified * scopes; otherwise, returns the same instance. diff --git a/oauth2_http/java/com/google/auth/oauth2/ServiceAccountCredentials.java b/oauth2_http/java/com/google/auth/oauth2/ServiceAccountCredentials.java index e12f8d412..aa9043611 100644 --- a/oauth2_http/java/com/google/auth/oauth2/ServiceAccountCredentials.java +++ b/oauth2_http/java/com/google/auth/oauth2/ServiceAccountCredentials.java @@ -53,6 +53,7 @@ import com.google.api.client.util.PemReader.Section; import com.google.api.client.util.Preconditions; import com.google.api.client.util.SecurityUtils; +import com.google.auth.RequestMetadataCallback; import com.google.auth.ServiceAccountSigner; import com.google.auth.http.HttpTransportFactory; import com.google.common.annotations.VisibleForTesting; @@ -80,6 +81,7 @@ import java.util.List; import java.util.Map; import java.util.Objects; +import java.util.concurrent.Executor; /** * OAuth2 credentials representing a Service Account for calling Google APIs. @@ -104,27 +106,29 @@ public class ServiceAccountCredentials extends GoogleCredentials private final String transportFactoryClassName; private final URI tokenServerUri; private final Collection scopes; + private final Collection defaultScopes; private final String quotaProjectId; private final int lifetime; private transient HttpTransportFactory transportFactory; + private transient ServiceAccountJwtAccessCredentials jwtCredentials = null; /** * Constructor with minimum identifying information and custom HTTP transport. * - * @param clientId Client ID of the service account from the console. May be null. - * @param clientEmail Client email address of the service account from the console. - * @param privateKey RSA private key object for the service account. - * @param privateKeyId Private key identifier for the service account. May be null. - * @param scopes Scope strings for the APIs to be called. May be null or an empty collection, - * which results in a credential that must have createScoped called before use. + * @param clientId client ID of the service account from the console. May be null. + * @param clientEmail client email address of the service account from the console + * @param privateKey RSA private key object for the service account + * @param privateKeyId private key identifier for the service account. May be null. + * @param scopes scope strings for the APIs to be called. May be null or an empty collection. + * @param defaultScopes default scope strings for the APIs to be called. May be null or an empty. * @param transportFactory HTTP transport factory, creates the transport used to get access * tokens. * @param tokenServerUri URI of the end point that provides tokens. - * @param serviceAccountUser Email of the user account to impersonate, if delegating domain-wide + * @param serviceAccountUser email of the user account to impersonate, if delegating domain-wide * authority to the service account. * @param projectId the project used for billing - * @param quotaProjectId The project used for quota and billing purposes. May be null. + * @param quotaProjectId the project used for quota and billing purposes. May be null. * @param lifetime number of seconds the access token should be valid for. The value should be at * most 43200 (12 hours). If the token is used for calling a Google API, then the value should * be at most 3600 (1 hour). If the given value is 0, then the default value 3600 will be used @@ -136,6 +140,7 @@ public class ServiceAccountCredentials extends GoogleCredentials PrivateKey privateKey, String privateKeyId, Collection scopes, + Collection defaultScopes, HttpTransportFactory transportFactory, URI tokenServerUri, String serviceAccountUser, @@ -147,6 +152,8 @@ public class ServiceAccountCredentials extends GoogleCredentials this.privateKey = Preconditions.checkNotNull(privateKey); this.privateKeyId = privateKeyId; this.scopes = (scopes == null) ? ImmutableSet.of() : ImmutableSet.copyOf(scopes); + this.defaultScopes = + (defaultScopes == null) ? ImmutableSet.of() : ImmutableSet.copyOf(defaultScopes); this.transportFactory = firstNonNull( transportFactory, @@ -160,6 +167,18 @@ public class ServiceAccountCredentials extends GoogleCredentials throw new IllegalStateException("lifetime must be less than or equal to 43200"); } this.lifetime = lifetime; + + // Use self signed JWT if scopes is not set, see https://google.aip.dev/auth/4111. + if (this.scopes.isEmpty()) { + jwtCredentials = + new ServiceAccountJwtAccessCredentials.Builder() + .setClientEmail(clientEmail) + .setClientId(clientId) + .setPrivateKey(privateKey) + .setPrivateKeyId(privateKeyId) + .setQuotaProjectId(quotaProjectId) + .build(); + } } /** @@ -204,6 +223,7 @@ static ServiceAccountCredentials fromJson( privateKeyPkcs8, privateKeyId, null, + null, transportFactory, tokenServerUriFromCreds, null, @@ -231,7 +251,51 @@ public static ServiceAccountCredentials fromPkcs8( Collection scopes) throws IOException { return fromPkcs8( - clientId, clientEmail, privateKeyPkcs8, privateKeyId, scopes, null, null, null, null, null); + clientId, + clientEmail, + privateKeyPkcs8, + privateKeyId, + scopes, + null, + null, + null, + null, + null, + null); + } + + /** + * Factory with minimum identifying information using PKCS#8 for the private key. + * + * @param clientId client ID of the service account from the console. May be null. + * @param clientEmail client email address of the service account from the console + * @param privateKeyPkcs8 RSA private key object for the service account in PKCS#8 format. + * @param privateKeyId private key identifier for the service account. May be null. + * @param scopes scope strings for the APIs to be called. May be null or an empty collection. + * @param defaultScopes default scope strings for the APIs to be called. May be null or an empty. + * @return new ServiceAccountCredentials created from a private key + * @throws IOException if the credential cannot be created from the private key + */ + public static ServiceAccountCredentials fromPkcs8( + String clientId, + String clientEmail, + String privateKeyPkcs8, + String privateKeyId, + Collection scopes, + Collection defaultScopes) + throws IOException { + return fromPkcs8( + clientId, + clientEmail, + privateKeyPkcs8, + privateKeyId, + scopes, + defaultScopes, + null, + null, + null, + null, + null); } /** @@ -265,6 +329,49 @@ public static ServiceAccountCredentials fromPkcs8( privateKeyPkcs8, privateKeyId, scopes, + null, + transportFactory, + tokenServerUri, + null, + null, + null); + } + + /** + * Factory with minimum identifying information and custom transport using PKCS#8 for the private + * key. + * + * @param clientId client ID of the service account from the console. May be null. + * @param clientEmail client email address of the service account from the console + * @param privateKeyPkcs8 RSA private key object for the service account in PKCS#8 format. + * @param privateKeyId private key identifier for the service account. May be null. + * @param scopes scope strings for the APIs to be called. May be null or an empty collection, + * which results in a credential that must have createScoped called before use. + * @param defaultScopes default scope strings for the APIs to be called. May be null or an empty + * collection, which results in a credential that must have createScoped called before use. + * @param transportFactory HTTP transport factory, creates the transport used to get access + * tokens. + * @param tokenServerUri URI of the end point that provides tokens + * @return new ServiceAccountCredentials created from a private key + * @throws IOException if the credential cannot be created from the private key + */ + public static ServiceAccountCredentials fromPkcs8( + String clientId, + String clientEmail, + String privateKeyPkcs8, + String privateKeyId, + Collection scopes, + Collection defaultScopes, + HttpTransportFactory transportFactory, + URI tokenServerUri) + throws IOException { + return fromPkcs8( + clientId, + clientEmail, + privateKeyPkcs8, + privateKeyId, + scopes, + defaultScopes, transportFactory, tokenServerUri, null, @@ -306,6 +413,52 @@ public static ServiceAccountCredentials fromPkcs8( privateKeyPkcs8, privateKeyId, scopes, + null, + transportFactory, + tokenServerUri, + serviceAccountUser, + null, + null); + } + + /** + * Factory with minimum identifying information and custom transport using PKCS#8 for the private + * key. + * + * @param clientId client ID of the service account from the console. May be null. + * @param clientEmail client email address of the service account from the console + * @param privateKeyPkcs8 RSA private key object for the service account in PKCS#8 format. + * @param privateKeyId private key identifier for the service account. May be null. + * @param scopes scope strings for the APIs to be called. May be null or an empty collection, + * which results in a credential that must have createScoped called before use. + * @param defaultScopes default scope strings for the APIs to be called. May be null or an empty + * collection, which results in a credential that must have createScoped called before use. + * @param transportFactory HTTP transport factory, creates the transport used to get access + * tokens. + * @param tokenServerUri URI of the end point that provides tokens + * @param serviceAccountUser the email of the user account to impersonate, if delegating + * domain-wide authority to the service account. + * @return new ServiceAccountCredentials created from a private key + * @throws IOException if the credential cannot be created from the private key + */ + public static ServiceAccountCredentials fromPkcs8( + String clientId, + String clientEmail, + String privateKeyPkcs8, + String privateKeyId, + Collection scopes, + Collection defaultScopes, + HttpTransportFactory transportFactory, + URI tokenServerUri, + String serviceAccountUser) + throws IOException { + return fromPkcs8( + clientId, + clientEmail, + privateKeyPkcs8, + privateKeyId, + scopes, + defaultScopes, transportFactory, tokenServerUri, serviceAccountUser, @@ -319,6 +472,7 @@ static ServiceAccountCredentials fromPkcs8( String privateKeyPkcs8, String privateKeyId, Collection scopes, + Collection defaultScopes, HttpTransportFactory transportFactory, URI tokenServerUri, String serviceAccountUser, @@ -332,6 +486,7 @@ static ServiceAccountCredentials fromPkcs8( privateKey, privateKeyId, scopes, + defaultScopes, transportFactory, tokenServerUri, serviceAccountUser, @@ -411,12 +566,6 @@ public static ServiceAccountCredentials fromStream( */ @Override public AccessToken refreshAccessToken() throws IOException { - if (createScopedRequired()) { - throw new IOException( - "Scopes not configured for service account. Scoped should be specified" - + " by calling createScoped or passing scopes to constructor."); - } - JsonFactory jsonFactory = OAuth2Utils.JSON_FACTORY; long currentTime = clock.currentTimeMillis(); String assertion = createAssertion(jsonFactory, currentTime, tokenServerUri.toString()); @@ -501,10 +650,14 @@ public IdToken idTokenWithAudience(String targetAudience, List