aboutsummaryrefslogtreecommitdiffstats
path: root/activesupport/test
diff options
context:
space:
mode:
authorEdouard CHIN <edouard.chin@shopify.com>2019-06-06 17:50:31 +0200
committerEdouard CHIN <edouard.chin@shopify.com>2019-06-06 19:08:53 +0200
commit123bcf5faa6d6963862a33489b2d678d6ef3c137 (patch)
tree80b3da27221b032aacf7b2c13729e46b7d3be1a0 /activesupport/test
parent480d9f2d2431e6a11c89edb45123181f9b6db958 (diff)
downloadrails-123bcf5faa6d6963862a33489b2d678d6ef3c137.tar.gz
rails-123bcf5faa6d6963862a33489b2d678d6ef3c137.tar.bz2
rails-123bcf5faa6d6963862a33489b2d678d6ef3c137.zip
Introduce a new ActiveSupport::SecureCompareRotator class:
- This class is used to rotate a previously determined value to a new one before making the comparions. We use this at Shopify to rotate Basic Auth crendials but I can imagine other use cases. The implementation uses the same `Messages::Rotator` module than the MessageEncryptor/MessageVerifier class so it works exactly the same way. You can use it as follow: ```ruby rotator = ActiveSupport::SecureCompareRotator.new('new_production_value') rotator.rotate('previous_production_value') rotator.secure_compare!('previous_production_value') ```
Diffstat (limited to 'activesupport/test')
-rw-r--r--activesupport/test/secure_compare_rotator_test.rb44
1 files changed, 44 insertions, 0 deletions
diff --git a/activesupport/test/secure_compare_rotator_test.rb b/activesupport/test/secure_compare_rotator_test.rb
new file mode 100644
index 0000000000..8acf13e38f
--- /dev/null
+++ b/activesupport/test/secure_compare_rotator_test.rb
@@ -0,0 +1,44 @@
+# frozen_string_literal: true
+
+require "abstract_unit"
+require "active_support/secure_compare_rotator"
+
+class SecureCompareRotatorTest < ActiveSupport::TestCase
+ test "#secure_compare! works correctly after rotation" do
+ wrapper = ActiveSupport::SecureCompareRotator.new("old_secret")
+ wrapper.rotate("new_secret")
+
+ assert_equal(true, wrapper.secure_compare!("new_secret"))
+ end
+
+ test "#secure_compare! works correctly after multiple rotation" do
+ wrapper = ActiveSupport::SecureCompareRotator.new("old_secret")
+ wrapper.rotate("new_secret")
+ wrapper.rotate("another_secret")
+ wrapper.rotate("and_another_one")
+
+ assert_equal(true, wrapper.secure_compare!("and_another_one"))
+ end
+
+ test "#secure_compare! fails correctly when credential is not part of the rotation" do
+ wrapper = ActiveSupport::SecureCompareRotator.new("old_secret")
+ wrapper.rotate("new_secret")
+
+ assert_raises(ActiveSupport::SecureCompareRotator::InvalidMatch) do
+ wrapper.secure_compare!("different_secret")
+ end
+ end
+
+ test "#secure_compare! calls the on_rotation proc" do
+ wrapper = ActiveSupport::SecureCompareRotator.new("old_secret")
+ wrapper.rotate("new_secret")
+ wrapper.rotate("another_secret")
+ wrapper.rotate("and_another_one")
+
+ @witness = nil
+
+ assert_changes(:@witness, from: nil, to: true) do
+ assert_equal(true, wrapper.secure_compare!("and_another_one", on_rotation: -> { @witness = true }))
+ end
+ end
+end