authlogic 1.3.2 → 1.3.3

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of authlogic might be problematic. Click here for more details.

@@ -1,3 +1,10 @@
1
+ == 1.3.3 released 2008-11-23
2
+
3
+ * Updated :act_like_restful_authentication for those using the older version where no site wide key is preset (REST_AUTH_SITE_KEY), Authlogic will adjust automatically based on the presence of this constant.
4
+ * Added :transition_from_crypto_provider option for acts_as_authentic to transition your user's passwords to a new algorithm.
5
+ * Added :transition_from_restful_authentication for acts_as_authentic to transition your users from restful_authentication to the Authlogic password system. Now you can choose to keep your passwords the same by using :act_like_restful_authentication, which will *NOT* do any transitioning, or you can use :transition_from_crypto_provider which will update your users passwords as they login or new accounts are created, while still allowing users with the old password system to log in.
6
+ * Modified the "interface" for the crypto providers to only provide a class level encrypt and matches? method, instead of a class level encrypt and decrypt method.
7
+
1
8
  == 1.3.2 released 2008-11-22
2
9
 
3
10
  * Updated code to work better with BCrypt, using root level class now.
@@ -74,7 +74,9 @@ Authlogic makes this a reality. This is just the tip of the ice berg. Keep readi
74
74
  * <b>Tutorial: Authlogic basic setup:</b> http://www.binarylogic.com/2008/11/3/tutorial-authlogic-basic-setup
75
75
  * <b>Tutorial: Reset passwords with Authlogic the RESTful way:</b> http://www.binarylogic.com/2008/11/16/tutorial-reset-passwords-with-authlogic
76
76
  * <b>Tutorial: Using OpenID with Authlogic:</b> http://www.binarylogic.com/2008/11/21/tutorial-using-openid-with-authlogic
77
- * <b>Live example of the setup tutorial above (with source):</b> http://authlogicexample.binarylogic.com
77
+ * <b>Live example of the tutorials above (with source):</b> http://authlogicexample.binarylogic.com
78
+ * <b>Tutorial: Easily migrate from restful_authentication:</b> http://www.binarylogic.com/2008/11/23/tutorial-easily-migrate-from-restful_authentication-to-authlogic
79
+ * <b>Tutorial: Upgrade passwords easily with Authlogic:</b> http://www.binarylogic.com/2008/11/23/tutorial-upgrade-passwords-easily-with-authlogic
78
80
  * <b>Bugs / feature suggestions:</b> http://binarylogic.lighthouseapp.com/projects/18752-authlogic
79
81
 
80
82
  == Install and use
@@ -124,7 +126,9 @@ Make sure you have a model that you will be authenticating with. For this exampl
124
126
  acts_as_authentic # for options see documentation: Authlogic::ORMAdapters::ActiveRecordAdapter::ActsAsAuthentic::Config
125
127
  end
126
128
 
127
- Done! Now go use it just like you would with any other ActiveRecord model. Either glance at the code at the beginning of this README or check out the tutorials (see above in "helpful links") for a more detailed walk through.
129
+ One thing to keep in mind here is that the default :crypto_provider for Authlogic is Sha512. You are *NOT* forced to use this. See the encryption methods section below for more information.
130
+
131
+ You are all set, now go use it just like you would with any other ActiveRecord model. Either glance at the code at the beginning of this README or check out the tutorials (see above in "helpful links") for a more detailed walk through.
128
132
 
129
133
  == Magic Columns
130
134
 
@@ -193,6 +197,25 @@ This will keep everything separate. The :secure session will store its info in a
193
197
 
194
198
  For more information on ids checkout Authlogic::Session::Base#id
195
199
 
200
+ == Encryption methods
201
+
202
+ Authlogic is designed so you can use *any* encryption method you want. It delegates this task to a class of your choice. By default Authlogic uses salted Sha512 with 20 stretches. It also comes preloaded with some other common encryption algorithms so that you can choose. For example, if you wanted to use the BCrypt algorithm just do the following:
203
+
204
+ acts_as_authentic :crypto_provider => Authlogic::CryptoProviders::BCrypt
205
+
206
+ For more information on BCrypt checkout my blog post on it: http://www.binarylogic.com/2008/11/22/storing-nuclear-launch-codes-in-your-app-enter-bcrypt-for-authlogic
207
+
208
+ Also, check out the Authlogic::CryptoProviders module and sublcasses to get an idea of how to write your own crypto provider. It's extremely easy, all that you have to do is make a class with a class level encrypt and matches? method. That's it, the sky is the limit.
209
+
210
+ == Switching to a new encryption method
211
+
212
+ Switching to a new encryption method used to be a pain in the ass. Authlogic has an option that makes this dead simple. Let's say you want to migrate to the BCrypt encryption method from Sha512:
213
+
214
+ acts_as_authentic :crypto_provider => Authlogic::CryptoProviders::BCrypt,
215
+ :transition_from_crypto_provider => Authlogic::CryptoProviders::Sha512
216
+
217
+ That's it. When a user successfully logs in and is using the old method their password will be updated with the new method and all new registrations will use the new method as well. Your users won't know anything changed.
218
+
196
219
  == Tokens (persistence, resetting passwords, private feed access, etc.)
197
220
 
198
221
  To start, let me define tokens as Authlogic sees it. A token is a form of credentials that grants some type of access to their account. Depending on the type of access, a different type of token may be needed. Put simply, it's a way for the user to say "I am this person, let me proceed". What types of different access you ask? Here are just a few:
@@ -369,12 +392,17 @@ Migrating from the restful_authentication plugin? I made an option especially fo
369
392
 
370
393
  # app/models/user.rb
371
394
  class User < ActiveRecord::Base
372
- acts_as_authentic :acts_like_restful_authentication => true
395
+ acts_as_authentic :act_like_restful_authentication => true
373
396
  end
374
397
 
375
- **What's the difference?**
398
+ Or you can transition your users to the Authlogic password system:
399
+
400
+ # app/models/user.rb
401
+ class User < ActiveRecord::Base
402
+ acts_as_authentic :transition_from_restful_authentication => true
403
+ end
376
404
 
377
- restful\_authentication uses Sha1 with 10 stretches to encrypt the password. Authlogic uses Sha512 with 20 stretches. Sha512 is stronger and more secure.
405
+ For more information checkout my blog post on this: http://www.binarylogic.com/2008/11/23/tutorial-easily-migrate-from-restful_authentication-to-authlogic
378
406
 
379
407
  == Framework agnostic (Rails, Merb, etc.)
380
408
 
@@ -2,11 +2,11 @@
2
2
 
3
3
  Gem::Specification.new do |s|
4
4
  s.name = %q{authlogic}
5
- s.version = "1.3.2"
5
+ s.version = "1.3.3"
6
6
 
7
7
  s.required_rubygems_version = Gem::Requirement.new(">= 1.2") if s.respond_to? :required_rubygems_version=
8
8
  s.authors = ["Ben Johnson of Binary Logic"]
9
- s.date = %q{2008-11-22}
9
+ s.date = %q{2008-11-23}
10
10
  s.description = %q{A clean, simple, and unobtrusive ruby authentication solution.}
11
11
  s.email = %q{bjohnson@binarylogic.com}
12
12
  s.extra_rdoc_files = ["CHANGELOG.rdoc", "lib/authlogic/controller_adapters/abstract_adapter.rb", "lib/authlogic/controller_adapters/merb_adapter.rb", "lib/authlogic/controller_adapters/rails_adapter.rb", "lib/authlogic/crypto_providers/bcrypt.rb", "lib/authlogic/crypto_providers/sha1.rb", "lib/authlogic/crypto_providers/sha512.rb", "lib/authlogic/orm_adapters/active_record_adapter/acts_as_authentic/config.rb", "lib/authlogic/orm_adapters/active_record_adapter/acts_as_authentic/credentials.rb", "lib/authlogic/orm_adapters/active_record_adapter/acts_as_authentic/logged_in.rb", "lib/authlogic/orm_adapters/active_record_adapter/acts_as_authentic/perishability.rb", "lib/authlogic/orm_adapters/active_record_adapter/acts_as_authentic/persistence.rb", "lib/authlogic/orm_adapters/active_record_adapter/acts_as_authentic/session_maintenance.rb", "lib/authlogic/orm_adapters/active_record_adapter/acts_as_authentic/single_access.rb", "lib/authlogic/orm_adapters/active_record_adapter/acts_as_authentic.rb", "lib/authlogic/orm_adapters/active_record_adapter/authenticates_many.rb", "lib/authlogic/session/active_record_trickery.rb", "lib/authlogic/session/authenticates_many_association.rb", "lib/authlogic/session/base.rb", "lib/authlogic/session/callbacks.rb", "lib/authlogic/session/config.rb", "lib/authlogic/session/cookies.rb", "lib/authlogic/session/errors.rb", "lib/authlogic/session/params.rb", "lib/authlogic/session/perishability.rb", "lib/authlogic/session/scopes.rb", "lib/authlogic/session/session.rb", "lib/authlogic/version.rb", "lib/authlogic.rb", "README.rdoc"]
@@ -7,7 +7,7 @@ module Authlogic
7
7
  module CryptoProviders
8
8
  # = Bcrypt
9
9
  #
10
- # 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
10
+ # For most apps Sha512 is plenty secure, but if you are building an app that stores nuclear launch codes you might want to consier BCrypt. This is an extremely
11
11
  # 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
12
12
  # password encrypted with a Sha algorithm. Keep in mind you are sacrificing performance by using this, generating a password takes exponentially longer than any
13
13
  # of the Sha algorithms. I did some benchmarking to save you some time with your decision:
@@ -16,14 +16,20 @@ module Authlogic
16
16
  # require "digest"
17
17
  # require "benchmark"
18
18
  #
19
- # Benchmark.bm do |x|
20
- # x.report("BCrypt:") { BCrypt::Password.create("mypass") }
21
- # x.report("Sha512:") { Digest::SHA512.hexdigest("mypass") }
19
+ # Benchmark.bm(18) do |x|
20
+ # x.report("BCrypt (cost = 10:") { 100.times { BCrypt::Password.create("mypass", :cost => 10) } }
21
+ # x.report("BCrypt (cost = 2:") { 100.times { BCrypt::Password.create("mypass", :cost => 2) } }
22
+ # x.report("Sha512:") { 100.times { Digest::SHA512.hexdigest("mypass") } }
23
+ # x.report("Sha1:") { 100.times { Digest::SHA1.hexdigest("mypass") } }
22
24
  # end
23
25
  #
24
- # user system total real
25
- # BCrypt: 0.110000 0.000000 0.110000 ( 0.113493)
26
- # Sha512: 0.010000 0.000000 0.010000 ( 0.000554)
26
+ # user system total real
27
+ # BCrypt (cost = 10): 10.780000 0.060000 10.840000 ( 11.100289)
28
+ # BCrypt (cost = 2): 0.180000 0.000000 0.180000 ( 0.181914)
29
+ # Sha512: 0.000000 0.000000 0.000000 ( 0.000829)
30
+ # Sha1: 0.000000 0.000000 0.000000 ( 0.000395)
31
+ #
32
+ # You can play around with the cost to get that perfect balance between performance and security.
27
33
  #
28
34
  # Decided BCrypt is for you? Just insall the bcrypt gem:
29
35
  #
@@ -37,20 +43,46 @@ module Authlogic
37
43
  class BCrypt
38
44
  class << self
39
45
  # This is the :cost option for the BCrpyt library. The higher the cost the more secure it is and the longer is take the generate a hash. By default this is 10.
46
+ # Set this to whatever you want, play around with it to get that perfect balance between security and performance.
40
47
  def cost
41
48
  @cost ||= 10
42
49
  end
43
50
  attr_writer :cost
44
51
 
45
52
  # Creates a BCrypt hash for the password passed.
46
- def encrypt(pass)
47
- ::BCrypt::Password.create(pass, :cost => cost)
53
+ def encrypt(*tokens)
54
+ ::BCrypt::Password.create(join_tokens(tokens), :cost => cost)
55
+ end
56
+
57
+ # Does the hash match the tokens? Uses the same tokens that were used to encrypt.
58
+ def matches?(hash, *tokens)
59
+ hash = new_from_hash(hash)
60
+ return false if hash.blank?
61
+ hash == join_tokens(tokens)
48
62
  end
49
63
 
50
- # 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.
51
- def decrypt(crypted_pass)
52
- ::BCrypt::Password.new(crypted_pass)
64
+ # This method is used as a flag to tell Authlogic to "resave" the password upon a successful login, using the new cost
65
+ def cost_matches?(hash)
66
+ hash = new_from_hash(hash)
67
+ if hash.blank?
68
+ false
69
+ else
70
+ hash.cost == cost
71
+ end
53
72
  end
73
+
74
+ private
75
+ def join_tokens(tokens)
76
+ tokens.flatten.join
77
+ end
78
+
79
+ def new_from_hash(hash)
80
+ begin
81
+ ::BCrypt::Password.new(hash)
82
+ rescue ::BCrypt::Errors::InvalidHash
83
+ return nil
84
+ end
85
+ end
54
86
  end
55
87
  end
56
88
  end
@@ -4,19 +4,31 @@ module Authlogic
4
4
  module CryptoProviders
5
5
  # = Sha1
6
6
  #
7
- # Uses the Sha1 hash algorithm to encrypt passwords. This class is useful if you are migrating from restful_authentication. This uses the
8
- # exact same excryption algorithm with 10 stretches, just like restful_authentication.
7
+ # This class was made for the users transitioning from restful_authentication. I highly discourage using this crypto provider as it inferior to your other options.
8
+ # Please use the Sha512 crypto provider or the BCrypt provider.
9
9
  class Sha1
10
10
  class << self
11
+ def join_token
12
+ @join_token ||= "--"
13
+ end
14
+ attr_writer :join_token
15
+
16
+ # The number of times to loop through the encryption. This is ten because that is what restful_authentication defaults to.
11
17
  def stretches
12
18
  @stretches ||= 10
13
19
  end
14
20
  attr_writer :stretches
15
21
 
16
- def encrypt(pass)
17
- digest = pass
18
- stretches.times { digest = Digest::SHA1.hexdigest(digest) }
19
- digest
22
+ # Turns your raw password into a Sha1 hash.
23
+ def encrypt(*tokens)
24
+ tokens = tokens.flatten
25
+ digest = tokens.shift
26
+ stretches.times { digest = Digest::SHA1.hexdigest([digest, *tokens].compact.join(join_token)) }
27
+ end
28
+
29
+ # Does the crypted password match the tokens? Uses the same tokens that were used to encrypt.
30
+ def matches?(crypted, *tokens)
31
+ encrypt(*tokens) == crypted
20
32
  end
21
33
  end
22
34
  end
@@ -4,26 +4,48 @@ module Authlogic
4
4
  # = Crypto Providers
5
5
  #
6
6
  # The acts_as_authentic method allows you to pass a :crypto_provider option. This allows you to use any type of encryption you like.
7
- # Just create a class with a class level encrypt and decrypt method. The password will be passed as the single parameter to each of these
8
- # methods so you can do your magic.
7
+ # Just create a class with a class level encrypt and matches? method. See example below.
9
8
  #
10
- # If you are encrypting via a hash just don't include a decrypt method, since hashes can't be decrypted. Authlogic will notice this adjust accordingly.
9
+ # === Example
10
+ #
11
+ # class MyAwesomeEncryptionMethod
12
+ # def self.encrypt(*tokens)
13
+ # # the tokens passed wil be an array of objects, what type of object is irrelevant
14
+ # # just do what you need to do with them and return a single encrypted string.
15
+ # # for example, you will most likely join all of the objects into a single string and then encrypt that string
16
+ # end
17
+ #
18
+ # def self.matches?(crypted, *tokens)
19
+ # # return true if the crypted string matches the tokens.
20
+ # # depending on your algorithm you might decrypt the string then compare it to the token, or you might
21
+ # # encrypt the tokens and make sure it matches the crypted string, its up to you
22
+ # end
23
+ # end
11
24
  module CryptoProviders
12
25
  # = Sha512
13
26
  #
14
27
  # Uses the Sha512 hash algorithm to encrypt passwords.
15
28
  class Sha512
16
29
  class << self
30
+ attr_accessor :join_token
31
+
32
+ # The number of times to loop through the encryption. This is ten because that is what restful_authentication defaults to.
17
33
  def stretches
18
34
  @stretches ||= 20
19
35
  end
20
36
  attr_writer :stretches
21
37
 
22
- def encrypt(pass)
23
- digest = pass
38
+ # Turns your raw password into a Sha512 hash.
39
+ def encrypt(*tokens)
40
+ digest = tokens.flatten.join(join_token)
24
41
  stretches.times { digest = Digest::SHA512.hexdigest(digest) }
25
42
  digest
26
43
  end
44
+
45
+ # Does the crypted password match the tokens? Uses the same tokens that were used to encrypt.
46
+ def matches?(crypted, *tokens)
47
+ encrypt(*tokens) == crypted
48
+ end
27
49
  end
28
50
  end
29
51
  end
@@ -22,12 +22,21 @@ module Authlogic
22
22
  # * <tt>crypto_provider</tt> - default: Authlogic::CryptoProviders::Sha512,
23
23
  # This is the class that provides your encryption. By default Authlogic provides its own crypto provider that uses Sha512 encrypton.
24
24
  #
25
+ # * <tt>transition_from_crypto_provider</tt> - default: nil,
26
+ # This will transition your users to a new encryption algorithm. Let's say you are using Sha1 and you want to transition to Sha512. Just set the
27
+ # :crypto_provider option to Authlogic::CryptoProviders::Sha512 and then set this option to Authlogic::CryptoProviders::Sha1. Every time a user
28
+ # logs in their password will be resaved with the new algorithm and all new registrations will use the new algorithm as well.
29
+ #
25
30
  # * <tt>act_like_restful_authentication</tt> - default: false,
26
31
  # 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
27
32
  # 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
28
33
  # 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
29
34
  # checkout Authlogic::CryptoProviders::BCrypt.
30
35
  #
36
+ # * <tt>transition_from_restful_authentication</tt> - default: false,
37
+ # This works just like :transition_from_crypto_provider, but it makes some special exceptions so that your users will transition from restful_authentication, since
38
+ # restful_authentication does things a little different than Authlogic.
39
+ #
31
40
  # * <tt>login_field</tt> - default: :login, :username, or :email, depending on which column is present, if none are present defaults to :login
32
41
  # The name of the field used for logging in. Only specify if you aren't using any of the defaults.
33
42
  #
@@ -190,8 +199,13 @@ module Authlogic
190
199
  options[:email_field_validates_uniqueness_of_options][:scope] ||= options[:scope]
191
200
  end
192
201
 
193
- if options[:act_like_restful_authentication]
194
- options[:crypto_provider] = CryptoProviders::Sha1
202
+ if options[:act_like_restful_authentication] || options[:transition_from_restful_authentication]
203
+ crypto_provider_key = options[:act_like_restful_authentication] ? :crypto_provider : :transition_from_crypto_provider
204
+ options[crypto_provider_key] = CryptoProviders::Sha1
205
+ if !defined?(REST_AUTH_SITE_KEY) || REST_AUTH_SITE_KEY.nil?
206
+ class_eval("::REST_AUTH_SITE_KEY = nil") unless defined?(REST_AUTH_SITE_KEY)
207
+ options[crypto_provider_key].stretches = 1
208
+ end
195
209
  end
196
210
 
197
211
  class_eval <<-"end_eval", __FILE__, __LINE__
@@ -53,6 +53,7 @@ module Authlogic
53
53
  end
54
54
 
55
55
  attr_reader options[:password_field]
56
+ attr_accessor :crypto_provider
56
57
 
57
58
  class_eval <<-"end_eval", __FILE__, __LINE__
58
59
  def self.friendly_unique_token
@@ -66,13 +67,37 @@ module Authlogic
66
67
  return if pass.blank?
67
68
  @#{options[:password_field]} = pass
68
69
  self.#{options[:password_salt_field]} = self.class.unique_token
69
- self.#{options[:crypted_password_field]} = #{options[:crypto_provider]}.encrypt(obfuscate_password(@#{options[:password_field]}))
70
+ self.#{options[:crypted_password_field]} = #{options[:crypto_provider]}.encrypt(*encrypt_arguments(@#{options[:password_field]}, #{options[:act_like_restful_authentication].inspect} ? :restful_authentication : nil))
70
71
  end
72
+ alias_method :update_#{options[:password_field]}, :#{options[:password_field]}= # this is to avoids the method chain, so we are ONLY changing the password
71
73
 
72
74
  def valid_#{options[:password_field]}?(attempted_password)
73
75
  return false if attempted_password.blank? || #{options[:crypted_password_field]}.blank? || #{options[:password_salt_field]}.blank?
74
- (#{options[:crypto_provider]}.respond_to?(:decrypt) && #{options[:crypto_provider]}.decrypt(#{options[:crypted_password_field]}) == attempted_password + #{options[:password_salt_field]}) ||
75
- (!#{options[:crypto_provider]}.respond_to?(:decrypt) && #{options[:crypto_provider]}.encrypt(obfuscate_password(attempted_password)) == #{options[:crypted_password_field]})
76
+
77
+ [#{options[:crypto_provider]}, #{options[:transition_from_crypto_provider].inspect}].compact.each do |encryptor|
78
+ # The arguments_type of for the transitioning from restful_authentication
79
+ arguments_type = nil
80
+ case encryptor
81
+ when #{options[:crypto_provider]}
82
+ arguments_type = :restful_authentication if #{options[:act_like_restful_authentication].inspect}
83
+ when #{options[:transition_from_crypto_provider].inspect}
84
+ arguments_type = :restful_authentication if #{options[:transition_from_restful_authentication].inspect}
85
+ end
86
+
87
+ if encryptor.matches?(#{options[:crypted_password_field]}, *encrypt_arguments(attempted_password, arguments_type))
88
+ # If we are transitioning from an older encryption algorithm and the password is still using the old algorithm
89
+ # then let's reset the password using the new algorithm. If the algorithm has a cost (BCrypt) and the cost has changed, update the password with
90
+ # the new cost.
91
+ if encryptor == #{options[:transition_from_crypto_provider].inspect} || (encryptor.respond_to?(:cost_matches?) && !encryptor.cost_matches?(#{options[:crypted_password_field]}))
92
+ update_#{options[:password_field]}(attempted_password)
93
+ save(false)
94
+ end
95
+
96
+ return true
97
+ end
98
+ end
99
+
100
+ false
76
101
  end
77
102
 
78
103
  def reset_#{options[:password_field]}
@@ -82,6 +107,11 @@ module Authlogic
82
107
  end
83
108
  alias_method :randomize_password, :reset_password
84
109
 
110
+ def confirm_#{options[:password_field]}
111
+ raise "confirm_#{options[:password_field]} has been removed, please use #{options[:password_field]}_confirmation. " +
112
+ "As this is the field that ActiveRecord automatically creates with validates_confirmation_of."
113
+ end
114
+
85
115
  def reset_#{options[:password_field]}!
86
116
  reset_#{options[:password_field]}
87
117
  save_without_session_maintenance(false)
@@ -89,11 +119,12 @@ module Authlogic
89
119
  alias_method :randomize_password!, :reset_password!
90
120
 
91
121
  private
92
- def obfuscate_password(raw_password)
93
- if #{options[:act_like_restful_authentication].inspect}
94
- [REST_AUTH_SITE_KEY, raw_password, #{options[:password_salt_field]}, REST_AUTH_SITE_KEY].join("--")
122
+ def encrypt_arguments(raw_password, arguments_type = nil)
123
+ case arguments_type
124
+ when :restful_authentication
125
+ [REST_AUTH_SITE_KEY, raw_password, #{options[:password_salt_field]}, REST_AUTH_SITE_KEY]
95
126
  else
96
- raw_password + #{options[:password_salt_field]}
127
+ [raw_password, #{options[:password_salt_field]}]
97
128
  end
98
129
  end
99
130
  end_eval
@@ -37,10 +37,7 @@ module Authlogic
37
37
 
38
38
  class_eval <<-"end_eval", __FILE__, __LINE__
39
39
  def self.unique_token
40
- # The persistence token should be a unique string that is not reversible, which is what a hash is all about
41
- # if you using encryption this defaults to Sha512.
42
- token_class = #{options[:crypto_provider].respond_to?(:decrypt) ? Authlogic::CryptoProviders::Sha512 : options[:crypto_provider]}
43
- token_class.encrypt(Time.now.to_s + (1..10).collect{ rand.to_s }.join)
40
+ Authlogic::CryptoProviders::Sha512.encrypt(Time.now.to_s + (1..10).collect{ rand.to_s }.join)
44
41
  end
45
42
 
46
43
  def forget!
@@ -45,19 +45,6 @@ module Authlogic
45
45
  yield self
46
46
  end
47
47
 
48
- # This works just like ActiveRecord's attr_accessible, except by default this ONLY allows the login, password, and remember me option.
49
- #
50
- # * <tt>Default:</tt> {:login_field}, {:password_field}, :remember_me, set to nil to disable
51
- # * <tt>Accepts:</tt> String
52
- def attr_accessible(*values)
53
- if values.blank?
54
- read_inheritable_attribute(:attr_accessible) || attr_accessible(login_field, password_field, :remember_me)
55
- else
56
- write_inheritable_attribute(:attr_accessible, value)
57
- end
58
- end
59
- alias_method :attr_accessible=, :attr_accessible
60
-
61
48
  # The name of the cookie or the key in the cookies hash. Be sure and use a unique name. If you have multiple sessions and they use the same cookie it will cause problems.
62
49
  # Also, if a id is set it will be inserted into the beginning of the string. Exmaple:
63
50
  #
@@ -193,7 +180,7 @@ module Authlogic
193
180
  # * <tt>Accepts:</tt> String
194
181
  def not_approved_message(value = nil)
195
182
  if value.nil?
196
- read_inheritable_attribute(:not_approved_message) || not_active_message("Your account is not approved")
183
+ read_inheritable_attribute(:not_approved_message) || not_approved_message("Your account is not approved")
197
184
  else
198
185
  write_inheritable_attribute(:not_approved_message, value)
199
186
  end
@@ -206,7 +193,7 @@ module Authlogic
206
193
  # * <tt>Accepts:</tt> String
207
194
  def not_confirmed_message(value = nil)
208
195
  if value.nil?
209
- read_inheritable_attribute(:not_confirmed_message) || not_active_message("Your account is not confirmed")
196
+ read_inheritable_attribute(:not_confirmed_message) || not_confirmed_message("Your account is not confirmed")
210
197
  else
211
198
  write_inheritable_attribute(:not_confirmed_message, value)
212
199
  end
@@ -263,7 +250,7 @@ module Authlogic
263
250
  # * <tt>Accepts:</tt> String
264
251
  def password_invalid_message(value = nil)
265
252
  if value.nil?
266
- read_inheritable_attribute(:password_invalid_message) || login_not_found_message("is invalid")
253
+ read_inheritable_attribute(:password_invalid_message) || password_invalid_message("is invalid")
267
254
  else
268
255
  write_inheritable_attribute(:password_invalid_message, value)
269
256
  end
@@ -44,7 +44,7 @@ module Authlogic # :nodoc:
44
44
 
45
45
  MAJOR = 1
46
46
  MINOR = 3
47
- TINY = 2
47
+ TINY = 3
48
48
 
49
49
  # The current version as a Version instance
50
50
  CURRENT = new(MAJOR, MINOR, TINY)
@@ -6,9 +6,9 @@ module CryptoProviderTests
6
6
  assert Authlogic::CryptoProviders::BCrypt.encrypt("mypass")
7
7
  end
8
8
 
9
- def test_decrypt
9
+ def test_matches
10
10
  hash = Authlogic::CryptoProviders::BCrypt.encrypt("mypass")
11
- assert Authlogic::CryptoProviders::BCrypt.decrypt(hash) == "mypass"
11
+ assert Authlogic::CryptoProviders::BCrypt.matches?(hash, "mypass")
12
12
  end
13
13
  end
14
14
  end
@@ -5,5 +5,10 @@ module CryptoProviderTests
5
5
  def test_encrypt
6
6
  assert Authlogic::CryptoProviders::Sha1.encrypt("mypass")
7
7
  end
8
+
9
+ def test_matches
10
+ hash = Authlogic::CryptoProviders::Sha1.encrypt("mypass")
11
+ assert Authlogic::CryptoProviders::Sha1.matches?(hash, "mypass")
12
+ end
8
13
  end
9
14
  end
@@ -5,5 +5,10 @@ module CryptoProviderTests
5
5
  def test_encrypt
6
6
  assert Authlogic::CryptoProviders::Sha512.encrypt("mypass")
7
7
  end
8
+
9
+ def test_matches
10
+ hash = Authlogic::CryptoProviders::Sha512.encrypt("mypass")
11
+ assert Authlogic::CryptoProviders::Sha512.matches?(hash, "mypass")
12
+ end
8
13
  end
9
14
  end
@@ -2,12 +2,12 @@ require "ezcrypto"
2
2
 
3
3
  class AES128CryptoProvider
4
4
  class << self
5
- def encrypt(term)
6
- [key.encrypt(term)].pack("m").chomp
5
+ def encrypt(*tokens)
6
+ [key.encrypt(tokens.join)].pack("m").chomp
7
7
  end
8
8
 
9
- def decrypt(term)
10
- key.decrypt(term.unpack("m").first)
9
+ def matches?(crypted, *tokens)
10
+ key.decrypt(crypted.unpack("m").first) == tokens.join
11
11
  end
12
12
 
13
13
  def key
@@ -4,6 +4,9 @@ module ORMAdaptersTests
4
4
  module ActiveRecordAdapterTests
5
5
  module ActsAsAuthenticTests
6
6
  class ConfigTest < ActiveSupport::TestCase
7
+ setup :get_default_configuration
8
+ teardown :restore_default_configuration
9
+
7
10
  def test_first_column_to_exist
8
11
  assert_equal :login, User.first_column_to_exist(:login, :crypted_password)
9
12
  assert_equal nil, User.first_column_to_exist(nil, :unknown)
@@ -45,6 +48,68 @@ module ORMAdaptersTests
45
48
  }
46
49
  assert_equal default_config, User.acts_as_authentic_config
47
50
  end
51
+
52
+ def test_session_class
53
+ EmployeeSession.authenticate_with User
54
+ User.acts_as_authentic(:session_class => EmployeeSession)
55
+ assert_equal EmployeeSession, User.acts_as_authentic_config[:session_class]
56
+
57
+ ben = users(:ben)
58
+ assert !EmployeeSession.find
59
+ ben.password = "benrocks"
60
+ ben.password_confirmation = "benrocks"
61
+ assert ben.save
62
+ assert EmployeeSession.find
63
+ EmployeeSession.authenticate_with Employee
64
+ end
65
+
66
+ def test_crypto_provider
67
+ User.acts_as_authentic(:crypto_provider => Authlogic::CryptoProviders::BCrypt)
68
+ ben = users(:ben)
69
+ assert !ben.valid_password?("benrocks")
70
+ ben.password = "benrocks"
71
+ ben.password_confirmation = "benrocks"
72
+ assert ben.save
73
+ assert ben.valid_password?("benrocks")
74
+ end
75
+
76
+ def test_transition_from_crypto_provider
77
+ ben = users(:ben)
78
+ convert_password_to(Authlogic::CryptoProviders::BCrypt, ben)
79
+ end
80
+
81
+ def test_act_like_restful_authentication
82
+ ben = users(:ben)
83
+ convert_password_to(Authlogic::CryptoProviders::Sha1, ben)
84
+ User.acts_as_authentic(:act_like_restful_authentication => true)
85
+ set_session_for(ben)
86
+ assert UserSession.find
87
+ end
88
+
89
+ def test_transition_from_restful_authentication
90
+ User.acts_as_authentic(:transition_from_restful_authentication => true)
91
+ assert_equal Authlogic::CryptoProviders::Sha512, User.acts_as_authentic_config[:crypto_provider]
92
+ assert_equal Authlogic::CryptoProviders::Sha1, User.acts_as_authentic_config[:transition_from_crypto_provider]
93
+ end
94
+
95
+ private
96
+ def get_default_configuration
97
+ @default_configuration = User.acts_as_authentic_config
98
+ end
99
+
100
+ def restore_default_configuration
101
+ User.acts_as_authentic @default_configuration
102
+ end
103
+
104
+ def convert_password_to(crypto_provider, *records)
105
+ User.acts_as_authentic(:crypto_provider => crypto_provider, :transition_from_crypto_provider => Authlogic::CryptoProviders::Sha512)
106
+ records.each do |record|
107
+ old_hash = record.crypted_password
108
+ assert record.valid_password?(password_for(record))
109
+ assert_not_equal old_hash, record.crypted_password
110
+ assert record.valid_password?(password_for(record))
111
+ end
112
+ end
48
113
  end
49
114
  end
50
115
  end
@@ -113,19 +113,19 @@ class Test::Unit::TestCase
113
113
  Authlogic::Session::Base.controller = @controller
114
114
  end
115
115
 
116
+ def password_for(user)
117
+ case user
118
+ when users(:ben)
119
+ "benrocks"
120
+ when users(:zack)
121
+ "zackrocks"
122
+ end
123
+ end
124
+
116
125
  def http_basic_auth_for(user = nil, &block)
117
126
  unless user.blank?
118
127
  @controller.http_user = user.login
119
-
120
- password = nil
121
- case user
122
- when users(:ben)
123
- password = "benrocks"
124
- when users(:zack)
125
- password = "zackrocks"
126
- end
127
-
128
- @controller.http_password = password
128
+ @controller.http_password = password_for(user)
129
129
  end
130
130
  yield
131
131
  @controller.http_user = @controller.http_password = nil
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: authlogic
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.3.2
4
+ version: 1.3.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ben Johnson of Binary Logic
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2008-11-22 00:00:00 -05:00
12
+ date: 2008-11-23 00:00:00 -05:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency