mongoid-kms 0.0.14 → 0.0.15
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/mongoid/kms/version.rb +1 -1
- data/lib/mongoid/kms.rb +100 -34
- data/spec/lib/mongoid/kms_spec.rb +24 -7
- data/spec/spec_helper.rb +9 -2
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 029a4f6efe9f5dafce5aef2c5fab0801229f04cc
|
4
|
+
data.tar.gz: 749be3c2641a52cebab3d4f7f2e8d1491a765649
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b1386752d377273539f4f06130d820316d7398e10aac8303b7794d84015c95213b2ad5d909ff64a77516a5491f2f9878c04957d78888f93dcc5c36808eac8f27
|
7
|
+
data.tar.gz: 759ce38aba35b4d9b49401e2b3cb08f64ef4017c832bf7b6608bd09b9caac659228d44517a9a0e0eac480fbdfca5167ee51095cb3245cfb4078656b99b3405bb
|
data/lib/mongoid/kms/version.rb
CHANGED
data/lib/mongoid/kms.rb
CHANGED
@@ -6,73 +6,144 @@ module Mongoid
|
|
6
6
|
module Kms
|
7
7
|
extend ActiveSupport::Concern
|
8
8
|
|
9
|
+
included do
|
10
|
+
@kms_field_map ||= {}
|
11
|
+
|
12
|
+
unless self.ancestors.include?(ActiveModel::Dirty)
|
13
|
+
include ActiveModel::Dirty
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
9
17
|
@configuration = {}
|
10
18
|
@kms = nil
|
11
19
|
|
12
|
-
|
13
|
-
|
14
|
-
|
20
|
+
# Module methods
|
21
|
+
class << self
|
22
|
+
def configure(args)
|
23
|
+
@configuration = args
|
24
|
+
end
|
15
25
|
|
16
|
-
|
17
|
-
|
18
|
-
|
26
|
+
def configuration
|
27
|
+
@configuration || {}
|
28
|
+
end
|
19
29
|
|
20
|
-
|
21
|
-
|
22
|
-
|
30
|
+
def kms
|
31
|
+
@kms ||= Aws::KMS::Client.new(region: self.region)
|
32
|
+
end
|
23
33
|
|
24
|
-
|
25
|
-
|
26
|
-
|
34
|
+
def region
|
35
|
+
configuration[:region]
|
36
|
+
end
|
37
|
+
|
38
|
+
def key
|
39
|
+
configuration[:key]
|
40
|
+
end
|
27
41
|
|
28
|
-
|
29
|
-
|
42
|
+
def bson_class
|
43
|
+
if defined? Moped::BSON
|
44
|
+
Moped::BSON
|
45
|
+
elsif defined? BSON
|
46
|
+
BSON
|
47
|
+
end
|
48
|
+
end
|
30
49
|
end
|
31
50
|
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
51
|
+
# Instance methods
|
52
|
+
def set_kms_values
|
53
|
+
self.class.kms_field_map.each do |field_name, settings|
|
54
|
+
if self.send("#{field_name}_changed?") || kms_context_value_changed?(field_name)
|
55
|
+
encrypted_field_name = self.class.get_encrypted_field_name(field_name)
|
56
|
+
|
57
|
+
if instance_variable_get("@#{field_name}").nil? && kms_context_value_changed?(field_name)
|
58
|
+
value = self.class.decrypt_field(self, field_name, self.send(encrypted_field_name), self.class.kms_context_was(self, field_name))
|
59
|
+
else
|
60
|
+
value = send("#{field_name}")
|
61
|
+
end
|
62
|
+
|
63
|
+
if value.nil?
|
64
|
+
self.send("#{encrypted_field_name}=", nil)
|
65
|
+
else
|
66
|
+
self.send("#{encrypted_field_name}=", self.class.encrypt_field(self, field_name, value))
|
67
|
+
end
|
68
|
+
end
|
37
69
|
end
|
38
70
|
end
|
39
71
|
|
72
|
+
def kms_context_value_changed?(field_name)
|
73
|
+
self.class.kms_context_array(self, field_name).find { |f| self.respond_to?(f) && self.send("#{f}_changed?") }
|
74
|
+
end
|
75
|
+
|
76
|
+
# Class methods
|
40
77
|
module ClassMethods
|
78
|
+
def kms_field_map
|
79
|
+
@kms_field_map
|
80
|
+
end
|
81
|
+
|
41
82
|
def encrypt_field(object, field_name, value)
|
42
83
|
Mongoid::Kms.kms.encrypt({
|
43
84
|
key_id: Mongoid::Kms.key,
|
44
85
|
plaintext: value,
|
45
86
|
encryption_context: kms_context(object, field_name)
|
46
87
|
})[:ciphertext_blob].force_encoding('UTF-8')
|
47
|
-
rescue ArgumentError
|
48
|
-
raise "Error using KMS context. If you use an object's field for context, set your encrypted fields explicitly: myobject.#{field_name} = #{value.inspect}"
|
49
88
|
end
|
50
89
|
|
51
|
-
def decrypt_field(object, field_name, data)
|
90
|
+
def decrypt_field(object, field_name, data, encryption_context = nil)
|
91
|
+
encryption_context ||= kms_context(object, field_name)
|
92
|
+
|
52
93
|
Mongoid::Kms.kms.decrypt({
|
53
94
|
ciphertext_blob: data,
|
54
|
-
encryption_context:
|
95
|
+
encryption_context: encryption_context
|
55
96
|
})[:plaintext]
|
56
97
|
end
|
57
98
|
|
58
99
|
def kms_context(object, field_name)
|
59
|
-
|
60
|
-
|
61
|
-
|
100
|
+
kms_context_array(object, field_name).inject({}) do |hash, key|
|
101
|
+
if object.respond_to?(key)
|
102
|
+
hash[key] = object.send(key)
|
103
|
+
else
|
104
|
+
hash[key] = key
|
105
|
+
end
|
106
|
+
|
107
|
+
hash
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
def kms_context_was(object, field_name)
|
112
|
+
kms_context_array(object, field_name).inject({}) do |hash, key|
|
113
|
+
if object.respond_to?("#{key}_was") && object.send("#{key}_changed?")
|
114
|
+
hash[key] = object.send("#{key}_was")
|
115
|
+
elsif object.respond_to?(key)
|
116
|
+
hash[key] = object.send(key)
|
117
|
+
else
|
118
|
+
hash[key] = key
|
119
|
+
end
|
120
|
+
|
121
|
+
hash
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
def kms_context_array(object, field_name)
|
126
|
+
@kms_field_map[field_name.to_s][:context] || []
|
62
127
|
end
|
63
128
|
|
64
129
|
def kms_type(field_name)
|
65
130
|
@kms_field_map[field_name.to_s][:type]
|
66
131
|
end
|
67
132
|
|
133
|
+
def get_encrypted_field_name(field_name)
|
134
|
+
"kms_secure_#{field_name}"
|
135
|
+
end
|
136
|
+
|
68
137
|
def secure_field(field_name, args)
|
69
|
-
encrypted_field_name =
|
138
|
+
encrypted_field_name = get_encrypted_field_name(field_name)
|
70
139
|
|
71
|
-
@kms_field_map ||= {}
|
72
140
|
@kms_field_map[field_name.to_s] = {context: args.delete(:context), type: args.delete(:type)}
|
73
141
|
|
74
142
|
field encrypted_field_name, args.merge(type: Mongoid::Kms.bson_class::Binary)
|
75
143
|
|
144
|
+
define_attribute_methods field_name.to_sym
|
145
|
+
before_save :set_kms_values
|
146
|
+
|
76
147
|
define_method(field_name) do
|
77
148
|
instance_variable_get("@#{field_name}") || begin
|
78
149
|
raw = send("kms_secure_#{field_name}")
|
@@ -88,13 +159,8 @@ module Mongoid
|
|
88
159
|
end
|
89
160
|
|
90
161
|
define_method("#{field_name}=") do |value|
|
162
|
+
self.send("#{field_name}_will_change!")
|
91
163
|
instance_variable_set("@#{field_name}", value)
|
92
|
-
|
93
|
-
if value.nil?
|
94
|
-
self.send("#{encrypted_field_name}=", nil)
|
95
|
-
else
|
96
|
-
self.send("#{encrypted_field_name}=", self.class.encrypt_field(self, field_name, value))
|
97
|
-
end
|
98
164
|
end
|
99
165
|
end
|
100
166
|
end
|
@@ -3,8 +3,7 @@ require 'spec_helper'
|
|
3
3
|
describe Mongoid::Kms do
|
4
4
|
|
5
5
|
it "encrypts the secure fields" do
|
6
|
-
o = MyClass.new(unsecure: "robin")
|
7
|
-
o.secure = "batman"
|
6
|
+
o = MyClass.new(secure: "batman", unsecure: "robin")
|
8
7
|
o.save!
|
9
8
|
|
10
9
|
expect(o.secure).to eq("batman")
|
@@ -12,8 +11,7 @@ describe Mongoid::Kms do
|
|
12
11
|
end
|
13
12
|
|
14
13
|
it "descripts the secure fields" do
|
15
|
-
o = MyClass.new(unsecure: "robin")
|
16
|
-
o.secure = "batman"
|
14
|
+
o = MyClass.new(unsecure: "robin", secure: "batman")
|
17
15
|
o.save!
|
18
16
|
|
19
17
|
o = MyClass.find(o.id)
|
@@ -21,9 +19,8 @@ describe Mongoid::Kms do
|
|
21
19
|
expect(o.unsecure).to eq("robin")
|
22
20
|
end
|
23
21
|
|
24
|
-
it "encrypts
|
25
|
-
o = OtherClass.new(unsecure: "pengiun")
|
26
|
-
o.super_secure = "joker"
|
22
|
+
it "encrypts the other fields" do
|
23
|
+
o = OtherClass.new(unsecure: "pengiun", super_secure: "joker")
|
27
24
|
o.save!
|
28
25
|
|
29
26
|
o = OtherClass.find(o.id)
|
@@ -31,4 +28,24 @@ describe Mongoid::Kms do
|
|
31
28
|
expect(o.unsecure).to eq("pengiun")
|
32
29
|
end
|
33
30
|
|
31
|
+
it "modifies the encryption if the context field changes" do
|
32
|
+
o = MyClass.new(unsecure: "robin", secure: "other")
|
33
|
+
o.save!
|
34
|
+
|
35
|
+
o = MyClass.find(o.id)
|
36
|
+
o.unsecure = "bla"
|
37
|
+
o.save!
|
38
|
+
|
39
|
+
o = MyClass.find(o.id)
|
40
|
+
expect(o.secure).to eq("other")
|
41
|
+
end
|
42
|
+
|
43
|
+
it "handles a class without context" do
|
44
|
+
o = MyClass.new(secure: "bla", unsecure: "blatoo")
|
45
|
+
o.save!
|
46
|
+
|
47
|
+
o = MyClass.find(o.id)
|
48
|
+
expect(o.secure).to eq("bla")
|
49
|
+
end
|
50
|
+
|
34
51
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -9,7 +9,7 @@ class MyClass
|
|
9
9
|
include Mongoid::Document
|
10
10
|
include Mongoid::Kms
|
11
11
|
|
12
|
-
secure_field :secure, type: String, context:
|
12
|
+
secure_field :secure, type: String, context: [:unsecure]
|
13
13
|
field :unsecure
|
14
14
|
end
|
15
15
|
|
@@ -17,9 +17,16 @@ class OtherClass
|
|
17
17
|
include Mongoid::Document
|
18
18
|
include Mongoid::Kms
|
19
19
|
|
20
|
-
secure_field :super_secure, type: String, context:
|
20
|
+
secure_field :super_secure, type: String, context: [:unsecure, "deployment"]
|
21
21
|
field :unsecure
|
22
22
|
end
|
23
23
|
|
24
|
+
class ClassWithoutContext
|
25
|
+
include Mongoid::Document
|
26
|
+
include Mongoid::Kms
|
27
|
+
|
28
|
+
secure_field :secure, type: String
|
29
|
+
field :unsecure
|
30
|
+
end
|
24
31
|
|
25
32
|
Mongoid::Kms.configure({region: "us-east-1", key: ENV['AWS_KMS_KEY_ID']})
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: mongoid-kms
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.15
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Chris Winslett
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-12-
|
11
|
+
date: 2014-12-15 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: mongoid
|