authlogic 3.5.0 → 3.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.github/ISSUE_TEMPLATE.md +13 -0
- data/.rubocop_todo.yml +1 -37
- data/.travis.yml +11 -6
- data/CHANGELOG.md +19 -0
- data/CONTRIBUTING.md +13 -2
- data/README.md +2 -3
- data/authlogic.gemspec +5 -5
- data/lib/authlogic/acts_as_authentic/base.rb +4 -2
- data/lib/authlogic/acts_as_authentic/email.rb +8 -3
- data/lib/authlogic/acts_as_authentic/logged_in_status.rb +21 -3
- data/lib/authlogic/acts_as_authentic/login.rb +44 -25
- data/lib/authlogic/acts_as_authentic/password.rb +28 -12
- data/lib/authlogic/acts_as_authentic/perishable_token.rb +21 -12
- data/lib/authlogic/acts_as_authentic/restful_authentication.rb +16 -9
- data/lib/authlogic/acts_as_authentic/session_maintenance.rb +5 -3
- data/lib/authlogic/authenticates_many/association.rb +7 -4
- data/lib/authlogic/controller_adapters/rack_adapter.rb +6 -2
- data/lib/authlogic/controller_adapters/rails_adapter.rb +11 -8
- data/lib/authlogic/crypto_providers/bcrypt.rb +4 -1
- data/lib/authlogic/crypto_providers/sha512.rb +15 -10
- data/lib/authlogic/session/activation.rb +19 -10
- data/lib/authlogic/session/cookies.rb +3 -1
- data/lib/authlogic/session/id.rb +13 -7
- data/lib/authlogic/session/magic_columns.rb +19 -10
- data/lib/authlogic/session/magic_states.rb +7 -1
- data/lib/authlogic/session/password.rb +48 -34
- data/lib/authlogic/session/perishable_token.rb +7 -3
- data/lib/authlogic/session/validation.rb +13 -11
- data/lib/authlogic/test_case.rb +52 -32
- data/test/acts_as_authentic_test/email_test.rb +33 -29
- data/test/acts_as_authentic_test/logged_in_status_test.rb +2 -2
- data/test/acts_as_authentic_test/login_test.rb +50 -37
- data/test/acts_as_authentic_test/magic_columns_test.rb +8 -8
- data/test/acts_as_authentic_test/password_test.rb +14 -14
- data/test/acts_as_authentic_test/perishable_token_test.rb +5 -5
- data/test/acts_as_authentic_test/persistence_token_test.rb +4 -4
- data/test/acts_as_authentic_test/restful_authentication_test.rb +6 -6
- data/test/acts_as_authentic_test/session_maintenance_test.rb +15 -10
- data/test/acts_as_authentic_test/single_access_test.rb +6 -6
- data/test/authenticates_many_test.rb +1 -1
- data/test/gemfiles/Gemfile.rails-5.1.x +6 -0
- data/test/session_test/activation_test.rb +1 -1
- data/test/session_test/active_record_trickery_test.rb +3 -3
- data/test/session_test/brute_force_protection_test.rb +19 -14
- data/test/session_test/cookies_test.rb +21 -12
- data/test/session_test/existence_test.rb +15 -10
- data/test/session_test/http_auth_test.rb +2 -2
- data/test/session_test/magic_columns_test.rb +7 -4
- data/test/session_test/magic_states_test.rb +7 -9
- data/test/session_test/params_test.rb +6 -6
- data/test/session_test/password_test.rb +2 -2
- data/test/session_test/perishability_test.rb +1 -1
- data/test/session_test/persistence_test.rb +2 -2
- data/test/session_test/timeout_test.rb +7 -5
- data/test/session_test/validation_test.rb +1 -1
- data/test/test_helper.rb +10 -2
- metadata +10 -7
@@ -1,9 +1,13 @@
|
|
1
1
|
module Authlogic
|
2
2
|
module ActsAsAuthentic
|
3
|
-
# This provides a handy token that is "perishable". Meaning the token is
|
4
|
-
#
|
5
|
-
#
|
6
|
-
#
|
3
|
+
# This provides a handy token that is "perishable". Meaning the token is
|
4
|
+
# only good for a certain amount of time. This is perfect for resetting
|
5
|
+
# password, confirming accounts, etc. Typically during these actions you
|
6
|
+
# send them this token in via their email. Once they use the token and do
|
7
|
+
# what they need to do, that token should expire. Don't worry about
|
8
|
+
# maintaining this, changing it, or expiring it yourself. Authlogic does all
|
9
|
+
# of this for you. See the sub modules for all of the tools Authlogic
|
10
|
+
# provides to you.
|
7
11
|
module PerishableToken
|
8
12
|
def self.included(klass)
|
9
13
|
klass.class_eval do
|
@@ -14,8 +18,9 @@ module Authlogic
|
|
14
18
|
|
15
19
|
# Change how the perishable token works.
|
16
20
|
module Config
|
17
|
-
# When using the find_using_perishable_token method the token can
|
18
|
-
#
|
21
|
+
# When using the find_using_perishable_token method the token can
|
22
|
+
# expire. If the token is expired, no record will be returned. Use this
|
23
|
+
# option to specify how long the token is valid for.
|
19
24
|
#
|
20
25
|
# * <tt>Default:</tt> 10.minutes
|
21
26
|
# * <tt>Accepts:</tt> Fixnum
|
@@ -24,9 +29,10 @@ module Authlogic
|
|
24
29
|
end
|
25
30
|
alias_method :perishable_token_valid_for=, :perishable_token_valid_for
|
26
31
|
|
27
|
-
# Authlogic tries to expire and change the perishable token as much as
|
28
|
-
# it's purpose. This is for security
|
29
|
-
#
|
32
|
+
# Authlogic tries to expire and change the perishable token as much as
|
33
|
+
# possible, without compromising it's purpose. This is for security
|
34
|
+
# reasons. If you want to manage it yourself, you can stop Authlogic
|
35
|
+
# from getting your in way by setting this to true.
|
30
36
|
#
|
31
37
|
# * <tt>Default:</tt> false
|
32
38
|
# * <tt>Accepts:</tt> Boolean
|
@@ -52,12 +58,14 @@ module Authlogic
|
|
52
58
|
|
53
59
|
# Class level methods for the perishable token
|
54
60
|
module ClassMethods
|
55
|
-
# Use this method to find a record with a perishable token. This
|
61
|
+
# Use this method to find a record with a perishable token. This
|
62
|
+
# method does 2 things for you:
|
56
63
|
#
|
57
64
|
# 1. It ignores blank tokens
|
58
65
|
# 2. It enforces the perishable_token_valid_for configuration option.
|
59
66
|
#
|
60
|
-
# If you want to use a different timeout value, just pass it as the
|
67
|
+
# If you want to use a different timeout value, just pass it as the
|
68
|
+
# second parameter:
|
61
69
|
#
|
62
70
|
# User.find_using_perishable_token(token, 1.hour)
|
63
71
|
def find_using_perishable_token(token, age = self.perishable_token_valid_for)
|
@@ -94,7 +102,8 @@ module Authlogic
|
|
94
102
|
save_without_session_maintenance(:validate => false)
|
95
103
|
end
|
96
104
|
|
97
|
-
# A convenience method based on the
|
105
|
+
# A convenience method based on the
|
106
|
+
# disable_perishable_token_maintenance configuration option.
|
98
107
|
def disable_perishable_token_maintenance?
|
99
108
|
self.class.disable_perishable_token_maintenance == true
|
100
109
|
end
|
@@ -1,6 +1,7 @@
|
|
1
1
|
module Authlogic
|
2
2
|
module ActsAsAuthentic
|
3
|
-
# This module is responsible for transitioning existing applications from
|
3
|
+
# This module is responsible for transitioning existing applications from
|
4
|
+
# the restful_authentication plugin.
|
4
5
|
module RestfulAuthentication
|
5
6
|
def self.included(klass)
|
6
7
|
klass.class_eval do
|
@@ -10,10 +11,13 @@ module Authlogic
|
|
10
11
|
end
|
11
12
|
|
12
13
|
module Config
|
13
|
-
# Switching an existing app to Authlogic from restful_authentication? No
|
14
|
-
#
|
15
|
-
#
|
16
|
-
#
|
14
|
+
# Switching an existing app to Authlogic from restful_authentication? No
|
15
|
+
# problem, just set this true and your users won't know anything
|
16
|
+
# changed. From your database perspective nothing will change at all.
|
17
|
+
# Authlogic will continue to encrypt passwords just like
|
18
|
+
# restful_authentication, so your app won't skip a beat. Although, might
|
19
|
+
# consider transitioning your users to a newer and stronger algorithm.
|
20
|
+
# Checkout the transition_from_restful_authentication option.
|
17
21
|
#
|
18
22
|
# * <tt>Default:</tt> false
|
19
23
|
# * <tt>Accepts:</tt> Boolean
|
@@ -24,10 +28,13 @@ module Authlogic
|
|
24
28
|
end
|
25
29
|
alias_method :act_like_restful_authentication=, :act_like_restful_authentication
|
26
30
|
|
27
|
-
# This works just like act_like_restful_authentication except that it
|
28
|
-
#
|
29
|
-
#
|
30
|
-
#
|
31
|
+
# This works just like act_like_restful_authentication except that it
|
32
|
+
# will start transitioning your users to the algorithm you specify with
|
33
|
+
# the crypto provider option. The next time they log in it will resave
|
34
|
+
# their password with the new algorithm and any new record will use the
|
35
|
+
# new algorithm as well. Make sure to update your users table if you are
|
36
|
+
# using the default migration since it will set crypted_password and
|
37
|
+
# salt columns to a maximum width of 40 characters which is not enough.
|
31
38
|
def transition_from_restful_authentication(value = nil)
|
32
39
|
r = rw_config(:transition_from_restful_authentication, value, false)
|
33
40
|
set_restful_authentication_config if value
|
@@ -102,7 +102,8 @@ module Authlogic
|
|
102
102
|
end
|
103
103
|
|
104
104
|
def get_session_information
|
105
|
-
# Need to determine if we are completely logged out, or logged in as
|
105
|
+
# Need to determine if we are completely logged out, or logged in as
|
106
|
+
# another user.
|
106
107
|
@_sessions = []
|
107
108
|
|
108
109
|
session_ids.each do |session_id|
|
@@ -120,8 +121,9 @@ module Authlogic
|
|
120
121
|
end
|
121
122
|
|
122
123
|
def create_session
|
123
|
-
# We only want to automatically login into the first session, since
|
124
|
-
#
|
124
|
+
# We only want to automatically login into the first session, since
|
125
|
+
# this is the main session. The other sessions are sessions that
|
126
|
+
# need to be created after logging into the main session.
|
125
127
|
session_id = session_ids.first
|
126
128
|
session_class.create(*[self, self, session_id].compact)
|
127
129
|
|
@@ -1,14 +1,17 @@
|
|
1
1
|
module Authlogic
|
2
2
|
module AuthenticatesMany
|
3
|
-
# An object of this class is used as a proxy for the authenticates_many
|
4
|
-
#
|
3
|
+
# An object of this class is used as a proxy for the authenticates_many
|
4
|
+
# relationship. It basically allows you to "save" scope details and call
|
5
|
+
# them on an object, which allows you to do the following:
|
5
6
|
#
|
6
7
|
# @account.user_sessions.new
|
7
8
|
# @account.user_sessions.find
|
8
9
|
# # ... etc
|
9
10
|
#
|
10
|
-
# You can call all of the class level methods off of an object with a saved
|
11
|
-
#
|
11
|
+
# You can call all of the class level methods off of an object with a saved
|
12
|
+
# scope, so that calling the above methods scopes the user sessions down to
|
13
|
+
# that specific account. To implement this via ActiveRecord do something
|
14
|
+
# like:
|
12
15
|
#
|
13
16
|
# class User < ActiveRecord::Base
|
14
17
|
# authenticates_many :user_sessions
|
@@ -2,8 +2,10 @@ require 'action_controller'
|
|
2
2
|
|
3
3
|
module Authlogic
|
4
4
|
module ControllerAdapters
|
5
|
-
# Adapts authlogic to work with rails. The point is to close the gap between
|
6
|
-
#
|
5
|
+
# Adapts authlogic to work with rails. The point is to close the gap between
|
6
|
+
# what authlogic expects and what the rails controller object provides.
|
7
|
+
# Similar to how ActiveRecord has an adapter for MySQL, PostgreSQL, SQLite,
|
8
|
+
# etc.
|
7
9
|
class RailsAdapter < AbstractAdapter
|
8
10
|
class AuthlogicLoadedTooLateError < StandardError; end
|
9
11
|
|
@@ -31,12 +33,13 @@ module Authlogic
|
|
31
33
|
if defined?(::ApplicationController)
|
32
34
|
raise AuthlogicLoadedTooLateError.new(
|
33
35
|
<<-EOS.strip_heredoc
|
34
|
-
Authlogic is trying to add a callback to ActionController::Base
|
35
|
-
ApplicationController has already been loaded, so the
|
36
|
-
be copied into your application. Generally this
|
37
|
-
|
38
|
-
|
39
|
-
|
36
|
+
Authlogic is trying to add a callback to ActionController::Base
|
37
|
+
but ApplicationController has already been loaded, so the
|
38
|
+
callback won't be copied into your application. Generally this
|
39
|
+
is due to another gem or plugin requiring your
|
40
|
+
ApplicationController prematurely, such as the
|
41
|
+
resource_controller plugin. Please require Authlogic first,
|
42
|
+
before these other gems / plugins.
|
40
43
|
EOS
|
41
44
|
)
|
42
45
|
end
|
@@ -56,7 +56,10 @@ module Authlogic
|
|
56
56
|
|
57
57
|
def cost=(val)
|
58
58
|
if val < ::BCrypt::Engine::MIN_COST
|
59
|
-
raise ArgumentError.new(
|
59
|
+
raise ArgumentError.new(
|
60
|
+
"Authlogic's bcrypt cost cannot be set below the engine's " \
|
61
|
+
"min cost (#{::BCrypt::Engine::MIN_COST})"
|
62
|
+
)
|
60
63
|
end
|
61
64
|
@cost = val
|
62
65
|
end
|
@@ -1,22 +1,25 @@
|
|
1
1
|
require "digest/sha2"
|
2
2
|
|
3
3
|
module Authlogic
|
4
|
-
# The acts_as_authentic method has a crypto_provider option. This allows you
|
5
|
-
#
|
4
|
+
# The acts_as_authentic method has a crypto_provider option. This allows you
|
5
|
+
# to use any type of encryption you like. Just create a class with a class
|
6
|
+
# level encrypt and matches? method. See example below.
|
6
7
|
#
|
7
8
|
# === Example
|
8
9
|
#
|
9
10
|
# class MyAwesomeEncryptionMethod
|
10
11
|
# def self.encrypt(*tokens)
|
11
|
-
# #
|
12
|
-
# # just do what you need to do with them and return a
|
13
|
-
# #
|
12
|
+
# # The tokens passed will be an array of objects, what type of object
|
13
|
+
# # is irrelevant, just do what you need to do with them and return a
|
14
|
+
# # single encrypted string. For example, you will most likely join all
|
15
|
+
# # of the objects into a single string and then encrypt that string.
|
14
16
|
# end
|
15
17
|
#
|
16
18
|
# def self.matches?(crypted, *tokens)
|
17
|
-
# #
|
18
|
-
# #
|
19
|
-
# # encrypt the tokens and make sure it matches the
|
19
|
+
# # Return true if the crypted string matches the tokens. Depending on
|
20
|
+
# # your algorithm you might decrypt the string then compare it to the
|
21
|
+
# # token, or you might encrypt the tokens and make sure it matches the
|
22
|
+
# # crypted string, its up to you.
|
20
23
|
# end
|
21
24
|
# end
|
22
25
|
module CryptoProviders
|
@@ -27,7 +30,8 @@ module Authlogic
|
|
27
30
|
class << self
|
28
31
|
attr_accessor :join_token
|
29
32
|
|
30
|
-
# The number of times to loop through the encryption. This is twenty
|
33
|
+
# The number of times to loop through the encryption. This is twenty
|
34
|
+
# because that is what restful_authentication defaults to.
|
31
35
|
def stretches
|
32
36
|
@stretches ||= 20
|
33
37
|
end
|
@@ -40,7 +44,8 @@ module Authlogic
|
|
40
44
|
digest
|
41
45
|
end
|
42
46
|
|
43
|
-
# Does the crypted password match the tokens? Uses the same tokens that
|
47
|
+
# Does the crypted password match the tokens? Uses the same tokens that
|
48
|
+
# were used to encrypt.
|
44
49
|
def matches?(crypted, *tokens)
|
45
50
|
encrypt(*tokens) == crypted
|
46
51
|
end
|
@@ -2,9 +2,11 @@ require 'request_store'
|
|
2
2
|
|
3
3
|
module Authlogic
|
4
4
|
module Session
|
5
|
-
# Activating Authlogic requires that you pass it an
|
6
|
-
#
|
7
|
-
#
|
5
|
+
# Activating Authlogic requires that you pass it an
|
6
|
+
# Authlogic::ControllerAdapters::AbstractAdapter object, or a class that
|
7
|
+
# extends it. This is sort of like a database connection for an ORM library,
|
8
|
+
# Authlogic can't do anything until it is "connected" to a controller. If
|
9
|
+
# you are using a supported framework, Authlogic takes care of this for you.
|
8
10
|
module Activation
|
9
11
|
class NotActivatedError < ::StandardError # :nodoc:
|
10
12
|
def initialize(session)
|
@@ -20,17 +22,24 @@ module Authlogic
|
|
20
22
|
end
|
21
23
|
|
22
24
|
module ClassMethods
|
23
|
-
# Returns true if a controller has been set and can be used properly.
|
24
|
-
#
|
25
|
-
#
|
26
|
-
#
|
25
|
+
# Returns true if a controller has been set and can be used properly.
|
26
|
+
# This MUST be set before anything can be done. Similar to how
|
27
|
+
# ActiveRecord won't allow you to do anything without establishing a DB
|
28
|
+
# connection. In your framework environment this is done for you, but if
|
29
|
+
# you are using Authlogic outside of your framework, you need to assign
|
30
|
+
# a controller object to Authlogic via
|
31
|
+
# Authlogic::Session::Base.controller = obj. See the controller= method
|
32
|
+
# for more information.
|
27
33
|
def activated?
|
28
34
|
!controller.nil?
|
29
35
|
end
|
30
36
|
|
31
|
-
# This accepts a controller object wrapped with the Authlogic controller
|
32
|
-
#
|
33
|
-
#
|
37
|
+
# This accepts a controller object wrapped with the Authlogic controller
|
38
|
+
# adapter. The controller adapters close the gap between the different
|
39
|
+
# controllers in each framework. That being said, Authlogic is expecting
|
40
|
+
# your object's class to extend
|
41
|
+
# Authlogic::ControllerAdapters::AbstractAdapter. See
|
42
|
+
# Authlogic::ControllerAdapters for more info.
|
34
43
|
#
|
35
44
|
# Lastly, this is thread safe.
|
36
45
|
def controller=(value)
|
@@ -91,7 +91,9 @@ module Authlogic
|
|
91
91
|
values = value.is_a?(Array) ? value : [value]
|
92
92
|
case values.first
|
93
93
|
when Hash
|
94
|
-
|
94
|
+
if values.first.with_indifferent_access.key?(:remember_me)
|
95
|
+
self.remember_me = values.first.with_indifferent_access[:remember_me]
|
96
|
+
end
|
95
97
|
else
|
96
98
|
r = values.find { |value| value.is_a?(TrueClass) || value.is_a?(FalseClass) }
|
97
99
|
self.remember_me = r if !r.nil?
|
data/lib/authlogic/session/id.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
module Authlogic
|
2
2
|
module Session
|
3
|
-
# Allows you to separate sessions with an id, ultimately letting you create
|
3
|
+
# Allows you to separate sessions with an id, ultimately letting you create
|
4
|
+
# multiple sessions for the same user.
|
4
5
|
module Id
|
5
6
|
def self.included(klass)
|
6
7
|
klass.class_eval do
|
@@ -15,18 +16,23 @@ module Authlogic
|
|
15
16
|
self.id = values.last if values.last.is_a?(Symbol)
|
16
17
|
end
|
17
18
|
|
18
|
-
# Allows you to set a unique identifier for your session, so that you can
|
19
|
-
#
|
20
|
-
#
|
21
|
-
#
|
19
|
+
# Allows you to set a unique identifier for your session, so that you can
|
20
|
+
# have more than 1 session at a time. A good example when this might be
|
21
|
+
# needed is when you want to have a normal user session and a "secure"
|
22
|
+
# user session. The secure user session would be created only when they
|
23
|
+
# want to modify their billing information, or other sensitive
|
24
|
+
# information. Similar to me.com. This requires 2 user sessions. Just use
|
25
|
+
# an id for the "secure" session and you should be good.
|
22
26
|
#
|
23
|
-
# You can set the id during initialization (see initialize for more
|
27
|
+
# You can set the id during initialization (see initialize for more
|
28
|
+
# information), or as an attribute:
|
24
29
|
#
|
25
30
|
# session.id = :my_id
|
26
31
|
#
|
27
32
|
# Just be sure and set your id before you save your session.
|
28
33
|
#
|
29
|
-
# Lastly, to retrieve your session with the id check out the find class
|
34
|
+
# Lastly, to retrieve your session with the id check out the find class
|
35
|
+
# method.
|
30
36
|
def id
|
31
37
|
@id
|
32
38
|
end
|
@@ -74,14 +74,18 @@ module Authlogic
|
|
74
74
|
end
|
75
75
|
end
|
76
76
|
|
77
|
-
# This method lets authlogic know whether it should allow the
|
78
|
-
#
|
79
|
-
#
|
80
|
-
# in your
|
77
|
+
# This method lets authlogic know whether it should allow the
|
78
|
+
# last_request_at field to be updated with the current time
|
79
|
+
# (Time.now). One thing to note here is that it also checks for the
|
80
|
+
# existence of a last_request_update_allowed? method in your
|
81
|
+
# controller. This allows you to control this method pragmatically in
|
82
|
+
# your controller.
|
81
83
|
#
|
82
|
-
# For example, what if you had a javascript function that polled the
|
83
|
-
#
|
84
|
-
#
|
84
|
+
# For example, what if you had a javascript function that polled the
|
85
|
+
# server updating how much time is left in their session before it
|
86
|
+
# times out. Obviously you would want to ignore this request, because
|
87
|
+
# then the user would never time out. So you can do something like
|
88
|
+
# this in your controller:
|
85
89
|
#
|
86
90
|
# def last_request_update_allowed?
|
87
91
|
# action_name != "update_session_time_left"
|
@@ -89,9 +93,14 @@ module Authlogic
|
|
89
93
|
#
|
90
94
|
# You can do whatever you want with that method.
|
91
95
|
def set_last_request_at? # :doc:
|
92
|
-
|
93
|
-
|
94
|
-
|
96
|
+
if !record || !klass.column_names.include?("last_request_at")
|
97
|
+
return false
|
98
|
+
end
|
99
|
+
if controller.responds_to_last_request_update_allowed? && !controller.last_request_update_allowed?
|
100
|
+
return false
|
101
|
+
end
|
102
|
+
record.last_request_at.blank? ||
|
103
|
+
last_request_at_threshold.to_i.seconds.ago >= record.last_request_at
|
95
104
|
end
|
96
105
|
|
97
106
|
def set_last_request_at
|
@@ -58,7 +58,13 @@ module Authlogic
|
|
58
58
|
return true if attempted_record.nil?
|
59
59
|
[:active, :approved, :confirmed].each do |required_status|
|
60
60
|
if attempted_record.respond_to?("#{required_status}?") && !attempted_record.send("#{required_status}?")
|
61
|
-
errors.add(
|
61
|
+
errors.add(
|
62
|
+
:base,
|
63
|
+
I18n.t(
|
64
|
+
"error_messages.not_#{required_status}",
|
65
|
+
:default => "Your account is not #{required_status}"
|
66
|
+
)
|
67
|
+
)
|
62
68
|
return false
|
63
69
|
end
|
64
70
|
end
|
@@ -16,16 +16,19 @@ module Authlogic
|
|
16
16
|
|
17
17
|
# Password configuration
|
18
18
|
module Config
|
19
|
-
# Authlogic tries to validate the credentials passed to it. One part of
|
20
|
-
#
|
19
|
+
# Authlogic tries to validate the credentials passed to it. One part of
|
20
|
+
# validation is actually finding the user and making sure it exists.
|
21
|
+
# What method it uses the do this is up to you.
|
21
22
|
#
|
22
|
-
# Let's say you have a UserSession that is authenticating a User. By
|
23
|
-
#
|
24
|
-
#
|
23
|
+
# Let's say you have a UserSession that is authenticating a User. By
|
24
|
+
# default UserSession will call User.find_by_login(login). You can
|
25
|
+
# change what method UserSession calls by specifying it here. Then in
|
26
|
+
# your User model you can make that method do anything you want, giving
|
27
|
+
# you complete control of how users are found by the UserSession.
|
25
28
|
#
|
26
|
-
# Let's take an example: You want to allow users to login by username or
|
27
|
-
# Set this to the name of the class method that does this in the
|
28
|
-
# call it "find_by_username_or_email"
|
29
|
+
# Let's take an example: You want to allow users to login by username or
|
30
|
+
# email. Set this to the name of the class method that does this in the
|
31
|
+
# User model. Let's call it "find_by_username_or_email"
|
29
32
|
#
|
30
33
|
# class User < ActiveRecord::Base
|
31
34
|
# def self.find_by_username_or_email(login)
|
@@ -33,10 +36,10 @@ module Authlogic
|
|
33
36
|
# end
|
34
37
|
# end
|
35
38
|
#
|
36
|
-
# Now just specify the name of this method for this configuration option
|
37
|
-
# are all set. You can do anything you want here. Maybe you
|
38
|
-
# multiple logins and you want to search a has_many
|
39
|
-
# the limit.
|
39
|
+
# Now just specify the name of this method for this configuration option
|
40
|
+
# and you are all set. You can do anything you want here. Maybe you
|
41
|
+
# allow users to have multiple logins and you want to search a has_many
|
42
|
+
# relationship, etc. The sky is the limit.
|
40
43
|
#
|
41
44
|
# * <tt>Default:</tt> "find_by_smart_case_login_field"
|
42
45
|
# * <tt>Accepts:</tt> Symbol or String
|
@@ -45,10 +48,11 @@ module Authlogic
|
|
45
48
|
end
|
46
49
|
alias_method :find_by_login_method=, :find_by_login_method
|
47
50
|
|
48
|
-
# The text used to identify credentials (username/password) combination
|
49
|
-
# login attempt occurs. When you show error messages for a
|
50
|
-
# considered good security practice to hide which field
|
51
|
-
# incorrectly (the login field or the password
|
51
|
+
# The text used to identify credentials (username/password) combination
|
52
|
+
# when a bad login attempt occurs. When you show error messages for a
|
53
|
+
# bad login, it's considered good security practice to hide which field
|
54
|
+
# the user has entered incorrectly (the login field or the password
|
55
|
+
# field). For a full explanation, see
|
52
56
|
# http://www.gnucitizen.org/blog/username-enumeration-vulnerabilities/
|
53
57
|
#
|
54
58
|
# Example of use:
|
@@ -57,7 +61,8 @@ module Authlogic
|
|
57
61
|
# generalize_credentials_error_messages true
|
58
62
|
# end
|
59
63
|
#
|
60
|
-
# This would make the error message for bad logins and bad passwords
|
64
|
+
# This would make the error message for bad logins and bad passwords
|
65
|
+
# look identical:
|
61
66
|
#
|
62
67
|
# Login/Password combination is not valid
|
63
68
|
#
|
@@ -69,12 +74,14 @@ module Authlogic
|
|
69
74
|
#
|
70
75
|
# This will instead show your custom error message when the UserSession is invalid.
|
71
76
|
#
|
72
|
-
# The downside to enabling this is that is can be too vague for a user
|
73
|
-
#
|
77
|
+
# The downside to enabling this is that is can be too vague for a user
|
78
|
+
# that has a hard time remembering their username and password
|
79
|
+
# combinations. It also disables the ability to to highlight the field
|
74
80
|
# with the error when you use form_for.
|
75
81
|
#
|
76
|
-
# If you are developing an app where security is an extreme priority
|
77
|
-
#
|
82
|
+
# If you are developing an app where security is an extreme priority
|
83
|
+
# (such as a financial application), then you should enable this.
|
84
|
+
# Otherwise, leaving this off is fine.
|
78
85
|
#
|
79
86
|
# * <tt>Default</tt> false
|
80
87
|
# * <tt>Accepts:</tt> Boolean
|
@@ -83,12 +90,13 @@ module Authlogic
|
|
83
90
|
end
|
84
91
|
alias_method :generalize_credentials_error_messages=, :generalize_credentials_error_messages
|
85
92
|
|
86
|
-
# The name of the method you want Authlogic to create for storing the
|
87
|
-
# username. Keep in mind this is just for your
|
88
|
-
#
|
89
|
-
#
|
90
|
-
#
|
91
|
-
#
|
93
|
+
# The name of the method you want Authlogic to create for storing the
|
94
|
+
# login / username. Keep in mind this is just for your
|
95
|
+
# Authlogic::Session, if you want it can be something completely
|
96
|
+
# different than the field in your model. So if you wanted people to
|
97
|
+
# login with a field called "login" and then find users by email this is
|
98
|
+
# completely doable. See the find_by_login_method configuration option
|
99
|
+
# for more details.
|
92
100
|
#
|
93
101
|
# * <tt>Default:</tt> klass.login_field || klass.email_field
|
94
102
|
# * <tt>Accepts:</tt> Symbol or String
|
@@ -97,7 +105,8 @@ module Authlogic
|
|
97
105
|
end
|
98
106
|
alias_method :login_field=, :login_field
|
99
107
|
|
100
|
-
# Works exactly like login_field, but for the password instead. Returns
|
108
|
+
# Works exactly like login_field, but for the password instead. Returns
|
109
|
+
# :password if a login_field exists.
|
101
110
|
#
|
102
111
|
# * <tt>Default:</tt> :password
|
103
112
|
# * <tt>Accepts:</tt> Symbol or String
|
@@ -106,8 +115,9 @@ module Authlogic
|
|
106
115
|
end
|
107
116
|
alias_method :password_field=, :password_field
|
108
117
|
|
109
|
-
# The name of the method in your model used to verify the password. This
|
110
|
-
# be
|
118
|
+
# The name of the method in your model used to verify the password. This
|
119
|
+
# should be an instance method. It should also be prepared to accept a
|
120
|
+
# raw password and a crytped password.
|
111
121
|
#
|
112
122
|
# * <tt>Default:</tt> "valid_password?"
|
113
123
|
# * <tt>Accepts:</tt> Symbol or String
|
@@ -127,7 +137,8 @@ module Authlogic
|
|
127
137
|
super
|
128
138
|
end
|
129
139
|
|
130
|
-
# Returns the login_field / password_field credentials combination in
|
140
|
+
# Returns the login_field / password_field credentials combination in
|
141
|
+
# hash form.
|
131
142
|
def credentials
|
132
143
|
if authenticating_with_password?
|
133
144
|
details = {}
|
@@ -139,7 +150,8 @@ module Authlogic
|
|
139
150
|
end
|
140
151
|
end
|
141
152
|
|
142
|
-
# Accepts the login_field / password_field credentials combination in
|
153
|
+
# Accepts the login_field / password_field credentials combination in
|
154
|
+
# hash form.
|
143
155
|
def credentials=(value)
|
144
156
|
super
|
145
157
|
values = parse_param_val(value) # add strong parameters check
|
@@ -168,10 +180,12 @@ module Authlogic
|
|
168
180
|
self.class.send(:attr_writer, password_field) if !respond_to?("#{password_field}=")
|
169
181
|
self.class.send(:define_method, password_field) {} if !respond_to?(password_field)
|
170
182
|
|
183
|
+
# The password should not be accessible publicly. This way forms
|
184
|
+
# using form_for don't fill the password with the attempted
|
185
|
+
# password. To prevent this we just create this method that is
|
186
|
+
# private.
|
171
187
|
self.class.class_eval <<-"end_eval", __FILE__, __LINE__
|
172
188
|
private
|
173
|
-
# The password should not be accessible publicly. This way forms using form_for don't fill the password with the
|
174
|
-
# attempted password. To prevent this we just create this method that is private.
|
175
189
|
def protected_#{password_field}
|
176
190
|
@#{password_field}
|
177
191
|
end
|