1// Copyright 2023 Google LLC
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15// Package transport provided internal helpers for the two transport packages
16// (grpctransport and httptransport).
17package transport
18
19import (
20 "crypto/tls"
21 "fmt"
22 "net"
23 "net/http"
24 "time"
25
26 "cloud.google.com/go/auth/credentials"
27)
28
29// CloneDetectOptions clones a user set detect option into some new memory that
30// we can internally manipulate before sending onto the detect package.
31func CloneDetectOptions(oldDo *credentials.DetectOptions) *credentials.DetectOptions {
32 if oldDo == nil {
33 // it is valid for users not to set this, but we will need to to default
34 // some options for them in this case so return some initialized memory
35 // to work with.
36 return &credentials.DetectOptions{}
37 }
38 newDo := &credentials.DetectOptions{
39 // Simple types
40 Audience: oldDo.Audience,
41 Subject: oldDo.Subject,
42 EarlyTokenRefresh: oldDo.EarlyTokenRefresh,
43 TokenURL: oldDo.TokenURL,
44 STSAudience: oldDo.STSAudience,
45 CredentialsFile: oldDo.CredentialsFile,
46 UseSelfSignedJWT: oldDo.UseSelfSignedJWT,
47 UniverseDomain: oldDo.UniverseDomain,
48
49 // These fields are are pointer types that we just want to use exactly
50 // as the user set, copy the ref
51 Client: oldDo.Client,
52 Logger: oldDo.Logger,
53 AuthHandlerOptions: oldDo.AuthHandlerOptions,
54 }
55
56 // Smartly size this memory and copy below.
57 if len(oldDo.CredentialsJSON) > 0 {
58 newDo.CredentialsJSON = make([]byte, len(oldDo.CredentialsJSON))
59 copy(newDo.CredentialsJSON, oldDo.CredentialsJSON)
60 }
61 if len(oldDo.Scopes) > 0 {
62 newDo.Scopes = make([]string, len(oldDo.Scopes))
63 copy(newDo.Scopes, oldDo.Scopes)
64 }
65
66 return newDo
67}
68
69// ValidateUniverseDomain verifies that the universe domain configured for the
70// client matches the universe domain configured for the credentials.
71func ValidateUniverseDomain(clientUniverseDomain, credentialsUniverseDomain string) error {
72 if clientUniverseDomain != credentialsUniverseDomain {
73 return fmt.Errorf(
74 "the configured universe domain (%q) does not match the universe "+
75 "domain found in the credentials (%q). If you haven't configured "+
76 "the universe domain explicitly, \"googleapis.com\" is the default",
77 clientUniverseDomain,
78 credentialsUniverseDomain)
79 }
80 return nil
81}
82
83// DefaultHTTPClientWithTLS constructs an HTTPClient using the provided tlsConfig, to support mTLS.
84func DefaultHTTPClientWithTLS(tlsConfig *tls.Config) *http.Client {
85 trans := BaseTransport()
86 trans.TLSClientConfig = tlsConfig
87 return &http.Client{Transport: trans}
88}
89
90// BaseTransport returns a default [http.Transport] which can be used if
91// [http.DefaultTransport] has been overwritten.
92func BaseTransport() *http.Transport {
93 return &http.Transport{
94 Proxy: http.ProxyFromEnvironment,
95 DialContext: (&net.Dialer{
96 Timeout: 30 * time.Second,
97 KeepAlive: 30 * time.Second,
98 DualStack: true,
99 }).DialContext,
100 MaxIdleConns: 100,
101 MaxIdleConnsPerHost: 100,
102 IdleConnTimeout: 90 * time.Second,
103 TLSHandshakeTimeout: 10 * time.Second,
104 ExpectContinueTimeout: 1 * time.Second,
105 }
106}