authlogic 3.8.0 → 6.0.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 +7 -0
- data/lib/authlogic/acts_as_authentic/base.rb +33 -36
- data/lib/authlogic/acts_as_authentic/email.rb +8 -141
- data/lib/authlogic/acts_as_authentic/logged_in_status.rb +17 -10
- data/lib/authlogic/acts_as_authentic/login.rb +14 -165
- data/lib/authlogic/acts_as_authentic/magic_columns.rb +13 -10
- data/lib/authlogic/acts_as_authentic/password.rb +186 -254
- data/lib/authlogic/acts_as_authentic/perishable_token.rb +30 -22
- data/lib/authlogic/acts_as_authentic/persistence_token.rb +19 -18
- data/lib/authlogic/acts_as_authentic/queries/case_sensitivity.rb +53 -0
- data/lib/authlogic/acts_as_authentic/queries/find_with_case.rb +83 -0
- data/lib/authlogic/acts_as_authentic/session_maintenance.rb +94 -62
- data/lib/authlogic/acts_as_authentic/single_access_token.rb +28 -14
- data/lib/authlogic/config.rb +29 -10
- data/lib/authlogic/controller_adapters/abstract_adapter.rb +43 -13
- data/lib/authlogic/controller_adapters/rack_adapter.rb +11 -5
- data/lib/authlogic/controller_adapters/rails_adapter.rb +11 -29
- data/lib/authlogic/controller_adapters/sinatra_adapter.rb +8 -2
- data/lib/authlogic/cookie_credentials.rb +63 -0
- data/lib/authlogic/crypto_providers/bcrypt.rb +24 -18
- data/lib/authlogic/crypto_providers/md5/v2.rb +35 -0
- data/lib/authlogic/crypto_providers/md5.rb +8 -6
- data/lib/authlogic/crypto_providers/scrypt.rb +24 -17
- data/lib/authlogic/crypto_providers/sha1/v2.rb +41 -0
- data/lib/authlogic/crypto_providers/sha1.rb +12 -5
- data/lib/authlogic/crypto_providers/sha256/v2.rb +58 -0
- data/lib/authlogic/crypto_providers/sha256.rb +18 -9
- data/lib/authlogic/crypto_providers/sha512/v2.rb +39 -0
- data/lib/authlogic/crypto_providers/sha512.rb +9 -26
- data/lib/authlogic/crypto_providers.rb +77 -1
- data/lib/authlogic/errors.rb +35 -0
- data/lib/authlogic/i18n/translator.rb +4 -1
- data/lib/authlogic/i18n.rb +29 -20
- data/lib/authlogic/random.rb +12 -28
- data/lib/authlogic/session/base.rb +2087 -33
- data/lib/authlogic/session/magic_column/assigns_last_request_at.rb +46 -0
- data/lib/authlogic/test_case/mock_controller.rb +7 -4
- data/lib/authlogic/test_case/mock_cookie_jar.rb +19 -3
- data/lib/authlogic/test_case/mock_logger.rb +2 -0
- data/lib/authlogic/test_case/mock_request.rb +8 -3
- data/lib/authlogic/test_case/rails_request_adapter.rb +5 -2
- data/lib/authlogic/test_case.rb +74 -2
- data/lib/authlogic/version.rb +22 -0
- data/lib/authlogic.rb +33 -54
- metadata +208 -234
- data/.github/ISSUE_TEMPLATE.md +0 -13
- data/.gitignore +0 -14
- data/.rubocop.yml +0 -33
- data/.rubocop_todo.yml +0 -391
- data/.travis.yml +0 -48
- data/CHANGELOG.md +0 -5
- data/CONTRIBUTING.md +0 -60
- data/Gemfile +0 -5
- data/LICENSE +0 -20
- data/README.md +0 -294
- data/Rakefile +0 -21
- data/authlogic.gemspec +0 -27
- data/lib/authlogic/acts_as_authentic/restful_authentication.rb +0 -70
- data/lib/authlogic/acts_as_authentic/validations_scope.rb +0 -32
- data/lib/authlogic/authenticates_many/association.rb +0 -50
- data/lib/authlogic/authenticates_many/base.rb +0 -65
- data/lib/authlogic/crypto_providers/aes256.rb +0 -66
- data/lib/authlogic/crypto_providers/wordpress.rb +0 -43
- data/lib/authlogic/regex.rb +0 -48
- data/lib/authlogic/session/activation.rb +0 -70
- data/lib/authlogic/session/active_record_trickery.rb +0 -61
- data/lib/authlogic/session/brute_force_protection.rb +0 -120
- data/lib/authlogic/session/callbacks.rb +0 -105
- data/lib/authlogic/session/cookies.rb +0 -244
- data/lib/authlogic/session/existence.rb +0 -93
- data/lib/authlogic/session/foundation.rb +0 -55
- data/lib/authlogic/session/http_auth.rb +0 -100
- data/lib/authlogic/session/id.rb +0 -48
- data/lib/authlogic/session/klass.rb +0 -70
- data/lib/authlogic/session/magic_columns.rb +0 -116
- data/lib/authlogic/session/magic_states.rb +0 -76
- data/lib/authlogic/session/params.rb +0 -116
- data/lib/authlogic/session/password.rb +0 -308
- data/lib/authlogic/session/perishable_token.rb +0 -23
- data/lib/authlogic/session/persistence.rb +0 -71
- data/lib/authlogic/session/priority_record.rb +0 -35
- data/lib/authlogic/session/scopes.rb +0 -119
- data/lib/authlogic/session/session.rb +0 -67
- data/lib/authlogic/session/timeout.rb +0 -103
- data/lib/authlogic/session/unauthorized_record.rb +0 -51
- data/lib/authlogic/session/validation.rb +0 -93
- data/test/acts_as_authentic_test/base_test.rb +0 -25
- data/test/acts_as_authentic_test/email_test.rb +0 -240
- data/test/acts_as_authentic_test/logged_in_status_test.rb +0 -62
- data/test/acts_as_authentic_test/login_test.rb +0 -156
- data/test/acts_as_authentic_test/magic_columns_test.rb +0 -27
- data/test/acts_as_authentic_test/password_test.rb +0 -249
- data/test/acts_as_authentic_test/perishable_token_test.rb +0 -90
- data/test/acts_as_authentic_test/persistence_token_test.rb +0 -56
- data/test/acts_as_authentic_test/restful_authentication_test.rb +0 -37
- data/test/acts_as_authentic_test/session_maintenance_test.rb +0 -96
- data/test/acts_as_authentic_test/single_access_test.rb +0 -44
- data/test/authenticates_many_test.rb +0 -31
- data/test/config_test.rb +0 -36
- data/test/crypto_provider_test/aes256_test.rb +0 -14
- data/test/crypto_provider_test/bcrypt_test.rb +0 -14
- data/test/crypto_provider_test/scrypt_test.rb +0 -14
- data/test/crypto_provider_test/sha1_test.rb +0 -23
- data/test/crypto_provider_test/sha256_test.rb +0 -14
- data/test/crypto_provider_test/sha512_test.rb +0 -14
- data/test/fixtures/companies.yml +0 -5
- data/test/fixtures/employees.yml +0 -17
- data/test/fixtures/projects.yml +0 -3
- data/test/fixtures/users.yml +0 -41
- data/test/gemfiles/Gemfile.rails-3.2.x +0 -7
- data/test/gemfiles/Gemfile.rails-4.0.x +0 -7
- data/test/gemfiles/Gemfile.rails-4.1.x +0 -7
- data/test/gemfiles/Gemfile.rails-4.2.x +0 -7
- data/test/gemfiles/Gemfile.rails-5.0.x +0 -6
- data/test/gemfiles/Gemfile.rails-5.1.x +0 -6
- data/test/gemfiles/Gemfile.rails-5.2.x +0 -6
- data/test/i18n/lol.yml +0 -4
- data/test/i18n_test.rb +0 -33
- data/test/libs/affiliate.rb +0 -7
- data/test/libs/company.rb +0 -6
- data/test/libs/employee.rb +0 -7
- data/test/libs/employee_session.rb +0 -2
- data/test/libs/ldaper.rb +0 -3
- data/test/libs/project.rb +0 -3
- data/test/libs/user.rb +0 -7
- data/test/libs/user_session.rb +0 -25
- data/test/random_test.rb +0 -43
- data/test/session_test/activation_test.rb +0 -43
- data/test/session_test/active_record_trickery_test.rb +0 -75
- data/test/session_test/brute_force_protection_test.rb +0 -108
- data/test/session_test/callbacks_test.rb +0 -34
- data/test/session_test/cookies_test.rb +0 -201
- data/test/session_test/credentials_test.rb +0 -0
- data/test/session_test/existence_test.rb +0 -75
- data/test/session_test/foundation_test.rb +0 -6
- data/test/session_test/http_auth_test.rb +0 -56
- data/test/session_test/id_test.rb +0 -17
- data/test/session_test/klass_test.rb +0 -40
- data/test/session_test/magic_columns_test.rb +0 -62
- data/test/session_test/magic_states_test.rb +0 -58
- data/test/session_test/params_test.rb +0 -53
- data/test/session_test/password_test.rb +0 -105
- data/test/session_test/perishability_test.rb +0 -15
- data/test/session_test/persistence_test.rb +0 -32
- data/test/session_test/scopes_test.rb +0 -60
- data/test/session_test/session_test.rb +0 -78
- data/test/session_test/timeout_test.rb +0 -82
- data/test/session_test/unauthorized_record_test.rb +0 -13
- data/test/session_test/validation_test.rb +0 -23
- data/test/test_helper.rb +0 -233
@@ -1,13 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Authlogic
|
2
4
|
module ActsAsAuthentic
|
3
|
-
# This provides a handy token that is "perishable"
|
4
|
-
# only good for a certain amount of time.
|
5
|
-
#
|
6
|
-
#
|
7
|
-
#
|
8
|
-
#
|
9
|
-
#
|
10
|
-
#
|
5
|
+
# This provides a handy token that is "perishable", meaning the token is
|
6
|
+
# only good for a certain amount of time.
|
7
|
+
#
|
8
|
+
# This is useful for resetting password, confirming accounts, etc. Typically
|
9
|
+
# during these actions you send them this token in an email. Once they use
|
10
|
+
# the token and do what they need to do, that token should expire.
|
11
|
+
#
|
12
|
+
# Don't worry about maintaining the token, changing it, or expiring it
|
13
|
+
# yourself. Authlogic does all of this for you. See the sub modules for all
|
14
|
+
# of the tools Authlogic provides to you.
|
11
15
|
module PerishableToken
|
12
16
|
def self.included(klass)
|
13
17
|
klass.class_eval do
|
@@ -16,7 +20,7 @@ module Authlogic
|
|
16
20
|
end
|
17
21
|
end
|
18
22
|
|
19
|
-
#
|
23
|
+
# Configure the perishable token.
|
20
24
|
module Config
|
21
25
|
# When using the find_using_perishable_token method the token can
|
22
26
|
# expire. If the token is expired, no record will be returned. Use this
|
@@ -25,38 +29,42 @@ module Authlogic
|
|
25
29
|
# * <tt>Default:</tt> 10.minutes
|
26
30
|
# * <tt>Accepts:</tt> Fixnum
|
27
31
|
def perishable_token_valid_for(value = nil)
|
28
|
-
rw_config(
|
32
|
+
rw_config(
|
33
|
+
:perishable_token_valid_for,
|
34
|
+
(!value.nil? && value.to_i) || value,
|
35
|
+
10.minutes.to_i
|
36
|
+
)
|
29
37
|
end
|
30
|
-
|
38
|
+
alias perishable_token_valid_for= perishable_token_valid_for
|
31
39
|
|
32
40
|
# Authlogic tries to expire and change the perishable token as much as
|
33
|
-
# possible, without compromising
|
34
|
-
#
|
35
|
-
# from getting your in way by setting this to true.
|
41
|
+
# possible, without compromising its purpose. If you want to manage it
|
42
|
+
# yourself, set this to true.
|
36
43
|
#
|
37
44
|
# * <tt>Default:</tt> false
|
38
45
|
# * <tt>Accepts:</tt> Boolean
|
39
46
|
def disable_perishable_token_maintenance(value = nil)
|
40
47
|
rw_config(:disable_perishable_token_maintenance, value, false)
|
41
48
|
end
|
42
|
-
|
49
|
+
alias disable_perishable_token_maintenance= disable_perishable_token_maintenance
|
43
50
|
end
|
44
51
|
|
45
52
|
# All methods relating to the perishable token.
|
46
53
|
module Methods
|
47
54
|
def self.included(klass)
|
48
|
-
return
|
55
|
+
return unless klass.column_names.include?("perishable_token")
|
49
56
|
|
50
57
|
klass.class_eval do
|
51
58
|
extend ClassMethods
|
52
59
|
include InstanceMethods
|
53
60
|
|
54
|
-
validates_uniqueness_of :perishable_token, :
|
55
|
-
|
61
|
+
validates_uniqueness_of :perishable_token, case_sensitive: true,
|
62
|
+
if: :will_save_change_to_perishable_token?
|
63
|
+
before_save :reset_perishable_token, unless: :disable_perishable_token_maintenance?
|
56
64
|
end
|
57
65
|
end
|
58
66
|
|
59
|
-
#
|
67
|
+
# :nodoc:
|
60
68
|
module ClassMethods
|
61
69
|
# Use this method to find a record with a perishable token. This
|
62
70
|
# method does 2 things for you:
|
@@ -68,7 +76,7 @@ module Authlogic
|
|
68
76
|
# second parameter:
|
69
77
|
#
|
70
78
|
# User.find_using_perishable_token(token, 1.hour)
|
71
|
-
def find_using_perishable_token(token, age =
|
79
|
+
def find_using_perishable_token(token, age = perishable_token_valid_for)
|
72
80
|
return if token.blank?
|
73
81
|
age = age.to_i
|
74
82
|
|
@@ -89,7 +97,7 @@ module Authlogic
|
|
89
97
|
end
|
90
98
|
end
|
91
99
|
|
92
|
-
#
|
100
|
+
# :nodoc:
|
93
101
|
module InstanceMethods
|
94
102
|
# Resets the perishable token to a random friendly token.
|
95
103
|
def reset_perishable_token
|
@@ -99,7 +107,7 @@ module Authlogic
|
|
99
107
|
# Same as reset_perishable_token, but then saves the record afterwards.
|
100
108
|
def reset_perishable_token!
|
101
109
|
reset_perishable_token
|
102
|
-
save_without_session_maintenance(:
|
110
|
+
save_without_session_maintenance(validate: false)
|
103
111
|
end
|
104
112
|
|
105
113
|
# A convenience method based on the
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Authlogic
|
2
4
|
module ActsAsAuthentic
|
3
5
|
# Maintains the persistence token, the token responsible for persisting sessions. This token
|
@@ -16,34 +18,33 @@ module Authlogic
|
|
16
18
|
extend ClassMethods
|
17
19
|
include InstanceMethods
|
18
20
|
|
21
|
+
# If the table does not have a password column, then
|
22
|
+
# `after_password_set` etc. will not be defined. See
|
23
|
+
# `Authlogic::ActsAsAuthentic::Password::Callbacks.included`
|
19
24
|
if respond_to?(:after_password_set) && respond_to?(:after_password_verification)
|
20
25
|
after_password_set :reset_persistence_token
|
21
|
-
after_password_verification :reset_persistence_token!, :
|
26
|
+
after_password_verification :reset_persistence_token!, if: :reset_persistence_token?
|
22
27
|
end
|
23
28
|
|
24
29
|
validates_presence_of :persistence_token
|
25
|
-
validates_uniqueness_of :persistence_token, :
|
30
|
+
validates_uniqueness_of :persistence_token, case_sensitive: true,
|
31
|
+
if: :will_save_change_to_persistence_token?
|
26
32
|
|
27
|
-
before_validation :reset_persistence_token, :
|
33
|
+
before_validation :reset_persistence_token, if: :reset_persistence_token?
|
28
34
|
end
|
29
35
|
end
|
30
36
|
|
31
|
-
#
|
37
|
+
# :nodoc:
|
32
38
|
module ClassMethods
|
33
|
-
# Resets ALL persistence tokens in the database, which will require
|
39
|
+
# Resets ALL persistence tokens in the database, which will require
|
40
|
+
# all users to re-authenticate.
|
34
41
|
def forget_all
|
35
42
|
# Paginate these to save on memory
|
36
|
-
|
37
|
-
i = 0
|
38
|
-
begin
|
39
|
-
records = limit(50).offset(i)
|
40
|
-
records.each { |record| record.forget! }
|
41
|
-
i += 50
|
42
|
-
end while !records.blank?
|
43
|
+
find_each(batch_size: 50, &:forget!)
|
43
44
|
end
|
44
45
|
end
|
45
46
|
|
46
|
-
#
|
47
|
+
# :nodoc:
|
47
48
|
module InstanceMethods
|
48
49
|
# Resets the persistence_token field to a random hex value.
|
49
50
|
def reset_persistence_token
|
@@ -53,15 +54,15 @@ module Authlogic
|
|
53
54
|
# Same as reset_persistence_token, but then saves the record.
|
54
55
|
def reset_persistence_token!
|
55
56
|
reset_persistence_token
|
56
|
-
save_without_session_maintenance(:
|
57
|
+
save_without_session_maintenance(validate: false)
|
57
58
|
end
|
58
|
-
|
59
|
+
alias forget! reset_persistence_token!
|
59
60
|
|
60
61
|
private
|
61
62
|
|
62
|
-
|
63
|
-
|
64
|
-
|
63
|
+
def reset_persistence_token?
|
64
|
+
persistence_token.blank?
|
65
|
+
end
|
65
66
|
end
|
66
67
|
end
|
67
68
|
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Authlogic
|
4
|
+
module ActsAsAuthentic
|
5
|
+
module Queries
|
6
|
+
# @api private
|
7
|
+
class CaseSensitivity
|
8
|
+
E_UNABLE_TO_DETERMINE_SENSITIVITY = <<~EOS
|
9
|
+
Authlogic was unable to determine what case-sensitivity to use when
|
10
|
+
searching for email/login. To specify a sensitivity, validate the
|
11
|
+
uniqueness of the email/login and use the `case_sensitive` option,
|
12
|
+
like this:
|
13
|
+
|
14
|
+
validates :email, uniqueness: { case_sensitive: false }
|
15
|
+
|
16
|
+
Authlogic will now perform a case-insensitive query.
|
17
|
+
EOS
|
18
|
+
|
19
|
+
# @api private
|
20
|
+
def initialize(model_class, attribute)
|
21
|
+
@model_class = model_class
|
22
|
+
@attribute = attribute.to_sym
|
23
|
+
end
|
24
|
+
|
25
|
+
# @api private
|
26
|
+
def sensitive?
|
27
|
+
sensitive = uniqueness_validator_options[:case_sensitive]
|
28
|
+
if sensitive.nil?
|
29
|
+
::Kernel.warn(E_UNABLE_TO_DETERMINE_SENSITIVITY)
|
30
|
+
false
|
31
|
+
else
|
32
|
+
sensitive
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
private
|
37
|
+
|
38
|
+
# @api private
|
39
|
+
def uniqueness_validator
|
40
|
+
@model_class.validators.select { |v|
|
41
|
+
v.is_a?(::ActiveRecord::Validations::UniquenessValidator) &&
|
42
|
+
v.attributes == [@attribute]
|
43
|
+
}.first
|
44
|
+
end
|
45
|
+
|
46
|
+
# @api private
|
47
|
+
def uniqueness_validator_options
|
48
|
+
uniqueness_validator&.options || {}
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,83 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Authlogic
|
4
|
+
module ActsAsAuthentic
|
5
|
+
module Queries
|
6
|
+
# The query used by public-API method `find_by_smart_case_login_field`.
|
7
|
+
#
|
8
|
+
# We use the rails methods `case_insensitive_comparison` and
|
9
|
+
# `case_sensitive_comparison`. These methods nicely take into account
|
10
|
+
# MySQL collations. (Consider the case where a user *says* they want a
|
11
|
+
# case-sensitive uniqueness validation, but then they configure their
|
12
|
+
# database to have an insensitive collation. Rails will handle this for
|
13
|
+
# us, by downcasing, see
|
14
|
+
# `active_record/connection_adapters/abstract_mysql_adapter.rb`) So that's
|
15
|
+
# great! But, these methods are not part of rails' public API, so there
|
16
|
+
# are no docs. So, everything we know about how to use the methods
|
17
|
+
# correctly comes from mimicing what we find in
|
18
|
+
# `active_record/validations/uniqueness.rb`.
|
19
|
+
#
|
20
|
+
# @api private
|
21
|
+
class FindWithCase
|
22
|
+
# Dup ActiveRecord.gem_version before freezing, in case someone
|
23
|
+
# else wants to modify it. Freezing modifies an object in place.
|
24
|
+
# https://github.com/binarylogic/authlogic/pull/590
|
25
|
+
AR_GEM_VERSION = ::ActiveRecord.gem_version.dup.freeze
|
26
|
+
|
27
|
+
# @api private
|
28
|
+
def initialize(model_class, field, value, sensitive)
|
29
|
+
@model_class = model_class
|
30
|
+
@field = field.to_s
|
31
|
+
@value = value
|
32
|
+
@sensitive = sensitive
|
33
|
+
end
|
34
|
+
|
35
|
+
# @api private
|
36
|
+
def execute
|
37
|
+
@model_class.where(comparison).first
|
38
|
+
end
|
39
|
+
|
40
|
+
private
|
41
|
+
|
42
|
+
# @api private
|
43
|
+
# @return Arel::Nodes::Equality
|
44
|
+
def comparison
|
45
|
+
@sensitive ? sensitive_comparison : insensitive_comparison
|
46
|
+
end
|
47
|
+
|
48
|
+
# @api private
|
49
|
+
def insensitive_comparison
|
50
|
+
if AR_GEM_VERSION > Gem::Version.new("5.3")
|
51
|
+
@model_class.connection.case_insensitive_comparison(
|
52
|
+
@model_class.arel_table[@field], @value
|
53
|
+
)
|
54
|
+
else
|
55
|
+
@model_class.connection.case_insensitive_comparison(
|
56
|
+
@model_class.arel_table,
|
57
|
+
@field,
|
58
|
+
@model_class.columns_hash[@field],
|
59
|
+
@value
|
60
|
+
)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
# @api private
|
65
|
+
def sensitive_comparison
|
66
|
+
bound_value = @model_class.predicate_builder.build_bind_attribute(@field, @value)
|
67
|
+
if AR_GEM_VERSION > Gem::Version.new("5.3")
|
68
|
+
@model_class.connection.case_sensitive_comparison(
|
69
|
+
@model_class.arel_table[@field], bound_value
|
70
|
+
)
|
71
|
+
else
|
72
|
+
@model_class.connection.case_sensitive_comparison(
|
73
|
+
@model_class.arel_table,
|
74
|
+
@field,
|
75
|
+
@model_class.columns_hash[@field],
|
76
|
+
bound_value
|
77
|
+
)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Authlogic
|
2
4
|
module ActsAsAuthentic
|
3
5
|
# This is one of my favorite features that I think is pretty cool. It's
|
@@ -29,18 +31,28 @@ module Authlogic
|
|
29
31
|
end
|
30
32
|
end
|
31
33
|
|
34
|
+
# Configuration for the session maintenance aspect of acts_as_authentic.
|
35
|
+
# These methods become class methods of ::ActiveRecord::Base.
|
32
36
|
module Config
|
33
|
-
#
|
34
|
-
#
|
35
|
-
# the session_ids method to a blank array. Both accomplish the same
|
36
|
-
# thing. This method is a little clearer in it's intentions though.
|
37
|
+
# In order to turn off automatic maintenance of sessions
|
38
|
+
# after create, just set this to false.
|
37
39
|
#
|
38
40
|
# * <tt>Default:</tt> true
|
39
41
|
# * <tt>Accepts:</tt> Boolean
|
40
|
-
def
|
41
|
-
rw_config(:
|
42
|
+
def log_in_after_create(value = nil)
|
43
|
+
rw_config(:log_in_after_create, value, true)
|
42
44
|
end
|
43
|
-
|
45
|
+
alias log_in_after_create= log_in_after_create
|
46
|
+
|
47
|
+
# In order to turn off automatic maintenance of sessions when updating
|
48
|
+
# the password, just set this to false.
|
49
|
+
#
|
50
|
+
# * <tt>Default:</tt> true
|
51
|
+
# * <tt>Accepts:</tt> Boolean
|
52
|
+
def log_in_after_password_change(value = nil)
|
53
|
+
rw_config(:log_in_after_password_change, value, true)
|
54
|
+
end
|
55
|
+
alias log_in_after_password_change= log_in_after_password_change
|
44
56
|
|
45
57
|
# As you may know, authlogic sessions can be separate by id (See
|
46
58
|
# Authlogic::Session::Base#id). You can specify here what session ids
|
@@ -52,7 +64,7 @@ module Authlogic
|
|
52
64
|
def session_ids(value = nil)
|
53
65
|
rw_config(:session_ids, value, [nil])
|
54
66
|
end
|
55
|
-
|
67
|
+
alias session_ids= session_ids
|
56
68
|
|
57
69
|
# The name of the associated session class. This is inferred by the name
|
58
70
|
# of the model.
|
@@ -60,17 +72,23 @@ module Authlogic
|
|
60
72
|
# * <tt>Default:</tt> "#{klass.name}Session".constantize
|
61
73
|
# * <tt>Accepts:</tt> Class
|
62
74
|
def session_class(value = nil)
|
63
|
-
const =
|
75
|
+
const = begin
|
76
|
+
"#{base_class.name}Session".constantize
|
77
|
+
rescue NameError
|
78
|
+
nil
|
79
|
+
end
|
64
80
|
rw_config(:session_class, value, const)
|
65
81
|
end
|
66
|
-
|
82
|
+
alias session_class= session_class
|
67
83
|
end
|
68
84
|
|
85
|
+
# This module, as one of the `acts_as_authentic_modules`, is only included
|
86
|
+
# into an ActiveRecord model if that model calls `acts_as_authentic`.
|
69
87
|
module Methods
|
70
88
|
def self.included(klass)
|
71
89
|
klass.class_eval do
|
72
|
-
before_save :get_session_information, :
|
73
|
-
before_save :maintain_sessions, :
|
90
|
+
before_save :get_session_information, if: :update_sessions?
|
91
|
+
before_save :maintain_sessions, if: :update_sessions?
|
74
92
|
end
|
75
93
|
end
|
76
94
|
|
@@ -84,70 +102,84 @@ module Authlogic
|
|
84
102
|
|
85
103
|
private
|
86
104
|
|
87
|
-
|
88
|
-
|
89
|
-
|
105
|
+
def skip_session_maintenance=(value)
|
106
|
+
@skip_session_maintenance = value
|
107
|
+
end
|
90
108
|
|
91
|
-
|
92
|
-
|
93
|
-
|
109
|
+
def skip_session_maintenance
|
110
|
+
@skip_session_maintenance ||= false
|
111
|
+
end
|
94
112
|
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
113
|
+
def update_sessions?
|
114
|
+
!skip_session_maintenance &&
|
115
|
+
session_class &&
|
116
|
+
session_class.activated? &&
|
117
|
+
maintain_session? &&
|
118
|
+
!session_ids.blank? &&
|
119
|
+
will_save_change_to_persistence_token?
|
120
|
+
end
|
121
|
+
|
122
|
+
def maintain_session?
|
123
|
+
log_in_after_create? || log_in_after_password_change?
|
124
|
+
end
|
103
125
|
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
126
|
+
def get_session_information
|
127
|
+
# Need to determine if we are completely logged out, or logged in as
|
128
|
+
# another user.
|
129
|
+
@_sessions = []
|
108
130
|
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
end
|
131
|
+
session_ids.each do |session_id|
|
132
|
+
session = session_class.find(session_id, self)
|
133
|
+
@_sessions << session if session&.record
|
113
134
|
end
|
135
|
+
end
|
114
136
|
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
end
|
137
|
+
def maintain_sessions
|
138
|
+
if @_sessions.empty?
|
139
|
+
create_session
|
140
|
+
else
|
141
|
+
update_sessions
|
121
142
|
end
|
143
|
+
end
|
122
144
|
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
145
|
+
def create_session
|
146
|
+
# We only want to automatically login into the first session, since
|
147
|
+
# this is the main session. The other sessions are sessions that
|
148
|
+
# need to be created after logging into the main session.
|
149
|
+
session_id = session_ids.first
|
150
|
+
session_class.create(*[self, self, session_id].compact)
|
151
|
+
|
152
|
+
true
|
153
|
+
end
|
129
154
|
|
130
|
-
|
155
|
+
def update_sessions
|
156
|
+
# We found sessions above, let's update them with the new info
|
157
|
+
@_sessions.each do |stale_session|
|
158
|
+
next if stale_session.record != self
|
159
|
+
stale_session.unauthorized_record = self
|
160
|
+
stale_session.save
|
131
161
|
end
|
132
162
|
|
133
|
-
|
134
|
-
|
135
|
-
@_sessions.each do |stale_session|
|
136
|
-
next if stale_session.record != self
|
137
|
-
stale_session.unauthorized_record = self
|
138
|
-
stale_session.save
|
139
|
-
end
|
163
|
+
true
|
164
|
+
end
|
140
165
|
|
141
|
-
|
142
|
-
|
166
|
+
def session_ids
|
167
|
+
self.class.session_ids
|
168
|
+
end
|
143
169
|
|
144
|
-
|
145
|
-
|
146
|
-
|
170
|
+
def session_class
|
171
|
+
self.class.session_class
|
172
|
+
end
|
147
173
|
|
148
|
-
|
149
|
-
|
150
|
-
|
174
|
+
def log_in_after_create?
|
175
|
+
new_record? && self.class.log_in_after_create
|
176
|
+
end
|
177
|
+
|
178
|
+
def log_in_after_password_change?
|
179
|
+
persisted? &&
|
180
|
+
will_save_change_to_persistence_token? &&
|
181
|
+
self.class.log_in_after_password_change
|
182
|
+
end
|
151
183
|
end
|
152
184
|
end
|
153
185
|
end
|
@@ -1,8 +1,10 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Authlogic
|
2
4
|
module ActsAsAuthentic
|
3
|
-
# This module is responsible for maintaining the single_access token. For
|
4
|
-
# information the single access token and how to use it, see
|
5
|
-
#
|
5
|
+
# This module is responsible for maintaining the single_access token. For
|
6
|
+
# more information the single access token and how to use it, see "Params"
|
7
|
+
# in `Session::Base`.
|
6
8
|
module SingleAccessToken
|
7
9
|
def self.included(klass)
|
8
10
|
klass.class_eval do
|
@@ -12,6 +14,8 @@ module Authlogic
|
|
12
14
|
end
|
13
15
|
|
14
16
|
# All configuration for the single_access token aspect of acts_as_authentic.
|
17
|
+
#
|
18
|
+
# These methods become class methods of ::ActiveRecord::Base.
|
15
19
|
module Config
|
16
20
|
# The single access token is used for authentication via URLs, such as a private
|
17
21
|
# feed. That being said, if the user changes their password, that token probably
|
@@ -23,24 +27,34 @@ module Authlogic
|
|
23
27
|
def change_single_access_token_with_password(value = nil)
|
24
28
|
rw_config(:change_single_access_token_with_password, value, false)
|
25
29
|
end
|
26
|
-
|
30
|
+
alias change_single_access_token_with_password= change_single_access_token_with_password
|
27
31
|
end
|
28
32
|
|
29
33
|
# All method, for the single_access token aspect of acts_as_authentic.
|
34
|
+
#
|
35
|
+
# This module, as one of the `acts_as_authentic_modules`, is only included
|
36
|
+
# into an ActiveRecord model if that model calls `acts_as_authentic`.
|
30
37
|
module Methods
|
31
38
|
def self.included(klass)
|
32
|
-
return
|
39
|
+
return unless klass.column_names.include?("single_access_token")
|
33
40
|
|
34
41
|
klass.class_eval do
|
35
42
|
include InstanceMethods
|
36
|
-
validates_uniqueness_of :single_access_token,
|
37
|
-
|
43
|
+
validates_uniqueness_of :single_access_token,
|
44
|
+
case_sensitive: true,
|
45
|
+
if: :will_save_change_to_single_access_token?
|
46
|
+
|
47
|
+
before_validation :reset_single_access_token, if: :reset_single_access_token?
|
38
48
|
if respond_to?(:after_password_set)
|
39
|
-
after_password_set(
|
49
|
+
after_password_set(
|
50
|
+
:reset_single_access_token,
|
51
|
+
if: :change_single_access_token_with_password?
|
52
|
+
)
|
40
53
|
end
|
41
54
|
end
|
42
55
|
end
|
43
56
|
|
57
|
+
# :nodoc:
|
44
58
|
module InstanceMethods
|
45
59
|
# Resets the single_access_token to a random friendly token.
|
46
60
|
def reset_single_access_token
|
@@ -55,13 +69,13 @@ module Authlogic
|
|
55
69
|
|
56
70
|
protected
|
57
71
|
|
58
|
-
|
59
|
-
|
60
|
-
|
72
|
+
def reset_single_access_token?
|
73
|
+
single_access_token.blank?
|
74
|
+
end
|
61
75
|
|
62
|
-
|
63
|
-
|
64
|
-
|
76
|
+
def change_single_access_token_with_password?
|
77
|
+
self.class.change_single_access_token_with_password == true
|
78
|
+
end
|
65
79
|
end
|
66
80
|
end
|
67
81
|
end
|
data/lib/authlogic/config.rb
CHANGED
@@ -1,8 +1,21 @@
|
|
1
|
-
#
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
2
3
|
module Authlogic
|
4
|
+
# Mixed into `Authlogic::ActsAsAuthentic::Base` and
|
5
|
+
# `Authlogic::Session::Base`.
|
3
6
|
module Config
|
7
|
+
E_USE_NORMAL_RAILS_VALIDATION = <<~EOS
|
8
|
+
This Authlogic configuration option (%s) is deprecated. Use normal
|
9
|
+
ActiveRecord validation instead. Detailed instructions:
|
10
|
+
https://github.com/binarylogic/authlogic/blob/master/doc/use_normal_rails_validation.md
|
11
|
+
EOS
|
12
|
+
|
4
13
|
def self.extended(klass)
|
5
14
|
klass.class_eval do
|
15
|
+
# TODO: Is this a confusing name, given this module is mixed into
|
16
|
+
# both `Authlogic::ActsAsAuthentic::Base` and
|
17
|
+
# `Authlogic::Session::Base`? Perhaps a more generic name, like
|
18
|
+
# `authlogic_config` would be better?
|
6
19
|
class_attribute :acts_as_authentic_config
|
7
20
|
self.acts_as_authentic_config ||= {}
|
8
21
|
end
|
@@ -10,15 +23,21 @@ module Authlogic
|
|
10
23
|
|
11
24
|
private
|
12
25
|
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
26
|
+
def deprecate_authlogic_config(method_name)
|
27
|
+
::ActiveSupport::Deprecation.warn(
|
28
|
+
format(E_USE_NORMAL_RAILS_VALIDATION, method_name)
|
29
|
+
)
|
30
|
+
end
|
31
|
+
|
32
|
+
# This is a one-liner method to write a config setting, read the config
|
33
|
+
# setting, and also set a default value for the setting.
|
34
|
+
def rw_config(key, value, default_value = nil)
|
35
|
+
if value.nil?
|
36
|
+
acts_as_authentic_config.include?(key) ? acts_as_authentic_config[key] : default_value
|
37
|
+
else
|
38
|
+
self.acts_as_authentic_config = acts_as_authentic_config.merge(key => value)
|
39
|
+
value
|
22
40
|
end
|
41
|
+
end
|
23
42
|
end
|
24
43
|
end
|