1package approle
2
3import (
4	"context"
5	"strings"
6	"testing"
7
8	"github.com/hashicorp/vault/sdk/logical"
9)
10
11func createBackendWithStorage(t *testing.T) (*backend, logical.Storage) {
12	config := logical.TestBackendConfig()
13	config.StorageView = &logical.InmemStorage{}
14
15	b, err := Backend(config)
16	if err != nil {
17		t.Fatal(err)
18	}
19	if b == nil {
20		t.Fatalf("failed to create backend")
21	}
22	err = b.Backend.Setup(context.Background(), config)
23	if err != nil {
24		t.Fatal(err)
25	}
26	return b, config.StorageView
27}
28
29func TestAppRole_RoleNameCaseSensitivity(t *testing.T) {
30	testFunc := func(t *testing.T, roleName string) {
31		var resp *logical.Response
32		var err error
33		b, s := createBackendWithStorage(t)
34
35		// Create the role
36		resp, err = b.HandleRequest(context.Background(), &logical.Request{
37			Path:      "role/" + roleName,
38			Operation: logical.CreateOperation,
39			Storage:   s,
40		})
41		if err != nil || (resp != nil && resp.IsError()) {
42			t.Fatalf("bad: resp: %#v\nerr:%v", resp, err)
43		}
44
45		// Get the role-id
46		resp, err = b.HandleRequest(context.Background(), &logical.Request{
47			Path:      "role/" + roleName + "/role-id",
48			Operation: logical.ReadOperation,
49			Storage:   s,
50		})
51		if err != nil || (resp != nil && resp.IsError()) {
52			t.Fatalf("bad: resp: %#v\nerr: %v", resp, err)
53		}
54		roleID := resp.Data["role_id"]
55
56		// Create a secret-id
57		resp, err = b.HandleRequest(context.Background(), &logical.Request{
58			Path:      "role/" + roleName + "/secret-id",
59			Operation: logical.UpdateOperation,
60			Storage:   s,
61		})
62		if err != nil || (resp != nil && resp.IsError()) {
63			t.Fatalf("bad: resp: %#v\nerr: %v", resp, err)
64		}
65		secretID := resp.Data["secret_id"]
66		secretIDAccessor := resp.Data["secret_id_accessor"]
67
68		// Ensure login works
69		resp, err = b.HandleRequest(context.Background(), &logical.Request{
70			Path:      "login",
71			Operation: logical.UpdateOperation,
72			Data: map[string]interface{}{
73				"role_id":   roleID,
74				"secret_id": secretID,
75			},
76			Storage: s,
77		})
78		if err != nil || (resp != nil && resp.IsError()) {
79			t.Fatalf("bad: resp: %#v\nerr: %v", resp, err)
80		}
81		if resp.Auth == nil {
82			t.Fatalf("failed to perform login")
83		}
84
85		// Destroy secret ID accessor
86		resp, err = b.HandleRequest(context.Background(), &logical.Request{
87			Path:      "role/" + roleName + "/secret-id-accessor/destroy",
88			Operation: logical.UpdateOperation,
89			Storage:   s,
90			Data: map[string]interface{}{
91				"secret_id_accessor": secretIDAccessor,
92			},
93		})
94		if err != nil || (resp != nil && resp.IsError()) {
95			t.Fatalf("bad: resp: %#v\nerr: %v", resp, err)
96		}
97
98		// Login again using the accessor's corresponding secret ID should fail
99		resp, err = b.HandleRequest(context.Background(), &logical.Request{
100			Path:      "login",
101			Operation: logical.UpdateOperation,
102			Data: map[string]interface{}{
103				"role_id":   roleID,
104				"secret_id": secretID,
105			},
106			Storage: s,
107		})
108		if err != nil {
109			t.Fatal(err)
110		}
111		if resp == nil || !resp.IsError() {
112			t.Fatalf("expected error due to invalid secret ID")
113		}
114
115		// Generate another secret ID
116		resp, err = b.HandleRequest(context.Background(), &logical.Request{
117			Path:      "role/" + roleName + "/secret-id",
118			Operation: logical.UpdateOperation,
119			Storage:   s,
120		})
121		if err != nil || (resp != nil && resp.IsError()) {
122			t.Fatalf("bad: resp: %#v\nerr: %v", resp, err)
123		}
124		secretID = resp.Data["secret_id"]
125		secretIDAccessor = resp.Data["secret_id_accessor"]
126
127		// Ensure login works
128		resp, err = b.HandleRequest(context.Background(), &logical.Request{
129			Path:      "login",
130			Operation: logical.UpdateOperation,
131			Data: map[string]interface{}{
132				"role_id":   roleID,
133				"secret_id": secretID,
134			},
135			Storage: s,
136		})
137		if err != nil || (resp != nil && resp.IsError()) {
138			t.Fatalf("bad: resp: %#v\nerr: %v", resp, err)
139		}
140		if resp.Auth == nil {
141			t.Fatalf("failed to perform login")
142		}
143
144		// Destroy the secret ID
145		resp, err = b.HandleRequest(context.Background(), &logical.Request{
146			Path:      "role/" + roleName + "/secret-id/destroy",
147			Operation: logical.UpdateOperation,
148			Storage:   s,
149			Data: map[string]interface{}{
150				"secret_id": secretID,
151			},
152		})
153		if err != nil || (resp != nil && resp.IsError()) {
154			t.Fatalf("bad: resp: %#v\nerr: %v", resp, err)
155		}
156
157		// Login again using the same secret ID should fail
158		resp, err = b.HandleRequest(context.Background(), &logical.Request{
159			Path:      "login",
160			Operation: logical.UpdateOperation,
161			Data: map[string]interface{}{
162				"role_id":   roleID,
163				"secret_id": secretID,
164			},
165			Storage: s,
166		})
167		if err != nil {
168			t.Fatal(err)
169		}
170		if resp == nil || !resp.IsError() {
171			t.Fatalf("expected error due to invalid secret ID")
172		}
173
174		// Generate another secret ID
175		resp, err = b.HandleRequest(context.Background(), &logical.Request{
176			Path:      "role/" + roleName + "/secret-id",
177			Operation: logical.UpdateOperation,
178			Storage:   s,
179		})
180		if err != nil || (resp != nil && resp.IsError()) {
181			t.Fatalf("bad: resp: %#v\nerr: %v", resp, err)
182		}
183		secretID = resp.Data["secret_id"]
184		secretIDAccessor = resp.Data["secret_id_accessor"]
185
186		// Ensure login works
187		resp, err = b.HandleRequest(context.Background(), &logical.Request{
188			Path:      "login",
189			Operation: logical.UpdateOperation,
190			Data: map[string]interface{}{
191				"role_id":   roleID,
192				"secret_id": secretID,
193			},
194			Storage: s,
195		})
196		if err != nil || (resp != nil && resp.IsError()) {
197			t.Fatalf("bad: resp: %#v\nerr: %v", resp, err)
198		}
199		if resp.Auth == nil {
200			t.Fatalf("failed to perform login")
201		}
202
203		// Destroy the secret ID using lower cased role name
204		resp, err = b.HandleRequest(context.Background(), &logical.Request{
205			Path:      "role/" + strings.ToLower(roleName) + "/secret-id/destroy",
206			Operation: logical.UpdateOperation,
207			Storage:   s,
208			Data: map[string]interface{}{
209				"secret_id": secretID,
210			},
211		})
212		if err != nil || (resp != nil && resp.IsError()) {
213			t.Fatalf("bad: resp: %#v\nerr: %v", resp, err)
214		}
215
216		// Login again using the same secret ID should fail
217		resp, err = b.HandleRequest(context.Background(), &logical.Request{
218			Path:      "login",
219			Operation: logical.UpdateOperation,
220			Data: map[string]interface{}{
221				"role_id":   roleID,
222				"secret_id": secretID,
223			},
224			Storage: s,
225		})
226		if err != nil {
227			t.Fatal(err)
228		}
229		if resp == nil || !resp.IsError() {
230			t.Fatalf("expected error due to invalid secret ID")
231		}
232
233		// Generate another secret ID
234		resp, err = b.HandleRequest(context.Background(), &logical.Request{
235			Path:      "role/" + roleName + "/secret-id",
236			Operation: logical.UpdateOperation,
237			Storage:   s,
238		})
239		if err != nil || (resp != nil && resp.IsError()) {
240			t.Fatalf("bad: resp: %#v\nerr: %v", resp, err)
241		}
242		secretID = resp.Data["secret_id"]
243		secretIDAccessor = resp.Data["secret_id_accessor"]
244
245		// Ensure login works
246		resp, err = b.HandleRequest(context.Background(), &logical.Request{
247			Path:      "login",
248			Operation: logical.UpdateOperation,
249			Data: map[string]interface{}{
250				"role_id":   roleID,
251				"secret_id": secretID,
252			},
253			Storage: s,
254		})
255		if err != nil || (resp != nil && resp.IsError()) {
256			t.Fatalf("bad: resp: %#v\nerr: %v", resp, err)
257		}
258		if resp.Auth == nil {
259			t.Fatalf("failed to perform login")
260		}
261
262		// Destroy the secret ID using upper cased role name
263		resp, err = b.HandleRequest(context.Background(), &logical.Request{
264			Path:      "role/" + strings.ToUpper(roleName) + "/secret-id/destroy",
265			Operation: logical.UpdateOperation,
266			Storage:   s,
267			Data: map[string]interface{}{
268				"secret_id": secretID,
269			},
270		})
271		if err != nil || (resp != nil && resp.IsError()) {
272			t.Fatalf("bad: resp: %#v\nerr: %v", resp, err)
273		}
274
275		// Login again using the same secret ID should fail
276		resp, err = b.HandleRequest(context.Background(), &logical.Request{
277			Path:      "login",
278			Operation: logical.UpdateOperation,
279			Data: map[string]interface{}{
280				"role_id":   roleID,
281				"secret_id": secretID,
282			},
283			Storage: s,
284		})
285		if err != nil {
286			t.Fatal(err)
287		}
288		if resp == nil || !resp.IsError() {
289			t.Fatalf("expected error due to invalid secret ID")
290		}
291
292		// Generate another secret ID
293		resp, err = b.HandleRequest(context.Background(), &logical.Request{
294			Path:      "role/" + roleName + "/secret-id",
295			Operation: logical.UpdateOperation,
296			Storage:   s,
297		})
298		if err != nil || (resp != nil && resp.IsError()) {
299			t.Fatalf("bad: resp: %#v\nerr: %v", resp, err)
300		}
301		secretID = resp.Data["secret_id"]
302		secretIDAccessor = resp.Data["secret_id_accessor"]
303
304		// Ensure login works
305		resp, err = b.HandleRequest(context.Background(), &logical.Request{
306			Path:      "login",
307			Operation: logical.UpdateOperation,
308			Data: map[string]interface{}{
309				"role_id":   roleID,
310				"secret_id": secretID,
311			},
312			Storage: s,
313		})
314		if err != nil || (resp != nil && resp.IsError()) {
315			t.Fatalf("bad: resp: %#v\nerr: %v", resp, err)
316		}
317		if resp.Auth == nil {
318			t.Fatalf("failed to perform login")
319		}
320
321		// Destroy the secret ID using mixed case name
322		resp, err = b.HandleRequest(context.Background(), &logical.Request{
323			Path:      "role/saMpleRolEnaMe/secret-id/destroy",
324			Operation: logical.UpdateOperation,
325			Storage:   s,
326			Data: map[string]interface{}{
327				"secret_id": secretID,
328			},
329		})
330		if err != nil || (resp != nil && resp.IsError()) {
331			t.Fatalf("bad: resp: %#v\nerr: %v", resp, err)
332		}
333
334		// Login again using the same secret ID should fail
335		resp, err = b.HandleRequest(context.Background(), &logical.Request{
336			Path:      "login",
337			Operation: logical.UpdateOperation,
338			Data: map[string]interface{}{
339				"role_id":   roleID,
340				"secret_id": secretID,
341			},
342			Storage: s,
343		})
344		if err != nil {
345			t.Fatal(err)
346		}
347		if resp == nil || !resp.IsError() {
348			t.Fatalf("expected error due to invalid secret ID")
349		}
350	}
351
352	// Lower case role name
353	testFunc(t, "samplerolename")
354	// Upper case role name
355	testFunc(t, "SAMPLEROLENAME")
356	// Mixed case role name
357	testFunc(t, "SampleRoleName")
358}
359