1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 package credentials
16
17 import (
18 "errors"
19 "fmt"
20
21 "cloud.google.com/go/auth"
22 "cloud.google.com/go/auth/credentials/internal/externalaccount"
23 "cloud.google.com/go/auth/credentials/internal/externalaccountuser"
24 "cloud.google.com/go/auth/credentials/internal/gdch"
25 "cloud.google.com/go/auth/credentials/internal/impersonate"
26 internalauth "cloud.google.com/go/auth/internal"
27 "cloud.google.com/go/auth/internal/credsfile"
28 )
29
30 func fileCredentials(b []byte, opts *DetectOptions) (*auth.Credentials, error) {
31 fileType, err := credsfile.ParseFileType(b)
32 if err != nil {
33 return nil, err
34 }
35
36 var projectID, quotaProjectID, universeDomain string
37 var tp auth.TokenProvider
38 switch fileType {
39 case credsfile.ServiceAccountKey:
40 f, err := credsfile.ParseServiceAccount(b)
41 if err != nil {
42 return nil, err
43 }
44 tp, err = handleServiceAccount(f, opts)
45 if err != nil {
46 return nil, err
47 }
48 projectID = f.ProjectID
49 universeDomain = resolveUniverseDomain(opts.UniverseDomain, f.UniverseDomain)
50 case credsfile.UserCredentialsKey:
51 f, err := credsfile.ParseUserCredentials(b)
52 if err != nil {
53 return nil, err
54 }
55 tp, err = handleUserCredential(f, opts)
56 if err != nil {
57 return nil, err
58 }
59 quotaProjectID = f.QuotaProjectID
60 universeDomain = f.UniverseDomain
61 case credsfile.ExternalAccountKey:
62 f, err := credsfile.ParseExternalAccount(b)
63 if err != nil {
64 return nil, err
65 }
66 tp, err = handleExternalAccount(f, opts)
67 if err != nil {
68 return nil, err
69 }
70 quotaProjectID = f.QuotaProjectID
71 universeDomain = resolveUniverseDomain(opts.UniverseDomain, f.UniverseDomain)
72 case credsfile.ExternalAccountAuthorizedUserKey:
73 f, err := credsfile.ParseExternalAccountAuthorizedUser(b)
74 if err != nil {
75 return nil, err
76 }
77 tp, err = handleExternalAccountAuthorizedUser(f, opts)
78 if err != nil {
79 return nil, err
80 }
81 quotaProjectID = f.QuotaProjectID
82 universeDomain = f.UniverseDomain
83 case credsfile.ImpersonatedServiceAccountKey:
84 f, err := credsfile.ParseImpersonatedServiceAccount(b)
85 if err != nil {
86 return nil, err
87 }
88 tp, err = handleImpersonatedServiceAccount(f, opts)
89 if err != nil {
90 return nil, err
91 }
92 universeDomain = resolveUniverseDomain(opts.UniverseDomain, f.UniverseDomain)
93 case credsfile.GDCHServiceAccountKey:
94 f, err := credsfile.ParseGDCHServiceAccount(b)
95 if err != nil {
96 return nil, err
97 }
98 tp, err = handleGDCHServiceAccount(f, opts)
99 if err != nil {
100 return nil, err
101 }
102 projectID = f.Project
103 universeDomain = f.UniverseDomain
104 default:
105 return nil, fmt.Errorf("credentials: unsupported filetype %q", fileType)
106 }
107 return auth.NewCredentials(&auth.CredentialsOptions{
108 TokenProvider: auth.NewCachedTokenProvider(tp, &auth.CachedTokenProviderOptions{
109 ExpireEarly: opts.EarlyTokenRefresh,
110 }),
111 JSON: b,
112 ProjectIDProvider: internalauth.StaticCredentialsProperty(projectID),
113 QuotaProjectIDProvider: internalauth.StaticCredentialsProperty(quotaProjectID),
114 UniverseDomainProvider: internalauth.StaticCredentialsProperty(universeDomain),
115 }), nil
116 }
117
118
119
120
121
122 func resolveUniverseDomain(optsUniverseDomain, fileUniverseDomain string) string {
123 if optsUniverseDomain != "" {
124 return optsUniverseDomain
125 }
126 return fileUniverseDomain
127 }
128
129 func handleServiceAccount(f *credsfile.ServiceAccountFile, opts *DetectOptions) (auth.TokenProvider, error) {
130 if opts.UseSelfSignedJWT {
131 return configureSelfSignedJWT(f, opts)
132 }
133 opts2LO := &auth.Options2LO{
134 Email: f.ClientEmail,
135 PrivateKey: []byte(f.PrivateKey),
136 PrivateKeyID: f.PrivateKeyID,
137 Scopes: opts.scopes(),
138 TokenURL: f.TokenURL,
139 Subject: opts.Subject,
140 }
141 if opts2LO.TokenURL == "" {
142 opts2LO.TokenURL = jwtTokenURL
143 }
144 return auth.New2LOTokenProvider(opts2LO)
145 }
146
147 func handleUserCredential(f *credsfile.UserCredentialsFile, opts *DetectOptions) (auth.TokenProvider, error) {
148 opts3LO := &auth.Options3LO{
149 ClientID: f.ClientID,
150 ClientSecret: f.ClientSecret,
151 Scopes: opts.scopes(),
152 AuthURL: googleAuthURL,
153 TokenURL: opts.tokenURL(),
154 AuthStyle: auth.StyleInParams,
155 EarlyTokenExpiry: opts.EarlyTokenRefresh,
156 RefreshToken: f.RefreshToken,
157 }
158 return auth.New3LOTokenProvider(opts3LO)
159 }
160
161 func handleExternalAccount(f *credsfile.ExternalAccountFile, opts *DetectOptions) (auth.TokenProvider, error) {
162 externalOpts := &externalaccount.Options{
163 Audience: f.Audience,
164 SubjectTokenType: f.SubjectTokenType,
165 TokenURL: f.TokenURL,
166 TokenInfoURL: f.TokenInfoURL,
167 ServiceAccountImpersonationURL: f.ServiceAccountImpersonationURL,
168 ClientSecret: f.ClientSecret,
169 ClientID: f.ClientID,
170 CredentialSource: f.CredentialSource,
171 QuotaProjectID: f.QuotaProjectID,
172 Scopes: opts.scopes(),
173 WorkforcePoolUserProject: f.WorkforcePoolUserProject,
174 Client: opts.client(),
175 }
176 if f.ServiceAccountImpersonation != nil {
177 externalOpts.ServiceAccountImpersonationLifetimeSeconds = f.ServiceAccountImpersonation.TokenLifetimeSeconds
178 }
179 return externalaccount.NewTokenProvider(externalOpts)
180 }
181
182 func handleExternalAccountAuthorizedUser(f *credsfile.ExternalAccountAuthorizedUserFile, opts *DetectOptions) (auth.TokenProvider, error) {
183 externalOpts := &externalaccountuser.Options{
184 Audience: f.Audience,
185 RefreshToken: f.RefreshToken,
186 TokenURL: f.TokenURL,
187 TokenInfoURL: f.TokenInfoURL,
188 ClientID: f.ClientID,
189 ClientSecret: f.ClientSecret,
190 Scopes: opts.scopes(),
191 Client: opts.client(),
192 }
193 return externalaccountuser.NewTokenProvider(externalOpts)
194 }
195
196 func handleImpersonatedServiceAccount(f *credsfile.ImpersonatedServiceAccountFile, opts *DetectOptions) (auth.TokenProvider, error) {
197 if f.ServiceAccountImpersonationURL == "" || f.CredSource == nil {
198 return nil, errors.New("missing 'source_credentials' field or 'service_account_impersonation_url' in credentials")
199 }
200
201 tp, err := fileCredentials(f.CredSource, opts)
202 if err != nil {
203 return nil, err
204 }
205 return impersonate.NewTokenProvider(&impersonate.Options{
206 URL: f.ServiceAccountImpersonationURL,
207 Scopes: opts.scopes(),
208 Tp: tp,
209 Delegates: f.Delegates,
210 Client: opts.client(),
211 })
212 }
213
214 func handleGDCHServiceAccount(f *credsfile.GDCHServiceAccountFile, opts *DetectOptions) (auth.TokenProvider, error) {
215 return gdch.NewTokenProvider(f, &gdch.Options{
216 STSAudience: opts.STSAudience,
217 Client: opts.client(),
218 })
219 }
220
View as plain text