-
Notifications
You must be signed in to change notification settings - Fork 1.1k
/
settings.go
233 lines (217 loc) · 8 KB
/
settings.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
// 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 internal supports the options and transport packages.
package internal
import (
"crypto/tls"
"errors"
"net/http"
"os"
"strconv"
"time"
"golang.org/x/oauth2"
"golang.org/x/oauth2/google"
"google.golang.org/api/internal/impersonate"
"google.golang.org/grpc"
)
const (
newAuthLibEnvVar = "GOOGLE_API_GO_EXPERIMENTAL_USE_NEW_AUTH_LIB"
universeDomainEnvVar = "GOOGLE_CLOUD_UNIVERSE_DOMAIN"
defaultUniverseDomain = "googleapis.com"
)
// DialSettings holds information needed to establish a connection with a
// Google API service.
type DialSettings struct {
Endpoint string
DefaultEndpoint string
DefaultEndpointTemplate string
DefaultMTLSEndpoint string
Scopes []string
DefaultScopes []string
EnableJwtWithScope bool
TokenSource oauth2.TokenSource
Credentials *google.Credentials
CredentialsFile string // if set, Token Source is ignored.
CredentialsJSON []byte
InternalCredentials *google.Credentials
UserAgent string
APIKey string
Audiences []string
DefaultAudience string
HTTPClient *http.Client
GRPCDialOpts []grpc.DialOption
GRPCConn *grpc.ClientConn
GRPCConnPool ConnPool
GRPCConnPoolSize int
NoAuth bool
TelemetryDisabled bool
ClientCertSource func(*tls.CertificateRequestInfo) (*tls.Certificate, error)
CustomClaims map[string]interface{}
SkipValidation bool
ImpersonationConfig *impersonate.Config
EnableDirectPath bool
EnableDirectPathXds bool
EnableNewAuthLibrary bool
AllowNonDefaultServiceAccount bool
DefaultUniverseDomain string
UniverseDomain string
// Google API system parameters. For more information please read:
// https://cloud.google.com/apis/docs/system-parameters
QuotaProject string
RequestReason string
}
// GetScopes returns the user-provided scopes, if set, or else falls back to the
// default scopes.
func (ds *DialSettings) GetScopes() []string {
if len(ds.Scopes) > 0 {
return ds.Scopes
}
return ds.DefaultScopes
}
// GetAudience returns the user-provided audience, if set, or else falls back to the default audience.
func (ds *DialSettings) GetAudience() string {
if ds.HasCustomAudience() {
return ds.Audiences[0]
}
return ds.DefaultAudience
}
// HasCustomAudience returns true if a custom audience is provided by users.
func (ds *DialSettings) HasCustomAudience() bool {
return len(ds.Audiences) > 0
}
// IsNewAuthLibraryEnabled returns true if the new auth library should be used.
func (ds *DialSettings) IsNewAuthLibraryEnabled() bool {
if ds.EnableNewAuthLibrary {
return true
}
if b, err := strconv.ParseBool(os.Getenv(newAuthLibEnvVar)); err == nil {
return b
}
return false
}
// Validate reports an error if ds is invalid.
func (ds *DialSettings) Validate() error {
if ds.SkipValidation {
return nil
}
hasCreds := ds.APIKey != "" || ds.TokenSource != nil || ds.CredentialsFile != "" || ds.Credentials != nil
if ds.NoAuth && hasCreds {
return errors.New("options.WithoutAuthentication is incompatible with any option that provides credentials")
}
// Credentials should not appear with other options.
// We currently allow TokenSource and CredentialsFile to coexist.
// TODO(jba): make TokenSource & CredentialsFile an error (breaking change).
nCreds := 0
if ds.Credentials != nil {
nCreds++
}
if ds.CredentialsJSON != nil {
nCreds++
}
if ds.CredentialsFile != "" {
nCreds++
}
if ds.APIKey != "" {
nCreds++
}
if ds.TokenSource != nil {
nCreds++
}
if len(ds.Scopes) > 0 && len(ds.Audiences) > 0 {
return errors.New("WithScopes is incompatible with WithAudience")
}
// Accept only one form of credentials, except we allow TokenSource and CredentialsFile for backwards compatibility.
if nCreds > 1 && !(nCreds == 2 && ds.TokenSource != nil && ds.CredentialsFile != "") {
return errors.New("multiple credential options provided")
}
if ds.GRPCConn != nil && ds.GRPCConnPool != nil {
return errors.New("WithGRPCConn is incompatible with WithConnPool")
}
if ds.HTTPClient != nil && ds.GRPCConnPool != nil {
return errors.New("WithHTTPClient is incompatible with WithConnPool")
}
if ds.HTTPClient != nil && ds.GRPCConn != nil {
return errors.New("WithHTTPClient is incompatible with WithGRPCConn")
}
if ds.HTTPClient != nil && ds.GRPCDialOpts != nil {
return errors.New("WithHTTPClient is incompatible with gRPC dial options")
}
if ds.HTTPClient != nil && ds.QuotaProject != "" {
return errors.New("WithHTTPClient is incompatible with QuotaProject")
}
if ds.HTTPClient != nil && ds.RequestReason != "" {
return errors.New("WithHTTPClient is incompatible with RequestReason")
}
if ds.HTTPClient != nil && ds.ClientCertSource != nil {
return errors.New("WithHTTPClient is incompatible with WithClientCertSource")
}
if ds.ClientCertSource != nil && (ds.GRPCConn != nil || ds.GRPCConnPool != nil || ds.GRPCConnPoolSize != 0 || ds.GRPCDialOpts != nil) {
return errors.New("WithClientCertSource is currently only supported for HTTP. gRPC settings are incompatible")
}
if ds.ImpersonationConfig != nil && len(ds.ImpersonationConfig.Scopes) == 0 && len(ds.Scopes) == 0 {
return errors.New("WithImpersonatedCredentials requires scopes being provided")
}
return nil
}
// GetDefaultUniverseDomain returns the Google default universe domain
// ("googleapis.com").
func (ds *DialSettings) GetDefaultUniverseDomain() string {
return defaultUniverseDomain
}
// GetUniverseDomain returns the default service domain for a given Cloud
// universe, with the following precedence:
//
// 1. A non-empty option.WithUniverseDomain.
// 2. A non-empty environment variable GOOGLE_CLOUD_UNIVERSE_DOMAIN.
// 3. The default value "googleapis.com".
func (ds *DialSettings) GetUniverseDomain() string {
if ds.UniverseDomain != "" {
return ds.UniverseDomain
}
if envUD := os.Getenv(universeDomainEnvVar); envUD != "" {
return envUD
}
return defaultUniverseDomain
}
// IsUniverseDomainGDU returns true if the universe domain is the default Google
// universe ("googleapis.com").
func (ds *DialSettings) IsUniverseDomainGDU() bool {
return ds.GetUniverseDomain() == defaultUniverseDomain
}
// GetUniverseDomain returns the default service domain for a given Cloud
// universe, from google.Credentials, for comparison with the value returned by
// (*DialSettings).GetUniverseDomain. This wrapper function should be removed
// to close https://github.com/googleapis/google-api-go-client/issues/2399.
func GetUniverseDomain(creds *google.Credentials) (string, error) {
timer := time.NewTimer(time.Second)
defer timer.Stop()
errors := make(chan error)
results := make(chan string)
go func() {
result, err := creds.GetUniverseDomain()
if err != nil {
errors <- err
return
}
results <- result
}()
select {
case <-errors:
// An error that is returned before the timer expires is likely to be
// connection refused. Temporarily (2024-03-21) return the GDU domain.
return defaultUniverseDomain, nil
case res := <-results:
return res, nil
case <-timer.C: // Timer is expired.
// If err or res was not returned, it means that creds.GetUniverseDomain()
// did not complete in 1s. Assume that MDS is likely never responding to
// the endpoint and will timeout. This is the source of issues such as
// https://github.com/googleapis/google-cloud-go/issues/9350.
// Temporarily (2024-02-02) return the GDU domain. Restore the original
// calls to creds.GetUniverseDomain() in grpc/dial.go and http/dial.go
// and remove this method to close
// https://github.com/googleapis/google-api-go-client/issues/2399.
return defaultUniverseDomain, nil
}
}