| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| |
|
| | using System; |
| | using System.IO; |
| | using System.Threading; |
| | using System.Threading.Tasks; |
| |
|
| | using Google.Apis.Auth.OAuth2.Flows; |
| | using Google.Apis.Auth.OAuth2.Responses; |
| | using Google.Apis.Json; |
| | using Google.Apis.Util; |
| |
|
| | namespace Google.Apis.Auth.OAuth2; |
| |
|
| | |
| | |
| | |
| | public static class CredentialFactory |
| | { |
| | |
| | |
| | |
| | private const string JsonDeserializationErrorMessage = "Error deserializing JSON credential data."; |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | public static async Task<T> FromFileAsync<T>(string credentialPath, CancellationToken cancellationToken) |
| | { |
| | using FileStream fileStream = File.OpenRead(credentialPath); |
| | return await FromStreamAsync<T>(fileStream, cancellationToken).ConfigureAwait(false); |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | public static async Task<GoogleCredential> FromFileAsync(string credentialPath, string credentialType, CancellationToken cancellationToken) |
| | { |
| | using FileStream fileStream = File.OpenRead(credentialPath); |
| | return await FromStreamAsync(fileStream, credentialType, cancellationToken).ConfigureAwait(false); |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | public static T FromFile<T>(string credentialPath) |
| | { |
| | using FileStream fileStream = File.OpenRead(credentialPath); |
| | return FromStream<T>(fileStream); |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | public static GoogleCredential FromFile(string credentialPath, string credentialType) |
| | { |
| | using FileStream fileStream = File.OpenRead(credentialPath); |
| | return FromStream(fileStream, credentialType); |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | public static async Task<T> FromStreamAsync<T>(Stream stream, CancellationToken cancellationToken) |
| | { |
| | JsonCredentialParameters jsonCredentialParameters; |
| | try |
| | { |
| | jsonCredentialParameters = await NewtonsoftJsonSerializer.Instance.DeserializeAsync<JsonCredentialParameters>(stream, cancellationToken).ConfigureAwait(false); |
| | } |
| | catch (Exception e) |
| | { |
| | throw new InvalidOperationException(JsonDeserializationErrorMessage, e); |
| | } |
| | return FromJsonParameters<T>(jsonCredentialParameters); |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | private static async Task<GoogleCredential> FromStreamAsync(Stream stream, string credentialType, CancellationToken cancellationToken) |
| | { |
| | JsonCredentialParameters jsonCredentialParameters; |
| | try |
| | { |
| | jsonCredentialParameters = await NewtonsoftJsonSerializer.Instance.DeserializeAsync<JsonCredentialParameters>(stream, cancellationToken).ConfigureAwait(false); |
| | } |
| | catch (Exception e) |
| | { |
| | throw new InvalidOperationException(JsonDeserializationErrorMessage, e); |
| | } |
| | return FromJsonParameters(jsonCredentialParameters, credentialType); |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | public static T FromStream<T>(Stream stream) |
| | { |
| | JsonCredentialParameters jsonCredentialParameters; |
| | try |
| | { |
| | jsonCredentialParameters = NewtonsoftJsonSerializer.Instance.Deserialize<JsonCredentialParameters>(stream); |
| | } |
| | catch (Exception e) |
| | { |
| | throw new InvalidOperationException(JsonDeserializationErrorMessage, e); |
| | } |
| | return FromJsonParameters<T>(jsonCredentialParameters); |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | private static GoogleCredential FromStream(Stream stream, string credentialType) |
| | { |
| | JsonCredentialParameters jsonCredentialParameters; |
| | try |
| | { |
| | jsonCredentialParameters = NewtonsoftJsonSerializer.Instance.Deserialize<JsonCredentialParameters>(stream); |
| | } |
| | catch (Exception e) |
| | { |
| | throw new InvalidOperationException(JsonDeserializationErrorMessage, e); |
| | } |
| | return FromJsonParameters(jsonCredentialParameters, credentialType); |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | public static T FromJson<T>(string json) |
| | { |
| | JsonCredentialParameters jsonCredentialParameters; |
| | try |
| | { |
| | jsonCredentialParameters = NewtonsoftJsonSerializer.Instance.Deserialize<JsonCredentialParameters>(json); |
| | } |
| | catch (Exception e) |
| | { |
| | throw new InvalidOperationException(JsonDeserializationErrorMessage, e); |
| | } |
| | return FromJsonParameters<T>(jsonCredentialParameters); |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | public static GoogleCredential FromJson(string json, string credentialType) |
| | { |
| | JsonCredentialParameters jsonCredentialParameters; |
| | try |
| | { |
| | jsonCredentialParameters = NewtonsoftJsonSerializer.Instance.Deserialize<JsonCredentialParameters>(json); |
| | } |
| | catch (Exception e) |
| | { |
| | throw new InvalidOperationException(JsonDeserializationErrorMessage, e); |
| | } |
| | return FromJsonParameters(jsonCredentialParameters, credentialType); |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | public static T FromJsonParameters<T>(JsonCredentialParameters credentialParameters) |
| | { |
| | credentialParameters.ThrowIfNull(nameof(credentialParameters)); |
| | if (FromJsonParameters(credentialParameters, typeof(T)) is T credentialAsT) |
| | { |
| | return credentialAsT; |
| | } |
| |
|
| | throw new InvalidOperationException( |
| | $"Found incompatible credential types, '{credentialParameters.Type}' and '{typeof(T).FullName}, even though a check" |
| | + " should have already taken place. We should never reach here, there's a bug in the code."); |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | private static GoogleCredential FromJsonParameters(JsonCredentialParameters credentialParameters, string credentialType) |
| | { |
| | credentialParameters.ThrowIfNull(nameof(credentialParameters)); |
| | if (credentialParameters.Type != credentialType) |
| | { |
| | throw new InvalidOperationException($"The credential type {credentialParameters.Type} is not compatible with the requested type {credentialType}"); |
| | } |
| |
|
| | |
| | Type targetType = typeof(IGoogleCredential); |
| | var rawCredentialType = FromJsonParameters(credentialParameters, targetType); |
| |
|
| | return rawCredentialType.ToGoogleCredential(); |
| | } |
| |
|
| | private static IGoogleCredential FromJsonParameters(JsonCredentialParameters credentialParameters, Type targetCredentialType) => |
| | credentialParameters.ThrowIfNull(nameof(credentialParameters)).Type switch |
| | { |
| | JsonCredentialParameters.AuthorizedUserCredentialType => CreateUserCredentialFromParameters(credentialParameters, targetCredentialType), |
| | JsonCredentialParameters.ServiceAccountCredentialType => CreateServiceAccountCredentialFromParameters(credentialParameters, targetCredentialType), |
| | JsonCredentialParameters.ExternalAccountCredentialType => CreateExternalCredentialFromParameters(credentialParameters, targetCredentialType), |
| | JsonCredentialParameters.ImpersonatedServiceAccountCredentialType => CreateImpersonatedServiceAccountCredentialFromParameters(credentialParameters, targetCredentialType), |
| | JsonCredentialParameters.ExternalAccountAuthorizedUserCredentialType => CreateExternalAccountAuthorizedUserCredentialFromParameters(credentialParameters, targetCredentialType), |
| | _ => throw new InvalidOperationException($"Error creating credential from JSON or JSON parameters. Unrecognized credential type {credentialParameters.Type}.") |
| | }; |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | static void CheckCompatibility(Type targetType, Type actualType) |
| | { |
| | if(!targetType.IsAssignableFrom(actualType)) |
| | { |
| | throw new InvalidOperationException($"The credential type {actualType.FullName} is not compatible with the requested type {targetType.FullName}"); |
| | } |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | private static UserCredential CreateUserCredentialFromParameters(JsonCredentialParameters credentialParameters, Type targetType) |
| | { |
| | if (credentialParameters.Type != JsonCredentialParameters.AuthorizedUserCredentialType || |
| | string.IsNullOrEmpty(credentialParameters.ClientId) || |
| | string.IsNullOrEmpty(credentialParameters.ClientSecret)) |
| | { |
| | 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 universe domains other than {GoogleAuthConsts.DefaultUniverseDomain}"); |
| | } |
| | CheckCompatibility(targetType, typeof(UserCredential)); |
| | var token = new TokenResponse |
| | { |
| | RefreshToken = credentialParameters.RefreshToken |
| | }; |
| |
|
| | var initializer = new GoogleAuthorizationCodeFlow.Initializer |
| | { |
| | ClientSecrets = new ClientSecrets |
| | { |
| | ClientId = credentialParameters.ClientId, |
| | ClientSecret = credentialParameters.ClientSecret |
| | }, |
| | ProjectId = credentialParameters.ProjectId |
| | }; |
| |
|
| | var flow = new GoogleAuthorizationCodeFlow(initializer); |
| |
|
| | return new UserCredential(flow, "ApplicationDefaultCredentials", token, credentialParameters.QuotaProject); |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | private static ServiceAccountCredential CreateServiceAccountCredentialFromParameters( |
| | JsonCredentialParameters credentialParameters, Type targetType) |
| | { |
| | if (credentialParameters.Type != JsonCredentialParameters.ServiceAccountCredentialType || |
| | string.IsNullOrEmpty(credentialParameters.ClientEmail) || |
| | string.IsNullOrEmpty(credentialParameters.PrivateKey)) |
| | { |
| | throw new InvalidOperationException("JSON data does not represent a valid service account credential."); |
| | } |
| | CheckCompatibility(targetType, typeof(ServiceAccountCredential)); |
| | var initializer = new ServiceAccountCredential.Initializer( |
| | credentialParameters.ClientEmail, credentialParameters.TokenUri) |
| | { |
| | ProjectId = credentialParameters.ProjectId, |
| | QuotaProject = credentialParameters.QuotaProject, |
| | KeyId = credentialParameters.PrivateKeyId, |
| | UniverseDomain = credentialParameters.UniverseDomain, |
| | UseJwtAccessWithScopes = credentialParameters.UniverseDomain is not null && credentialParameters.UniverseDomain != GoogleAuthConsts.DefaultUniverseDomain |
| | }; |
| |
|
| | return new ServiceAccountCredential(initializer.FromPrivateKey(credentialParameters.PrivateKey)); |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | private static IGoogleCredential CreateExternalCredentialFromParameters(JsonCredentialParameters parameters, Type targetType) |
| | { |
| | if (parameters.Type != JsonCredentialParameters.ExternalAccountCredentialType || parameters.CredentialSourceConfig is null) |
| | { |
| | throw new InvalidOperationException("JSON data does not represent a valid external account credential."); |
| | } |
| |
|
| | |
| | |
| | if (!string.IsNullOrEmpty(parameters.CredentialSourceConfig.EnvironmentId)) |
| | { |
| | if (!parameters.CredentialSourceConfig.EnvironmentId.Equals(AwsExternalAccountCredential.SupportedVersion, StringComparison.OrdinalIgnoreCase)) |
| | { |
| | throw new InvalidOperationException( |
| | $"Only {AwsExternalAccountCredential.SupportedVersion} version of AWS external account credentials is supported by this library."); |
| | } |
| | CheckCompatibility(targetType, typeof(AwsExternalAccountCredential)); |
| |
|
| | return new AwsExternalAccountCredential(new AwsExternalAccountCredential.Initializer( |
| | parameters.TokenUrl, parameters.Audience, parameters.SubjectTokenType, |
| | parameters.CredentialSourceConfig.RegionalCredentialVerificationUrl) |
| | { |
| | QuotaProject = parameters.QuotaProject, |
| | ServiceAccountImpersonationUrl = parameters.ServiceAccountImpersonationUrl, |
| | WorkforcePoolUserProject = parameters.WorkforcePoolUserProject, |
| | ClientId = parameters.ClientId, |
| | ClientSecret = parameters.ClientSecret, |
| | RegionUrl = parameters.CredentialSourceConfig.RegionUrl, |
| | SecurityCredentialsUrl = parameters.CredentialSourceConfig.Url, |
| | ImdsV2SessionTokenUrl = parameters.CredentialSourceConfig.ImdsV2SessionTokenUrl, |
| | UniverseDomain = parameters.UniverseDomain, |
| | }); |
| | } |
| | else if (!string.IsNullOrEmpty(parameters.CredentialSourceConfig.File)) |
| | { |
| | CheckCompatibility(targetType, typeof(FileSourcedExternalAccountCredential)); |
| | return new FileSourcedExternalAccountCredential(new FileSourcedExternalAccountCredential.Initializer( |
| | parameters.TokenUrl, parameters.Audience, parameters.SubjectTokenType, parameters.CredentialSourceConfig.File) |
| | { |
| | QuotaProject = parameters.QuotaProject, |
| | ServiceAccountImpersonationUrl = parameters.ServiceAccountImpersonationUrl, |
| | WorkforcePoolUserProject = parameters.WorkforcePoolUserProject, |
| | ClientId = parameters.ClientId, |
| | ClientSecret = parameters.ClientSecret, |
| | SubjectTokenJsonFieldName = parameters.ExtractSubjectTokenFieldName(), |
| | UniverseDomain = parameters.UniverseDomain, |
| | }); |
| | } |
| | else if (!string.IsNullOrEmpty(parameters.CredentialSourceConfig.Url)) |
| | { |
| | CheckCompatibility(targetType, typeof(UrlSourcedExternalAccountCredential)); |
| | var initializer = new UrlSourcedExternalAccountCredential.Initializer( |
| | parameters.TokenUrl, parameters.Audience, parameters.SubjectTokenType, parameters.CredentialSourceConfig.Url) |
| | { |
| | QuotaProject = parameters.QuotaProject, |
| | ServiceAccountImpersonationUrl = parameters.ServiceAccountImpersonationUrl, |
| | WorkforcePoolUserProject = parameters.WorkforcePoolUserProject, |
| | ClientId = parameters.ClientId, |
| | ClientSecret = parameters.ClientSecret, |
| | SubjectTokenJsonFieldName = parameters.ExtractSubjectTokenFieldName(), |
| | UniverseDomain = parameters.UniverseDomain, |
| | }; |
| | if (parameters.CredentialSourceConfig.Headers is object) |
| | { |
| | foreach (var header in parameters.CredentialSourceConfig.Headers) |
| | { |
| | initializer.Headers.Add(header); |
| | } |
| | } |
| |
|
| | return new UrlSourcedExternalAccountCredential(initializer); |
| | } |
| | else |
| | { |
| | throw new InvalidOperationException("Unrecognized external credential configuration"); |
| | } |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | private static ImpersonatedCredential CreateImpersonatedServiceAccountCredentialFromParameters(JsonCredentialParameters parameters, Type targetType) |
| | { |
| | if (parameters.Type != JsonCredentialParameters.ImpersonatedServiceAccountCredentialType |
| | || parameters.SourceCredential is null |
| | || string.IsNullOrEmpty(parameters.ServiceAccountImpersonationUrl)) |
| | { |
| | throw new InvalidOperationException("JSON data does not represent a valid impersonated service account credential."); |
| | } |
| | CheckCompatibility(targetType, typeof(ImpersonatedCredential)); |
| |
|
| | |
| | |
| | var sourceCredential = FromJsonParameters<IGoogleCredential>(parameters.SourceCredential); |
| | var maybeTargetPrincipal = ImpersonatedCredential.ExtractTargetPrincipal(parameters.ServiceAccountImpersonationUrl); |
| | var initializer = new ImpersonatedCredential.Initializer(parameters.ServiceAccountImpersonationUrl, maybeTargetPrincipal) |
| | { |
| | 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); |
| | if (parameters.UniverseDomain != parameters.SourceCredential.UniverseDomain) |
| | { |
| | return (impersonatedCredential as IGoogleCredential).WithUniverseDomain(parameters.UniverseDomain) as ImpersonatedCredential; |
| | } |
| |
|
| | return impersonatedCredential; |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | private static ExternalAccountAuthorizedUserCredential CreateExternalAccountAuthorizedUserCredentialFromParameters(JsonCredentialParameters parameters, Type targetType) |
| | { |
| | if (parameters.Type != JsonCredentialParameters.ExternalAccountAuthorizedUserCredentialType |
| | || string.IsNullOrEmpty(parameters.TokenUrl) |
| | || string.IsNullOrEmpty(parameters.RefreshToken) |
| | || string.IsNullOrEmpty(parameters.ClientId) |
| | || string.IsNullOrEmpty(parameters.ClientSecret)) |
| | { |
| | throw new InvalidOperationException("JSON data does not represent a valid external account authorized user credential."); |
| | } |
| | CheckCompatibility(targetType, typeof(ExternalAccountAuthorizedUserCredential)); |
| |
|
| | var initializer = new ExternalAccountAuthorizedUserCredential.Initializer( |
| | parameters.TokenUrl, parameters.RefreshToken, parameters.ClientId, parameters.ClientSecret) |
| | { |
| | Audience = parameters.Audience, |
| | QuotaProject = parameters.QuotaProject, |
| | TokenInfoUrl = parameters.TokenInfoUrl, |
| | UniverseDomain = parameters.UniverseDomain, |
| | }; |
| |
|
| | return new ExternalAccountAuthorizedUserCredential(initializer); |
| | } |
| | } |
| |
|