diff options
author | Michael Koziarski <michael@koziarski.com> | 2008-11-23 15:29:11 +0100 |
---|---|---|
committer | Michael Koziarski <michael@koziarski.com> | 2008-11-23 15:33:59 +0100 |
commit | d460c9a25560f43e7c3789abadf7b455053eb686 (patch) | |
tree | 993601a1ca249b95874d433d207a04770e21b532 /activesupport | |
parent | c4a0143854e6fecae5e1820f4f054e33547e866f (diff) | |
download | rails-d460c9a25560f43e7c3789abadf7b455053eb686.tar.gz rails-d460c9a25560f43e7c3789abadf7b455053eb686.tar.bz2 rails-d460c9a25560f43e7c3789abadf7b455053eb686.zip |
Add ActiveSupport::MessageVerifier to aid users who need to store tamper-proof messages in cookies etc.
This is particularly useful for things like remember-me tokens in web applications and auto-unsubscribe links in emails.
Diffstat (limited to 'activesupport')
-rw-r--r-- | activesupport/CHANGELOG | 2 | ||||
-rw-r--r-- | activesupport/lib/active_support.rb | 1 | ||||
-rw-r--r-- | activesupport/lib/active_support/message_verifier.rb | 45 | ||||
-rw-r--r-- | activesupport/test/message_verifier_test.rb | 25 |
4 files changed, 73 insertions, 0 deletions
diff --git a/activesupport/CHANGELOG b/activesupport/CHANGELOG index 5e1b1cb4b0..755ec246ab 100644 --- a/activesupport/CHANGELOG +++ b/activesupport/CHANGELOG @@ -1,5 +1,7 @@ *2.3.0 [Edge]* +* Added ActiveSupport::MessageVerifier to aid users who need to store signed messages. [Koz] + * Added ActiveSupport::BacktraceCleaner to cut down on backtrace noise according to filters and silencers [DHH] * Added Object#try. ( Taken from http://ozmm.org/posts/try.html ) [Chris Wanstrath] diff --git a/activesupport/lib/active_support.rb b/activesupport/lib/active_support.rb index cbfd95f092..7337b55a21 100644 --- a/activesupport/lib/active_support.rb +++ b/activesupport/lib/active_support.rb @@ -56,6 +56,7 @@ require 'active_support/base64' require 'active_support/time_with_zone' require 'active_support/secure_random' +require 'active_support/message_verifier' require 'active_support/rescuable' diff --git a/activesupport/lib/active_support/message_verifier.rb b/activesupport/lib/active_support/message_verifier.rb new file mode 100644 index 0000000000..f3f905c15e --- /dev/null +++ b/activesupport/lib/active_support/message_verifier.rb @@ -0,0 +1,45 @@ +module ActiveSupport + # MessageVerifier makes it easy to generate and verify messages which are signed + # to prevent tampering. + # + # This is useful for cases like remember-me tokens and auto-unsubscribe links where the + # session store isn't suitable or available. + # + # Remember Me: + # cookies[:remember_me] = @verifier.generate_message([@user.id, 2.weeks.from_now]) + # + # In the authentication filter: + # + # id, time = @verifier.verify_message(cookies[:remember_me]) + # if time < Time.now + # self.current_user = User.find(id) + # end + # + class MessageVerifier + class InvalidSignature < StandardError; end + + def initialize(secret, digest = 'SHA1') + @secret = secret + @digest = digest + end + + def verify_message(signed_message) + data, digest = signed_message.split("--") + if digest != generate_digest(data) + raise InvalidSignature + else + Marshal.load(ActiveSupport::Base64.decode64(data)) + end + end + + def generate_message(value) + data = ActiveSupport::Base64.encode64s(Marshal.dump(value)) + "#{data}--#{generate_digest(data)}" + end + + private + def generate_digest(data) + OpenSSL::HMAC.hexdigest(OpenSSL::Digest::Digest.new(@digest), @secret, data) + end + end +end
\ No newline at end of file diff --git a/activesupport/test/message_verifier_test.rb b/activesupport/test/message_verifier_test.rb new file mode 100644 index 0000000000..c7ea4cb962 --- /dev/null +++ b/activesupport/test/message_verifier_test.rb @@ -0,0 +1,25 @@ +require 'abstract_unit' + +class MessageVerifierTest < Test::Unit::TestCase + def setup + @verifier = ActiveSupport::MessageVerifier.new("Hey, I'm a secret!") + @data = {:some=>"data", :now=>Time.now} + end + + def test_simple_round_tripping + message = @verifier.generate_message(@data) + assert_equal @data, @verifier.verify_message(message) + end + + def test_tampered_data_raises + data, hash = @verifier.generate_message(@data).split("--") + assert_not_verified("#{data.reverse}--#{hash}") + assert_not_verified("#{data}--#{hash.reverse}") + end + + def assert_not_verified(message) + assert_raises(ActiveSupport::MessageVerifier::InvalidSignature) do + @verifier.verify_message(message) + end + end +end |