1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 package impersonate_test
16
17 import (
18 "context"
19 "flag"
20 "fmt"
21 "log"
22 "math/rand"
23 "os"
24 "testing"
25 "time"
26
27 "cloud.google.com/go/auth"
28 "cloud.google.com/go/auth/credentials"
29 "cloud.google.com/go/auth/credentials/idtoken"
30 "cloud.google.com/go/auth/credentials/impersonate"
31 "cloud.google.com/go/auth/internal/credsfile"
32 "cloud.google.com/go/auth/internal/testutil"
33 "cloud.google.com/go/auth/internal/testutil/testgcs"
34 )
35
36 const (
37 envProjectID = "GCLOUD_TESTS_GOLANG_PROJECT_ID"
38 envReaderCreds = "GCLOUD_TESTS_IMPERSONATE_READER_KEY"
39 envReaderEmail = "GCLOUD_TESTS_IMPERSONATE_READER_EMAIL"
40 envWriterEmail = "GCLOUD_TESTS_IMPERSONATE_WRITER_EMAIL"
41 )
42
43 var (
44 baseKeyFile string
45 readerKeyFile string
46 readerEmail string
47 writerEmail string
48 projectID string
49 random *rand.Rand
50 )
51
52 func TestMain(m *testing.M) {
53 flag.Parse()
54 random = rand.New(rand.NewSource(time.Now().UnixNano()))
55 baseKeyFile = os.Getenv(credsfile.GoogleAppCredsEnvVar)
56 projectID = os.Getenv(envProjectID)
57 readerKeyFile = os.Getenv(envReaderCreds)
58 readerEmail = os.Getenv(envReaderEmail)
59 writerEmail = os.Getenv(envWriterEmail)
60
61 if !testing.Short() && (baseKeyFile == "" ||
62 readerKeyFile == "" ||
63 readerEmail == "" ||
64 writerEmail == "" ||
65 projectID == "") {
66 log.Println("required environment variable not set, skipping")
67 os.Exit(0)
68 }
69
70 os.Exit(m.Run())
71 }
72
73 func TestNewCredentialsIntegration(t *testing.T) {
74 testutil.IntegrationTestCheck(t)
75 tests := []struct {
76 name string
77 baseKeyFile string
78 delegates []string
79 useDefaultCreds bool
80 }{
81 {
82 name: "SA -> SA",
83 baseKeyFile: readerKeyFile,
84 },
85 {
86 name: "SA -> SA (Default)",
87 baseKeyFile: readerKeyFile,
88 useDefaultCreds: true,
89 },
90 {
91 name: "SA -> Delegate -> SA",
92 baseKeyFile: baseKeyFile,
93 delegates: []string{readerEmail},
94 },
95 }
96
97 for _, tt := range tests {
98 t.Run(tt.name, func(t *testing.T) {
99 ctx := context.Background()
100 var baseCreds *auth.Credentials
101 if !tt.useDefaultCreds {
102 var err error
103 baseCreds, err = credentials.DetectDefault(&credentials.DetectOptions{
104 Scopes: []string{"https://www.googleapis.com/auth/cloud-platform"},
105 CredentialsFile: tt.baseKeyFile,
106 })
107 if err != nil {
108 t.Fatalf("credentials.DetectDefault() = %v", err)
109 }
110 }
111
112 opts := &impersonate.CredentialsOptions{
113 TargetPrincipal: writerEmail,
114 Scopes: []string{"https://www.googleapis.com/auth/devstorage.full_control"},
115 Delegates: tt.delegates,
116 }
117 if !tt.useDefaultCreds {
118 opts.Credentials = baseCreds
119 }
120 creds, err := impersonate.NewCredentials(opts)
121 if err != nil {
122 t.Fatalf("failed to create ts: %v", err)
123 }
124 client := testgcs.NewClient(creds)
125 bucketName := fmt.Sprintf("%s-impersonate-test-%d", projectID, random.Int63())
126 if err := client.CreateBucket(ctx, projectID, bucketName); err != nil {
127 t.Fatalf("error creating bucket: %v", err)
128 }
129 if err := client.DeleteBucket(ctx, bucketName); err != nil {
130 t.Fatalf("unable to cleanup bucket %q: %v", bucketName, err)
131 }
132 })
133 }
134 }
135
136 func TestNewIDTokenCredentialsIntegration(t *testing.T) {
137 testutil.IntegrationTestCheck(t)
138
139 ctx := context.Background()
140 tests := []struct {
141 name string
142 baseKeyFile string
143 delegates []string
144 useDefaultCreds bool
145 }{
146 {
147 name: "SA -> SA",
148 baseKeyFile: readerKeyFile,
149 },
150 {
151 name: "SA -> SA (Default)",
152 useDefaultCreds: true,
153 },
154 {
155 name: "SA -> Delegate -> SA",
156 baseKeyFile: baseKeyFile,
157 delegates: []string{readerEmail},
158 },
159 }
160
161 for _, tt := range tests {
162 name := tt.name
163 t.Run(name, func(t *testing.T) {
164 var baseCreds *auth.Credentials
165 if !tt.useDefaultCreds {
166 var err error
167 baseCreds, err = credentials.DetectDefault(&credentials.DetectOptions{
168 Scopes: []string{"https://www.googleapis.com/auth/cloud-platform"},
169 CredentialsFile: tt.baseKeyFile,
170 })
171 if err != nil {
172 t.Fatalf("credentials.DetectDefault() = %v", err)
173 }
174 }
175 aud := "http://example.com/"
176 opts := &impersonate.IDTokenOptions{
177 TargetPrincipal: writerEmail,
178 Audience: aud,
179 Delegates: tt.delegates,
180 IncludeEmail: true,
181 }
182 if !tt.useDefaultCreds {
183 opts.Credentials = baseCreds
184 }
185 creds, err := impersonate.NewIDTokenCredentials(opts)
186 if err != nil {
187 t.Fatalf("failed to create ts: %v", err)
188 }
189 tok, err := creds.Token(ctx)
190 if err != nil {
191 t.Fatalf("unable to retrieve Token: %v", err)
192 }
193 validTok, err := idtoken.Validate(ctx, tok.Value, aud)
194 if err != nil {
195 t.Fatalf("token validation failed: %v", err)
196 }
197 if validTok.Audience != aud {
198 t.Fatalf("got %q, want %q", validTok.Audience, aud)
199 }
200 if validTok.Claims["email"] != writerEmail {
201 t.Fatalf("got %q, want %q", validTok.Claims["email"], writerEmail)
202 }
203 })
204 }
205 }
206
View as plain text