| // Copyright 2017 Google LLC. |
| // Use of this source code is governed by a BSD-style |
| // license that can be found in the LICENSE file. |
| |
| // Package option contains options for Google API clients. |
| package option |
| |
| import ( |
| "crypto/tls" |
| "log/slog" |
| "net/http" |
| |
| "cloud.google.com/go/auth" |
| "golang.org/x/oauth2" |
| "golang.org/x/oauth2/google" |
| "google.golang.org/api/internal" |
| "google.golang.org/api/internal/credentialstype" |
| "google.golang.org/api/internal/impersonate" |
| "google.golang.org/grpc" |
| ) |
| |
| // CredentialsType specifies the type of JSON credentials being provided |
| // to a loading function such as [WithAuthCredentialsFile] or |
| // [WithAuthCredentialsJSON]. |
| type CredentialsType = credentialstype.CredType |
| |
| const ( |
| // ServiceAccount represents a service account file type. |
| ServiceAccount = credentialstype.ServiceAccount |
| // AuthorizedUser represents an authorized user credentials file type. |
| AuthorizedUser = credentialstype.AuthorizedUser |
| // ImpersonatedServiceAccount represents an impersonated service account file type. |
| // |
| // IMPORTANT: |
| // This credential type does not validate the credential configuration. A security |
| // risk occurs when a credential configuration configured with malicious urls |
| // is used. |
| // You should validate credential configurations provided by untrusted sources. |
| // See [Security requirements when using credential configurations from an external |
| // source] https://cloud.google.com/docs/authentication/external/externally-sourced-credentials |
| // for more details. |
| ImpersonatedServiceAccount = credentialstype.ImpersonatedServiceAccount |
| // ExternalAccount represents an external account file type. |
| // |
| // IMPORTANT: |
| // This credential type does not validate the credential configuration. A security |
| // risk occurs when a credential configuration configured with malicious urls |
| // is used. |
| // You should validate credential configurations provided by untrusted sources. |
| // See [Security requirements when using credential configurations from an external |
| // source] https://cloud.google.com/docs/authentication/external/externally-sourced-credentials |
| // for more details. |
| ExternalAccount = credentialstype.ExternalAccount |
| ) |
| |
| // A ClientOption is an option for a Google API client. |
| type ClientOption interface { |
| Apply(*internal.DialSettings) |
| } |
| |
| // WithTokenSource returns a ClientOption that specifies an OAuth2 token |
| // source to be used as the basis for authentication. |
| func WithTokenSource(s oauth2.TokenSource) ClientOption { |
| return withTokenSource{s} |
| } |
| |
| type withTokenSource struct{ ts oauth2.TokenSource } |
| |
| func (w withTokenSource) Apply(o *internal.DialSettings) { |
| o.TokenSource = w.ts |
| } |
| |
| type withCredFile string |
| |
| func (w withCredFile) Apply(o *internal.DialSettings) { |
| o.CredentialsFile = string(w) |
| } |
| |
| // WithCredentialsFile returns a ClientOption that authenticates |
| // API calls with the given service account or refresh token JSON |
| // credentials file. |
| // |
| // Deprecated: This function is being deprecated because of a potential security risk. |
| // |
| // This function does not validate the credential configuration. The security |
| // risk occurs when a credential configuration is accepted from a source that |
| // is not under your control and used without validation on your side. |
| // |
| // If you know that you will be loading credential configurations of a |
| // specific type, it is recommended to use a credential-type-specific |
| // option function. |
| // This will ensure that an unexpected credential type with potential for |
| // malicious intent is not loaded unintentionally. You might still have to do |
| // validation for certain credential types. Please follow the recommendation |
| // for that function. For example, if you want to load only service accounts, |
| // you can use [WithAuthCredentialsFile] with [ServiceAccount]: |
| // |
| // option.WithAuthCredentialsFile(option.ServiceAccount, "/path/to/file.json") |
| // |
| // If you are loading your credential configuration from an untrusted source and have |
| // not mitigated the risks (e.g. by validating the configuration yourself), make |
| // these changes as soon as possible to prevent security risks to your environment. |
| // |
| // Regardless of the function used, it is always your responsibility to validate |
| // configurations received from external sources. |
| func WithCredentialsFile(filename string) ClientOption { |
| return withCredFile(filename) |
| } |
| |
| // WithAuthCredentialsFile returns a ClientOption that authenticates API calls |
| // with the given JSON credentials file and credential type. |
| // |
| // Important: If you accept a credential configuration (credential |
| // JSON/File/Stream) from an external source for authentication to Google |
| // Cloud Platform, you must validate it before providing it to any Google |
| // API or library. Providing an unvalidated credential configuration to |
| // Google APIs can compromise the security of your systems and data. For |
| // more information, refer to [Validate credential configurations from |
| // external sources](https://cloud.google.com/docs/authentication/external/externally-sourced-credentials). |
| func WithAuthCredentialsFile(credType CredentialsType, filename string) ClientOption { |
| return withAuthCredentialsFile{ |
| credsType: credType, |
| filename: filename, |
| } |
| } |
| |
| type withAuthCredentialsFile struct { |
| credsType CredentialsType |
| filename string |
| } |
| |
| func (w withAuthCredentialsFile) Apply(o *internal.DialSettings) { |
| o.AuthCredentialsFile = w.filename |
| o.AuthCredentialsType = w.credsType |
| } |
| |
| // WithServiceAccountFile returns a ClientOption that uses a Google service |
| // account credentials file to authenticate. |
| // |
| // Important: If you accept a credential configuration (credential |
| // JSON/File/Stream) from an external source for authentication to Google |
| // Cloud Platform, you must validate it before providing it to any Google |
| // API or library. Providing an unvalidated credential configuration to |
| // Google APIs can compromise the security of your systems and data. For |
| // more information, refer to [Validate credential configurations from |
| // external sources](https://cloud.google.com/docs/authentication/external/externally-sourced-credentials). |
| // |
| // Deprecated: Use WithAuthCredentialsFile instead. |
| func WithServiceAccountFile(filename string) ClientOption { |
| return WithAuthCredentialsFile(ServiceAccount, filename) |
| } |
| |
| // WithCredentialsJSON returns a ClientOption that authenticates |
| // API calls with the given service account or refresh token JSON |
| // credentials. |
| // |
| // Deprecated: This function is being deprecated because of a potential security risk. |
| // |
| // This function does not validate the credential configuration. The security |
| // risk occurs when a credential configuration is accepted from a source that |
| // is not under your control and used without validation on your side. |
| // |
| // If you know that you will be loading credential configurations of a |
| // specific type, it is recommended to use a credential-type-specific |
| // option function. |
| // This will ensure that an unexpected credential type with potential for |
| // malicious intent is not loaded unintentionally. You might still have to do |
| // validation for certain credential types. Please follow the recommendation |
| // for that function. For example, if you want to load only service accounts, |
| // you can use [WithAuthCredentialsJSON] with [ServiceAccount]: |
| // |
| // option.WithAuthCredentialsJSON(option.ServiceAccount, json) |
| // |
| // If you are loading your credential configuration from an untrusted source and have |
| // not mitigated the risks (e.g. by validating the configuration yourself), make |
| // these changes as soon as possible to prevent security risks to your environment. |
| // |
| // Regardless of the function used, it is always your responsibility to validate |
| // configurations received from external sources. |
| func WithCredentialsJSON(p []byte) ClientOption { |
| return withCredentialsJSON(p) |
| } |
| |
| type withCredentialsJSON []byte |
| |
| func (w withCredentialsJSON) Apply(o *internal.DialSettings) { |
| o.CredentialsJSON = make([]byte, len(w)) |
| copy(o.CredentialsJSON, w) |
| } |
| |
| // WithAuthCredentialsJSON returns a ClientOption that authenticates API calls |
| // with the given JSON credentials and credential type. |
| // |
| // Important: If you accept a credential configuration (credential |
| // JSON/File/Stream) from an external source for authentication to Google |
| // Cloud Platform, you must validate it before providing it to any Google |
| // API or library. Providing an unvalidated credential configuration to |
| // Google APIs can compromise the security of your systems and data. For |
| // more information, refer to [Validate credential configurations from |
| // external sources](https://cloud.google.com/docs/authentication/external/externally-sourced-credentials). |
| func WithAuthCredentialsJSON(credType CredentialsType, json []byte) ClientOption { |
| return withAuthCredentialsJSON{ |
| credsType: credType, |
| json: json, |
| } |
| } |
| |
| type withAuthCredentialsJSON struct { |
| credsType CredentialsType |
| json []byte |
| } |
| |
| func (w withAuthCredentialsJSON) Apply(o *internal.DialSettings) { |
| o.AuthCredentialsJSON = w.json |
| o.AuthCredentialsType = w.credsType |
| } |
| |
| // WithEndpoint returns a ClientOption that overrides the default endpoint |
| // to be used for a service. Please note that by default Google APIs only |
| // accept HTTPS traffic. |
| // |
| // For a gRPC client, the port number is typically included in the endpoint. |
| // Example: "us-central1-speech.googleapis.com:443". |
| // |
| // For a REST client, the port number is typically not included. Example: |
| // "https://speech.googleapis.com". |
| func WithEndpoint(url string) ClientOption { |
| return withEndpoint(url) |
| } |
| |
| type withEndpoint string |
| |
| func (w withEndpoint) Apply(o *internal.DialSettings) { |
| o.Endpoint = string(w) |
| } |
| |
| // WithScopes returns a ClientOption that overrides the default OAuth2 scopes |
| // to be used for a service. |
| // |
| // If both WithScopes and WithTokenSource are used, scope settings from the |
| // token source will be used instead. |
| func WithScopes(scope ...string) ClientOption { |
| return withScopes(scope) |
| } |
| |
| type withScopes []string |
| |
| func (w withScopes) Apply(o *internal.DialSettings) { |
| o.Scopes = make([]string, len(w)) |
| copy(o.Scopes, w) |
| } |
| |
| // WithUserAgent returns a ClientOption that sets the User-Agent. This option |
| // is incompatible with the [WithHTTPClient] option. If you wish to provide a |
| // custom client you will need to add this header via RoundTripper middleware. |
| func WithUserAgent(ua string) ClientOption { |
| return withUA(ua) |
| } |
| |
| type withUA string |
| |
| func (w withUA) Apply(o *internal.DialSettings) { o.UserAgent = string(w) } |
| |
| // WithHTTPClient returns a ClientOption that specifies the HTTP client to use |
| // as the basis of communications. This option may only be used with services |
| // that support HTTP as their communication transport. When used, the |
| // WithHTTPClient option takes precedent over all other supplied options. |
| func WithHTTPClient(client *http.Client) ClientOption { |
| return withHTTPClient{client} |
| } |
| |
| type withHTTPClient struct{ client *http.Client } |
| |
| func (w withHTTPClient) Apply(o *internal.DialSettings) { |
| o.HTTPClient = w.client |
| } |
| |
| // WithGRPCConn returns a ClientOption that specifies the gRPC client |
| // connection to use as the basis of communications. This option may only be |
| // used with services that support gRPC as their communication transport. When |
| // used, the WithGRPCConn option takes precedent over all other supplied |
| // options. |
| func WithGRPCConn(conn *grpc.ClientConn) ClientOption { |
| return withGRPCConn{conn} |
| } |
| |
| type withGRPCConn struct{ conn *grpc.ClientConn } |
| |
| func (w withGRPCConn) Apply(o *internal.DialSettings) { |
| o.GRPCConn = w.conn |
| } |
| |
| // WithGRPCDialOption returns a ClientOption that appends a new grpc.DialOption |
| // to an underlying gRPC dial. It does not work with WithGRPCConn. |
| func WithGRPCDialOption(opt grpc.DialOption) ClientOption { |
| return withGRPCDialOption{opt} |
| } |
| |
| type withGRPCDialOption struct{ opt grpc.DialOption } |
| |
| func (w withGRPCDialOption) Apply(o *internal.DialSettings) { |
| o.GRPCDialOpts = append(o.GRPCDialOpts, w.opt) |
| } |
| |
| // WithGRPCConnectionPool returns a ClientOption that creates a pool of gRPC |
| // connections that requests will be balanced between. |
| func WithGRPCConnectionPool(size int) ClientOption { |
| return withGRPCConnectionPool(size) |
| } |
| |
| type withGRPCConnectionPool int |
| |
| func (w withGRPCConnectionPool) Apply(o *internal.DialSettings) { |
| o.GRPCConnPoolSize = int(w) |
| } |
| |
| // WithAPIKey returns a ClientOption that specifies an API key to be used |
| // as the basis for authentication. |
| // |
| // API Keys can only be used for JSON-over-HTTP APIs, including those under |
| // the import path google.golang.org/api/.... |
| func WithAPIKey(apiKey string) ClientOption { |
| return withAPIKey(apiKey) |
| } |
| |
| type withAPIKey string |
| |
| func (w withAPIKey) Apply(o *internal.DialSettings) { o.APIKey = string(w) } |
| |
| // WithAudiences returns a ClientOption that specifies an audience to be used |
| // as the audience field ("aud") for the JWT token authentication. |
| func WithAudiences(audience ...string) ClientOption { |
| return withAudiences(audience) |
| } |
| |
| type withAudiences []string |
| |
| func (w withAudiences) Apply(o *internal.DialSettings) { |
| o.Audiences = make([]string, len(w)) |
| copy(o.Audiences, w) |
| } |
| |
| // WithoutAuthentication returns a ClientOption that specifies that no |
| // authentication should be used. It is suitable only for testing and for |
| // accessing public resources, like public Google Cloud Storage buckets. |
| // It is an error to provide both WithoutAuthentication and any of WithAPIKey, |
| // WithTokenSource, WithCredentialsFile or WithServiceAccountFile. |
| func WithoutAuthentication() ClientOption { |
| return withoutAuthentication{} |
| } |
| |
| type withoutAuthentication struct{} |
| |
| func (w withoutAuthentication) Apply(o *internal.DialSettings) { o.NoAuth = true } |
| |
| // WithQuotaProject returns a ClientOption that specifies the project used |
| // for quota and billing purposes. |
| // |
| // For more information please read: |
| // https://cloud.google.com/apis/docs/system-parameters |
| func WithQuotaProject(quotaProject string) ClientOption { |
| return withQuotaProject(quotaProject) |
| } |
| |
| type withQuotaProject string |
| |
| func (w withQuotaProject) Apply(o *internal.DialSettings) { |
| o.QuotaProject = string(w) |
| } |
| |
| // WithRequestReason returns a ClientOption that specifies a reason for |
| // making the request, which is intended to be recorded in audit logging. |
| // An example reason would be a support-case ticket number. |
| // |
| // For more information please read: |
| // https://cloud.google.com/apis/docs/system-parameters |
| func WithRequestReason(requestReason string) ClientOption { |
| return withRequestReason(requestReason) |
| } |
| |
| type withRequestReason string |
| |
| func (w withRequestReason) Apply(o *internal.DialSettings) { |
| o.RequestReason = string(w) |
| } |
| |
| // WithTelemetryDisabled returns a ClientOption that disables default telemetry (OpenCensus) |
| // settings on gRPC and HTTP clients. |
| // An example reason would be to bind custom telemetry that overrides the defaults. |
| func WithTelemetryDisabled() ClientOption { |
| return withTelemetryDisabled{} |
| } |
| |
| type withTelemetryDisabled struct{} |
| |
| func (w withTelemetryDisabled) Apply(o *internal.DialSettings) { |
| o.TelemetryDisabled = true |
| } |
| |
| // ClientCertSource is a function that returns a TLS client certificate to be used |
| // when opening TLS connections. |
| // |
| // It follows the same semantics as crypto/tls.Config.GetClientCertificate. |
| // |
| // This is an EXPERIMENTAL API and may be changed or removed in the future. |
| type ClientCertSource = func(*tls.CertificateRequestInfo) (*tls.Certificate, error) |
| |
| // WithClientCertSource returns a ClientOption that specifies a |
| // callback function for obtaining a TLS client certificate. |
| // |
| // This option is used for supporting mTLS authentication, where the |
| // server validates the client certifcate when establishing a connection. |
| // |
| // The callback function will be invoked whenever the server requests a |
| // certificate from the client. Implementations of the callback function |
| // should try to ensure that a valid certificate can be repeatedly returned |
| // on demand for the entire life cycle of the transport client. If a nil |
| // Certificate is returned (i.e. no Certificate can be obtained), an error |
| // should be returned. |
| // |
| // This is an EXPERIMENTAL API and may be changed or removed in the future. |
| func WithClientCertSource(s ClientCertSource) ClientOption { |
| return withClientCertSource{s} |
| } |
| |
| type withClientCertSource struct{ s ClientCertSource } |
| |
| func (w withClientCertSource) Apply(o *internal.DialSettings) { |
| o.ClientCertSource = w.s |
| } |
| |
| // ImpersonateCredentials returns a ClientOption that will impersonate the |
| // target service account. |
| // |
| // In order to impersonate the target service account |
| // the base service account must have the Service Account Token Creator role, |
| // roles/iam.serviceAccountTokenCreator, on the target service account. |
| // See https://cloud.google.com/iam/docs/understanding-service-accounts. |
| // |
| // Optionally, delegates can be used during impersonation if the base service |
| // account lacks the token creator role on the target. When using delegates, |
| // each service account must be granted roles/iam.serviceAccountTokenCreator |
| // on the next service account in the chain. |
| // |
| // For example, if a base service account of SA1 is trying to impersonate target |
| // service account SA2 while using delegate service accounts DSA1 and DSA2, |
| // the following must be true: |
| // |
| // 1. Base service account SA1 has roles/iam.serviceAccountTokenCreator on |
| // DSA1. |
| // 2. DSA1 has roles/iam.serviceAccountTokenCreator on DSA2. |
| // 3. DSA2 has roles/iam.serviceAccountTokenCreator on target SA2. |
| // |
| // The resulting impersonated credential will either have the default scopes of |
| // the client being instantiating or the scopes from WithScopes if provided. |
| // Scopes are required for creating impersonated credentials, so if this option |
| // is used while not using a NewClient/NewService function, WithScopes must also |
| // be explicitly passed in as well. |
| // |
| // If the base credential is an authorized user and not a service account, or if |
| // the option WithQuotaProject is set, the target service account must have a |
| // role that grants the serviceusage.services.use permission such as |
| // roles/serviceusage.serviceUsageConsumer. |
| // |
| // This is an EXPERIMENTAL API and may be changed or removed in the future. |
| // |
| // Deprecated: This option has been replaced by `impersonate` package: |
| // `google.golang.org/api/impersonate`. Please use the `impersonate` package |
| // instead with the WithTokenSource option. |
| func ImpersonateCredentials(target string, delegates ...string) ClientOption { |
| return impersonateServiceAccount{ |
| target: target, |
| delegates: delegates, |
| } |
| } |
| |
| type impersonateServiceAccount struct { |
| target string |
| delegates []string |
| } |
| |
| func (i impersonateServiceAccount) Apply(o *internal.DialSettings) { |
| o.ImpersonationConfig = &impersonate.Config{ |
| Target: i.target, |
| } |
| o.ImpersonationConfig.Delegates = make([]string, len(i.delegates)) |
| copy(o.ImpersonationConfig.Delegates, i.delegates) |
| } |
| |
| type withCreds google.Credentials |
| |
| func (w *withCreds) Apply(o *internal.DialSettings) { |
| o.Credentials = (*google.Credentials)(w) |
| } |
| |
| // WithCredentials returns a ClientOption that authenticates API calls. |
| func WithCredentials(creds *google.Credentials) ClientOption { |
| return (*withCreds)(creds) |
| } |
| |
| // WithAuthCredentials returns a ClientOption that specifies an |
| // [cloud.google.com/go/auth.Credentials] to be used as the basis for |
| // authentication. |
| func WithAuthCredentials(creds *auth.Credentials) ClientOption { |
| return withAuthCredentials{creds} |
| } |
| |
| type withAuthCredentials struct{ creds *auth.Credentials } |
| |
| func (w withAuthCredentials) Apply(o *internal.DialSettings) { |
| o.AuthCredentials = w.creds |
| } |
| |
| // WithUniverseDomain returns a ClientOption that sets the universe domain. |
| func WithUniverseDomain(ud string) ClientOption { |
| return withUniverseDomain(ud) |
| } |
| |
| type withUniverseDomain string |
| |
| func (w withUniverseDomain) Apply(o *internal.DialSettings) { |
| o.UniverseDomain = string(w) |
| } |
| |
| // WithLogger returns a ClientOption that sets the logger used throughout the |
| // client library call stack. If this option is provided it takes precedence |
| // over the value set in GOOGLE_SDK_GO_LOGGING_LEVEL. Specifying this option |
| // enables logging at the provided logger's configured level. |
| func WithLogger(l *slog.Logger) ClientOption { |
| return withLogger{l} |
| } |
| |
| type withLogger struct{ l *slog.Logger } |
| |
| func (w withLogger) Apply(o *internal.DialSettings) { |
| o.Logger = w.l |
| } |