-
Notifications
You must be signed in to change notification settings - Fork 384
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: defines ExternalAccountClient abstract class for external_account credentials #1030
feat: defines ExternalAccountClient abstract class for external_account credentials #1030
Conversation
Codecov Report
@@ Coverage Diff @@
## byoid #1030 +/- ##
========================================
Coverage ? 92.85%
========================================
Files ? 24
Lines ? 4884
Branches ? 564
========================================
Hits ? 4535
Misses ? 349
Partials ? 0 Continue to review full report at Codecov.
|
* chore: updated samples/package.json [ci skip] * chore: updated CHANGELOG.md [ci skip] * chore: updated package.json Co-authored-by: release-please[bot] <55107282+release-please[bot]@users.noreply.github.com>
This PR was generated using Autosynth. 🌈 Synth log will be available here: https://source.cloud.google.com/results/invocations/5f7f9c6d-c75a-4c60-8bb8-0026a14cead7/targets - [ ] To automatically regenerate this PR, check this box. Source-Link: googleapis/synthtool@94421c4
…brary-nodejs into external-account-client
We found a Contributor License Agreement for you (the sender of this pull request), but were unable to find agreements for all the commit author(s) or Co-authors. If you authored these, maybe you used a different email address in the git commits than was used to sign the CLA (login here to double check)? If these were authored by someone else, then they will need to sign a CLA as well, and confirm that they're okay with these being contributed to Google. ℹ️ Googlers: Go here for more info. |
We found a Contributor License Agreement for you (the sender of this pull request), but were unable to find agreements for all the commit author(s) or Co-authors. If you authored these, maybe you used a different email address in the git commits than was used to sign the CLA (login here to double check)? If these were authored by someone else, then they will need to sign a CLA as well, and confirm that they're okay with these being contributed to Google. ℹ️ Googlers: Go here for more info. |
A Googler has manually verified that the CLAs look good. (Googler, please make sure the reason for overriding the CLA status is clearly documented in these comments.) ℹ️ Googlers: Go here for more info. |
This PR was generated using Autosynth. 🌈 Synth log will be available here: https://source.cloud.google.com/results/invocations/b742586e-df31-4aac-8092-78288e9ea8e7/targets - [ ] To automatically regenerate this PR, check this box. Source-Link: googleapis/synthtool@bd0deaa
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.
Left a few nits, this is looking solid to me.
import {ClientAuthentication} from './oauth2common'; | ||
|
||
/** | ||
* The required token exchange grant_type: rfc8693#section-2.1 |
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.
I appreciate the links to RFCs, this will be useful for future generations.
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.
Yeah, definitely. Let me know anytime something is not clear. I can provide relevant links and context so the code is self-explanatory.
/** | ||
* Offset to take into account network delays and server clock skews. | ||
*/ | ||
export const EXPIRATION_TIME_OFFSET = 5 * 60 * 1000; |
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.
Where does the 5 minute value come from? wondering if this is similar to where other clients landed.
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.
It is defined here:
opts.eagerRefreshThresholdMillis || 5 * 60 * 1000; |
and used here
? expiryDate <= new Date().getTime() + this.eagerRefreshThresholdMillis |
It defaults to 5mins but they allow it to be overridden.
I added a second optional object argument to constructor that takes in a similar RefreshOptions
. So the default behavior here is now the same as oauth2client
. That object can be extended with additional customization parameters in the future, if needed.
I updated the tests to cover this (custom threshold and option to force refresh or disable refresh on 401/403).
src/auth/externalclient.ts
Outdated
* @param options The external account options object typically loaded | ||
* from the external account JSON credential file. | ||
*/ | ||
constructor(private readonly options: ExternalAccountClientOptions) { |
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.
do you know if the readonly
modifier applies to accessing properties on the object? I fixed a variety of bugs in this library related to people modifying an object, not realizing it's passed by reference.
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.
If you mean:
client.options.audience = 'overrwrite';
Unfortunately, this will not throw.
I guess readonly
acts more like a const
for a private
or public
property.
client.options = 'this will throw';
Though, even then, there are workarounds for that:
Object.defineProperty(client, 'options', {
value: 'overrwrite of entire options',
});
I find it good practice to use it as it ensures I don't overwrite private and public properties internally that should not be overwritten.
Are you worried that developers could accidentally update the options content and break the behavior here? If so, I have updated the logic so that we just keep copies by value of the options content. So changes to that object will not break the behavior.
// - The response was a 401 or a 403 | ||
// - The request didn't send a readableStream | ||
const isReadableStream = res.config.data instanceof stream.Readable; | ||
const isAuthErr = statusCode === 401 || statusCode === 403; |
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.
Do we use this retry logic in a few places, it seems like something we should abstract into a helper.
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.
Seems to be mainly in oauth2client
which most other clients extend:
const isAuthErr = statusCode === 401 || statusCode === 403; |
There may be some subtle differences but I can define requestAsync
in the base class AuthClient
which both classes extend. I can look into it in a separate dedicated PR as this PR is getting a bit too large.
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.
I'd even be happy with a tracking issue, just seems like an area for some code cleanup.
A Googler has manually verified that the CLAs look good. (Googler, please make sure the reason for overriding the CLA status is clearly documented in these comments.) ℹ️ Googlers: Go here for more info. |
A Googler has manually verified that the CLAs look good. (Googler, please make sure the reason for overriding the CLA status is clearly documented in these comments.) ℹ️ Googlers: Go here for more info. |
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.
LGTM.
feat: implements the OAuth token exchange spec based on rfc8693 (#1026) feat: defines ExternalAccountClient abstract class for external_account credentials (#1030) feat: adds service account impersonation to `ExternalAccountClient` (#1041) feat: defines `IdentityPoolClient` used for K8s and Azure workloads (#1042) feat: implements AWS signature version 4 for signing requests (#1047) feat: defines `ExternalAccountClient` used to instantiate external account clients (#1050) feat!: integrates external_accounts with `GoogleAuth` and ADC (#1052) feat: adds text/json credential_source support to IdentityPoolClients (#1059) feat: get AWS region from environment variable (#1067) Co-authored-by: Wilfred van der Deijl <wilfred@vanderdeijl.com> Co-authored-by: Benjamin E. Coe <bencoe@google.com>
Base external account client is used to instantiate
AuthClients
for exchanging external account credentials for GCP access token and authorizing requests to GCP APIs.The base class implements common logic for exchanging various type of external credentials via GCP STS token exchange endpoint for GCP access tokens. The logic of determining and retrieving the external credential based on the environment and
credential_source
in the credentials JSON file will be left for the subclasses.