-
Notifications
You must be signed in to change notification settings - Fork 546
feat: Add support for file-sourced external credentials. #2206
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
Conversation
jskeet
left a comment
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.
Various nits and a few questions, but basically fine as far as I can see - I'm not a subject-matter expert on this though.
| get => new TheoryData<string, Type> | ||
| { | ||
| { DummyUrlSourcedExternalAccountCredentialFileContents, typeof(UrlSourcedExternalAccountCredential) }, | ||
| { DummyFileSourcedExternalAccountCredentialFileContents, typeof (FileSourcedExternalAccountCredential) }, |
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.
Nit: remove space after typeof. (I wouldn't have noticed it if it hadn't been for the inconsistency with the one above.
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.
(Note: both of these comments apply twice below as well.)
|
|
||
| [Fact] | ||
| public async Task GetDefaultCredential_UrlSourcedExternalAccountCredential() | ||
| public static TheoryData<string, Type> ExternalAccountCredentialTestData |
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.
Just make this expression-bodied?
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.
Done, on all three
| Assert.Contains($"subject_token={SubjectTokenText}", contentText); | ||
| Assert.Contains($"scope={scope}", contentText); | ||
|
|
||
| return new HttpResponseMessage |
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 probably do the serialization in a separate statement above, then just return new HttpResponseMessage { Content = new StringContent(content, Encoding.UTF8) }; - aside from anything else, that's simpler when debugging.
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.
Given all the code below, it might also be worth extracting new HttpResponseMessage { Content = new StringContent(content, Encoding.UTF8) } into a helper method.
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.
In fact, we might want a helper method to do everything - just given the access token and expiry, as that's all that really seems to vary.
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.
Done.
| { | ||
| accessToken = ImpersonatedAccessToken, | ||
| expireTime = "2020-05-13T16:00:00.045123456Z" | ||
| })) |
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 one doesn't specify UTF-8 - is that relevant?
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.
After extracting it does, not sure if it was default already.
| /// <inheritdoc/> | ||
| protected override Task<string> GetSubjectTokenAsync(CancellationToken taskCancellationToken) | ||
| { | ||
| var fileContent = File.ReadAllText(SubjectTokenFilePath); |
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 definitely want to read the file here, rather than in the constructor? What's the expected behavior if this file changes over time?
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.
The file content can change at any time, so I think it's correct to read the file here.
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.
Yes, it is expected that the subject token may be refreshed and the refreshed subject token should be used each time.
I had this question in general for subject tokens, regardless of whether they are URL or file or otherwise sourced, they can always change, on every access token refresh the subject tokens should be requested anew.
| } | ||
| else | ||
| { | ||
| var jsonResponse = NewtonsoftJsonSerializer.Instance.Deserialize<Dictionary<string, string>>(fileContent); |
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.
Are we okay with this failing with a Json.NET-specific error if the field doesn't exist, or isn't a string?
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'll wrap the exceptions from here on the parent class, as we could also get IOExceptions if the file is not present, etc. I've added tests as well for both credentials.
| /// <inheritdoc/> | ||
| protected override Task<string> GetSubjectTokenAsync(CancellationToken taskCancellationToken) | ||
| { | ||
| var fileContent = File.ReadAllText(SubjectTokenFilePath); |
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 is an async method, so you could read the file asynchronously too
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.
There's no File.ReadAllTextAsync pre .NET 7 (which surprised me a little) and I prefered code simplicity. But yes, changing now...
| /// <inheritdoc/> | ||
| protected override Task<string> GetSubjectTokenAsync(CancellationToken taskCancellationToken) | ||
| { | ||
| var fileContent = File.ReadAllText(SubjectTokenFilePath); |
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.
The file content can change at any time, so I think it's correct to read the file here.
65d548a to
829927a
Compare
amanda-tarafa
left a comment
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've addressed all review comments, PTAL.
|
|
||
| [Fact] | ||
| public async Task GetDefaultCredential_UrlSourcedExternalAccountCredential() | ||
| public static TheoryData<string, Type> ExternalAccountCredentialTestData |
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.
Done, on all three
| /// <inheritdoc/> | ||
| protected override Task<string> GetSubjectTokenAsync(CancellationToken taskCancellationToken) | ||
| { | ||
| var fileContent = File.ReadAllText(SubjectTokenFilePath); |
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.
Yes, it is expected that the subject token may be refreshed and the refreshed subject token should be used each time.
I had this question in general for subject tokens, regardless of whether they are URL or file or otherwise sourced, they can always change, on every access token refresh the subject tokens should be requested anew.
| /// <inheritdoc/> | ||
| protected override Task<string> GetSubjectTokenAsync(CancellationToken taskCancellationToken) | ||
| { | ||
| var fileContent = File.ReadAllText(SubjectTokenFilePath); |
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.
There's no File.ReadAllTextAsync pre .NET 7 (which surprised me a little) and I prefered code simplicity. But yes, changing now...
| } | ||
| else | ||
| { | ||
| var jsonResponse = NewtonsoftJsonSerializer.Instance.Deserialize<Dictionary<string, string>>(fileContent); |
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'll wrap the exceptions from here on the parent class, as we could also get IOExceptions if the file is not present, etc. I've added tests as well for both credentials.
| Assert.Contains($"subject_token={SubjectTokenText}", contentText); | ||
| Assert.Contains($"scope={scope}", contentText); | ||
|
|
||
| return new HttpResponseMessage |
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.
Done.
| { | ||
| accessToken = ImpersonatedAccessToken, | ||
| expireTime = "2020-05-13T16:00:00.045123456Z" | ||
| })) |
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.
After extracting it does, not sure if it was default already.
| { | ||
| return await GetSubjectTokenAsyncImpl(taskCancellationTokne).ConfigureAwait(false); | ||
| } | ||
| catch(Exception ex) |
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.
Micro-nit: space before (
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.
Done. I'll rebase all and merge after green! Thanks.
829927a to
a16f320
Compare
Features - googleapis#2228 Supports Quota Project environment variable for ADC. - googleapis#2219 Removes obsolete OOB code. BREAKING CHANGE: We have removed OOB support from the library because the feature is not supported by Google OAuth as of October 3rd 2022. See the [official announcement](https://developers.googleblog.com/2022/02/making-oauth-flows-safer.html#disallowed-oob) for more information. - googleapis#2216 Log errors when trying to reach Compute's metadata server. - googleapis#2177, googleapis#2197, googleapis#2200, googleapis#2206, googleapis#2215, googleapis#2235 Support for Workload Identity Federation and Worforce Identity Federation. - googleapis#2103 Compute credentials support explicit scopes. - googleapis#2096 Improves deserialization error handling.
Features - #2228 Supports Quota Project environment variable for ADC. - #2219 Removes obsolete OOB code. BREAKING CHANGE: We have removed OOB support from the library because the feature is not supported by Google OAuth as of October 3rd 2022. See the [official announcement](https://developers.googleblog.com/2022/02/making-oauth-flows-safer.html#disallowed-oob) for more information. - #2216 Log errors when trying to reach Compute's metadata server. - #2177, #2197, #2200, #2206, #2215, #2235 Support for Workload Identity Federation and Worforce Identity Federation. - #2103 Compute credentials support explicit scopes. - #2096 Improves deserialization error handling.
And support version: 1.58.0-beta02 => 1.58.0 Bug fixes: - googleapis#2273 Don't attempt to use an empty/null media type in batch responses - googleapis#2251 Which fixes a typo on then name of one of the AWS Credential environment variables. - googleapis#2264 Which adds a missing line break in AWS Credential canonical request. Features - googleapis#2269 Support per-request max retry configuration. - googleapis#2228 Supports Quota Project environment variable for ADC. - googleapis#2219 Removes obsolete OOB code. BREAKING CHANGE: We have removed OOB support from the library because the feature is not supported by Google OAuth as of October 3rd 2022. See the [official announcement](https://developers.googleblog.com/2022/02/making-oauth-flows-safer.html#disallowed-oob) for more information. - googleapis#2216 Log errors when trying to reach Compute's metadata server. - googleapis#2177, googleapis#2197, googleapis#2200, googleapis#2206, googleapis#2215, googleapis#2235 Support for Workload Identity Federation and Worforce Identity Federation. - googleapis#2103 Compute credentials support explicit scopes. - googleapis#2096 Improves deserialization error handling.
And support version: 1.58.0-beta02 => 1.58.0 Dependencies: - Client libraries no longer target netstandard1.0 or net40. Bug fixes: - googleapis#2273 Don't attempt to use an empty/null media type in batch responses - googleapis#2251 Which fixes a typo on then name of one of the AWS Credential environment variables. - googleapis#2264 Which adds a missing line break in AWS Credential canonical request. Features - googleapis#2269 Support per-request max retry configuration. - googleapis#2228 Supports Quota Project environment variable for ADC. - googleapis#2219 Removes obsolete OOB code. BREAKING CHANGE: We have removed OOB support from the library because the feature is not supported by Google OAuth as of October 3rd 2022. See the [official announcement](https://developers.googleblog.com/2022/02/making-oauth-flows-safer.html#disallowed-oob) for more information. - googleapis#2216 Log errors when trying to reach Compute's metadata server. - googleapis#2177, googleapis#2197, googleapis#2200, googleapis#2206, googleapis#2215, googleapis#2235 Support for Workload Identity Federation and Worforce Identity Federation. - googleapis#2103 Compute credentials support explicit scopes. - googleapis#2096 Improves deserialization error handling.
And support version: 1.58.0-beta02 => 1.58.0 Dependencies: - Client libraries no longer target netstandard1.0 or net40. Bug fixes: - #2273 Don't attempt to use an empty/null media type in batch responses - #2251 Which fixes a typo on then name of one of the AWS Credential environment variables. - #2264 Which adds a missing line break in AWS Credential canonical request. Features - #2269 Support per-request max retry configuration. - #2228 Supports Quota Project environment variable for ADC. - #2219 Removes obsolete OOB code. BREAKING CHANGE: We have removed OOB support from the library because the feature is not supported by Google OAuth as of October 3rd 2022. See the [official announcement](https://developers.googleblog.com/2022/02/making-oauth-flows-safer.html#disallowed-oob) for more information. - #2216 Log errors when trying to reach Compute's metadata server. - #2177, #2197, #2200, #2206, #2215, #2235 Support for Workload Identity Federation and Worforce Identity Federation. - #2103 Compute credentials support explicit scopes. - #2096 Improves deserialization error handling.
Towards #2033.
Also refactors the existing external account credential tests to make it easier to reuse test code.
FYI: @lsirac, @jpassing , @moserware