vault-rails 0.3.2 → 0.7.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -42,12 +42,22 @@ describe Vault::Rails do
42
42
 
43
43
  it "allows attributes to be unset" do
44
44
  person = Person.create!(ssn: "123-45-6789")
45
- person.update_attributes!(ssn: nil)
45
+ person.update!(ssn: nil)
46
46
  person.reload
47
47
 
48
48
  expect(person.ssn).to be(nil)
49
49
  end
50
50
 
51
+ it "allows dirty attributes to be unset" do
52
+ person = Person.create!(ssn: "123-45-6789")
53
+ person.ssn = nil
54
+ expect(person.ssn).to be_nil
55
+
56
+ person2 = Person.create!(ssn: "123-45-6789")
57
+ person2.assign_attributes(ssn: nil)
58
+ expect(person2.ssn).to be_nil
59
+ end
60
+
51
61
  it "allows saving without validations" do
52
62
  person = Person.new(ssn: "123-456-7890")
53
63
  person.save(validate: false)
@@ -57,7 +67,7 @@ describe Vault::Rails do
57
67
  it "allows attributes to be unset after reload" do
58
68
  person = Person.create!(ssn: "123-45-6789")
59
69
  person.reload
60
- person.update_attributes!(ssn: nil)
70
+ person.update!(ssn: nil)
61
71
  person.reload
62
72
 
63
73
  expect(person.ssn).to be(nil)
@@ -65,10 +75,20 @@ describe Vault::Rails do
65
75
 
66
76
  it "allows attributes to be blank" do
67
77
  person = Person.create!(ssn: "123-45-6789")
68
- person.update_attributes!(ssn: "")
78
+ person.update!(ssn: "")
69
79
  person.reload
70
80
 
71
81
  expect(person.ssn).to eq("")
82
+ expect(person.ssn_encrypted).to eq("")
83
+ end
84
+
85
+ it "allows attributes to be null" do
86
+ person = Person.create!(ssn: "123-45-6789")
87
+ person.update!(ssn: nil)
88
+ person.reload
89
+
90
+ expect(person.ssn).to eq(nil)
91
+ expect(person.ssn_encrypted).to eq(nil)
72
92
  end
73
93
 
74
94
  it "reloads instance variables on reload" do
@@ -87,6 +107,18 @@ describe Vault::Rails do
87
107
  person.name = "Cinderella"
88
108
  person.save!
89
109
  end
110
+
111
+ it "does not register a Vault attribute as necessarily being backed by a column" do
112
+ expect(Person.attribute_names).to include("ssn")
113
+ expect(Person.column_names).not_to include("ssn")
114
+ end
115
+
116
+ it "does not reload encrypted attributes on destroy" do
117
+ person = Person.create!(ssn: "123-45-6789")
118
+
119
+ expect(Vault::Rails).to_not receive(:decrypt)
120
+ person.destroy
121
+ end
90
122
  end
91
123
 
92
124
  context "lazy decrypt" do
@@ -130,16 +162,33 @@ describe Vault::Rails do
130
162
  expect(person.ssn_changed?).to be(true)
131
163
  expect(person.ssn_change).to eq(["123-45-6789", "111-11-1111"])
132
164
  expect(person.ssn_was).to eq("123-45-6789")
165
+
166
+ person.assign_attributes(ssn: "222-22-2222")
167
+
168
+ expect(person.ssn_changed?).to be(true)
169
+ expect(person.ssn_change).to eq(["123-45-6789", "222-22-2222"])
170
+ expect(person.ssn_was).to eq("123-45-6789")
133
171
  end
134
172
 
135
173
  it "allows attributes to be unset" do
136
174
  person = LazyPerson.create!(ssn: "123-45-6789")
137
- person.update_attributes!(ssn: nil)
175
+ person.update!(ssn: nil)
138
176
  person.reload
139
177
 
140
178
  expect(person.ssn).to be(nil)
141
179
  end
142
180
 
181
+ it "allows dirty attributes to be unset" do
182
+ person = LazyPerson.create!(ssn: "123-45-6789")
183
+ person.ssn = nil
184
+ expect(person.ssn).to be_nil
185
+
186
+ person2 = LazyPerson.create!(ssn: "123-45-6789")
187
+ person2.assign_attributes(ssn: nil)
188
+ expect(person2.ssn).to be_nil
189
+ end
190
+
191
+
143
192
  it "allows saving without validations" do
144
193
  person = LazyPerson.new(ssn: "123-456-7890")
145
194
  expect(person.save(validate: false)).to be(true)
@@ -149,7 +198,7 @@ describe Vault::Rails do
149
198
  it "allows attributes to be unset after reload" do
150
199
  person = LazyPerson.create!(ssn: "123-45-6789")
151
200
  person.reload
152
- person.update_attributes!(ssn: nil)
201
+ person.update!(ssn: nil)
153
202
  person.reload
154
203
 
155
204
  expect(person.ssn).to be(nil)
@@ -157,7 +206,7 @@ describe Vault::Rails do
157
206
 
158
207
  it "allows attributes to be blank" do
159
208
  person = LazyPerson.create!(ssn: "123-45-6789")
160
- person.update_attributes!(ssn: "")
209
+ person.update!(ssn: "")
161
210
  person.reload
162
211
 
163
212
  expect(person.ssn).to eq("")
@@ -180,6 +229,145 @@ describe Vault::Rails do
180
229
  person.name = "Cinderella"
181
230
  person.save!
182
231
  end
232
+
233
+ it "allows attributes to be accessed after a destroy" do
234
+ person = LazyPerson.create!(ssn: "123-45-6789")
235
+
236
+ person.destroy
237
+ expect { person.ssn }.not_to raise_error
238
+ end
239
+ end
240
+
241
+ context "lazy single decrypt" do
242
+ before(:all) do
243
+ Vault::Rails.logical.write("transit/keys/dummy_people_ssn")
244
+ end
245
+
246
+ it "encrypts attributes" do
247
+ person = LazySinglePerson.create!(ssn: "123-45-6789")
248
+ expect(person.ssn_encrypted.length).to eq(61)
249
+ expect(person.ssn_encrypted).to start_with("vault:v1:")
250
+ expect(person.ssn_encrypted.encoding).to eq(Encoding::UTF_8)
251
+ end
252
+
253
+ it "decrypts attributes" do
254
+ person = LazySinglePerson.create!(ssn: "123-45-6789")
255
+ person.reload
256
+
257
+ expect(person.ssn).to eq("123-45-6789")
258
+ expect(person.ssn.encoding).to eq(Encoding::UTF_8)
259
+ end
260
+
261
+ it "does not decrypt on initialization" do
262
+ person = LazySinglePerson.create!(ssn: "123-45-6789")
263
+ person.reload
264
+
265
+ p2 = LazySinglePerson.find(person.id)
266
+
267
+ expect(p2.instance_variable_get("@ssn")).to eq(nil)
268
+ expect(p2.ssn).to eq("123-45-6789")
269
+ end
270
+
271
+ it "does not decrypt all attributes on single read" do
272
+ person = LazySinglePerson.create!(ssn: "123-45-6789")
273
+ person.update!(credit_card: "abcd-efgh-hijk-lmno")
274
+ expect(person.credit_card).to eq("abcd-efgh-hijk-lmno")
275
+
276
+ person.reload
277
+
278
+ p2 = LazySinglePerson.find(person.id)
279
+
280
+ expect(p2.instance_variable_get("@ssn")).to eq(nil)
281
+ expect(p2.ssn).to eq("123-45-6789")
282
+ expect(p2.instance_variable_get("@credit_card")).to eq(nil)
283
+ expect(p2.credit_card).to eq("abcd-efgh-hijk-lmno")
284
+ end
285
+
286
+ it "does not decrypt all attributes on single write" do
287
+ person = LazySinglePerson.create!(ssn: "123-45-6789")
288
+ person.update!(credit_card: "abcd-efgh-hijk-lmno")
289
+ expect(person.credit_card).to eq("abcd-efgh-hijk-lmno")
290
+
291
+ person.reload
292
+
293
+ p2 = LazySinglePerson.find(person.id)
294
+
295
+ expect(p2.instance_variable_get("@ssn")).to eq(nil)
296
+ expect(p2.ssn).to eq("123-45-6789")
297
+ person.ssn = "111-11-1111"
298
+ expect(p2.instance_variable_get("@credit_card")).to eq(nil)
299
+ expect(p2.credit_card).to eq("abcd-efgh-hijk-lmno")
300
+ end
301
+
302
+ it "tracks dirty attributes" do
303
+ person = LazySinglePerson.create!(ssn: "123-45-6789")
304
+
305
+ expect(person.ssn_changed?).to be(false)
306
+ expect(person.ssn_change).to be(nil)
307
+ expect(person.ssn_was).to eq("123-45-6789")
308
+
309
+ person.ssn = "111-11-1111"
310
+
311
+ expect(person.ssn_changed?).to be(true)
312
+ expect(person.ssn_change).to eq(["123-45-6789", "111-11-1111"])
313
+ expect(person.ssn_was).to eq("123-45-6789")
314
+ end
315
+
316
+ it "allows attributes to be unset" do
317
+ person = LazySinglePerson.create!(ssn: "123-45-6789")
318
+ person.update!(ssn: nil)
319
+ person.reload
320
+
321
+ expect(person.ssn).to be(nil)
322
+ end
323
+
324
+ it "allows saving without validations" do
325
+ person = LazySinglePerson.new(ssn: "123-456-7890")
326
+ expect(person.save(validate: false)).to be(true)
327
+ expect(person.ssn_encrypted).to match("vault:")
328
+ end
329
+
330
+ it "allows attributes to be unset after reload" do
331
+ person = LazySinglePerson.create!(ssn: "123-45-6789")
332
+ person.reload
333
+ person.update!(ssn: nil)
334
+ person.reload
335
+
336
+ expect(person.ssn).to be(nil)
337
+ end
338
+
339
+ it "allows attributes to be blank" do
340
+ person = LazySinglePerson.create!(ssn: "123-45-6789")
341
+ person.update!(ssn: "")
342
+ person.reload
343
+
344
+ expect(person.ssn).to eq("")
345
+ end
346
+
347
+ it "reloads instance variables on reload" do
348
+ person = LazySinglePerson.create!(ssn: "123-45-6789")
349
+ expect(person.instance_variable_get(:@ssn)).to eq("123-45-6789")
350
+
351
+ person.ssn = "111-11-1111"
352
+ person.reload
353
+
354
+ expect(person.ssn).to eq("123-45-6789")
355
+ end
356
+
357
+ it "does not try to encrypt unchanged attributes" do
358
+ person = LazySinglePerson.create!(ssn: "123-45-6789")
359
+
360
+ expect(Vault::Rails).to_not receive(:encrypt)
361
+ person.name = "Cinderella"
362
+ person.save!
363
+ end
364
+
365
+ it "allows attributes to be accessed after a destroy" do
366
+ person = LazyPerson.create!(ssn: "123-45-6789")
367
+
368
+ person.destroy
369
+ expect { person.ssn }.not_to raise_error
370
+ end
183
371
  end
184
372
 
185
373
  context "with custom options" do
@@ -218,7 +406,7 @@ describe Vault::Rails do
218
406
 
219
407
  it "allows attributes to be unset" do
220
408
  person = Person.create!(credit_card: "1234567890111213")
221
- person.update_attributes!(credit_card: nil)
409
+ person.update!(credit_card: nil)
222
410
  person.reload
223
411
 
224
412
  expect(person.credit_card).to be(nil)
@@ -226,7 +414,7 @@ describe Vault::Rails do
226
414
 
227
415
  it "allows attributes to be blank" do
228
416
  person = Person.create!(credit_card: "1234567890111213")
229
- person.update_attributes!(credit_card: "")
417
+ person.update!(credit_card: "")
230
418
  person.reload
231
419
 
232
420
  expect(person.credit_card).to eq("")
@@ -269,7 +457,7 @@ describe Vault::Rails do
269
457
 
270
458
  it "allows attributes to be unset" do
271
459
  person = Person.create!(non_ascii: "dás ümlaut")
272
- person.update_attributes!(non_ascii: nil)
460
+ person.update!(non_ascii: nil)
273
461
  person.reload
274
462
 
275
463
  expect(person.non_ascii).to be(nil)
@@ -277,26 +465,80 @@ describe Vault::Rails do
277
465
 
278
466
  it "allows attributes to be blank" do
279
467
  person = Person.create!(non_ascii: "dás ümlaut")
280
- person.update_attributes!(non_ascii: "")
468
+ person.update!(non_ascii: "")
281
469
  person.reload
282
470
 
283
471
  expect(person.non_ascii).to eq("")
284
472
  end
285
473
  end
286
474
 
475
+ context "with a default" do
476
+ %i[new create].each do |creation_method|
477
+ context "on #{creation_method}" do
478
+ context "without an initial attribute" do
479
+ it "sets the default" do
480
+ person = Person.public_send(creation_method)
481
+ expect(person.default).to eq("abc123")
482
+ person.save!
483
+ person.reload
484
+ expect(person.default).to eq("abc123")
485
+ end
486
+ end
487
+
488
+ context "with an initial attribute" do
489
+ it "does not set the default" do
490
+ person = Person.public_send(creation_method, default: "another")
491
+ expect(person.default).to eq("another")
492
+ person.save!
493
+ person.reload
494
+ expect(person.default).to eq("another")
495
+ end
496
+ end
497
+ end
498
+ end
499
+ end
500
+
501
+ context "with a default and serializer" do
502
+ %i[new create].each do |creation_method|
503
+ context "on #{creation_method}" do
504
+ context "without an initial attribute" do
505
+ it "sets the default" do
506
+ person = Person.public_send(creation_method)
507
+ expect(person.default_with_serializer).to eq({})
508
+ person.save!
509
+ person.reload
510
+ expect(person.default_with_serializer).to eq({})
511
+ end
512
+ end
513
+
514
+ context "with an initial attribute" do
515
+ it "does not set the default" do
516
+ person = Person.public_send(
517
+ creation_method,
518
+ default_with_serializer: { "foo" => "bar" }
519
+ )
520
+
521
+ expect(person.default_with_serializer).to eq({ "foo" => "bar" })
522
+ person.save!
523
+ person.reload
524
+ expect(person.default_with_serializer).to eq({ "foo" => "bar" })
525
+ end
526
+ end
527
+ end
528
+ end
529
+ end
530
+
287
531
  context "with the :json serializer" do
288
532
  before(:all) do
289
533
  Vault::Rails.logical.write("transit/keys/dummy_people_details")
290
534
  end
291
535
 
292
- it "has a default value for unpersisted records" do
536
+ it "does not default to a hash" do
293
537
  person = Person.new
294
- expect(person.details).to eq({})
295
- end
296
-
297
- it "has a default value for persisted records" do
298
- person = Person.create!
299
- expect(person.details).to eq({})
538
+ expect(person.details).to eq(nil)
539
+ person.save!
540
+ person.reload
541
+ expect(person.details).to eq(nil)
300
542
  end
301
543
 
302
544
  it "tracks dirty attributes" do
@@ -356,6 +598,129 @@ describe Vault::Rails do
356
598
  end
357
599
  end
358
600
 
601
+ context "with context" do
602
+ it "encodes and decodes with a string context" do
603
+ person = Person.create!(context_string: "foobar")
604
+ person.reload
605
+
606
+ raw = Vault::Rails.decrypt(
607
+ "transit", "dummy_people_context_string",
608
+ person.context_string_encrypted, context: "production")
609
+
610
+ expect(raw).to eq("foobar")
611
+
612
+ expect(person.context_string).to eq("foobar")
613
+
614
+ # Decrypting without the correct context fails
615
+ expect {
616
+ Vault::Rails.decrypt(
617
+ "transit", "dummy_people_context_string",
618
+ person.context_string_encrypted, context: "wrongcontext")
619
+ }.to raise_error(Vault::HTTPClientError, /invalid ciphertext/)
620
+
621
+ # Decrypting without a context fails
622
+ expect {
623
+ Vault::Rails.decrypt(
624
+ "transit", "dummy_people_context_string",
625
+ person.context_string_encrypted)
626
+ }.to raise_error(Vault::HTTPClientError, /context/)
627
+ end
628
+
629
+ it "encodes and decodes with a symbol context" do
630
+ person = Person.create!(context_symbol: "foobar")
631
+ person.reload
632
+
633
+ raw = Vault::Rails.decrypt(
634
+ "transit", "dummy_people_context_symbol",
635
+ person.context_symbol_encrypted, context: person.encryption_context)
636
+
637
+ expect(raw).to eq("foobar")
638
+
639
+ expect(person.context_symbol).to eq("foobar")
640
+
641
+ # Decrypting without the correct context fails
642
+ expect {
643
+ Vault::Rails.decrypt(
644
+ "transit", "dummy_people_context_symbol",
645
+ person.context_symbol_encrypted, context: "wrongcontext")
646
+ }.to raise_error(Vault::HTTPClientError, /invalid ciphertext/)
647
+
648
+ # Decrypting without a context fails
649
+ expect {
650
+ Vault::Rails.decrypt(
651
+ "transit", "dummy_people_context_symbol",
652
+ person.context_symbol_encrypted)
653
+ }.to raise_error(Vault::HTTPClientError, /context/)
654
+ end
655
+
656
+ it "encodes and decodes with a proc context" do
657
+ person = Person.create!(context_proc: "foobar")
658
+ person.reload
659
+
660
+ raw = Vault::Rails.decrypt(
661
+ "transit", "dummy_people_context_proc",
662
+ person.context_proc_encrypted, context: person.encryption_context)
663
+
664
+ expect(raw).to eq("foobar")
665
+
666
+ expect(person.context_proc).to eq("foobar")
667
+
668
+ # Decrypting without the correct context fails
669
+ expect {
670
+ Vault::Rails.decrypt(
671
+ "transit", "dummy_people_context_proc",
672
+ person.context_proc_encrypted, context: "wrongcontext")
673
+ }.to raise_error(Vault::HTTPClientError, /invalid ciphertext/)
674
+
675
+ # Decrypting without a context fails
676
+ expect {
677
+ Vault::Rails.decrypt(
678
+ "transit", "dummy_people_context_proc",
679
+ person.context_proc_encrypted)
680
+ }.to raise_error(Vault::HTTPClientError, /context/)
681
+ end
682
+ end
683
+
684
+ context 'with transform_secret', ent_vault: ">= 1.4" do
685
+ before(:all) do
686
+ Vault::Rails.sys.mount("transform", :transform)
687
+ Vault::Rails.client.transform.create_transformation(
688
+ "social_sec",
689
+ template: "builtin/socialsecuritynumber",
690
+ tweak_source: "internal",
691
+ type: "fpe",
692
+ allowed_roles: [Vault::Rails.application]
693
+ )
694
+ Vault::Rails.client.transform.create_role(Vault::Rails.application, transformations: ["social_sec"])
695
+ Vault::Rails.client.transform.create_role("foobar_role", transformations: ["social_sec"])
696
+ end
697
+
698
+ it "encrypts the attribute using the given transformation" do
699
+ person = Person.create!(transform_ssn: "123-45-6789")
700
+ expect(person[:transform_ssn_encrypted]).not_to eq("123-45-6789")
701
+ expect(person[:transform_ssn_encrypted]).to match(/\d{3}-\d{2}-\d{4}/)
702
+ expect(person.transform_ssn).to eq("123-45-6789")
703
+ end
704
+
705
+ it "raises an error if the format is incorrect" do
706
+ expect{ Person.create!(transform_ssn: "1234-5678-90") }.to(
707
+ raise_error(Vault::HTTPClientError, /unable to find matching expression/)
708
+ )
709
+ end
710
+
711
+ it "raises an error if the transformation does not exist" do
712
+ expect{ Person.create!(bad_transform: "nope") }.to(
713
+ raise_error(Vault::HTTPClientError, /unable to find transformation/)
714
+ )
715
+ end
716
+
717
+ it "raises an error if the provided role doesn't have the ability to use the transformation" do
718
+ expect{ Person.create!(bad_role_transform: "123-45-6789") }.to(
719
+ raise_error(Vault::HTTPClientError, /is not an allowed role for the transformation/)
720
+ )
721
+ end
722
+ end
723
+
359
724
  context 'with errors' do
360
725
  it 'raises the appropriate exception' do
361
726
  expect {
@@ -363,4 +728,19 @@ describe Vault::Rails do
363
728
  }.to raise_error(Vault::HTTPClientError)
364
729
  end
365
730
  end
731
+
732
+ context "without a server" do
733
+ it "encrypts attributes with a dev prefix" do
734
+ allow(Vault::Rails).to receive(:enabled?).and_return(false)
735
+ person = Person.create!(credit_card: "1234567890111213")
736
+ expect(person.cc_encrypted).to start_with(Vault::Rails::DEV_PREFIX)
737
+ end
738
+
739
+ it "decrypts attributes" do
740
+ allow(Vault::Rails).to receive(:enabled?).and_return(false)
741
+ person = Person.create!(credit_card: "1234567890111213")
742
+ person.reload
743
+ expect(person.credit_card).to eq("1234567890111213")
744
+ end
745
+ end
366
746
  end