mirror of
https://github.com/rails/rails.git
synced 2022-11-09 12:12:34 -05:00
Allow token length configuration for has_secure_token method
The minimum token length is set to 24 due to security constraints. We can now specify a longer length through the length: parameter. This is especially useful for cases when your data storage is case-insensitive and you want to increase your entropy.
This commit is contained in:
parent
dd58d040b2
commit
51443e22f3
4 changed files with 47 additions and 9 deletions
|
@ -1,3 +1,22 @@
|
|||
* Allow length configuration for `has_secure_token` method. The minimum length
|
||||
is set at 24 characters.
|
||||
|
||||
Before:
|
||||
|
||||
```ruby
|
||||
has_secure_token :auth_token
|
||||
```
|
||||
|
||||
After:
|
||||
|
||||
```ruby
|
||||
has_secure_token :default_token # 24 characters
|
||||
has_secure_token :auth_token, length: 36 # 36 characters
|
||||
has_secure_token :invalid_token, length: 12 # => ActiveRecord::SecureToken::MinimumLengthError
|
||||
```
|
||||
|
||||
*Bernardo de Araujo*
|
||||
|
||||
* Raise `ArgumentError` for invalid `:limit` and `:precision` like as other options.
|
||||
|
||||
Before:
|
||||
|
|
|
@ -2,6 +2,10 @@
|
|||
|
||||
module ActiveRecord
|
||||
module SecureToken
|
||||
class MinimumLengthError < StandardError; end
|
||||
|
||||
MINIMUM_TOKEN_LENGTH = 24
|
||||
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
module ClassMethods
|
||||
|
@ -10,30 +14,32 @@ module ActiveRecord
|
|||
# # Schema: User(token:string, auth_token:string)
|
||||
# class User < ActiveRecord::Base
|
||||
# has_secure_token
|
||||
# has_secure_token :auth_token
|
||||
# has_secure_token :auth_token, length: 36
|
||||
# end
|
||||
#
|
||||
# user = User.new
|
||||
# user.save
|
||||
# user.token # => "pX27zsMN2ViQKta1bGfLmVJE"
|
||||
# user.auth_token # => "77TMHrHJFvFDwodq8w7Ev2m7"
|
||||
# user.auth_token # => "tU9bLuZseefXQ4yQxQo8wjtBvsAfPc78os6R"
|
||||
# user.regenerate_token # => true
|
||||
# user.regenerate_auth_token # => true
|
||||
#
|
||||
# <tt>SecureRandom::base58</tt> is used to generate the 24-character unique token, so collisions are highly unlikely.
|
||||
# <tt>SecureRandom::base58</tt> is used to generate at minimum a 24-character unique token, so collisions are highly unlikely.
|
||||
#
|
||||
# Note that it's still possible to generate a race condition in the database in the same way that
|
||||
# {validates_uniqueness_of}[rdoc-ref:Validations::ClassMethods#validates_uniqueness_of] can.
|
||||
# You're encouraged to add a unique index in the database to deal with this even more unlikely scenario.
|
||||
def has_secure_token(attribute = :token)
|
||||
def has_secure_token(attribute = :token, length: MINIMUM_TOKEN_LENGTH)
|
||||
raise MinimumLengthError, "Token requires a minimum length of 24 characters." if length < MINIMUM_TOKEN_LENGTH
|
||||
|
||||
# Load securerandom only when has_secure_token is used.
|
||||
require "active_support/core_ext/securerandom"
|
||||
define_method("regenerate_#{attribute}") { update! attribute => self.class.generate_unique_secure_token }
|
||||
before_create { send("#{attribute}=", self.class.generate_unique_secure_token) unless send("#{attribute}?") }
|
||||
define_method("regenerate_#{attribute}") { update! attribute => self.class.generate_unique_secure_token(length: length) }
|
||||
before_create { send("#{attribute}=", self.class.generate_unique_secure_token(length: length)) unless send("#{attribute}?") }
|
||||
end
|
||||
|
||||
def generate_unique_secure_token
|
||||
SecureRandom.base58(24)
|
||||
def generate_unique_secure_token(length: MINIMUM_TOKEN_LENGTH)
|
||||
SecureRandom.base58(length)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -12,6 +12,8 @@ class SecureTokenTest < ActiveRecord::TestCase
|
|||
@user.save
|
||||
assert_not_nil @user.token
|
||||
assert_not_nil @user.auth_token
|
||||
assert_equal 24, @user.token.size
|
||||
assert_equal 36, @user.auth_token.size
|
||||
end
|
||||
|
||||
def test_regenerating_the_secure_token
|
||||
|
@ -23,6 +25,9 @@ class SecureTokenTest < ActiveRecord::TestCase
|
|||
|
||||
assert_not_equal @user.token, old_token
|
||||
assert_not_equal @user.auth_token, old_auth_token
|
||||
|
||||
assert_equal 24, @user.token.size
|
||||
assert_equal 36, @user.auth_token.size
|
||||
end
|
||||
|
||||
def test_token_value_not_overwritten_when_present
|
||||
|
@ -31,4 +36,12 @@ class SecureTokenTest < ActiveRecord::TestCase
|
|||
|
||||
assert_equal "custom-secure-token", @user.token
|
||||
end
|
||||
|
||||
def test_token_length_cannot_be_less_than_24_characters
|
||||
assert_raises(ActiveRecord::SecureToken::MinimumLengthError) do
|
||||
@user.class_eval do
|
||||
has_secure_token :not_valid_token, length: 12
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -4,7 +4,7 @@ require "models/job"
|
|||
|
||||
class User < ActiveRecord::Base
|
||||
has_secure_token
|
||||
has_secure_token :auth_token
|
||||
has_secure_token :auth_token, length: 36
|
||||
|
||||
has_and_belongs_to_many :jobs_pool,
|
||||
class_name: "Job",
|
||||
|
|
Loading…
Reference in a new issue