1package http
2
3import (
4	"encoding/hex"
5	"encoding/json"
6	"fmt"
7	"net/http"
8	"reflect"
9	"testing"
10
11	"github.com/go-test/deep"
12	"github.com/hashicorp/vault/vault"
13)
14
15// Test to check if the API errors out when wrong number of PGP keys are
16// supplied for rekey
17func TestSysRekey_Init_pgpKeysEntriesForRekey(t *testing.T) {
18	core, _, token := vault.TestCoreUnsealed(t)
19	ln, addr := TestServer(t, core)
20	defer ln.Close()
21	TestServerAuth(t, addr, token)
22
23	resp := testHttpPut(t, token, addr+"/v1/sys/rekey/init", map[string]interface{}{
24		"secret_shares":    5,
25		"secret_threshold": 3,
26		"pgp_keys":         []string{"pgpkey1"},
27	})
28	testResponseStatus(t, resp, 400)
29}
30
31func TestSysRekey_Init_Status(t *testing.T) {
32	t.Run("status-barrier-default", func(t *testing.T) {
33		core, _, token := vault.TestCoreUnsealed(t)
34		ln, addr := TestServer(t, core)
35		defer ln.Close()
36		TestServerAuth(t, addr, token)
37
38		resp, err := http.Get(addr + "/v1/sys/rekey/init")
39		if err != nil {
40			t.Fatalf("err: %s", err)
41		}
42
43		var actual map[string]interface{}
44		expected := map[string]interface{}{
45			"started":               false,
46			"t":                     json.Number("0"),
47			"n":                     json.Number("0"),
48			"progress":              json.Number("0"),
49			"required":              json.Number("3"),
50			"pgp_fingerprints":      interface{}(nil),
51			"backup":                false,
52			"nonce":                 "",
53			"verification_required": false,
54		}
55		testResponseStatus(t, resp, 200)
56		testResponseBody(t, resp, &actual)
57		if !reflect.DeepEqual(actual, expected) {
58			t.Fatalf("\nexpected: %#v\nactual: %#v", expected, actual)
59		}
60	})
61}
62
63func TestSysRekey_Init_Setup(t *testing.T) {
64	t.Run("init-barrier-barrier-key", func(t *testing.T) {
65		core, _, token := vault.TestCoreUnsealed(t)
66		ln, addr := TestServer(t, core)
67		defer ln.Close()
68		TestServerAuth(t, addr, token)
69
70		// Start rekey
71		resp := testHttpPut(t, token, addr+"/v1/sys/rekey/init", map[string]interface{}{
72			"secret_shares":    5,
73			"secret_threshold": 3,
74		})
75		testResponseStatus(t, resp, 200)
76
77		var actual map[string]interface{}
78		expected := map[string]interface{}{
79			"started":               true,
80			"t":                     json.Number("3"),
81			"n":                     json.Number("5"),
82			"progress":              json.Number("0"),
83			"required":              json.Number("3"),
84			"pgp_fingerprints":      interface{}(nil),
85			"backup":                false,
86			"verification_required": false,
87		}
88		testResponseStatus(t, resp, 200)
89		testResponseBody(t, resp, &actual)
90		if actual["nonce"].(string) == "" {
91			t.Fatalf("nonce was empty")
92		}
93		expected["nonce"] = actual["nonce"]
94		if diff := deep.Equal(actual, expected); diff != nil {
95			t.Fatal(diff)
96		}
97
98		// Get rekey status
99		resp = testHttpGet(t, token, addr+"/v1/sys/rekey/init")
100
101		actual = map[string]interface{}{}
102		expected = map[string]interface{}{
103			"started":               true,
104			"t":                     json.Number("3"),
105			"n":                     json.Number("5"),
106			"progress":              json.Number("0"),
107			"required":              json.Number("3"),
108			"pgp_fingerprints":      interface{}(nil),
109			"backup":                false,
110			"verification_required": false,
111		}
112		testResponseStatus(t, resp, 200)
113		testResponseBody(t, resp, &actual)
114		if actual["nonce"].(string) == "" {
115			t.Fatalf("nonce was empty")
116		}
117		if actual["nonce"].(string) == "" {
118			t.Fatalf("nonce was empty")
119		}
120		expected["nonce"] = actual["nonce"]
121		if !reflect.DeepEqual(actual, expected) {
122			t.Fatalf("\nexpected: %#v\nactual: %#v", expected, actual)
123		}
124	})
125}
126
127func TestSysRekey_Init_Cancel(t *testing.T) {
128	t.Run("cancel-barrier-barrier-key", func(t *testing.T) {
129		core, _, token := vault.TestCoreUnsealed(t)
130		ln, addr := TestServer(t, core)
131		defer ln.Close()
132		TestServerAuth(t, addr, token)
133
134		resp := testHttpPut(t, token, addr+"/v1/sys/rekey/init", map[string]interface{}{
135			"secret_shares":    5,
136			"secret_threshold": 3,
137		})
138		testResponseStatus(t, resp, 200)
139
140		resp = testHttpDelete(t, token, addr+"/v1/sys/rekey/init")
141		testResponseStatus(t, resp, 204)
142
143		resp, err := http.Get(addr + "/v1/sys/rekey/init")
144		if err != nil {
145			t.Fatalf("err: %s", err)
146		}
147
148		var actual map[string]interface{}
149		expected := map[string]interface{}{
150			"started":               false,
151			"t":                     json.Number("0"),
152			"n":                     json.Number("0"),
153			"progress":              json.Number("0"),
154			"required":              json.Number("3"),
155			"pgp_fingerprints":      interface{}(nil),
156			"backup":                false,
157			"nonce":                 "",
158			"verification_required": false,
159		}
160		testResponseStatus(t, resp, 200)
161		testResponseBody(t, resp, &actual)
162		if !reflect.DeepEqual(actual, expected) {
163			t.Fatalf("\nexpected: %#v\nactual: %#v", expected, actual)
164		}
165	})
166}
167
168func TestSysRekey_badKey(t *testing.T) {
169	core, _, token := vault.TestCoreUnsealed(t)
170	ln, addr := TestServer(t, core)
171	defer ln.Close()
172	TestServerAuth(t, addr, token)
173
174	resp := testHttpPut(t, token, addr+"/v1/sys/rekey/update", map[string]interface{}{
175		"key": "0123",
176	})
177	testResponseStatus(t, resp, 400)
178}
179
180func TestSysRekey_Update(t *testing.T) {
181	t.Run("rekey-barrier-barrier-key", func(t *testing.T) {
182		core, keys, token := vault.TestCoreUnsealed(t)
183		ln, addr := TestServer(t, core)
184		defer ln.Close()
185		TestServerAuth(t, addr, token)
186
187		resp := testHttpPut(t, token, addr+"/v1/sys/rekey/init", map[string]interface{}{
188			"secret_shares":    5,
189			"secret_threshold": 3,
190		})
191		var rekeyStatus map[string]interface{}
192		testResponseStatus(t, resp, 200)
193		testResponseBody(t, resp, &rekeyStatus)
194
195		var actual map[string]interface{}
196		var expected map[string]interface{}
197
198		for i, key := range keys {
199			resp = testHttpPut(t, token, addr+"/v1/sys/rekey/update", map[string]interface{}{
200				"nonce": rekeyStatus["nonce"].(string),
201				"key":   hex.EncodeToString(key),
202			})
203
204			actual = map[string]interface{}{}
205			expected = map[string]interface{}{
206				"started":               true,
207				"nonce":                 rekeyStatus["nonce"].(string),
208				"backup":                false,
209				"pgp_fingerprints":      interface{}(nil),
210				"required":              json.Number("3"),
211				"t":                     json.Number("3"),
212				"n":                     json.Number("5"),
213				"progress":              json.Number(fmt.Sprintf("%d", i+1)),
214				"verification_required": false,
215			}
216			testResponseStatus(t, resp, 200)
217			testResponseBody(t, resp, &actual)
218
219			if i+1 == len(keys) {
220				delete(expected, "started")
221				delete(expected, "required")
222				delete(expected, "t")
223				delete(expected, "n")
224				delete(expected, "progress")
225				expected["complete"] = true
226				expected["keys"] = actual["keys"]
227				expected["keys_base64"] = actual["keys_base64"]
228			}
229
230			if i+1 < len(keys) && (actual["nonce"] == nil || actual["nonce"].(string) == "") {
231				t.Fatalf("expected a nonce, i is %d, actual is %#v", i, actual)
232			}
233
234			if !reflect.DeepEqual(actual, expected) {
235				t.Fatalf("\nexpected: \n%#v\nactual: \n%#v", expected, actual)
236			}
237		}
238
239		retKeys := actual["keys"].([]interface{})
240		if len(retKeys) != 5 {
241			t.Fatalf("bad: %#v", retKeys)
242		}
243		keysB64 := actual["keys_base64"].([]interface{})
244		if len(keysB64) != 5 {
245			t.Fatalf("bad: %#v", keysB64)
246		}
247	})
248}
249
250func TestSysRekey_ReInitUpdate(t *testing.T) {
251	core, keys, token := vault.TestCoreUnsealed(t)
252	ln, addr := TestServer(t, core)
253	defer ln.Close()
254	TestServerAuth(t, addr, token)
255
256	resp := testHttpPut(t, token, addr+"/v1/sys/rekey/init", map[string]interface{}{
257		"secret_shares":    5,
258		"secret_threshold": 3,
259	})
260	testResponseStatus(t, resp, 200)
261
262	resp = testHttpDelete(t, token, addr+"/v1/sys/rekey/init")
263	testResponseStatus(t, resp, 204)
264
265	resp = testHttpPut(t, token, addr+"/v1/sys/rekey/init", map[string]interface{}{
266		"secret_shares":    5,
267		"secret_threshold": 3,
268	})
269	testResponseStatus(t, resp, 200)
270
271	resp = testHttpPut(t, token, addr+"/v1/sys/rekey/update", map[string]interface{}{
272		"key": hex.EncodeToString(keys[0]),
273	})
274
275	testResponseStatus(t, resp, 400)
276}
277