mirror of
https://github.com/rails/rails.git
synced 2022-11-09 12:12:34 -05:00
Validate that proper keys are configured when declaring attributes
This enables to disable deterministic encryption by just not setting deterministic_key.
This commit is contained in:
parent
575a2c6ce0
commit
e24fb5524a
4 changed files with 65 additions and 7 deletions
|
@ -24,7 +24,7 @@ module ActiveRecord
|
|||
@previous_schemes = Array.wrap(previous_schemes)
|
||||
@context_properties = context_properties
|
||||
|
||||
validate!
|
||||
validate_config!
|
||||
end
|
||||
|
||||
def ignore_case?
|
||||
|
@ -45,7 +45,10 @@ module ActiveRecord
|
|||
end
|
||||
|
||||
def key_provider
|
||||
@key_provider ||= @key_provider_param || build_key_provider
|
||||
@key_provider ||= begin
|
||||
validate_keys!
|
||||
@key_provider_param || build_key_provider
|
||||
end
|
||||
end
|
||||
|
||||
def merge(other_scheme)
|
||||
|
@ -66,11 +69,24 @@ module ActiveRecord
|
|||
end
|
||||
|
||||
private
|
||||
def validate!
|
||||
def validate_config!
|
||||
raise Errors::Configuration, "ignore_case: can only be used with deterministic encryption" if @ignore_case && !@deterministic
|
||||
raise Errors::Configuration, "key_provider: and key: can't be used simultaneously" if @key_provider_param && @key
|
||||
end
|
||||
|
||||
def validate_keys!
|
||||
validate_credential :key_derivation_salt
|
||||
validate_credential :primary_key, "needs to be configured to use non-deterministic encryption" unless @deterministic
|
||||
validate_credential :deterministic_key, "needs to be configured to use deterministic encryption" if @deterministic
|
||||
end
|
||||
|
||||
def validate_credential(key, error_message = "is not configured")
|
||||
unless ActiveRecord::Encryption.config.public_send(key).present?
|
||||
raise Errors::Configuration, "#{key} #{error_message}. Please configure it via credential"\
|
||||
"active_record_encryption.#{key} or by setting config.active_record.encryption.#{key}"
|
||||
end
|
||||
end
|
||||
|
||||
def build_key_provider
|
||||
return DerivedSecretKeyProvider.new(@key) if @key.present?
|
||||
|
||||
|
|
|
@ -141,8 +141,8 @@ class ActiveRecord::EncryptionTestCase < ActiveRecord::TestCase
|
|||
include ActiveRecord::Encryption::EncryptionHelpers, ActiveRecord::Encryption::PerformanceHelpers
|
||||
# , PerformanceHelpers
|
||||
|
||||
ENCRYPTION_ATTRIBUTES_TO_RESET = %i[ primary_key deterministic_key store_key_references key_derivation_salt support_unencrypted_data
|
||||
encrypt_fixtures ]
|
||||
ENCRYPTION_ATTRIBUTES_TO_RESET = %i[ primary_key deterministic_key key_derivation_salt store_key_references
|
||||
key_derivation_salt support_unencrypted_data encrypt_fixtures ]
|
||||
|
||||
setup do
|
||||
ENCRYPTION_ATTRIBUTES_TO_RESET.each do |property|
|
||||
|
|
|
@ -4,7 +4,7 @@ require "cases/encryption/helper"
|
|||
require "models/book"
|
||||
|
||||
class ActiveRecord::Encryption::SchemeTest < ActiveRecord::EncryptionTestCase
|
||||
test "validate config options when declaring encrypted attributes" do
|
||||
test "validates config options when declaring encrypted attributes" do
|
||||
assert_invalid_declaration deterministic: false, ignore_case: true
|
||||
assert_invalid_declaration key: "1234", key_provider: ActiveRecord::Encryption::DerivedSecretKeyProvider.new("my secret")
|
||||
|
||||
|
@ -13,6 +13,38 @@ class ActiveRecord::Encryption::SchemeTest < ActiveRecord::EncryptionTestCase
|
|||
assert_valid_declaration key_provider: ActiveRecord::Encryption::DerivedSecretKeyProvider.new("my secret")
|
||||
end
|
||||
|
||||
test "validates primary_key is set for non deterministic encryption" do
|
||||
ActiveRecord::Encryption.config.primary_key = nil
|
||||
|
||||
assert_raise ActiveRecord::Encryption::Errors::Configuration do
|
||||
declare_and_use_class
|
||||
end
|
||||
|
||||
assert_nothing_raised do
|
||||
declare_and_use_class deterministic: true
|
||||
end
|
||||
end
|
||||
|
||||
test "validates deterministic_key is set for non deterministic encryption" do
|
||||
ActiveRecord::Encryption.config.deterministic_key = nil
|
||||
|
||||
assert_raise ActiveRecord::Encryption::Errors::Configuration do
|
||||
declare_and_use_class deterministic: true
|
||||
end
|
||||
|
||||
assert_nothing_raised do
|
||||
declare_and_use_class
|
||||
end
|
||||
end
|
||||
|
||||
test "validates key_derivation_salt is set" do
|
||||
ActiveRecord::Encryption.config.key_derivation_salt = nil
|
||||
|
||||
assert_raise ActiveRecord::Encryption::Errors::Configuration do
|
||||
declare_and_use_class
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
def assert_invalid_declaration(**options)
|
||||
assert_raises ActiveRecord::Encryption::Errors::Configuration do
|
||||
|
@ -21,11 +53,19 @@ class ActiveRecord::Encryption::SchemeTest < ActiveRecord::EncryptionTestCase
|
|||
end
|
||||
|
||||
def assert_valid_declaration(**options)
|
||||
assert_nothing_raised do
|
||||
assert_nothing_raised do
|
||||
declare_encrypts_with(options)
|
||||
end
|
||||
end
|
||||
|
||||
def declare_and_use_class(**options)
|
||||
encrypted_book_class = Class.new(Book) do
|
||||
encrypts :name, **options
|
||||
end
|
||||
|
||||
encrypted_book_class.create! name: "Some name"
|
||||
end
|
||||
|
||||
def declare_encrypts_with(options)
|
||||
Class.new(Book) do
|
||||
encrypts :name, **options
|
||||
|
|
|
@ -80,6 +80,8 @@ The recommendation is using the default (non deterministic) unless you need to q
|
|||
|
||||
NOTE: In non-deterministic mode, encryption is done using AES-GCM with a 256-bits key and a random initialization vector. In deterministic mode, it uses AES-GCM too but the initialization vector is generated as a HMAC-SHA-256 digest of the key and contents to encrypt.
|
||||
|
||||
NOTE: You can disable deterministic encryption just by not configuring a `deterministic_key`.
|
||||
|
||||
## Features
|
||||
|
||||
### Action Text
|
||||
|
|
Loading…
Reference in a new issue