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.
- data/CHANGELOG.rdoc +7 -0
- data/README.rdoc +33 -5
- data/authlogic.gemspec +2 -2
- data/lib/authlogic/crypto_providers/bcrypt.rb +44 -12
- data/lib/authlogic/crypto_providers/sha1.rb +18 -6
- data/lib/authlogic/crypto_providers/sha512.rb +27 -5
- data/lib/authlogic/orm_adapters/active_record_adapter/acts_as_authentic/config.rb +16 -2
- data/lib/authlogic/orm_adapters/active_record_adapter/acts_as_authentic/credentials.rb +38 -7
- data/lib/authlogic/orm_adapters/active_record_adapter/acts_as_authentic/persistence.rb +1 -4
- data/lib/authlogic/session/config.rb +3 -16
- data/lib/authlogic/version.rb +1 -1
- data/test/crypto_provider_tests/bcrypt_test.rb +2 -2
- data/test/crypto_provider_tests/sha1_test.rb +5 -0
- data/test/crypto_provider_tests/sha512_test.rb +5 -0
- data/test/libs/aes128_crypto_provider.rb +4 -4
- data/test/orm_adapters_tests/active_record_adapter_tests/acts_as_authentic_tests/config_test.rb +65 -0
- data/test/test_helper.rb +10 -10
- metadata +2 -2
data/CHANGELOG.rdoc
CHANGED
@@ -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.
|
data/README.rdoc
CHANGED
@@ -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
|
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
|
-
|
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 :
|
395
|
+
acts_as_authentic :act_like_restful_authentication => true
|
373
396
|
end
|
374
397
|
|
375
|
-
|
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
|
-
|
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
|
|
data/authlogic.gemspec
CHANGED
@@ -2,11 +2,11 @@
|
|
2
2
|
|
3
3
|
Gem::Specification.new do |s|
|
4
4
|
s.name = %q{authlogic}
|
5
|
-
s.version = "1.3.
|
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-
|
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
|
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("
|
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
|
-
#
|
25
|
-
# BCrypt:
|
26
|
-
#
|
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(
|
47
|
-
::BCrypt::Password.create(
|
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
|
51
|
-
def
|
52
|
-
|
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
|
-
#
|
8
|
-
#
|
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
|
-
|
17
|
-
|
18
|
-
|
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
|
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
|
-
#
|
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
|
-
|
23
|
-
|
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[:
|
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(
|
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
|
-
|
75
|
-
|
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
|
93
|
-
|
94
|
-
|
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
|
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
|
-
|
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) ||
|
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) ||
|
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) ||
|
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
|
data/lib/authlogic/version.rb
CHANGED
@@ -6,9 +6,9 @@ module CryptoProviderTests
|
|
6
6
|
assert Authlogic::CryptoProviders::BCrypt.encrypt("mypass")
|
7
7
|
end
|
8
8
|
|
9
|
-
def
|
9
|
+
def test_matches
|
10
10
|
hash = Authlogic::CryptoProviders::BCrypt.encrypt("mypass")
|
11
|
-
assert Authlogic::CryptoProviders::BCrypt.
|
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(
|
6
|
-
[key.encrypt(
|
5
|
+
def encrypt(*tokens)
|
6
|
+
[key.encrypt(tokens.join)].pack("m").chomp
|
7
7
|
end
|
8
8
|
|
9
|
-
def
|
10
|
-
key.decrypt(
|
9
|
+
def matches?(crypted, *tokens)
|
10
|
+
key.decrypt(crypted.unpack("m").first) == tokens.join
|
11
11
|
end
|
12
12
|
|
13
13
|
def key
|
data/test/orm_adapters_tests/active_record_adapter_tests/acts_as_authentic_tests/config_test.rb
CHANGED
@@ -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
|
data/test/test_helper.rb
CHANGED
@@ -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.
|
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-
|
12
|
+
date: 2008-11-23 00:00:00 -05:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|