1package alicloud
2
3import (
4	"context"
5	"fmt"
6	"testing"
7
8	"github.com/hashicorp/vault/sdk/logical"
9)
10
11/*
12	testEnv allows us to reuse the same requests and response-checking
13	for both integration tests that don't hit Alibaba's real API, and
14	for acceptance tests that do hit their real API.
15*/
16type testEnv struct {
17	AccessKey string
18	SecretKey string
19	RoleARN   string
20
21	Backend logical.Backend
22	Context context.Context
23	Storage logical.Storage
24
25	MostRecentSecret *logical.Secret
26}
27
28func (e *testEnv) AddConfig(t *testing.T) {
29	req := &logical.Request{
30		Operation: logical.UpdateOperation,
31		Path:      "config",
32		Storage:   e.Storage,
33		Data: map[string]interface{}{
34			"access_key": e.AccessKey,
35			"secret_key": e.SecretKey,
36		},
37	}
38	resp, err := e.Backend.HandleRequest(e.Context, req)
39	if err != nil || (resp != nil && resp.IsError()) {
40		t.Fatalf("bad: resp: %#v\nerr:%v", resp, err)
41	}
42	if resp != nil {
43		t.Fatal("expected nil response to represent a 204")
44	}
45}
46
47func (e *testEnv) ReadFirstConfig(t *testing.T) {
48	req := &logical.Request{
49		Operation: logical.ReadOperation,
50		Path:      "config",
51		Storage:   e.Storage,
52	}
53	resp, err := e.Backend.HandleRequest(e.Context, req)
54	if err != nil || (resp != nil && resp.IsError()) {
55		t.Fatalf("bad: resp: %#v\nerr:%v", resp, err)
56	}
57	if resp == nil {
58		t.Fatal("expected a response")
59	}
60	if resp.Data["access_key"] != e.AccessKey {
61		t.Fatal("expected access_key of " + e.AccessKey)
62	}
63	if resp.Data["secret_key"] != nil {
64		t.Fatal("secret_key should not be returned")
65	}
66}
67
68func (e *testEnv) UpdateConfig(t *testing.T) {
69	req := &logical.Request{
70		Operation: logical.UpdateOperation,
71		Path:      "config",
72		Storage:   e.Storage,
73		Data: map[string]interface{}{
74			"access_key": "foo",
75			"secret_key": "bar",
76		},
77	}
78	resp, err := e.Backend.HandleRequest(e.Context, req)
79	if err != nil || (resp != nil && resp.IsError()) {
80		t.Fatalf("bad: resp: %#v\nerr:%v", resp, err)
81	}
82	if resp != nil {
83		t.Fatal("expected nil response to represent a 204")
84	}
85}
86
87func (e *testEnv) ReadSecondConfig(t *testing.T) {
88	req := &logical.Request{
89		Operation: logical.ReadOperation,
90		Path:      "config",
91		Storage:   e.Storage,
92	}
93	resp, err := e.Backend.HandleRequest(e.Context, req)
94	if err != nil || (resp != nil && resp.IsError()) {
95		t.Fatalf("bad: resp: %#v\nerr:%v", resp, err)
96	}
97	if resp == nil {
98		t.Fatal("expected a response")
99	}
100	if resp.Data["access_key"] != "foo" {
101		t.Fatal("expected access_key of foo")
102	}
103	if resp.Data["secret_key"] != nil {
104		t.Fatal("secret_key should not be returned")
105	}
106}
107
108func (e *testEnv) DeleteConfig(t *testing.T) {
109	req := &logical.Request{
110		Operation: logical.DeleteOperation,
111		Path:      "config",
112		Storage:   e.Storage,
113	}
114	resp, err := e.Backend.HandleRequest(e.Context, req)
115	if err != nil || (resp != nil && resp.IsError()) {
116		t.Fatalf("bad: resp: %#v\nerr:%v", resp, err)
117	}
118	if resp != nil {
119		t.Fatal("expected nil response to represent a 204")
120	}
121}
122
123func (e *testEnv) ReadEmptyConfig(t *testing.T) {
124	req := &logical.Request{
125		Operation: logical.ReadOperation,
126		Path:      "config",
127		Storage:   e.Storage,
128	}
129	resp, err := e.Backend.HandleRequest(e.Context, req)
130	if err != nil || (resp != nil && resp.IsError()) {
131		t.Fatalf("bad: resp: %#v\nerr:%v", resp, err)
132	}
133	if resp != nil {
134		t.Fatal("expected nil response to represent a 204")
135	}
136}
137
138func (e *testEnv) AddPolicyBasedRole(t *testing.T) {
139	req := &logical.Request{
140		Operation: logical.CreateOperation,
141		Path:      "role/policy-based",
142		Storage:   e.Storage,
143		Data: map[string]interface{}{
144			"remote_policies": []string{
145				"name:AliyunOSSReadOnlyAccess,type:System",
146				"name:AliyunRDSReadOnlyAccess,type:System",
147			},
148			"inline_policies": rawInlinePolicies,
149		},
150	}
151	resp, err := e.Backend.HandleRequest(e.Context, req)
152	if err != nil || (resp != nil && resp.IsError()) {
153		t.Fatalf("bad: resp: %#v\nerr:%v", resp, err)
154	}
155	if resp != nil {
156		t.Fatal("expected nil response to represent a 204")
157	}
158}
159
160func (e *testEnv) ReadPolicyBasedRole(t *testing.T) {
161	req := &logical.Request{
162		Operation: logical.ReadOperation,
163		Path:      "role/policy-based",
164		Storage:   e.Storage,
165	}
166	resp, err := e.Backend.HandleRequest(e.Context, req)
167	if err != nil || (resp != nil && resp.IsError()) {
168		t.Fatalf("bad: resp: %#v\nerr:%v", resp, err)
169	}
170	if resp == nil {
171		t.Fatal("expected a response")
172	}
173
174	if resp.Data["role_arn"] != "" {
175		t.Fatalf("expected no role_arn but received %s", resp.Data["role_arn"])
176	}
177
178	inlinePolicies := resp.Data["inline_policies"].([]*inlinePolicy)
179	for i, inlinePolicy := range inlinePolicies {
180		if inlinePolicy.PolicyDocument["Version"] != "1" {
181			t.Fatalf("expected version of 1 but received %s", inlinePolicy.PolicyDocument["Version"])
182		}
183		stmts := inlinePolicy.PolicyDocument["Statement"].([]interface{})
184		if len(stmts) != 1 {
185			t.Fatalf("expected 1 statement but received %d", len(stmts))
186		}
187		stmt := stmts[0].(map[string]interface{})
188		action := stmt["Action"].([]interface{})[0].(string)
189		if stmt["Effect"] != "Allow" {
190			t.Fatalf("expected Allow statement but received %s", stmt["Effect"])
191		}
192		resource := stmt["Resource"].([]interface{})[0].(string)
193		if resource != "acs:oss:*:*:*" {
194			t.Fatalf("received incorrect resource: %s", resource)
195		}
196		switch i {
197		case 0:
198			if action != "rds:*" {
199				t.Fatalf("expected rds:* but received %s", action)
200			}
201		case 1:
202			if action != "oss:*" {
203				t.Fatalf("expected oss:* but received %s", action)
204			}
205		}
206	}
207
208	remotePolicies := resp.Data["remote_policies"].([]*remotePolicy)
209	for i, remotePol := range remotePolicies {
210		switch i {
211		case 0:
212			if remotePol.Name != "AliyunOSSReadOnlyAccess" {
213				t.Fatalf("received unexpected policy name of %s", remotePol.Name)
214			}
215			if remotePol.Type != "System" {
216				t.Fatalf("received unexpected policy type of %s", remotePol.Type)
217			}
218		case 1:
219			if remotePol.Name != "AliyunRDSReadOnlyAccess" {
220				t.Fatalf("received unexpected policy name of %s", remotePol.Name)
221			}
222			if remotePol.Type != "System" {
223				t.Fatalf("received unexpected policy type of %s", remotePol.Type)
224			}
225		}
226	}
227
228	ttl := fmt.Sprintf("%d", resp.Data["ttl"])
229	if ttl != "0" {
230		t.Fatalf("expected ttl of 0 but received %s", ttl)
231	}
232
233	maxTTL := fmt.Sprintf("%d", resp.Data["max_ttl"])
234	if maxTTL != "0" {
235		t.Fatalf("expected max_ttl of 0 but received %s", maxTTL)
236	}
237}
238
239func (e *testEnv) AddARNBasedRole(t *testing.T) {
240	req := &logical.Request{
241		Operation: logical.CreateOperation,
242		Path:      "role/role-based",
243		Storage:   e.Storage,
244		Data: map[string]interface{}{
245			"role_arn": e.RoleARN,
246		},
247	}
248	resp, err := e.Backend.HandleRequest(e.Context, req)
249	if err != nil || (resp != nil && resp.IsError()) {
250		t.Fatalf("bad: resp: %#v\nerr:%v", resp, err)
251	}
252	if resp != nil {
253		t.Fatal("expected nil response to represent a 204")
254	}
255}
256
257func (e *testEnv) ReadARNBasedRole(t *testing.T) {
258	req := &logical.Request{
259		Operation: logical.ReadOperation,
260		Path:      "role/role-based",
261		Storage:   e.Storage,
262	}
263	resp, err := e.Backend.HandleRequest(e.Context, req)
264	if err != nil || (resp != nil && resp.IsError()) {
265		t.Fatalf("bad: resp: %#v\nerr:%v", resp, err)
266	}
267	if resp == nil {
268		t.Fatal("expected a response")
269	}
270
271	if resp.Data["role_arn"] != e.RoleARN {
272		t.Fatalf("received unexpected role_arn of %s", resp.Data["role_arn"])
273	}
274
275	inlinePolicies := resp.Data["inline_policies"].([]*inlinePolicy)
276	if len(inlinePolicies) != 0 {
277		t.Fatalf("expected no inline policies but received %+v", inlinePolicies)
278	}
279
280	remotePolicies := resp.Data["remote_policies"].([]*remotePolicy)
281	if len(remotePolicies) != 0 {
282		t.Fatalf("expected no remote policies but received %+v", remotePolicies)
283	}
284
285	ttl := fmt.Sprintf("%d", resp.Data["ttl"])
286	if ttl != "0" {
287		t.Fatalf("expected ttl of 0 but received %s", ttl)
288	}
289
290	maxTTL := fmt.Sprintf("%d", resp.Data["max_ttl"])
291	if maxTTL != "0" {
292		t.Fatalf("expected max_ttl of 0 but received %s", maxTTL)
293	}
294}
295
296func (e *testEnv) UpdateARNBasedRole(t *testing.T) {
297	req := &logical.Request{
298		Operation: logical.UpdateOperation,
299		Path:      "role/role-based",
300		Storage:   e.Storage,
301		Data: map[string]interface{}{
302			"role_arn": "acs:ram::5138828231865461:role/notrustedactors",
303		},
304	}
305	resp, err := e.Backend.HandleRequest(e.Context, req)
306	if err != nil || (resp != nil && resp.IsError()) {
307		t.Fatalf("bad: resp: %#v\nerr:%v", resp, err)
308	}
309	if resp != nil {
310		t.Fatal("expected nil response to represent a 204")
311	}
312}
313
314func (e *testEnv) ReadUpdatedRole(t *testing.T) {
315	req := &logical.Request{
316		Operation: logical.ReadOperation,
317		Path:      "role/role-based",
318		Storage:   e.Storage,
319	}
320	resp, err := e.Backend.HandleRequest(e.Context, req)
321	if err != nil || (resp != nil && resp.IsError()) {
322		t.Fatalf("bad: resp: %#v\nerr:%v", resp, err)
323	}
324	if resp == nil {
325		t.Fatal("expected a response")
326	}
327
328	if resp.Data["role_arn"] != "acs:ram::5138828231865461:role/notrustedactors" {
329		t.Fatalf("received unexpected role_arn of %s", resp.Data["role_arn"])
330	}
331
332	inlinePolicies := resp.Data["inline_policies"].([]*inlinePolicy)
333	if len(inlinePolicies) != 0 {
334		t.Fatalf("expected no inline policies but received %+v", inlinePolicies)
335	}
336
337	remotePolicies := resp.Data["remote_policies"].([]*remotePolicy)
338	if len(remotePolicies) != 0 {
339		t.Fatalf("expected no remote policies but received %+v", remotePolicies)
340	}
341
342	ttl := fmt.Sprintf("%d", resp.Data["ttl"])
343	if ttl != "0" {
344		t.Fatalf("expected ttl of 100 but received %s", ttl)
345	}
346
347	maxTTL := fmt.Sprintf("%d", resp.Data["max_ttl"])
348	if maxTTL != "0" {
349		t.Fatalf("expected max_ttl of 1000 but received %s", maxTTL)
350	}
351}
352
353func (e *testEnv) ListTwoRoles(t *testing.T) {
354	req := &logical.Request{
355		Operation: logical.ListOperation,
356		Path:      "role",
357		Storage:   e.Storage,
358	}
359	resp, err := e.Backend.HandleRequest(e.Context, req)
360	if err != nil || (resp != nil && resp.IsError()) {
361		t.Fatalf("bad: resp: %#v\nerr:%v", resp, err)
362	}
363	if resp == nil {
364		t.Fatal("expected a response")
365	}
366	keys := resp.Data["keys"].([]string)
367	if len(keys) != 2 {
368		t.Fatalf("expected 2 keys but received %d", len(keys))
369	}
370	if keys[0] != "policy-based" {
371		t.Fatalf("expectied policy-based role name but received %s", keys[0])
372	}
373	if keys[1] != "role-based" {
374		t.Fatalf("expected role-based role name but received %s", keys[1])
375	}
376}
377
378func (e *testEnv) DeleteARNBasedRole(t *testing.T) {
379	req := &logical.Request{
380		Operation: logical.DeleteOperation,
381		Path:      "role/role-based",
382		Storage:   e.Storage,
383	}
384	resp, err := e.Backend.HandleRequest(e.Context, req)
385	if err != nil || (resp != nil && resp.IsError()) {
386		t.Fatalf("bad: resp: %#v\nerr:%v", resp, err)
387	}
388	if resp != nil {
389		t.Fatal("expected nil response to represent a 204")
390	}
391}
392
393func (e *testEnv) ListOneRole(t *testing.T) {
394	req := &logical.Request{
395		Operation: logical.ListOperation,
396		Path:      "role",
397		Storage:   e.Storage,
398	}
399	resp, err := e.Backend.HandleRequest(e.Context, req)
400	if err != nil || (resp != nil && resp.IsError()) {
401		t.Fatalf("bad: resp: %#v\nerr:%v", resp, err)
402	}
403	if resp == nil {
404		t.Fatal("expected a response")
405	}
406	keys := resp.Data["keys"].([]string)
407	if len(keys) != 1 {
408		t.Fatalf("expected 2 keys but received %d", len(keys))
409	}
410	if keys[0] != "policy-based" {
411		t.Fatalf("expectied policy-based role name but received %s", keys[0])
412	}
413}
414
415func (e *testEnv) ReadPolicyBasedCreds(t *testing.T) {
416	req := &logical.Request{
417		Operation: logical.ReadOperation,
418		Path:      "creds/policy-based",
419		Storage:   e.Storage,
420	}
421	resp, err := e.Backend.HandleRequest(e.Context, req)
422	if err != nil || (resp != nil && resp.IsError()) {
423		t.Fatalf("bad: resp: %#v\nerr:%v", resp, err)
424	}
425	if resp == nil {
426		t.Fatal("expected a response")
427	}
428
429	if resp.Data["access_key"] == "" {
430		t.Fatal("failed to receive access_key")
431	}
432	if resp.Data["secret_key"] == "" {
433		t.Fatal("failed to receive secret_key")
434	}
435	e.MostRecentSecret = resp.Secret
436}
437
438func (e *testEnv) RenewPolicyBasedCreds(t *testing.T) {
439	req := &logical.Request{
440		Operation: logical.RenewOperation,
441		Storage:   e.Storage,
442		Secret:    e.MostRecentSecret,
443		Data: map[string]interface{}{
444			"lease_id": "foo",
445		},
446	}
447	resp, err := e.Backend.HandleRequest(e.Context, req)
448	if err != nil || (resp != nil && resp.IsError()) {
449		t.Fatalf("bad: resp: %#v\nerr:%v", resp, err)
450	}
451	if resp == nil {
452		t.Fatal("expected a response")
453	}
454	if resp.Secret != e.MostRecentSecret {
455		t.Fatalf("expected %+v but got %+v", e.MostRecentSecret, resp.Secret)
456	}
457}
458
459func (e *testEnv) RevokePolicyBasedCreds(t *testing.T) {
460	req := &logical.Request{
461		Operation: logical.RevokeOperation,
462		Storage:   e.Storage,
463		Secret:    e.MostRecentSecret,
464		Data: map[string]interface{}{
465			"lease_id": "foo",
466		},
467	}
468	resp, err := e.Backend.HandleRequest(e.Context, req)
469	if err != nil || (resp != nil && resp.IsError()) {
470		t.Fatalf("bad: resp: %#v\nerr:%v", resp, err)
471	}
472	if resp != nil {
473		t.Fatal("expected nil response to represent a 204")
474	}
475}
476
477func (e *testEnv) ReadARNBasedCreds(t *testing.T) {
478	req := &logical.Request{
479		Operation: logical.ReadOperation,
480		Path:      "creds/role-based",
481		Storage:   e.Storage,
482	}
483	resp, err := e.Backend.HandleRequest(e.Context, req)
484	if err != nil || (resp != nil && resp.IsError()) {
485		t.Fatalf("bad: resp: %#v\nerr:%v", resp, err)
486	}
487	if resp == nil {
488		t.Fatal("expected a response")
489	}
490
491	if resp.Data["access_key"] == "" {
492		t.Fatal("received blank access_key")
493	}
494	if resp.Data["secret_key"] == "" {
495		t.Fatal("received blank secret_key")
496	}
497	if fmt.Sprintf("%s", resp.Data["expiration"]) == "" {
498		t.Fatal("received blank expiration")
499	}
500	if resp.Data["security_token"] == "" {
501		t.Fatal("received blank security_token")
502	}
503	e.MostRecentSecret = resp.Secret
504}
505
506func (e *testEnv) RenewARNBasedCreds(t *testing.T) {
507	req := &logical.Request{
508		Operation: logical.RenewOperation,
509		Storage:   e.Storage,
510		Secret:    e.MostRecentSecret,
511		Data: map[string]interface{}{
512			"lease_id": "foo",
513		},
514	}
515	resp, err := e.Backend.HandleRequest(e.Context, req)
516	if err != nil || (resp != nil && resp.IsError()) {
517		t.Fatalf("bad: resp: %#v\nerr:%v", resp, err)
518	}
519	if resp != nil {
520		t.Fatal("expected nil response to represent a 204")
521	}
522}
523
524func (e *testEnv) RevokeARNBasedCreds(t *testing.T) {
525	req := &logical.Request{
526		Operation: logical.RevokeOperation,
527		Storage:   e.Storage,
528		Secret:    e.MostRecentSecret,
529		Data: map[string]interface{}{
530			"lease_id": "foo",
531		},
532	}
533	resp, err := e.Backend.HandleRequest(e.Context, req)
534	if err != nil || (resp != nil && resp.IsError()) {
535		t.Fatalf("bad: resp: %#v\nerr:%v", resp, err)
536	}
537	if resp != nil {
538		t.Fatal("expected nil response to represent a 204")
539	}
540}
541
542const rawInlinePolicies = `[
543	{
544		"Statement": [{
545			"Action": ["rds:*"],
546			"Effect": "Allow",
547			"Resource": ["acs:oss:*:*:*"]
548		}],
549		"Version": "1"
550	},
551	{
552		"Statement": [{
553			"Action": ["oss:*"],
554			"Effect": "Allow",
555			"Resource": ["acs:oss:*:*:*"]
556		}],
557		"Version": "1"
558	}
559]
560`
561