1 // Copyright 2017 Google LLC. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 // Package option contains options for Google API clients. 6 package option 7 8 import ( 9 "crypto/tls" 10 "net/http" 11 12 "cloud.google.com/go/auth" 13 "golang.org/x/oauth2" 14 "golang.org/x/oauth2/google" 15 "google.golang.org/api/internal" 16 "google.golang.org/api/internal/impersonate" 17 "google.golang.org/grpc" 18 ) 19 20 // A ClientOption is an option for a Google API client. 21 type ClientOption interface { 22 Apply(*internal.DialSettings) 23 } 24 25 // WithTokenSource returns a ClientOption that specifies an OAuth2 token 26 // source to be used as the basis for authentication. 27 func WithTokenSource(s oauth2.TokenSource) ClientOption { 28 return withTokenSource{s} 29 } 30 31 type withTokenSource struct{ ts oauth2.TokenSource } 32 33 func (w withTokenSource) Apply(o *internal.DialSettings) { 34 o.TokenSource = w.ts 35 } 36 37 type withCredFile string 38 39 func (w withCredFile) Apply(o *internal.DialSettings) { 40 o.CredentialsFile = string(w) 41 } 42 43 // WithCredentialsFile returns a ClientOption that authenticates 44 // API calls with the given service account or refresh token JSON 45 // credentials file. 46 func WithCredentialsFile(filename string) ClientOption { 47 return withCredFile(filename) 48 } 49 50 // WithServiceAccountFile returns a ClientOption that uses a Google service 51 // account credentials file to authenticate. 52 // 53 // Deprecated: Use WithCredentialsFile instead. 54 func WithServiceAccountFile(filename string) ClientOption { 55 return WithCredentialsFile(filename) 56 } 57 58 // WithCredentialsJSON returns a ClientOption that authenticates 59 // API calls with the given service account or refresh token JSON 60 // credentials. 61 func WithCredentialsJSON(p []byte) ClientOption { 62 return withCredentialsJSON(p) 63 } 64 65 type withCredentialsJSON []byte 66 67 func (w withCredentialsJSON) Apply(o *internal.DialSettings) { 68 o.CredentialsJSON = make([]byte, len(w)) 69 copy(o.CredentialsJSON, w) 70 } 71 72 // WithEndpoint returns a ClientOption that overrides the default endpoint 73 // to be used for a service. 74 func WithEndpoint(url string) ClientOption { 75 return withEndpoint(url) 76 } 77 78 type withEndpoint string 79 80 func (w withEndpoint) Apply(o *internal.DialSettings) { 81 o.Endpoint = string(w) 82 } 83 84 // WithScopes returns a ClientOption that overrides the default OAuth2 scopes 85 // to be used for a service. 86 // 87 // If both WithScopes and WithTokenSource are used, scope settings from the 88 // token source will be used instead. 89 func WithScopes(scope ...string) ClientOption { 90 return withScopes(scope) 91 } 92 93 type withScopes []string 94 95 func (w withScopes) Apply(o *internal.DialSettings) { 96 o.Scopes = make([]string, len(w)) 97 copy(o.Scopes, w) 98 } 99 100 // WithUserAgent returns a ClientOption that sets the User-Agent. This option 101 // is incompatible with the [WithHTTPClient] option. If you wish to provide a 102 // custom client you will need to add this header via RoundTripper middleware. 103 func WithUserAgent(ua string) ClientOption { 104 return withUA(ua) 105 } 106 107 type withUA string 108 109 func (w withUA) Apply(o *internal.DialSettings) { o.UserAgent = string(w) } 110 111 // WithHTTPClient returns a ClientOption that specifies the HTTP client to use 112 // as the basis of communications. This option may only be used with services 113 // that support HTTP as their communication transport. When used, the 114 // WithHTTPClient option takes precedent over all other supplied options. 115 func WithHTTPClient(client *http.Client) ClientOption { 116 return withHTTPClient{client} 117 } 118 119 type withHTTPClient struct{ client *http.Client } 120 121 func (w withHTTPClient) Apply(o *internal.DialSettings) { 122 o.HTTPClient = w.client 123 } 124 125 // WithGRPCConn returns a ClientOption that specifies the gRPC client 126 // connection to use as the basis of communications. This option may only be 127 // used with services that support gRPC as their communication transport. When 128 // used, the WithGRPCConn option takes precedent over all other supplied 129 // options. 130 func WithGRPCConn(conn *grpc.ClientConn) ClientOption { 131 return withGRPCConn{conn} 132 } 133 134 type withGRPCConn struct{ conn *grpc.ClientConn } 135 136 func (w withGRPCConn) Apply(o *internal.DialSettings) { 137 o.GRPCConn = w.conn 138 } 139 140 // WithGRPCDialOption returns a ClientOption that appends a new grpc.DialOption 141 // to an underlying gRPC dial. It does not work with WithGRPCConn. 142 func WithGRPCDialOption(opt grpc.DialOption) ClientOption { 143 return withGRPCDialOption{opt} 144 } 145 146 type withGRPCDialOption struct{ opt grpc.DialOption } 147 148 func (w withGRPCDialOption) Apply(o *internal.DialSettings) { 149 o.GRPCDialOpts = append(o.GRPCDialOpts, w.opt) 150 } 151 152 // WithGRPCConnectionPool returns a ClientOption that creates a pool of gRPC 153 // connections that requests will be balanced between. 154 func WithGRPCConnectionPool(size int) ClientOption { 155 return withGRPCConnectionPool(size) 156 } 157 158 type withGRPCConnectionPool int 159 160 func (w withGRPCConnectionPool) Apply(o *internal.DialSettings) { 161 o.GRPCConnPoolSize = int(w) 162 } 163 164 // WithAPIKey returns a ClientOption that specifies an API key to be used 165 // as the basis for authentication. 166 // 167 // API Keys can only be used for JSON-over-HTTP APIs, including those under 168 // the import path google.golang.org/api/.... 169 func WithAPIKey(apiKey string) ClientOption { 170 return withAPIKey(apiKey) 171 } 172 173 type withAPIKey string 174 175 func (w withAPIKey) Apply(o *internal.DialSettings) { o.APIKey = string(w) } 176 177 // WithAudiences returns a ClientOption that specifies an audience to be used 178 // as the audience field ("aud") for the JWT token authentication. 179 func WithAudiences(audience ...string) ClientOption { 180 return withAudiences(audience) 181 } 182 183 type withAudiences []string 184 185 func (w withAudiences) Apply(o *internal.DialSettings) { 186 o.Audiences = make([]string, len(w)) 187 copy(o.Audiences, w) 188 } 189 190 // WithoutAuthentication returns a ClientOption that specifies that no 191 // authentication should be used. It is suitable only for testing and for 192 // accessing public resources, like public Google Cloud Storage buckets. 193 // It is an error to provide both WithoutAuthentication and any of WithAPIKey, 194 // WithTokenSource, WithCredentialsFile or WithServiceAccountFile. 195 func WithoutAuthentication() ClientOption { 196 return withoutAuthentication{} 197 } 198 199 type withoutAuthentication struct{} 200 201 func (w withoutAuthentication) Apply(o *internal.DialSettings) { o.NoAuth = true } 202 203 // WithQuotaProject returns a ClientOption that specifies the project used 204 // for quota and billing purposes. 205 // 206 // For more information please read: 207 // https://cloud.google.com/apis/docs/system-parameters 208 func WithQuotaProject(quotaProject string) ClientOption { 209 return withQuotaProject(quotaProject) 210 } 211 212 type withQuotaProject string 213 214 func (w withQuotaProject) Apply(o *internal.DialSettings) { 215 o.QuotaProject = string(w) 216 } 217 218 // WithRequestReason returns a ClientOption that specifies a reason for 219 // making the request, which is intended to be recorded in audit logging. 220 // An example reason would be a support-case ticket number. 221 // 222 // For more information please read: 223 // https://cloud.google.com/apis/docs/system-parameters 224 func WithRequestReason(requestReason string) ClientOption { 225 return withRequestReason(requestReason) 226 } 227 228 type withRequestReason string 229 230 func (w withRequestReason) Apply(o *internal.DialSettings) { 231 o.RequestReason = string(w) 232 } 233 234 // WithTelemetryDisabled returns a ClientOption that disables default telemetry (OpenCensus) 235 // settings on gRPC and HTTP clients. 236 // An example reason would be to bind custom telemetry that overrides the defaults. 237 func WithTelemetryDisabled() ClientOption { 238 return withTelemetryDisabled{} 239 } 240 241 type withTelemetryDisabled struct{} 242 243 func (w withTelemetryDisabled) Apply(o *internal.DialSettings) { 244 o.TelemetryDisabled = true 245 } 246 247 // ClientCertSource is a function that returns a TLS client certificate to be used 248 // when opening TLS connections. 249 // 250 // It follows the same semantics as crypto/tls.Config.GetClientCertificate. 251 // 252 // This is an EXPERIMENTAL API and may be changed or removed in the future. 253 type ClientCertSource = func(*tls.CertificateRequestInfo) (*tls.Certificate, error) 254 255 // WithClientCertSource returns a ClientOption that specifies a 256 // callback function for obtaining a TLS client certificate. 257 // 258 // This option is used for supporting mTLS authentication, where the 259 // server validates the client certifcate when establishing a connection. 260 // 261 // The callback function will be invoked whenever the server requests a 262 // certificate from the client. Implementations of the callback function 263 // should try to ensure that a valid certificate can be repeatedly returned 264 // on demand for the entire life cycle of the transport client. If a nil 265 // Certificate is returned (i.e. no Certificate can be obtained), an error 266 // should be returned. 267 // 268 // This is an EXPERIMENTAL API and may be changed or removed in the future. 269 func WithClientCertSource(s ClientCertSource) ClientOption { 270 return withClientCertSource{s} 271 } 272 273 type withClientCertSource struct{ s ClientCertSource } 274 275 func (w withClientCertSource) Apply(o *internal.DialSettings) { 276 o.ClientCertSource = w.s 277 } 278 279 // ImpersonateCredentials returns a ClientOption that will impersonate the 280 // target service account. 281 // 282 // In order to impersonate the target service account 283 // the base service account must have the Service Account Token Creator role, 284 // roles/iam.serviceAccountTokenCreator, on the target service account. 285 // See https://cloud.google.com/iam/docs/understanding-service-accounts. 286 // 287 // Optionally, delegates can be used during impersonation if the base service 288 // account lacks the token creator role on the target. When using delegates, 289 // each service account must be granted roles/iam.serviceAccountTokenCreator 290 // on the next service account in the chain. 291 // 292 // For example, if a base service account of SA1 is trying to impersonate target 293 // service account SA2 while using delegate service accounts DSA1 and DSA2, 294 // the following must be true: 295 // 296 // 1. Base service account SA1 has roles/iam.serviceAccountTokenCreator on 297 // DSA1. 298 // 2. DSA1 has roles/iam.serviceAccountTokenCreator on DSA2. 299 // 3. DSA2 has roles/iam.serviceAccountTokenCreator on target SA2. 300 // 301 // The resulting impersonated credential will either have the default scopes of 302 // the client being instantiating or the scopes from WithScopes if provided. 303 // Scopes are required for creating impersonated credentials, so if this option 304 // is used while not using a NewClient/NewService function, WithScopes must also 305 // be explicitly passed in as well. 306 // 307 // If the base credential is an authorized user and not a service account, or if 308 // the option WithQuotaProject is set, the target service account must have a 309 // role that grants the serviceusage.services.use permission such as 310 // roles/serviceusage.serviceUsageConsumer. 311 // 312 // This is an EXPERIMENTAL API and may be changed or removed in the future. 313 // 314 // Deprecated: This option has been replaced by `impersonate` package: 315 // `google.golang.org/api/impersonate`. Please use the `impersonate` package 316 // instead with the WithTokenSource option. 317 func ImpersonateCredentials(target string, delegates ...string) ClientOption { 318 return impersonateServiceAccount{ 319 target: target, 320 delegates: delegates, 321 } 322 } 323 324 type impersonateServiceAccount struct { 325 target string 326 delegates []string 327 } 328 329 func (i impersonateServiceAccount) Apply(o *internal.DialSettings) { 330 o.ImpersonationConfig = &impersonate.Config{ 331 Target: i.target, 332 } 333 o.ImpersonationConfig.Delegates = make([]string, len(i.delegates)) 334 copy(o.ImpersonationConfig.Delegates, i.delegates) 335 } 336 337 type withCreds google.Credentials 338 339 func (w *withCreds) Apply(o *internal.DialSettings) { 340 o.Credentials = (*google.Credentials)(w) 341 } 342 343 // WithCredentials returns a ClientOption that authenticates API calls. 344 func WithCredentials(creds *google.Credentials) ClientOption { 345 return (*withCreds)(creds) 346 } 347 348 // WithAuthCredentials returns a ClientOption that specifies an 349 // [cloud.google.com/go/auth.Credentials] to be used as the basis for 350 // authentication. 351 func WithAuthCredentials(creds *auth.Credentials) ClientOption { 352 return withAuthCredentials{creds} 353 } 354 355 type withAuthCredentials struct{ creds *auth.Credentials } 356 357 func (w withAuthCredentials) Apply(o *internal.DialSettings) { 358 o.AuthCredentials = w.creds 359 } 360 361 // WithUniverseDomain returns a ClientOption that sets the universe domain. 362 // 363 // This is an EXPERIMENTAL API and may be changed or removed in the future. 364 func WithUniverseDomain(ud string) ClientOption { 365 return withUniverseDomain(ud) 366 } 367 368 type withUniverseDomain string 369 370 func (w withUniverseDomain) Apply(o *internal.DialSettings) { 371 o.UniverseDomain = string(w) 372 } 373