Skip to content

Commit

Permalink
Added :acts_like_restful_authentication to help with the transition, …
Browse files Browse the repository at this point in the history
…and a new crypto provider BCrypt
  • Loading branch information
binarylogic committed Nov 22, 2008
1 parent 2b85651 commit 387c12c
Show file tree
Hide file tree
Showing 5 changed files with 78 additions and 7 deletions.
12 changes: 7 additions & 5 deletions CHANGELOG.rdoc
Original file line number Original file line Diff line number Diff line change
@@ -1,11 +1,13 @@
== 1.3.1 released 2008-11-20 == 1.3.1 released 2008-11-22


* Fixed typo in acts_as_authentic config when passing the :scope option * Fixed typo in acts_as_authentic config when passing the :scope option.
* Added :act_like_restful_authentication option for acts_as_authentic
* Added a new crypto provider: BCrypt, this is for the hardcore paranoid, or for those storing the nuclear launch codes in their apps


== 1.3.0 released 2008-11-20 == 1.3.0 released 2008-11-21


* BREAKS BACKWARDS COMPATIBILITY: changed the confirm_password field to password_confirmation for acts_as_authentic, since the rails validates_confirmation_of handles creating this attribute. * BREAKS BACKWARDS COMPATIBILITY: changed the confirm_password field to password_confirmation for acts_as_authentic, since the rails validates_confirmation_of handles creating this attribute and there is no option to change the name of this.
* BREAKS BACKWARDS COMPATIBILITY: Cleaned up all of the validation configuration for acts_as_authentic, as well as the documentation that goes with it, you can accomplish the same things as before, but this is much more flexible and much more organized. * BREAKS BACKWARDS COMPATIBILITY: Cleaned up all of the validation configuration for acts_as_authentic, as well as the documentation that goes with it, you can accomplish the same things as before, but this is much more flexible and much more organized. This is mainly for those implementing i18n support. Instead of :whatever_message, its now :login_field_validates_length_of_options => {:message => "your i18n friendly message"}. As a side note, with the new i18n support in rails I would not be surprised if this is already done for you since Authlogic uses the ActiveRecord validation methods.
* Got rid of simple delegator for the abstract controller, apparently this has performance issues. * Got rid of simple delegator for the abstract controller, apparently this has performance issues.
* Cleaned up validations to assume ActiveRecord dirty attributes are present, I think this is a safe assumption. * Cleaned up validations to assume ActiveRecord dirty attributes are present, I think this is a safe assumption.


Expand Down
1 change: 1 addition & 0 deletions lib/authlogic.rb
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@


require File.dirname(__FILE__) + "/authlogic/crypto_providers/sha1" require File.dirname(__FILE__) + "/authlogic/crypto_providers/sha1"
require File.dirname(__FILE__) + "/authlogic/crypto_providers/sha512" require File.dirname(__FILE__) + "/authlogic/crypto_providers/sha512"
require File.dirname(__FILE__) + "/authlogic/crypto_providers/bcrypt"


if defined?(ActiveRecord) if defined?(ActiveRecord)
require File.dirname(__FILE__) + "/authlogic/orm_adapters/active_record_adapter/acts_as_authentic" require File.dirname(__FILE__) + "/authlogic/orm_adapters/active_record_adapter/acts_as_authentic"
Expand Down
49 changes: 49 additions & 0 deletions lib/authlogic/crypto_providers/bcrypt.rb
Original file line number Original file line Diff line number Diff line change
@@ -0,0 +1,49 @@
begin
require "bcrypt"
rescue LoadError
end

module Authlogic
module CryptoProviders
# = Bcrypt
#
# For most apps Sha512 is plenty secure, but if you are building an app that stores the nuclear launch codes you might want to consier BCrypt. This is an extremely
# secure hashing algorithm, mainly because it is slow. A brute force attack on a BCrypt encrypted password would take much longer than a brute force attack on a
# password encrypted with a Sha algorithm. Keep in mind you are sacrificing performance by using this, generating a password takes exponentially longer than any
# of the Sha algorithms. I did some benchmarking to save you some time with your decision:
#
# require "bcrypt"
# require "digest"
# require "benchmark"
#
# Benchmark.bm do |x|
# x.report("BCrypt:") { BCrypt::Password.create("mypass") }
# x.report("Sha512:") { Digest::SHA512.hexdigest("mypass") }
# end
#
# user system total real
# BCrypt: 0.110000 0.000000 0.110000 ( 0.113493)
# Sha512: 0.010000 0.000000 0.010000 ( 0.000554)
#
# Decided BCrypt is for you? Just insall the bcrypt gem:
#
# gem install bcrypt-ruby
class Bcrypt
class << self
def cost
@cost ||= 10
end
attr_writer :cost

def encrypt(pass)
BCrypt::Password.create(pass, :cost => cost)
end

# This does not actually decrypt the password, BCrypt is *not* reversible. The way the bcrypt library is set up requires us to do it this way.
def decrypt(crypted_pass)
BCrypt::Password.create(crypted_pass)
end
end
end
end
end
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -22,6 +22,12 @@ module ActsAsAuthentic
# * <tt>crypto_provider</tt> - default: Authlogic::CryptoProviders::Sha512, # * <tt>crypto_provider</tt> - default: Authlogic::CryptoProviders::Sha512,
# This is the class that provides your encryption. By default Authlogic provides its own crypto provider that uses Sha512 encrypton. # This is the class that provides your encryption. By default Authlogic provides its own crypto provider that uses Sha512 encrypton.
# #
# * <tt>act_like_restful_authentication</tt> - default: false,
# If you are migrating from restful_authentication you will want to set this to true, this way your users will still be able to log in and it will seems as
# if nothing has changed. If you don't do this none of your users will be able to log in. If you are starting a new project I do not recommend enabling this
# as the password encryption algorithm used in restful_authentication (Sha1) is not as secure as the one used in authlogic (Sha512). IF you REALLY want to be secure
# checkout Authlogic::CryptoProviders::BCrypt.
#
# * <tt>login_field</tt> - default: :login, :username, or :email, depending on which column is present, if none are present defaults to :login # * <tt>login_field</tt> - default: :login, :username, or :email, depending on which column is present, if none are present defaults to :login
# The name of the field used for logging in. Only specify if you aren't using any of the defaults. # The name of the field used for logging in. Only specify if you aren't using any of the defaults.
# #
Expand Down Expand Up @@ -183,6 +189,10 @@ def acts_as_authentic_with_config(options = {})
options[:login_field_validates_uniqueness_of_options][:scope] ||= options[:scope] options[:login_field_validates_uniqueness_of_options][:scope] ||= options[:scope]
options[:email_field_validates_uniqueness_of_options][:scope] ||= options[:scope] options[:email_field_validates_uniqueness_of_options][:scope] ||= options[:scope]
end end

if options[:act_like_restful_authentication]
options[:crypto_provider] = CryptoProviders::Sha1
end


class_eval <<-"end_eval", __FILE__, __LINE__ class_eval <<-"end_eval", __FILE__, __LINE__
def self.acts_as_authentic_config def self.acts_as_authentic_config
Expand Down
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -66,13 +66,13 @@ def #{options[:password_field]}=(pass)
return if pass.blank? return if pass.blank?
@#{options[:password_field]} = pass @#{options[:password_field]} = pass
self.#{options[:password_salt_field]} = self.class.unique_token self.#{options[:password_salt_field]} = self.class.unique_token
self.#{options[:crypted_password_field]} = #{options[:crypto_provider]}.encrypt(@#{options[:password_field]} + #{options[:password_salt_field]}) self.#{options[:crypted_password_field]} = #{options[:crypto_provider]}.encrypt(obfuscate_password(@#{options[:password_field]}))
end end
def valid_#{options[:password_field]}?(attempted_password) def valid_#{options[:password_field]}?(attempted_password)
return false if attempted_password.blank? || #{options[:crypted_password_field]}.blank? || #{options[:password_salt_field]}.blank? return false if attempted_password.blank? || #{options[:crypted_password_field]}.blank? || #{options[:password_salt_field]}.blank?
(#{options[:crypto_provider]}.respond_to?(:decrypt) && #{options[:crypto_provider]}.decrypt(#{options[:crypted_password_field]}) == attempted_password + #{options[:password_salt_field]}) || (#{options[:crypto_provider]}.respond_to?(:decrypt) && #{options[:crypto_provider]}.decrypt(#{options[:crypted_password_field]}) == attempted_password + #{options[:password_salt_field]}) ||
(!#{options[:crypto_provider]}.respond_to?(:decrypt) && #{options[:crypto_provider]}.encrypt(attempted_password + #{options[:password_salt_field]}) == #{options[:crypted_password_field]}) (!#{options[:crypto_provider]}.respond_to?(:decrypt) && #{options[:crypto_provider]}.encrypt(obfuscate_password(attempted_password)) == #{options[:crypted_password_field]})
end end
def reset_#{options[:password_field]} def reset_#{options[:password_field]}
Expand All @@ -87,6 +87,15 @@ def reset_#{options[:password_field]}!
save_without_session_maintenance(false) save_without_session_maintenance(false)
end end
alias_method :randomize_password!, :reset_password! alias_method :randomize_password!, :reset_password!
private
def obfuscate_password(raw_password)
if #{options[:act_like_restful_authentication].inspect}
[REST_AUTH_SITE_KEY, raw_password, #{options[:password_salt_field]}, REST_AUTH_SITE_KEY].join("--")
else
raw_password + #{options[:password_salt_field]}
end
end
end_eval end_eval
end end
end end
Expand Down

0 comments on commit 387c12c

Please sign in to comment.