Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,16 @@ public class GoogleCredentialTests
{
private const string QuotaProjectHeaderKey = "x-goog-user-project";
private const string FakeAuthUri = "https://www.googleapis.com/google.some_google_api";
private const string FakeImpersonatedCredentialFileContents = @"{
""service_account_impersonation_url"": ""https://example.com"",
""type"": ""impersonated_service_account"",
""scopes"": [""SCOPE""],
""source_credentials"": {
""client_id"": ""CLIENT_ID"",
""client_secret"": ""CLIENT_SECRET"",
""refresh_token"": ""REFRESH_TOKEN"",
""type"": ""authorized_user""
}}";
private const string FakeUserCredentialFileContents = @"{
""client_id"": ""CLIENT_ID"",
""client_secret"": ""CLIENT_SECRET"",
Expand Down Expand Up @@ -697,6 +707,31 @@ public void CreateScoped_Impersonated()
Assert.Collection(impersonatedCredential.Scopes, scope => Assert.Equal("new_scope", scope));
}

[Fact]
public void CreateScoped_Impersonated_FromJson()
{
var impersonatedCredential = CredentialFactory.FromJson<ImpersonatedCredential>(FakeImpersonatedCredentialFileContents);

// The scopes passed in through the credential json should be the scopes set on the impersonated credential
Assert.Equal(["SCOPE"], impersonatedCredential.Scopes);
}

[Fact]
public void CreateScoped_Impersonated_FromJsonScopesOverwritten()
{
var manuallySetScopes = new[] { "manuallySetScope" };

var credentialFromJson = CredentialFactory.FromJson<ImpersonatedCredential>(FakeImpersonatedCredentialFileContents).ToGoogleCredential();
var manuallyScopedCredential = credentialFromJson.CreateScoped(manuallySetScopes);
var originalImpersonatedCredential = Assert.IsType<ImpersonatedCredential>(credentialFromJson.UnderlyingCredential);
var newImpersonatedCredential = Assert.IsType<ImpersonatedCredential>(manuallyScopedCredential.UnderlyingCredential);

// If scopes are explicitly set in code, these should override the scopes passed through the credential json
Assert.Equal(manuallySetScopes, newImpersonatedCredential.Scopes);
// The original credential's scopes should remain unchanged
Assert.Equal(["SCOPE"], originalImpersonatedCredential.Scopes);
}

[Fact]
public void CreateWithQuotaProject_Impersonated()
{
Expand Down
3 changes: 2 additions & 1 deletion Src/Support/Google.Apis.Auth/OAuth2/CredentialFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -334,8 +334,9 @@ private static ImpersonatedCredential CreateImpersonatedServiceAccountCredential
var maybeTargetPrincipal = ImpersonatedCredential.ExtractTargetPrincipal(parameters.ServiceAccountImpersonationUrl);
var initializer = new ImpersonatedCredential.Initializer(parameters.ServiceAccountImpersonationUrl, maybeTargetPrincipal)
{
DelegateAccounts = parameters.Delegates?.Length > 0 ? parameters.Delegates.ToList() : null,
DelegateAccounts = parameters.Delegates?.Length > 0 ? parameters.Delegates : null,
QuotaProject = parameters.QuotaProject,
Scopes = parameters.Scopes?.Length > 0 ? parameters.Scopes : null,
};

var impersonatedCredential = ImpersonatedCredential.Create(sourceCredential.ToGoogleCredential(), initializer);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,12 @@ public class JsonCredentialParameters
[JsonProperty("delegates")]
public string[] Delegates { get; set; }

/// <summary>
/// Scopes associated with the impersonated credential.
/// </summary>
[JsonProperty("scopes")]
public string[] Scopes { get; set; }

/// <summary>
/// The source credential associated to the impersonated credential.
/// </summary>
Expand Down