1
2
3
4
5 package impersonate_test
6
7 import (
8 "context"
9 "flag"
10 "fmt"
11 "math/rand"
12 "os"
13 "testing"
14 "time"
15
16 admin "google.golang.org/api/admin/directory/v1"
17 "google.golang.org/api/idtoken"
18 "google.golang.org/api/impersonate"
19 "google.golang.org/api/option"
20
21 "google.golang.org/api/storage/v1"
22 )
23
24 var (
25 baseKeyFile string
26 readerKeyFile string
27 readerEmail string
28 writerEmail string
29 projectID string
30 domain string
31 domainAdmin string
32 )
33
34 func TestMain(m *testing.M) {
35 flag.Parse()
36 rand.Seed(time.Now().UnixNano())
37 baseKeyFile = os.Getenv("GOOGLE_APPLICATION_CREDENTIALS")
38 projectID = os.Getenv("GOOGLE_CLOUD_PROJECT")
39 readerKeyFile = os.Getenv("GCLOUD_TESTS_IMPERSONATE_READER_KEY")
40 readerEmail = os.Getenv("GCLOUD_TESTS_IMPERSONATE_READER_EMAIL")
41 writerEmail = os.Getenv("GCLOUD_TESTS_IMPERSONATE_WRITER_EMAIL")
42 domain = os.Getenv("GCLOUD_TESTS_IMPERSONATE_DOMAIN")
43 domainAdmin = os.Getenv("GCLOUD_TESTS_IMPERSONATE_DOMAIN_ADMIN")
44
45 os.Exit(m.Run())
46 }
47
48 func validateEnvVars(t *testing.T) {
49 t.Helper()
50 if baseKeyFile == "" ||
51 readerKeyFile == "" ||
52 readerEmail == "" ||
53 writerEmail == "" ||
54 projectID == "" {
55 t.Skip("required environment variable not set, skipping")
56 }
57 }
58
59 func TestCredentialsTokenSourceIntegration(t *testing.T) {
60 if testing.Short() {
61 t.Skip("skipping integration test")
62 }
63 validateEnvVars(t)
64
65 ctx := context.Background()
66 tests := []struct {
67 name string
68 baseKeyFile string
69 delegates []string
70 }{
71 {
72 name: "SA -> SA",
73 baseKeyFile: readerKeyFile,
74 },
75 {
76 name: "SA -> Delegate -> SA",
77 baseKeyFile: baseKeyFile,
78 delegates: []string{readerEmail},
79 },
80 }
81
82 for _, tt := range tests {
83 t.Run(tt.name, func(t *testing.T) {
84 ts, err := impersonate.CredentialsTokenSource(ctx,
85 impersonate.CredentialsConfig{
86 TargetPrincipal: writerEmail,
87 Scopes: []string{"https://www.googleapis.com/auth/devstorage.full_control"},
88 Delegates: tt.delegates,
89 },
90 option.WithCredentialsFile(tt.baseKeyFile),
91 )
92 if err != nil {
93 t.Fatalf("failed to create ts: %v", err)
94 }
95 svc, err := storage.NewService(ctx, option.WithTokenSource(ts))
96 if err != nil {
97 t.Fatalf("failed to create client: %v", err)
98 }
99 bucketName := fmt.Sprintf("%s-%d", projectID, rand.Int63())
100 if _, err := svc.Buckets.Insert(projectID, &storage.Bucket{
101 Name: bucketName,
102 }).Do(); err != nil {
103 t.Fatalf("error creating bucket: %v", err)
104 }
105 if err := svc.Buckets.Delete(bucketName).Do(); err != nil {
106 t.Fatalf("unable to cleanup bucket %q: %v", bucketName, err)
107 }
108 })
109 }
110 }
111
112 func TestIDTokenSourceIntegration(t *testing.T) {
113 if testing.Short() {
114 t.Skip("skipping integration test")
115 }
116 validateEnvVars(t)
117
118 ctx := context.Background()
119 tests := []struct {
120 name string
121 baseKeyFile string
122 delegates []string
123 }{
124 {
125 name: "SA -> SA",
126 baseKeyFile: readerKeyFile,
127 },
128 {
129 name: "SA -> Delegate -> SA",
130 baseKeyFile: baseKeyFile,
131 delegates: []string{readerEmail},
132 },
133 }
134
135 for _, tt := range tests {
136 name := tt.name
137 t.Run(name, func(t *testing.T) {
138 aud := "http://example.com/"
139 ts, err := impersonate.IDTokenSource(ctx,
140 impersonate.IDTokenConfig{
141 TargetPrincipal: writerEmail,
142 Audience: aud,
143 Delegates: tt.delegates,
144 IncludeEmail: true,
145 },
146 option.WithCredentialsFile(tt.baseKeyFile),
147 )
148 if err != nil {
149 t.Fatalf("failed to create ts: %v", err)
150 }
151 tok, err := ts.Token()
152 if err != nil {
153 t.Fatalf("unable to retrieve Token: %v", err)
154 }
155 validTok, err := idtoken.Validate(context.Background(), tok.AccessToken, aud)
156 if err != nil {
157 t.Fatalf("token validation failed: %v", err)
158 }
159 if validTok.Audience != aud {
160 t.Fatalf("got %q, want %q", validTok.Audience, aud)
161 }
162 if validTok.Claims["email"] != writerEmail {
163 t.Fatalf("got %q, want %q", validTok.Claims["email"], writerEmail)
164 }
165 })
166 }
167 }
168
169 func TestTokenSourceIntegration_user(t *testing.T) {
170 t.Skip("https://github.com/googleapis/google-api-go-client/issues/948")
171 if testing.Short() {
172 t.Skip("skipping integration test")
173 }
174 validateEnvVars(t)
175 ctx := context.Background()
176 tests := []struct {
177 name string
178 baseKeyFile string
179 delegates []string
180 }{
181 {
182 name: "SA -> SA",
183 baseKeyFile: readerKeyFile,
184 },
185 {
186 name: "SA -> Delegate -> SA",
187 baseKeyFile: baseKeyFile,
188 delegates: []string{readerEmail},
189 },
190 }
191
192 for _, tt := range tests {
193 t.Run(tt.name, func(t *testing.T) {
194 ts, err := impersonate.CredentialsTokenSource(ctx,
195 impersonate.CredentialsConfig{
196 TargetPrincipal: writerEmail,
197 Delegates: tt.delegates,
198 Scopes: []string{"https://www.googleapis.com/auth/admin.directory.user", "https://www.googleapis.com/auth/admin.directory.group"},
199 Subject: domainAdmin,
200 },
201 option.WithCredentialsFile(baseKeyFile),
202 )
203 if err != nil {
204 t.Fatalf("failed to create ts: %v", err)
205 }
206 svc, err := admin.NewService(ctx, option.WithTokenSource(ts))
207 if err != nil {
208 t.Fatalf("failed to create client: %v", err)
209 }
210 if _, err := svc.Users.List().Domain(domain).Do(); err != nil {
211 t.Fatalf("failed to list users: %v", err)
212 }
213 })
214 }
215 }
216
View as plain text