1
0
Fork 0
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:
Marcelo Silveira 2009-11-10 13:27:43 -02:00
parent fdea519df8
commit 262a33f71f
11 changed files with 202 additions and 107 deletions

View file

@ -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.

View 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

View 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

View 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

View 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

View 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

View file

@ -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

View file

@ -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

View file

@ -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

View 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

View file

@ -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