acts_as_secure 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/MIT-LICENSE +20 -0
- data/README +149 -0
- data/init.rb +1 -0
- data/lib/acts_as_secure.rb +98 -0
- metadata +50 -0
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2007 Revolution Health Group LLC. All rights reserved.
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README
ADDED
@@ -0,0 +1,149 @@
|
|
1
|
+
== Introduction
|
2
|
+
|
3
|
+
ActsAsSecure adds an ability to store ActiveRecord model's fields encrypted in a DB. When a model is marked with acts_as_secure, the :binary type fields are recognized as needed to be stored encrypted. The plugin does before_save/after_save/after_find encryption/decryption thus making it transparent for a code using the secure models.
|
4
|
+
|
5
|
+
The plugin supports a master key approach as well as individual records encryption keys. It does not contain any crypto provider but allows to plug in any external one as long as it supports encrypt/decrypt methods.
|
6
|
+
|
7
|
+
The fields are converted to a YAML form before encryption. After description they are restored via YAML.load. Since fields are stored encrypted, the find usage is very limited.
|
8
|
+
|
9
|
+
== Usage
|
10
|
+
|
11
|
+
=== Master Key Provider Usage
|
12
|
+
|
13
|
+
class SecureModel < ActiveRecord::Base
|
14
|
+
acts_as_secure :crypto_provider => MasterKeyProviderClassOrInstance
|
15
|
+
end
|
16
|
+
|
17
|
+
SecureModel.create()
|
18
|
+
SecureModel.find(:first)
|
19
|
+
|
20
|
+
=== Individual Keys Provider Usage
|
21
|
+
|
22
|
+
class SecureModel < ActiveRecord::Base
|
23
|
+
acts_as_secure
|
24
|
+
end
|
25
|
+
|
26
|
+
SecureModel.with_crypto_provider(SomeProvider.new(some_param)) { SecureModel.find(:first) }
|
27
|
+
SecureModel.with_crypto_provider(SomeProvider.new(some_param)) { SecureModel.create() }
|
28
|
+
|
29
|
+
=== Other Options
|
30
|
+
|
31
|
+
acts_as_secure :storage_type => :text -- changes the secure storage type from :binary to the supplied one
|
32
|
+
acts_as_secure :except => [:field1, :field2] -- disables the secure behavior for the :binary type fields in a supplied list
|
33
|
+
|
34
|
+
== Example
|
35
|
+
|
36
|
+
Let's define three models: Fruit (not secure), SecretFruit (uses the master key approach), and UberSecretFruit (uses the individual key approach).
|
37
|
+
|
38
|
+
Rot13CryptoProvider represents a master key provider. SaltedRot13CryptoProvider depends on a salt individual for each record.
|
39
|
+
|
40
|
+
|
41
|
+
=== Models
|
42
|
+
|
43
|
+
class Fruit < ActiveRecord::Base
|
44
|
+
has_one :secret_fruit
|
45
|
+
has_one :uber_secret_fruit
|
46
|
+
end
|
47
|
+
|
48
|
+
class CreateFruits < ActiveRecord::Migration
|
49
|
+
def self.up
|
50
|
+
create_table :fruits do |t|
|
51
|
+
t.column :name, :string
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
class Rot13CryptoProvider
|
57
|
+
class << self
|
58
|
+
def encrypt(arg)
|
59
|
+
arg.tr("A-Za-z", "N-ZA-Mn-za-m")
|
60
|
+
end
|
61
|
+
alias_method :decrypt, :encrypt
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
class SecretFruit < ActiveRecord::Base
|
66
|
+
acts_as_secure :crypto_provider => Rot13CryptoProvider
|
67
|
+
belongs_to :fruit
|
68
|
+
end
|
69
|
+
|
70
|
+
class CreateSecretFruits < ActiveRecord::Migration
|
71
|
+
def self.up
|
72
|
+
create_table :secret_fruits do |t|
|
73
|
+
t.column :name, :binary
|
74
|
+
t.column :fruit_id, :integer
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
class SaltedRot13CryptoProvider
|
80
|
+
def initialize(salt)
|
81
|
+
@salt = salt
|
82
|
+
end
|
83
|
+
def encrypt(arg)
|
84
|
+
@salt + arg.tr("A-Za-z", "N-ZA-Mn-za-m")
|
85
|
+
end
|
86
|
+
def decrypt(arg)
|
87
|
+
arg[@salt.size .. -1].tr("A-Za-z", "N-ZA-Mn-za-m")
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
class UberSecretFruit < ActiveRecord::Base
|
92
|
+
acts_as_secure
|
93
|
+
belongs_to :fruit
|
94
|
+
end
|
95
|
+
|
96
|
+
class CreateUberSecretFruits < ActiveRecord::Migration
|
97
|
+
def self.up
|
98
|
+
create_table :uber_secret_fruits do |t|
|
99
|
+
t.column :name, :binary
|
100
|
+
t.column :fruit_id, :integer
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
=== Usage
|
106
|
+
|
107
|
+
>> f = Fruit.create(:name => 'passion fruit')
|
108
|
+
>> SecretFruit.create(:name => 'maracuya', :fruit => f)
|
109
|
+
>> puts f.secret_fruit.name
|
110
|
+
maracuya
|
111
|
+
>> secret = readline.chomp
|
112
|
+
uber_secret
|
113
|
+
>> crypto_provider = SaltedRot13CryptoProvider.new(secret)
|
114
|
+
>> UberSecretFruit.with_crypto_provider(crypto_provider) { UberSecretFruit.create(:name => 'Passiflora edulis', :fruit => f) }
|
115
|
+
>> UberSecretFruit.with_crypto_provider(crypto_provider) { puts f.uber_secret_fruit.name }
|
116
|
+
Passiflora edulis
|
117
|
+
|
118
|
+
=== DB
|
119
|
+
|
120
|
+
> select * from secret_fruits;
|
121
|
+
+----+---------------+----------+
|
122
|
+
| id | name | fruit_id |
|
123
|
+
+----+---------------+----------+
|
124
|
+
| 1 | --- znenphln | 1 |
|
125
|
+
+----+---------------+----------+
|
126
|
+
|
127
|
+
> select * from uber_secret_fruits;
|
128
|
+
+----+-----------------------------------+----------+
|
129
|
+
| id | name | fruit_id |
|
130
|
+
+----+-----------------------------------+----------+
|
131
|
+
| 1 | uber_secret--- Cnffvsyben rqhyvf | 1 |
|
132
|
+
+----+-----------------------------------+----------+
|
133
|
+
|
134
|
+
|
135
|
+
== Installation
|
136
|
+
|
137
|
+
As plugin:
|
138
|
+
script/plugin install svn://rubyforge.org/var/svn/acts-as-secure/trunk/vendor/plugins/acts_as_secure
|
139
|
+
|
140
|
+
|
141
|
+
== License
|
142
|
+
|
143
|
+
ActsAsSecure released under the MIT license.
|
144
|
+
|
145
|
+
|
146
|
+
== Support
|
147
|
+
|
148
|
+
The plugin RubyForge page is http://rubyforge.org/projects/acts-as-secure
|
149
|
+
|
data/init.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require 'acts_as_secure'
|
@@ -0,0 +1,98 @@
|
|
1
|
+
# Copyright (c) 2007 Revolution Health Group LLC. All rights reserved.
|
2
|
+
|
3
|
+
module ActiveRecord; module Acts; end; end
|
4
|
+
|
5
|
+
module ActiveRecord::Acts::ActsAsSecure
|
6
|
+
|
7
|
+
require 'yaml'
|
8
|
+
|
9
|
+
def self.included(base)
|
10
|
+
base.extend(ClassMethods)
|
11
|
+
end
|
12
|
+
|
13
|
+
module ClassMethods
|
14
|
+
|
15
|
+
@@secure_crypto_providers = {}
|
16
|
+
|
17
|
+
def acts_as_secure(options = {})
|
18
|
+
parse_options!(options)
|
19
|
+
add_callbacks
|
20
|
+
send(:include, InstanceMethods)
|
21
|
+
end
|
22
|
+
|
23
|
+
def with_crypto_provider(provider)
|
24
|
+
begin
|
25
|
+
@@secure_crypto_providers[Thread.current.object_id] = provider
|
26
|
+
yield
|
27
|
+
ensure
|
28
|
+
@@secure_crypto_providers.delete(Thread.current.object_id)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def secure_columns
|
33
|
+
columns.reject { |col| (col.type != @secure_storage_type) || @secure_except.include?(col.name) }
|
34
|
+
end
|
35
|
+
|
36
|
+
def secure_crypto_provider
|
37
|
+
@@secure_crypto_providers[Thread.current.object_id] || @secure_class_crypto_provider
|
38
|
+
end
|
39
|
+
|
40
|
+
private
|
41
|
+
|
42
|
+
def parse_options!(options)
|
43
|
+
@secure_except = unsecure_columns(options.delete(:except))
|
44
|
+
@secure_storage_type = options.delete(:storage_type) || :binary
|
45
|
+
@secure_class_crypto_provider = options.delete(:crypto_provider)
|
46
|
+
fail("Unknown option(s): #{ options.keys.join(', ') }") unless options.empty?
|
47
|
+
end
|
48
|
+
|
49
|
+
def add_callbacks
|
50
|
+
before_save :encrypt_secure_columns
|
51
|
+
after_save :decrypt_secure_columns
|
52
|
+
after_find :decrypt_secure_columns
|
53
|
+
define_method(:after_find) { }
|
54
|
+
end
|
55
|
+
|
56
|
+
def unsecure_columns(*names)
|
57
|
+
names.flatten.collect(&:to_s)
|
58
|
+
end
|
59
|
+
|
60
|
+
module InstanceMethods
|
61
|
+
|
62
|
+
def encrypt_secure_columns
|
63
|
+
self.class.secure_columns.each do |col|
|
64
|
+
self[col.name] = secure_encrypt(self[col.name])
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def decrypt_secure_columns
|
69
|
+
self.class.secure_columns.each do |col|
|
70
|
+
self[col.name] = secure_decrypt(send("#{ col.name }_before_type_cast"))
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
private
|
75
|
+
|
76
|
+
def secure_encrypt(arg)
|
77
|
+
secure_crypto_provider.encrypt(arg.to_yaml)
|
78
|
+
end
|
79
|
+
|
80
|
+
def secure_decrypt(arg)
|
81
|
+
begin
|
82
|
+
YAML.load(secure_crypto_provider.decrypt(arg))
|
83
|
+
rescue Exception => ex
|
84
|
+
raise "Failed to decode the field. Incorrect key?"
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
def secure_crypto_provider
|
89
|
+
self.class.secure_crypto_provider || fail('No crypto provider defined')
|
90
|
+
end
|
91
|
+
|
92
|
+
end
|
93
|
+
|
94
|
+
end
|
95
|
+
|
96
|
+
end
|
97
|
+
|
98
|
+
ActiveRecord::Base.send(:include, ActiveRecord::Acts::ActsAsSecure)
|
metadata
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
rubygems_version: 0.9.2
|
3
|
+
specification_version: 1
|
4
|
+
name: acts_as_secure
|
5
|
+
version: !ruby/object:Gem::Version
|
6
|
+
version: 0.0.1
|
7
|
+
date: 2007-06-07 00:00:00 -04:00
|
8
|
+
summary: acts_as_secure adds attributes encryption to ActiveRecord models
|
9
|
+
require_paths:
|
10
|
+
- lib
|
11
|
+
email: rails-trunk@revolution.com
|
12
|
+
homepage:
|
13
|
+
rubyforge_project:
|
14
|
+
description:
|
15
|
+
autorequire: acts_as_secure
|
16
|
+
default_executable:
|
17
|
+
bindir: bin
|
18
|
+
has_rdoc: false
|
19
|
+
required_ruby_version: !ruby/object:Gem::Version::Requirement
|
20
|
+
requirements:
|
21
|
+
- - ">"
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: 0.0.0
|
24
|
+
version:
|
25
|
+
platform: ruby
|
26
|
+
signing_key:
|
27
|
+
cert_chain:
|
28
|
+
post_install_message:
|
29
|
+
authors:
|
30
|
+
- RHG Team
|
31
|
+
files:
|
32
|
+
- init.rb
|
33
|
+
- lib/acts_as_secure.rb
|
34
|
+
- README
|
35
|
+
- MIT-LICENSE
|
36
|
+
test_files: []
|
37
|
+
|
38
|
+
rdoc_options: []
|
39
|
+
|
40
|
+
extra_rdoc_files:
|
41
|
+
- README
|
42
|
+
- MIT-LICENSE
|
43
|
+
executables: []
|
44
|
+
|
45
|
+
extensions: []
|
46
|
+
|
47
|
+
requirements: []
|
48
|
+
|
49
|
+
dependencies: []
|
50
|
+
|