1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 package idtoken
16
17 import (
18 "encoding/json"
19 "fmt"
20 "path/filepath"
21 "strings"
22
23 "cloud.google.com/go/auth"
24 "cloud.google.com/go/auth/credentials"
25 "cloud.google.com/go/auth/credentials/impersonate"
26 "cloud.google.com/go/auth/internal"
27 "cloud.google.com/go/auth/internal/credsfile"
28 )
29
30 const (
31 jwtTokenURL = "https://oauth2.googleapis.com/token"
32 iamCredAud = "https://iamcredentials.googleapis.com/"
33 )
34
35 var (
36 defaultScopes = []string{
37 "https://iamcredentials.googleapis.com/",
38 "https://www.googleapis.com/auth/cloud-platform",
39 }
40 )
41
42 func credsFromBytes(b []byte, opts *Options) (*auth.Credentials, error) {
43 t, err := credsfile.ParseFileType(b)
44 if err != nil {
45 return nil, err
46 }
47 switch t {
48 case credsfile.ServiceAccountKey:
49 f, err := credsfile.ParseServiceAccount(b)
50 if err != nil {
51 return nil, err
52 }
53 opts2LO := &auth.Options2LO{
54 Email: f.ClientEmail,
55 PrivateKey: []byte(f.PrivateKey),
56 PrivateKeyID: f.PrivateKeyID,
57 TokenURL: f.TokenURL,
58 UseIDToken: true,
59 }
60 if opts2LO.TokenURL == "" {
61 opts2LO.TokenURL = jwtTokenURL
62 }
63
64 var customClaims map[string]interface{}
65 if opts != nil {
66 customClaims = opts.CustomClaims
67 }
68 if customClaims == nil {
69 customClaims = make(map[string]interface{})
70 }
71 customClaims["target_audience"] = opts.Audience
72
73 opts2LO.PrivateClaims = customClaims
74 tp, err := auth.New2LOTokenProvider(opts2LO)
75 if err != nil {
76 return nil, err
77 }
78 tp = auth.NewCachedTokenProvider(tp, nil)
79 return auth.NewCredentials(&auth.CredentialsOptions{
80 TokenProvider: tp,
81 JSON: b,
82 ProjectIDProvider: internal.StaticCredentialsProperty(f.ProjectID),
83 UniverseDomainProvider: internal.StaticCredentialsProperty(f.UniverseDomain),
84 }), nil
85 case credsfile.ImpersonatedServiceAccountKey, credsfile.ExternalAccountKey:
86 type url struct {
87 ServiceAccountImpersonationURL string `json:"service_account_impersonation_url"`
88 }
89 var accountURL url
90 if err := json.Unmarshal(b, &accountURL); err != nil {
91 return nil, err
92 }
93 account := filepath.Base(accountURL.ServiceAccountImpersonationURL)
94 account = strings.Split(account, ":")[0]
95
96 baseCreds, err := credentials.DetectDefault(&credentials.DetectOptions{
97 Scopes: defaultScopes,
98 CredentialsJSON: b,
99 Client: opts.client(),
100 UseSelfSignedJWT: true,
101 })
102 if err != nil {
103 return nil, err
104 }
105
106 config := impersonate.IDTokenOptions{
107 Audience: opts.Audience,
108 TargetPrincipal: account,
109 IncludeEmail: true,
110 Client: opts.client(),
111 Credentials: baseCreds,
112 }
113 creds, err := impersonate.NewIDTokenCredentials(&config)
114 if err != nil {
115 return nil, err
116 }
117 return auth.NewCredentials(&auth.CredentialsOptions{
118 TokenProvider: creds,
119 JSON: b,
120 ProjectIDProvider: auth.CredentialsPropertyFunc(baseCreds.ProjectID),
121 UniverseDomainProvider: auth.CredentialsPropertyFunc(baseCreds.UniverseDomain),
122 QuotaProjectIDProvider: auth.CredentialsPropertyFunc(baseCreds.QuotaProjectID),
123 }), nil
124 default:
125 return nil, fmt.Errorf("idtoken: unsupported credentials type: %v", t)
126 }
127 }
128
View as plain text