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: Support universe domain #2635

Merged
merged 13 commits into from
Jan 17, 2024
Merged

feat: Support universe domain #2635

merged 13 commits into from
Jan 17, 2024

Conversation

amanda-tarafa
Copy link
Contributor

@jskeet for when you get to this, as usual, one commit at a time.

@amanda-tarafa amanda-tarafa requested a review from jskeet December 15, 2023 22:18
@amanda-tarafa amanda-tarafa requested a review from a team as a code owner December 15, 2023 22:18
Copy link
Collaborator

@jskeet jskeet left a comment

Choose a reason for hiding this comment

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

Almost entirely typo nits; one breaking change that does need fixing.

For ComputeCredential, it looks like we don't detect when we're using a ComputeCredential with an explicitly set universe domain, but that's not the one it's actually running in. I'll need to check the specs again to see if that's okay.

/// After that, this method will always return a completed task.
/// The task's result will never be null.
/// </remarks>
Task<string> GetUniverseDomainAsync(CancellationToken cancellationToken);
Copy link
Collaborator

Choose a reason for hiding this comment

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

And presumably the cancellation token should only ever apply to this call - if this call times out, a later call could still succeed?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes! And even viceversa assuming the first cancellation token waits for a shorter time than a second call cancellation token. I'm adding this in docs.


/// <summary>IAM access token verb.</summary>
internal const string IamAccessTokenVerb = "generateAccessToken";

/// <summary>IAM access token endpoint format string. To use it insert the service account email.</summary>
internal static readonly string IamAccessTokenEndpointFormatString = $"{IamServiceAccountEndpointCommonPrefix}{{0}}:{IamAccessTokenVerb}";
internal static readonly string IamAccessTokenEndpointFormatString = $"{IamServiceAccountEndpointCommonPrefixFormat}{{1}}:{IamAccessTokenVerb}";
Copy link
Collaborator

Choose a reason for hiding this comment

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

We can make all of these const, I believe. (Before .NET 6, we couldn't - but IamServiceAccountEndpointCommonPrefixFormat proves that we can use const interpolated strings.)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ah yes, true! Done.

using System.Threading.Tasks;
using Xunit;

namespace Google.Apis.Auth.Tests.OAuth2
Copy link
Collaborator

Choose a reason for hiding this comment

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

File-scoped namespace?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done


public IDataStore DataStore => throw new NotImplementedException();

public AuthorizationCodeRequestUrl CreateAuthorizationCodeRequest(string redirectUri)
Copy link
Collaborator

Choose a reason for hiding this comment

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

Use expression-bodied members for all of these? (I think it's fine for that to mean long lines, probably not even with line-breaks between the methods, for just a block of "stuff we haven't implemented.)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done.

using System.Threading.Tasks;
using Xunit;

namespace Google.Apis.Auth.Tests.OAuth2
Copy link
Collaborator

Choose a reason for hiding this comment

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

And again... I won't add any more comments like this.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done, and yes, I'll o through all, thanks!

[Fact]
public async Task WithUniverseDomain()
{
string principal = "principal";
Copy link
Collaborator

Choose a reason for hiding this comment

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

Some comments occasionally would help to make the structure of this test clearer, I think.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes, done!

// i.e. we could calculate the endpoint synchronusly on credential creation.
return TokenServerUrl;
}
string univerDomain = await (this as IGoogleCredential).GetUniverseDomainAsync(cancellationToken: default).ConfigureAwait(false);
Copy link
Collaborator

Choose a reason for hiding this comment

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

univerDomain => universeDomain

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done

private void ThrowIfCustomTokenUrl()
/// <summary>
/// Returns the token URL to be used by this credential, which may be a custom token URL
/// or the IAM API access tokne endpoint URL which is built using the universe domain and the
Copy link
Collaborator

Choose a reason for hiding this comment

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

tokne => token

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done

}

/// <summary>
/// Get's the id token URL if this credential supports id token emission.
Copy link
Collaborator

Choose a reason for hiding this comment

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

Get's => Gets

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done

@@ -228,6 +228,10 @@ private static UserCredential CreateUserCredentialFromParameters(JsonCredentialP
{
throw new InvalidOperationException("JSON data does not represent a valid user credential.");
}
if (credentialParameters.UniverseDomain is not null && credentialParameters.UniverseDomain != GoogleAuthConsts.DefaultUniverseDomain)
{
throw new InvalidOperationException($"{nameof(UserCredential)} is not supported in other than {GoogleAuthConsts.DefaultUniverseDomain}");
Copy link
Collaborator

Choose a reason for hiding this comment

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

"not supported in other than" => "not supported in universe domains other than"

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done


return await response.Content.ReadAsStringAsync().ConfigureAwait(false);
}
catch (Exception) when (response?.StatusCode == HttpStatusCode.NotFound)
Copy link
Contributor

@TimurSadykov TimurSadykov Dec 21, 2023

Choose a reason for hiding this comment

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

Passing by comment )

what if status code is not 404, but still an error? technically possible.. would it fall into the InvalidOperaition?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

In that case, and if it's not a timeout (timeout is handled by catching the OperationCanceldException) then the original exception is bubled up. This is also what happens on token fetching, and I'm mimicking that here as per spec.
Does that sound good?

Copy link
Contributor

Choose a reason for hiding this comment

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

Oh got it.. I misunderstood the Exception catch the first time. Looks good.

Copy link
Contributor Author

@amanda-tarafa amanda-tarafa left a comment

Choose a reason for hiding this comment

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

@jskeet , @TimurSadykov I've addressed all your comments.

Changes are in ordered commits that start with Address Review:, and the last commit is also new.

PTAL, thanks!


/// <summary>IAM access token verb.</summary>
internal const string IamAccessTokenVerb = "generateAccessToken";

/// <summary>IAM access token endpoint format string. To use it insert the service account email.</summary>
internal static readonly string IamAccessTokenEndpointFormatString = $"{IamServiceAccountEndpointCommonPrefix}{{0}}:{IamAccessTokenVerb}";
internal static readonly string IamAccessTokenEndpointFormatString = $"{IamServiceAccountEndpointCommonPrefixFormat}{{1}}:{IamAccessTokenVerb}";
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ah yes, true! Done.

/// After that, this method will always return a completed task.
/// The task's result will never be null.
/// </remarks>
Task<string> GetUniverseDomainAsync(CancellationToken cancellationToken);
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes! And even viceversa assuming the first cancellation token waits for a shorter time than a second call cancellation token. I'm adding this in docs.

using System.Threading.Tasks;
using Xunit;

namespace Google.Apis.Auth.Tests.OAuth2
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done


public IDataStore DataStore => throw new NotImplementedException();

public AuthorizationCodeRequestUrl CreateAuthorizationCodeRequest(string redirectUri)
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done.

using System.Threading.Tasks;
using Xunit;

namespace Google.Apis.Auth.Tests.OAuth2
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done, and yes, I'll o through all, thanks!

private void ThrowIfCustomTokenUrl()
/// <summary>
/// Returns the token URL to be used by this credential, which may be a custom token URL
/// or the IAM API access tokne endpoint URL which is built using the universe domain and the
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done

// i.e. we could calculate the endpoint synchronusly on credential creation.
return TokenServerUrl;
}
string univerDomain = await (this as IGoogleCredential).GetUniverseDomainAsync(cancellationToken: default).ConfigureAwait(false);
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done

}

/// <summary>
/// Get's the id token URL if this credential supports id token emission.
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done

[Fact]
public async Task WithUniverseDomain()
{
string principal = "principal";
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes, done!

@@ -228,6 +228,10 @@ private static UserCredential CreateUserCredentialFromParameters(JsonCredentialP
{
throw new InvalidOperationException("JSON data does not represent a valid user credential.");
}
if (credentialParameters.UniverseDomain is not null && credentialParameters.UniverseDomain != GoogleAuthConsts.DefaultUniverseDomain)
{
throw new InvalidOperationException($"{nameof(UserCredential)} is not supported in other than {GoogleAuthConsts.DefaultUniverseDomain}");
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done

@amanda-tarafa
Copy link
Contributor Author

For ComputeCredential, it looks like we don't detect when we're using a ComputeCredential with an explicitly set universe domain, but that's not the one it's actually running in. I'll need to check the specs again to see if that's okay.

Yes, thats OK, apparently there will be cases in which one universe accepts credentials from another (related) universe.

What we'll need to check is that the service client "intentions" are matched by the credential, i.e. the universe specified for the service client is the same as the one specified for the credential.

Copy link
Contributor

@TimurSadykov TimurSadykov left a comment

Choose a reason for hiding this comment

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

LGTM

@amanda-tarafa amanda-tarafa added the do not merge Indicates a pull request not ready for merge, due to either quality or timing. label Jan 12, 2024
@jskeet
Copy link
Collaborator

jskeet commented Jan 15, 2024

@amanda-tarafa: Is there anything new you'd like me to review here?

@amanda-tarafa
Copy link
Contributor Author

Nope, my last push wash just about squashing the "address review" commits.

I'll merge and release later today.

@amanda-tarafa amanda-tarafa removed the do not merge Indicates a pull request not ready for merge, due to either quality or timing. label Jan 17, 2024
@amanda-tarafa amanda-tarafa merged commit 9f1c8cb into main Jan 17, 2024
7 checks passed
@amanda-tarafa amanda-tarafa deleted the universe_domain branch January 17, 2024 16:29
amanda-tarafa added a commit that referenced this pull request Jan 17, 2024
- feat: [#2635](#2635) Authentication support for multiple universe domains.
amanda-tarafa added a commit that referenced this pull request Jan 17, 2024
- feat: [#2635](#2635) Authentication support for multiple universe domains.
amanda-tarafa added a commit that referenced this pull request Feb 22, 2024
Features

- Universe domain support:
- feat: [#2675](#2675) Universe domain support for Discovery based libraries.
- feat: [#2635](#2635) Universe domain support for authentication.
amanda-tarafa added a commit that referenced this pull request Feb 22, 2024
Features

- Universe domain support:
  - feat: [#2675](#2675) Universe domain support for Discovery based libraries.
  - feat: [#2635](#2635) Universe domain support for authentication.
amanda-tarafa added a commit that referenced this pull request Feb 22, 2024
Features

- Universe domain support:
  - feat: [#2675](#2675) Universe domain support for Discovery based libraries.
  - feat: [#2635](#2635) Universe domain support for authentication.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants