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: Adds support for user defined subject token suppliers in AWSCredentials and IdentityPoolCredentials #1336

Merged
merged 44 commits into from
Jan 25, 2024

Conversation

aeitzman
Copy link
Contributor

@aeitzman aeitzman commented Nov 27, 2023

see go/programmable-auth-design.
Also adds quality of life improvements for building credentials directly via the builder methods, and a subject token type enum.

@product-auto-label product-auto-label bot added the size: l Pull request size is large. label Nov 27, 2023
@aeitzman aeitzman marked this pull request as ready for review November 28, 2023 21:29
@aeitzman aeitzman requested review from a team as code owners November 28, 2023 21:29
# Conflicts:
#	oauth2_http/java/com/google/auth/oauth2/IdentityPoolCredentials.java
#	oauth2_http/javatests/com/google/auth/oauth2/AwsCredentialsTest.java
#	oauth2_http/javatests/com/google/auth/oauth2/ExternalAccountCredentialsTest.java
@product-auto-label product-auto-label bot added size: xl Pull request size is extra large. and removed size: l Pull request size is large. labels Dec 1, 2023
@lsirac
Copy link
Contributor

lsirac commented Dec 6, 2023

We should also update the README here + add integration tests

@@ -103,13 +107,15 @@ public class AwsCredentials extends ExternalAccountCredentials {
this.awsSecurityCredentialsProvider =
new ProgrammaticAwsSecurityCredentialsProvider(
builder.awsSecurityCredentialsSupplier, this.awsRegion);
this.builtWithSupplier = true;
Copy link
Contributor

Choose a reason for hiding this comment

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

Hmm, we shouldn't have to track this. Why not handle this in the builder so we can set the provider directly and not have to handle this logic here?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Figured out a better way to handle in the builder, we can just check whether the builder has a credential source, and only set the supplier if it doesn't

*
* @return a valid subject token.
* @throws IOException
*/
Copy link
Contributor

Choose a reason for hiding this comment

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

Should we just call this getCredentials()?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I don't think so, its getting a subject token, not some sort of credential object.

*
* @return the supplier used for getSubjectToken.
*/
abstract Supplier<String> getSupplier();
Copy link

Choose a reason for hiding this comment

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

Maybe similar to @lsirac comment: we can probably remove getSupplier() and use getToken() directly (it would call the supplier in the programmatic case);

That said, it might be better if customers provided a SubjectTokenProvider directly. The (internal) API allows us to cheat and deal with IOException in a way we don't allow via Supplier<String>; I see both problems of us eating IOException and turning them into RTEs as well as us catching RTEs and turning them into not-retryable IOException -- even though we can anticipate that there will be network, IPC or File errors present based on all of our own implementations.

So...my suggestion is to ditch "Supplier" and offer "Provider" to our customers. Now everyone has the same API String getSubjectToken() throws IOException; they can implement Retryable on their exceptions. You might need to find another way to support the metrics header value if you're worried about clients overriding it, but overall the code should be simpler.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Made this change - I wanted to keep the supplier so we could have a functional interface for users so they could use a lambda instead of creating a whole class, but I agree that its creating more problems than its worth. Refactored everything to be public. I named the objects IdentityPoolSubjectTokenSupplier and AwsSecurityCredentialSupplier instead of provider just because I call the similar function/object supplier in other PR's for other languages (still in flight, not merged) but don't feel super strongly about that either way.

@VisibleForTesting
boolean shouldUseMetadataServer() {
return (!canRetrieveRegionFromEnvironment()
|| !canRetrieveSecurityCredentialsFromEnvironment());
Copy link

Choose a reason for hiding this comment

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

This can happen in the future, but:

now that you have an indirection to choose token providers, this logic can happen when installing a token provider and therefore break this class into one for environment and one for MDS.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Unfortunately I think that would be a breaking change because the currently implementation checks the environment variables when get security credentials is called instead of in the constructor, so technically its possible for a user to create the credential and set environment variables after.

*/
abstract Supplier<String> getSupplier();

protected static String parseToken(
Copy link

Choose a reason for hiding this comment

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

Can this live with FileIDPoolCredential?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Both file and URL need this, moved to file provider for now since it can't live in the interface and I don't think its worth creating a new class to hold 1 utility method.

Copy link

@westarle westarle left a comment

Choose a reason for hiding this comment

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

This is looking pretty good now, can you please comment on the coverage of the change in unit and functional tests?

@aeitzman
Copy link
Contributor Author

This is looking pretty good now, can you please comment on the coverage of the change in unit and functional tests?

Added unit tests for the builders using the new supplier objects, as well as tests for the new default values. Also added tests for the credentials built with the suppliers (happy path with/without service account impersonation and error paths). Did not add tests for the internal suppliers since those paths are covered by existing testing. Also added integration tests for AWS and IdentityPool subject token supplier built credentials.

Copy link
Contributor

@lsirac lsirac left a comment

Choose a reason for hiding this comment

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

LGTM thanks Alex 💯

@aeitzman aeitzman added the do not merge Indicates a pull request not ready for merge, due to either quality or timing. label Jan 17, 2024
@aeitzman aeitzman requested a review from a team as a code owner January 17, 2024 21:59
Copy link

Warning: This pull request is touching the following templated files:

  • .github/CODEOWNERS

Copy link

@westarle westarle left a comment

Choose a reason for hiding this comment

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

If @lsirac or another reviewer has covered the Java details for bugs etc. this looks good to me.

Copy link

sonarcloud bot commented Jan 25, 2024

Quality Gate Passed Quality Gate passed

Kudos, no new issues were introduced!

0 New issues
0 Security Hotspots
No data about Coverage
0.0% Duplication on New Code

See analysis details on SonarCloud

@aeitzman aeitzman removed the do not merge Indicates a pull request not ready for merge, due to either quality or timing. label Jan 25, 2024
@aeitzman aeitzman merged commit 64ce8a1 into googleapis:main Jan 25, 2024
18 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
size: xl Pull request size is extra large.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants