Skip to content
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

Merged
merged 14 commits into from
Aug 14, 2020
Merged

feat: defines ExternalAccountClient abstract class for external_account credentials #1030

merged 14 commits into from
Aug 14, 2020

Conversation

bojeil-google
Copy link
Contributor

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.

@bojeil-google bojeil-google requested a review from a team as a code owner August 11, 2020 22:14
@codecov
Copy link

codecov bot commented Aug 11, 2020

Codecov Report

❗ No coverage uploaded for pull request base (byoid@7f8b124). Click here to learn what that means.
The diff coverage is n/a.

Impacted file tree graph

@@           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.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 7f8b124...436067f. Read the comment docs.

@google-cla google-cla bot added the cla: yes This human has signed the Contributor License Agreement. label Aug 11, 2020
* 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>
@sofisl sofisl added automerge Merge the pull request once unit tests and other checks pass. and removed automerge Merge the pull request once unit tests and other checks pass. labels Aug 12, 2020
@google-cla
Copy link

google-cla bot commented Aug 12, 2020

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.
In order to pass this check, please resolve this problem and then comment @googlebot I fixed it.. If the bot doesn't comment, it means it doesn't think anything has changed.

ℹ️ Googlers: Go here for more info.

@google-cla google-cla bot added cla: no This human has *not* signed the Contributor License Agreement. and removed cla: yes This human has signed the Contributor License Agreement. labels Aug 12, 2020
@googlebot
Copy link

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.
In order to pass this check, please resolve this problem and then comment @googlebot I fixed it.. If the bot doesn't comment, it means it doesn't think anything has changed.

ℹ️ Googlers: Go here for more info.

@bcoe bcoe added the cla: yes This human has signed the Contributor License Agreement. label Aug 12, 2020
@google-cla
Copy link

google-cla bot commented Aug 12, 2020

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.

@google-cla google-cla bot removed the cla: no This human has *not* signed the Contributor License Agreement. label Aug 12, 2020
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
Copy link
Contributor

@bcoe bcoe left a 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
Copy link
Contributor

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.

Copy link
Contributor Author

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;
Copy link
Contributor

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.

Copy link
Contributor Author

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 Show resolved Hide resolved
* @param options The external account options object typically loaded
* from the external account JSON credential file.
*/
constructor(private readonly options: ExternalAccountClientOptions) {
Copy link
Contributor

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.

Copy link
Contributor Author

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;
Copy link
Contributor

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.

Copy link
Contributor Author

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.

Copy link
Contributor

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.

@google-cla google-cla bot added cla: no This human has *not* signed the Contributor License Agreement. and removed cla: yes This human has signed the Contributor License Agreement. labels Aug 13, 2020
@bcoe bcoe added the cla: yes This human has signed the Contributor License Agreement. label Aug 14, 2020
@bcoe bcoe removed the cla: no This human has *not* signed the Contributor License Agreement. label Aug 14, 2020
@google-cla
Copy link

google-cla bot commented Aug 14, 2020

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.

@google-cla google-cla bot added cla: no This human has *not* signed the Contributor License Agreement. and removed cla: yes This human has signed the Contributor License Agreement. labels Aug 14, 2020
@bojeil-google bojeil-google requested a review from bcoe August 14, 2020 18:54
@bcoe bcoe added cla: yes This human has signed the Contributor License Agreement. and removed cla: no This human has *not* signed the Contributor License Agreement. labels Aug 14, 2020
@google-cla
Copy link

google-cla bot commented Aug 14, 2020

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.

Copy link
Contributor

@bcoe bcoe left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM.

@bcoe bcoe merged commit 1174e4a into googleapis:byoid Aug 14, 2020
bcoe added a commit that referenced this pull request Feb 6, 2021
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>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
cla: yes This human has signed the Contributor License Agreement.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants