mirror of
https://github.com/heartcombo/devise.git
synced 2022-11-09 12:18:31 -05:00
finished implementation of encryptors and created encryptors for clearance, authlogic and restful-authentication
This commit is contained in:
parent
fdea519df8
commit
262a33f71f
11 changed files with 202 additions and 107 deletions
|
@ -10,9 +10,13 @@ Devise.setup do |config|
|
|||
|
||||
# Define what will be the encryption algorithm. Sha1 is the default.
|
||||
# Supported encryptions:
|
||||
# => ::Devise::Models::Encryptors::Sha1
|
||||
# => ::Devise::Models::Encryptors::Sha512
|
||||
# config.encryptor = ::Devise::Models::Encryptors::Sha1
|
||||
# ::Devise::Encryptors::Sha1
|
||||
# ::Devise::Encryptors::Sha512
|
||||
# ::Devise::Encryptors::ClearanceSha1
|
||||
# ::Devise::Encryptors::AuthlogicSha512 (Should set stretches to 20 for default behavior)
|
||||
# ::Devise::Encryptors::RestfulAuthenticationSha1 (Should set stretches to 10 and copy REST_AUTH_SITE_KEY to pepper
|
||||
# for default behavior)
|
||||
# config.encryptor = ::Devise::Encryptors::Sha1
|
||||
|
||||
# The time you want give to your user to confirm his account. During this time
|
||||
# he will be able to access your application without confirming. Default is nil.
|
||||
|
|
28
lib/devise/encryptors/authlogic_sha512.rb
Normal file
28
lib/devise/encryptors/authlogic_sha512.rb
Normal file
|
@ -0,0 +1,28 @@
|
|||
require "digest/sha2"
|
||||
|
||||
module Devise
|
||||
# Implements a way of adding different encryptions.
|
||||
# The class should implement a self.digest method that taks the following params:
|
||||
# - password
|
||||
# - stretches: the number of times the encryption will be applied
|
||||
# - salt: the password salt as defined by devise
|
||||
# - pepper: Devise config option
|
||||
#
|
||||
module Encryptors
|
||||
# = AuthlogicSha512
|
||||
# Simulates Authlogic's default encryption mechanism.
|
||||
# Warning: it uses Devise's stretches configuration to port Authlogic's one. Should be set to 20 in the initializer to silumate
|
||||
# the default behavior.
|
||||
class AuthlogicSha512
|
||||
|
||||
# Gererates a default password digest based on salt, pepper and the
|
||||
# incoming password.
|
||||
def self.digest(password, stretches, salt, pepper)
|
||||
digest = [password, salt].flatten.join('')
|
||||
stretches.times { digest = Digest::SHA512.hexdigest(digest) }
|
||||
digest
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
26
lib/devise/encryptors/clearance_sha1.rb
Normal file
26
lib/devise/encryptors/clearance_sha1.rb
Normal file
|
@ -0,0 +1,26 @@
|
|||
require "digest/sha1"
|
||||
|
||||
module Devise
|
||||
# Implements a way of adding different encryptions.
|
||||
# The class should implement a self.digest method that taks the following params:
|
||||
# - password
|
||||
# - stretches: the number of times the encryption will be applied
|
||||
# - salt: the password salt as defined by devise
|
||||
# - pepper: Devise config option
|
||||
#
|
||||
module Encryptors
|
||||
# = ClearanceSha1
|
||||
# Simulates Clearance's default encryption mechanism.
|
||||
# Warning: it uses Devise's pepper to port the concept of REST_AUTH_SITE_KEY
|
||||
# Warning: it uses Devise's stretches configuration to port the concept of REST_AUTH_DIGEST_STRETCHES
|
||||
class ClearanceSha1
|
||||
|
||||
# Gererates a default password digest based on salt, pepper and the
|
||||
# incoming password.
|
||||
def self.digest(password, stretches, salt, pepper)
|
||||
Digest::SHA1.hexdigest("--#{salt}--#{password}--")
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
29
lib/devise/encryptors/restful_authentication_sha1.rb
Normal file
29
lib/devise/encryptors/restful_authentication_sha1.rb
Normal file
|
@ -0,0 +1,29 @@
|
|||
require "digest/sha1"
|
||||
|
||||
module Devise
|
||||
# Implements a way of adding different encryptions.
|
||||
# The class should implement a self.digest method that taks the following params:
|
||||
# - password
|
||||
# - stretches: the number of times the encryption will be applied
|
||||
# - salt: the password salt as defined by devise
|
||||
# - pepper: Devise config option
|
||||
#
|
||||
module Encryptors
|
||||
# = RestfulAuthenticationSha1
|
||||
# Simulates Restful Authentication's default encryption mechanism.
|
||||
# Warning: it uses Devise's pepper to port the concept of REST_AUTH_SITE_KEY
|
||||
# Warning: it uses Devise's stretches configuration to port the concept of REST_AUTH_DIGEST_STRETCHES. Should be set to 10 in
|
||||
# the initializer to silumate the default behavior.
|
||||
class RestfulAuthenticationSha1
|
||||
|
||||
# Gererates a default password digest based on salt, pepper and the
|
||||
# incoming password.
|
||||
def self.digest(password, stretches, salt, pepper)
|
||||
digest = pepper
|
||||
stretches.times { digest = Digest::SHA1.hexdigest([digest, salt, password, pepper].flatten.join('--')) }
|
||||
digest
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
34
lib/devise/encryptors/sha1.rb
Normal file
34
lib/devise/encryptors/sha1.rb
Normal file
|
@ -0,0 +1,34 @@
|
|||
require 'digest/sha1'
|
||||
|
||||
module Devise
|
||||
# Implements a way of adding different encryptions.
|
||||
# The class should implement a self.digest method that taks the following params:
|
||||
# - password
|
||||
# - stretches: the number of times the encryption will be applied
|
||||
# - salt: the password salt as defined by devise
|
||||
# - pepper: Devise config option
|
||||
#
|
||||
module Encryptors
|
||||
# = Sha1
|
||||
# Uses the Sha1 hash algorithm to encrypt passwords.
|
||||
class Sha1
|
||||
|
||||
# Gererates a default password digest based on stretches, salt, pepper and the
|
||||
# incoming password.
|
||||
def self.digest(password, stretches, salt, pepper)
|
||||
digest = pepper
|
||||
stretches.times { digest = self.secure_digest(salt, digest, password, pepper) }
|
||||
digest
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
# Generate a SHA1 digest joining args. Generated token is something like
|
||||
# --arg1--arg2--arg3--argN--
|
||||
def self.secure_digest(*tokens)
|
||||
::Digest::SHA1.hexdigest('--' << tokens.flatten.join('--') << '--')
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
34
lib/devise/encryptors/sha512.rb
Normal file
34
lib/devise/encryptors/sha512.rb
Normal file
|
@ -0,0 +1,34 @@
|
|||
require "digest/sha2"
|
||||
|
||||
module Devise
|
||||
# Implements a way of adding different encryptions.
|
||||
# The class should implement a self.digest method that taks the following params:
|
||||
# - password
|
||||
# - stretches: the number of times the encryption will be applied
|
||||
# - salt: the password salt as defined by devise
|
||||
# - pepper: Devise config option
|
||||
#
|
||||
module Encryptors
|
||||
# = Sha512
|
||||
# Uses the Sha512 hash algorithm to encrypt passwords.
|
||||
class Sha512
|
||||
|
||||
# Gererates a default password digest based on salt, pepper and the
|
||||
# incoming password.
|
||||
def self.digest(password, stretches, salt, pepper)
|
||||
digest = pepper
|
||||
stretches.times { digest = self.secure_digest(salt, digest, password, pepper) }
|
||||
digest
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
# Generate a Sha512 digest joining args. Generated token is something like
|
||||
# --arg1--arg2--arg3--argN--
|
||||
def self.secure_digest(*tokens)
|
||||
::Digest::SHA512.hexdigest('--' << tokens.flatten.join('--') << '--')
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
|
@ -38,22 +38,22 @@ module Devise
|
|||
def password=(new_password)
|
||||
@password = new_password
|
||||
self.password_salt = friendly_token
|
||||
self.encrypted_password = encryptor.digest(@password, encryptor_params)
|
||||
self.encrypted_password = password_digest(@password)
|
||||
end
|
||||
|
||||
# Verifies whether an incoming_password (ie from login) is the user
|
||||
# password.
|
||||
def valid_password?(incoming_password)
|
||||
encryptor.digest(incoming_password, encryptor_params) == encrypted_password
|
||||
password_digest(incoming_password) == encrypted_password
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
# Puts the encryptor default params together
|
||||
def encryptor_params
|
||||
{ :salt => password_salt, :pepper => pepper }
|
||||
# Digests the password using the configured encryptor
|
||||
def password_digest(password)
|
||||
encryptor.digest(password, stretches, password_salt, pepper)
|
||||
end
|
||||
|
||||
|
||||
# Generate a friendly string randomically to be used as token.
|
||||
def friendly_token
|
||||
ActiveSupport::SecureRandom.base64(15).tr('+/=', '-_ ').strip.delete("\n")
|
||||
|
@ -81,7 +81,7 @@ module Devise
|
|||
|
||||
Devise::Models.config(self, :pepper)
|
||||
Devise::Models.config(self, :stretches, 10)
|
||||
Devise::Models.config(self, :encryptor, ::Devise::Models::Encryptors::Sha1)
|
||||
Devise::Models.config(self, :encryptor, ::Devise::Encryptors::Sha1)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,40 +0,0 @@
|
|||
require 'digest/sha1'
|
||||
|
||||
module Devise
|
||||
module Models
|
||||
|
||||
# Implements a way of adding different encryptions.
|
||||
# The class should implement a self.digest method that taks the following params:
|
||||
# - password to be digest
|
||||
# - params (#hash)
|
||||
# - salt: the password salt as defined by devise
|
||||
# - pepper: Devise config option
|
||||
# - stretches: Devise config option
|
||||
#
|
||||
module Encryptors
|
||||
# = Sha1
|
||||
#
|
||||
# Uses the Sha1 hash algorithm to encrypt passwords.
|
||||
class Sha1
|
||||
|
||||
# Gererates a default password digest based on salt, pepper and the
|
||||
# incoming password.
|
||||
def self.digest(password_to_digest, params)
|
||||
digest = params[:pepper]
|
||||
Devise.stretches.times { digest = self.secure_digest(params[:salt], digest, password_to_digest, params[:pepper]) }
|
||||
digest
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
# Generate a SHA1 digest joining args. Generated token is something like
|
||||
#
|
||||
# --arg1--arg2--arg3--argN--
|
||||
def self.secure_digest(*tokens)
|
||||
::Digest::SHA1.hexdigest('--' << tokens.flatten.join('--') << '--')
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,40 +0,0 @@
|
|||
require "digest/sha2"
|
||||
|
||||
module Devise
|
||||
module Models
|
||||
|
||||
# Implements a way of adding different encryptions.
|
||||
# The class should implement a self.digest method that taks the following params:
|
||||
# - password to be digest
|
||||
# - params (#hash)
|
||||
# - salt: the password salt as defined by devise
|
||||
# - pepper: Devise config option
|
||||
# - stretches: Devise config option
|
||||
#
|
||||
module Encryptors
|
||||
# = Sha512
|
||||
#
|
||||
# Uses the Sha512 hash algorithm to encrypt passwords.
|
||||
class Sha512
|
||||
|
||||
# Gererates a default password digest based on salt, pepper and the
|
||||
# incoming password.
|
||||
def self.digest(password_to_digest, params)
|
||||
digest = params[:pepper]
|
||||
Devise.stretches.times { digest = self.secure_digest(params[:salt], digest, password_to_digest, params[:pepper]) }
|
||||
digest
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
# Generate a Sha512 digest joining args. Generated token is something like
|
||||
#
|
||||
# --arg1--arg2--arg3--argN--
|
||||
def self.secure_digest(*tokens)
|
||||
::Digest::SHA512.hexdigest('--' << tokens.flatten.join('--') << '--')
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
21
test/encryptors/encryptors_test.rb
Normal file
21
test/encryptors/encryptors_test.rb
Normal file
|
@ -0,0 +1,21 @@
|
|||
class Encryptors < ActiveSupport::TestCase
|
||||
|
||||
test 'should match a password created by authlogic' do
|
||||
authlogic = "b623c3bc9c775b0eb8edb218a382453396fec4146422853e66ecc4b6bc32d7162ee42074dcb5f180a770dc38b5df15812f09bbf497a4a1b95fe5e7d2b8eb7eb4"
|
||||
encryptor = Devise::Encryptors::AuthlogicSha512.digest('123mudar', 20, 'usZK_z_EAaF61Gwkw-ed', '')
|
||||
assert_equal authlogic, encryptor
|
||||
end
|
||||
|
||||
test 'should match a password created by restful_authentication' do
|
||||
restful_authentication = "93110f71309ce91366375ea44e2a6f5cc73fa8d4"
|
||||
encryptor = Devise::Encryptors::RestfulAuthenticationSha1.digest('123mudar', 10, '48901d2b247a54088acb7f8ea3e695e50fe6791b', 'fee9a51ec0a28d11be380ca6dee6b4b760c1a3bf')
|
||||
assert_equal restful_authentication, encryptor
|
||||
end
|
||||
|
||||
test 'should match a password created by clearance' do
|
||||
clearance = "0f40bbae18ddefd7066276c3ef209d40729b0378"
|
||||
encryptor = Devise::Encryptors::ClearanceSha1.digest('123mudar', nil, '65c58472c207c829f28c68619d3e3aefed18ab3f', nil)
|
||||
assert_equal clearance, encryptor
|
||||
end
|
||||
|
||||
end
|
|
@ -3,10 +3,8 @@ require 'digest/sha1'
|
|||
|
||||
class AuthenticatableTest < ActiveSupport::TestCase
|
||||
|
||||
def encrypt_password(user, pepper=nil, stretches=1)
|
||||
user.class_eval { define_method(:stretches) { stretches } } if stretches
|
||||
user.password = '123456'
|
||||
user.encryptor.digest('123456', { :salt => user.password_salt, :pepper => pepper })
|
||||
def encrypt_password(user, pepper=User.pepper, stretches=User.stretches, encryptor = ::Devise::Encryptors::Sha1)
|
||||
encryptor.digest('123456', stretches, user.password_salt, pepper)
|
||||
end
|
||||
|
||||
test 'should respond to password and password confirmation' do
|
||||
|
@ -59,7 +57,7 @@ class AuthenticatableTest < ActiveSupport::TestCase
|
|||
assert_not_equal encrypted_password, user.encrypted_password
|
||||
end
|
||||
|
||||
test 'should encrypt password using a sha1 hash' do
|
||||
test 'should fallback to Sha1 as default encryption' do
|
||||
user = new_user
|
||||
assert_equal encrypt_password(user), user.encrypted_password
|
||||
end
|
||||
|
@ -69,12 +67,15 @@ class AuthenticatableTest < ActiveSupport::TestCase
|
|||
Devise.pepper = ''
|
||||
user = new_user
|
||||
assert_equal encrypt_password(user), user.encrypted_password
|
||||
assert_not_equal encrypt_password(user, 'another_pepper'), user.encrypted_password
|
||||
Devise.pepper = 'new_pepper'
|
||||
user = new_user
|
||||
assert_equal encrypt_password(user, 'new_pepper'), user.encrypted_password
|
||||
assert_not_equal encrypt_password(user, 'another_pepper'), user.encrypted_password
|
||||
Devise.pepper = '123456'
|
||||
user = new_user
|
||||
assert_equal encrypt_password(user, '123456'), user.encrypted_password
|
||||
assert_not_equal encrypt_password(user, 'another_pepper'), user.encrypted_password
|
||||
ensure
|
||||
Devise.pepper = nil
|
||||
end
|
||||
|
@ -85,23 +86,21 @@ class AuthenticatableTest < ActiveSupport::TestCase
|
|||
default_stretches = Devise.stretches
|
||||
Devise.stretches = 1
|
||||
user = new_user
|
||||
assert_equal encrypt_password(user, nil, nil), user.encrypted_password
|
||||
assert_equal encrypt_password(user, nil, 1), user.encrypted_password
|
||||
assert_not_equal encrypt_password(user, nil, 2), user.encrypted_password
|
||||
ensure
|
||||
Devise.stretches = default_stretches
|
||||
end
|
||||
end
|
||||
|
||||
test 'should fallback to Sha1 as default encryption' do
|
||||
user = create_user
|
||||
puts user.encrypted_password
|
||||
assert_equal user.encrypted_password, ::Devise::Models::Encryptors::Sha1.digest('123456', { :pepper => Devise.pepper, :salt => user.password_salt })
|
||||
end
|
||||
|
||||
test 'should act according to encryptor configuration' do
|
||||
Devise.encryptor = ::Devise::Models::Encryptors::Sha512
|
||||
user = create_user
|
||||
puts user.encrypted_password
|
||||
assert_equal user.encrypted_password, ::Devise::Models::Encryptors::Sha512.digest('123456', { :pepper => Devise.pepper, :salt => user.password_salt })
|
||||
test 'should respect encryptor configuration' do
|
||||
begin
|
||||
Devise.encryptor = ::Devise::Encryptors::Sha512
|
||||
user = create_user
|
||||
assert_equal user.encrypted_password, encrypt_password(user, User.pepper, User.stretches, ::Devise::Encryptors::Sha512)
|
||||
ensure
|
||||
Devise.encryptor = ::Devise::Encryptors::Sha1
|
||||
end
|
||||
end
|
||||
|
||||
test 'should test for a valid password' do
|
||||
|
|
Loading…
Reference in a new issue