mongoid-kms 0.0.14 → 0.0.15
Sign up to get free protection for your applications and to get access to all the features.
- 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
|