aboutsummaryrefslogtreecommitdiffstats
path: root/activesupport/test/message_verifier_test.rb
diff options
context:
space:
mode:
authorMichael Coyne <mikeycgto@gmail.com>2017-09-23 17:16:21 -0400
committerMichael Coyne <mikeycgto@gmail.com>2017-09-23 17:16:21 -0400
commit39f8ca64cec8667b66628e970211b4d18abbc373 (patch)
treee71ac29cf6352af844075fb1fb863a6e4b8987ca /activesupport/test/message_verifier_test.rb
parent8b139444dd419306e70792ff286ffecd75d67d23 (diff)
downloadrails-39f8ca64cec8667b66628e970211b4d18abbc373.tar.gz
rails-39f8ca64cec8667b66628e970211b4d18abbc373.tar.bz2
rails-39f8ca64cec8667b66628e970211b4d18abbc373.zip
Add key rotation message Encryptor and Verifier
Both classes now have a rotate method where new instances are added for each call. When decryption or verification fails the next rotation instance is tried.
Diffstat (limited to 'activesupport/test/message_verifier_test.rb')
-rw-r--r--activesupport/test/message_verifier_test.rb90
1 files changed, 90 insertions, 0 deletions
diff --git a/activesupport/test/message_verifier_test.rb b/activesupport/test/message_verifier_test.rb
index fbeafca203..3079c48c02 100644
--- a/activesupport/test/message_verifier_test.rb
+++ b/activesupport/test/message_verifier_test.rb
@@ -20,6 +20,7 @@ class MessageVerifierTest < ActiveSupport::TestCase
def setup
@verifier = ActiveSupport::MessageVerifier.new("Hey, I'm a secret!")
@data = { some: "data", now: Time.utc(2010) }
+ @secret = SecureRandom.random_bytes(32)
end
def test_valid_message
@@ -90,6 +91,95 @@ class MessageVerifierTest < ActiveSupport::TestCase
signed_message = "BAh7BzoJc29tZUkiCWRhdGEGOgZFVDoIbm93SXU6CVRpbWUNIIAbgAAAAAAHOgtvZmZzZXRpADoJem9uZUkiCFVUQwY7BkY=--d03c52c91dfe4ccc5159417c660461bcce005e96"
assert_equal @data, @verifier.verify(signed_message)
end
+
+ def test_with_rotated_raw_key
+ old_raw_key = SecureRandom.random_bytes(32)
+
+ old_verifier = ActiveSupport::MessageVerifier.new(old_raw_key, digest: "SHA1")
+ old_message = old_verifier.generate("message verified with old raw key")
+
+ verifier = ActiveSupport::MessageVerifier.new(@secret, digest: "SHA1")
+ verifier.rotate raw_key: old_raw_key, digest: "SHA1"
+
+ assert_equal "message verified with old raw key", verifier.verified(old_message)
+ end
+
+ def test_with_rotated_secret_and_salt
+ old_secret, old_salt = SecureRandom.random_bytes(32), "old salt"
+
+ old_raw_key = ActiveSupport::KeyGenerator.new(old_secret, iterations: 1000).generate_key(old_salt)
+ old_verifier = ActiveSupport::MessageVerifier.new(old_raw_key, digest: "SHA1")
+ old_message = old_verifier.generate("message verified with old secret and salt")
+
+ verifier = ActiveSupport::MessageVerifier.new(@secret, digest: "SHA1")
+ verifier.rotate secret: old_secret, salt: old_salt, digest: "SHA1"
+
+ assert_equal "message verified with old secret and salt", verifier.verified(old_message)
+ end
+
+ def test_with_rotated_key_generator
+ old_key_gen, old_salt = ActiveSupport::KeyGenerator.new(SecureRandom.random_bytes(32), iterations: 256), "old salt"
+
+ old_raw_key = old_key_gen.generate_key(old_salt)
+ old_verifier = ActiveSupport::MessageVerifier.new(old_raw_key, digest: "SHA1")
+ old_message = old_verifier.generate("message verified with old key generator and salt")
+
+ verifier = ActiveSupport::MessageVerifier.new(@secret, digest: "SHA1")
+ verifier.rotate key_generator: old_key_gen, salt: old_salt, digest: "SHA1"
+
+ assert_equal "message verified with old key generator and salt", verifier.verified(old_message)
+ end
+
+ def test_with_rotating_multiple_verifiers
+ old_raw_key, older_raw_key = SecureRandom.random_bytes(32), SecureRandom.random_bytes(32)
+
+ old_verifier = ActiveSupport::MessageVerifier.new(old_raw_key, digest: "SHA256")
+ old_message = old_verifier.generate("message verified with old raw key")
+
+ older_verifier = ActiveSupport::MessageVerifier.new(older_raw_key, digest: "SHA1")
+ older_message = older_verifier.generate("message verified with older raw key")
+
+ verifier = ActiveSupport::MessageVerifier.new("new secret", digest: "SHA512")
+ verifier.rotate raw_key: old_raw_key, digest: "SHA256"
+ verifier.rotate raw_key: older_raw_key, digest: "SHA1"
+
+ assert_equal "verified message", verifier.verified(verifier.generate("verified message"))
+ assert_equal "message verified with old raw key", verifier.verified(old_message)
+ assert_equal "message verified with older raw key", verifier.verified(older_message)
+ end
+
+ def test_on_rotation_keyword_block_is_called_and_verified_returns_message
+ callback_ran, message = nil, nil
+
+ old_raw_key, older_raw_key = SecureRandom.random_bytes(32), SecureRandom.random_bytes(32)
+
+ older_verifier = ActiveSupport::MessageVerifier.new(older_raw_key, digest: "SHA1")
+ older_message = older_verifier.generate(encoded: "message")
+
+ verifier = ActiveSupport::MessageVerifier.new("new secret", digest: "SHA512")
+ verifier.rotate raw_key: old_raw_key, digest: "SHA256"
+ verifier.rotate raw_key: older_raw_key, digest: "SHA1"
+
+ message = verifier.verified(older_message, on_rotation: proc { callback_ran = true })
+
+ assert callback_ran, "callback was ran"
+ assert_equal({ encoded: "message" }, message)
+ end
+
+ def test_with_rotated_metadata
+ old_secret, old_salt = SecureRandom.random_bytes(32), "old salt"
+
+ old_raw_key = ActiveSupport::KeyGenerator.new(old_secret, iterations: 1000).generate_key(old_salt)
+ old_verifier = ActiveSupport::MessageVerifier.new(old_raw_key, digest: "SHA1")
+ old_message = old_verifier.generate(
+ "message verified with old secret, salt, and metadata", purpose: "rotation")
+
+ verifier = ActiveSupport::MessageVerifier.new(@secret, digest: "SHA1")
+ verifier.rotate secret: old_secret, salt: old_salt, digest: "SHA1"
+
+ assert_equal "message verified with old secret, salt, and metadata",
+ verifier.verified(old_message, purpose: "rotation")
+ end
end
class MessageVerifierMetadataTest < ActiveSupport::TestCase