-
Notifications
You must be signed in to change notification settings - Fork 107
Conversation
Codecov Report
@@ Coverage Diff @@
## master #1294 +/- ##
============================================
- Coverage 79.34% 79.24% -0.10%
- Complexity 1235 1245 +10
============================================
Files 209 209
Lines 5398 5455 +57
Branches 454 464 +10
============================================
+ Hits 4283 4323 +40
- Misses 936 945 +9
- Partials 179 187 +8
Continue to review full report at Codecov.
|
} | ||
|
||
/** | ||
* If user doesn't provide custom endpoint and scopes, and the credentials is service account |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is --> are
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you for all the comments. Will address them in the next commit.
/** | ||
* If user doesn't provide custom endpoint and scopes, and the credentials is service account | ||
* credentials, then we need to create a new ServiceAccountJwtAccessCredentials to use self signed | ||
* jwt. See https://google.aip.dev/auth/4111. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
JWT
|
||
/** | ||
* If user doesn't provide custom endpoint and scopes, and the credentials is service account | ||
* credentials, then we need to create a new ServiceAccountJwtAccessCredentials to use self signed |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
rewrite in third person
This doc comment only seems to describe one detail of the method's implementation, not the entire method.
@@ -134,9 +161,20 @@ public static Builder newBuilder() { | |||
@BetaApi | |||
public abstract List<String> getJwtEnabledScopes(); | |||
|
|||
/** | |||
* Default scopes is for client libraries to use. Users should use setScopesToApply to set |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is --> are
@@ -134,9 +161,20 @@ public static Builder newBuilder() { | |||
@BetaApi | |||
public abstract List<String> getJwtEnabledScopes(); | |||
|
|||
/** | |||
* Default scopes is for client libraries to use. Users should use setScopesToApply to set | |||
* scopes, or setJwtEnabledScopes to force to use ServiceAccountJWTCredentials. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
force what?
@@ -132,6 +140,73 @@ public static ClientContext create(ClientSettings settings) throws IOException { | |||
return create(settings.getStubSettings()); | |||
} | |||
|
|||
/** | |||
* If user doesn't provide custom endpoint and scopes, and the credentials is service account | |||
* credentials, then we need to create a new ServiceAccountJwtAccessCredentials to use self signed |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
avoid first person in doc comments, per google style
@@ -597,4 +602,70 @@ public void testUserAgentConcat() throws Exception { | |||
assertThat(transportChannel.getHeaders()) | |||
.containsEntry("user-agent", "user-supplied-agent internal-agent"); | |||
} | |||
|
|||
@Test | |||
public void testSelfSignedJwtEndpointNotDefault() throws Exception { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can exception be more specific?
// Test when endpoint is null. | ||
Credentials returnedCredentials = | ||
ClientContext.determineSelfSignedJWTCredentials(provider, null, "https://foo"); | ||
assertThat(returnedCredentials).isEqualTo(credentials); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
unnecessary use of Truth for simple equality
} | ||
|
||
@Test | ||
public void testSelfSignedJwtWithGoogleCredentialsProvider() throws Exception { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can exception be more specific?
} | ||
|
||
@Test | ||
public void testSelfSignedJwtWithFixedCredentialsProvider() throws Exception { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can exception be more specific?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hi, thanks for working on this. However I think there are a couple of flaws here:
- this breaks existing functionality of restricting access by scope
- it prevents usage of jwts custom endpoints: for example this will prevent bigtable dataflow connector from being able to access batch-bigtable.googleapis.com using JWTs (its the same OP service, with different routing rules).
2b. audiences arent necessarily tied to the endpoint, it just happens that it aligns most of the time. Forcing the audience to be a prefix of the endpoint will prevent that usecase - This prevents adding outgoing sidecar proxies in front of our clients.
- Given that this a new api, anything exposed as public should be marked as internal api or beta api in case it turns out that we need to change this because it doesnt account for everything that client devs or customers need.
@@ -134,9 +161,20 @@ public static Builder newBuilder() { | |||
@BetaApi | |||
public abstract List<String> getJwtEnabledScopes(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please deprecate the previous approach of setJwtEnabledScopes
, it's still marked as BetaApi and we shouldnt have 2 ways to opt into jwt
// provide scopes, then we create a ServiceAccountJwtAccessCredentials and use this credentials | ||
// instead. This credential uses self signed jwt, and it is more efficient since the network | ||
// call to token endpoint is avoided. See https://google.aip.dev/auth/4111. | ||
if (provider instanceof GoogleCredentialsProvider) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can all of this move into a static helper in CredentialsProvider (or anything that is more related to credentials)? Having the credential logic split between CredentialsProviders and here makes it very hard to follow the logic unless you know what you are looking for
* credentials, then we need to create a new ServiceAccountJwtAccessCredentials to use self signed | ||
* jwt. See https://google.aip.dev/auth/4111. | ||
*/ | ||
public Credentials getCredentials(boolean endpointIsDefault, URI audienceForSelfSignedJwt) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please mark audience as @Nullable
if (!scopes.contains(scope)) { | ||
scopes.add(scope); | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This breaks an existing usecase of using a narrow scope to restrict functionality. For example if a customer wanted to restrict bigtable access in an application to just read only, they would change the scopes to https://www.googleapis.com/auth/cloud-bigtable.data.readonly
.
And if this is an intentional breakage, this needs to be made a lot more apparent in a separate PR that explicitly changes that behavior
@@ -120,6 +123,10 @@ public final String getEndpoint() { | |||
return endpoint; | |||
} | |||
|
|||
public final String getDefaultApiEndpoint() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
should this be public? it seems like this entire api is designed for client authors, I dont think this should be made public to end users
Yes, this is a mistake.
Yes, I was waiting for cl/356594013 to unblock custom endpoints. It seems cl will be submitted soon, I will change the design.
I guess I can change the design to use the prefix of endpoint, only if prefix of endpoint == prefix of audiences. For http client like java-compute, only the prefix of endpoint is a valid audience.
How does this design prevent it?
Yep. |
The problem is that you are tying the audience to the endpoint. Example scenario: bigtable client with a caching read through forward proxy. The proxy will forward the request to bigtable if the response is not cached. In this case, the endpoint is the proxy, while the audience of the creds is bigtable.googleapis.com. |
The audience being set is a default audience, which is not used if uri is provided when creating the token. Currently for ServiceAccountJWTCredentials, if uri and default audience are both not set, program will throw exception. Since the jwt credentials set by gax-java via jwt enabled scopes doesn't have default audience, so I think this scenario uri must be already set, so it won't be affected. |
I changed the design and now the major implementation is in auth library. On one hand, cl/356594013 is submitted so we no longer need to worry about if the endpoint is default or not, which makes it easy to implement the feature in auth lib; on the other hand, the changes to gax-java is now minimal and shouldn't affect any existing client libs. Please check out this PR in auth lib and this PR in gax-java. Thanks! @elharo @igorbernstein2 |
This PR adds self signed jwt support (https://google.aip.dev/auth/4111). Googlers see this doc for more details.
If user uses
ServiceAccountCredentials
, and doesn't provide custom endpoint, scopes, and audience, then a newServiceAccountJwtAccessCredentials
should be created and used for self signed jwt feature.This PR doesn't break existing client libraries.
1. Details
endpoint
In
StubSettings.java
, currently because both user and client library set theendpoint
property, so we cannot tell whether theendpoint
property is a custom endpoint set by user. To solve this problem, this PR creates a newdefaultApiEndpoint
property for the client libraries to use. Then we can compareendpoint
withdefaultApiEndpoint
to know ifendpoint
is a custom endpoint.Client library example PR using java-cloudbuild
Note: once cl/356594013 is checked in and rolled out, then all the changes in this section is not needed anymore. Depending on the actual timeline, I can update this PR or create a subsequent PR.
scopes
There are two types of
CredentialsProvider
for the user to provide a credentials:GoogleCredentialsProvider
andFixedCredentialsProvider
. Whether scopes are provided by user depends on the provider type.GoogleCredentialsProvider
provides ADC credential. Currently both user and client library usesetScopesToApply
method to set scopes. To tell the difference, this PR creates a newsetDefaultScopes
method for the client library to use. Client library example PR using java-cloudbuildFixedCredentialsProvider
wraps a credential created by the user. If the credential isServiceAccountCredentials
, then we can look at thescopes
property.audience
Users cannot set audience for
ServiceAccountCredentials
regardless of the credential provider type, so this doesn't apply.2. Client examples PRs
This PR works for both GAPIC and DIREGAPIC clients. Examples PRs for client libraries: