authlogic 3.8.0 → 6.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (150) hide show
  1. checksums.yaml +7 -0
  2. data/lib/authlogic/acts_as_authentic/base.rb +33 -36
  3. data/lib/authlogic/acts_as_authentic/email.rb +8 -141
  4. data/lib/authlogic/acts_as_authentic/logged_in_status.rb +17 -10
  5. data/lib/authlogic/acts_as_authentic/login.rb +14 -165
  6. data/lib/authlogic/acts_as_authentic/magic_columns.rb +13 -10
  7. data/lib/authlogic/acts_as_authentic/password.rb +186 -254
  8. data/lib/authlogic/acts_as_authentic/perishable_token.rb +30 -22
  9. data/lib/authlogic/acts_as_authentic/persistence_token.rb +19 -18
  10. data/lib/authlogic/acts_as_authentic/queries/case_sensitivity.rb +53 -0
  11. data/lib/authlogic/acts_as_authentic/queries/find_with_case.rb +83 -0
  12. data/lib/authlogic/acts_as_authentic/session_maintenance.rb +94 -62
  13. data/lib/authlogic/acts_as_authentic/single_access_token.rb +28 -14
  14. data/lib/authlogic/config.rb +29 -10
  15. data/lib/authlogic/controller_adapters/abstract_adapter.rb +43 -13
  16. data/lib/authlogic/controller_adapters/rack_adapter.rb +11 -5
  17. data/lib/authlogic/controller_adapters/rails_adapter.rb +11 -29
  18. data/lib/authlogic/controller_adapters/sinatra_adapter.rb +8 -2
  19. data/lib/authlogic/cookie_credentials.rb +63 -0
  20. data/lib/authlogic/crypto_providers/bcrypt.rb +24 -18
  21. data/lib/authlogic/crypto_providers/md5/v2.rb +35 -0
  22. data/lib/authlogic/crypto_providers/md5.rb +8 -6
  23. data/lib/authlogic/crypto_providers/scrypt.rb +24 -17
  24. data/lib/authlogic/crypto_providers/sha1/v2.rb +41 -0
  25. data/lib/authlogic/crypto_providers/sha1.rb +12 -5
  26. data/lib/authlogic/crypto_providers/sha256/v2.rb +58 -0
  27. data/lib/authlogic/crypto_providers/sha256.rb +18 -9
  28. data/lib/authlogic/crypto_providers/sha512/v2.rb +39 -0
  29. data/lib/authlogic/crypto_providers/sha512.rb +9 -26
  30. data/lib/authlogic/crypto_providers.rb +77 -1
  31. data/lib/authlogic/errors.rb +35 -0
  32. data/lib/authlogic/i18n/translator.rb +4 -1
  33. data/lib/authlogic/i18n.rb +29 -20
  34. data/lib/authlogic/random.rb +12 -28
  35. data/lib/authlogic/session/base.rb +2087 -33
  36. data/lib/authlogic/session/magic_column/assigns_last_request_at.rb +46 -0
  37. data/lib/authlogic/test_case/mock_controller.rb +7 -4
  38. data/lib/authlogic/test_case/mock_cookie_jar.rb +19 -3
  39. data/lib/authlogic/test_case/mock_logger.rb +2 -0
  40. data/lib/authlogic/test_case/mock_request.rb +8 -3
  41. data/lib/authlogic/test_case/rails_request_adapter.rb +5 -2
  42. data/lib/authlogic/test_case.rb +74 -2
  43. data/lib/authlogic/version.rb +22 -0
  44. data/lib/authlogic.rb +33 -54
  45. metadata +208 -234
  46. data/.github/ISSUE_TEMPLATE.md +0 -13
  47. data/.gitignore +0 -14
  48. data/.rubocop.yml +0 -33
  49. data/.rubocop_todo.yml +0 -391
  50. data/.travis.yml +0 -48
  51. data/CHANGELOG.md +0 -5
  52. data/CONTRIBUTING.md +0 -60
  53. data/Gemfile +0 -5
  54. data/LICENSE +0 -20
  55. data/README.md +0 -294
  56. data/Rakefile +0 -21
  57. data/authlogic.gemspec +0 -27
  58. data/lib/authlogic/acts_as_authentic/restful_authentication.rb +0 -70
  59. data/lib/authlogic/acts_as_authentic/validations_scope.rb +0 -32
  60. data/lib/authlogic/authenticates_many/association.rb +0 -50
  61. data/lib/authlogic/authenticates_many/base.rb +0 -65
  62. data/lib/authlogic/crypto_providers/aes256.rb +0 -66
  63. data/lib/authlogic/crypto_providers/wordpress.rb +0 -43
  64. data/lib/authlogic/regex.rb +0 -48
  65. data/lib/authlogic/session/activation.rb +0 -70
  66. data/lib/authlogic/session/active_record_trickery.rb +0 -61
  67. data/lib/authlogic/session/brute_force_protection.rb +0 -120
  68. data/lib/authlogic/session/callbacks.rb +0 -105
  69. data/lib/authlogic/session/cookies.rb +0 -244
  70. data/lib/authlogic/session/existence.rb +0 -93
  71. data/lib/authlogic/session/foundation.rb +0 -55
  72. data/lib/authlogic/session/http_auth.rb +0 -100
  73. data/lib/authlogic/session/id.rb +0 -48
  74. data/lib/authlogic/session/klass.rb +0 -70
  75. data/lib/authlogic/session/magic_columns.rb +0 -116
  76. data/lib/authlogic/session/magic_states.rb +0 -76
  77. data/lib/authlogic/session/params.rb +0 -116
  78. data/lib/authlogic/session/password.rb +0 -308
  79. data/lib/authlogic/session/perishable_token.rb +0 -23
  80. data/lib/authlogic/session/persistence.rb +0 -71
  81. data/lib/authlogic/session/priority_record.rb +0 -35
  82. data/lib/authlogic/session/scopes.rb +0 -119
  83. data/lib/authlogic/session/session.rb +0 -67
  84. data/lib/authlogic/session/timeout.rb +0 -103
  85. data/lib/authlogic/session/unauthorized_record.rb +0 -51
  86. data/lib/authlogic/session/validation.rb +0 -93
  87. data/test/acts_as_authentic_test/base_test.rb +0 -25
  88. data/test/acts_as_authentic_test/email_test.rb +0 -240
  89. data/test/acts_as_authentic_test/logged_in_status_test.rb +0 -62
  90. data/test/acts_as_authentic_test/login_test.rb +0 -156
  91. data/test/acts_as_authentic_test/magic_columns_test.rb +0 -27
  92. data/test/acts_as_authentic_test/password_test.rb +0 -249
  93. data/test/acts_as_authentic_test/perishable_token_test.rb +0 -90
  94. data/test/acts_as_authentic_test/persistence_token_test.rb +0 -56
  95. data/test/acts_as_authentic_test/restful_authentication_test.rb +0 -37
  96. data/test/acts_as_authentic_test/session_maintenance_test.rb +0 -96
  97. data/test/acts_as_authentic_test/single_access_test.rb +0 -44
  98. data/test/authenticates_many_test.rb +0 -31
  99. data/test/config_test.rb +0 -36
  100. data/test/crypto_provider_test/aes256_test.rb +0 -14
  101. data/test/crypto_provider_test/bcrypt_test.rb +0 -14
  102. data/test/crypto_provider_test/scrypt_test.rb +0 -14
  103. data/test/crypto_provider_test/sha1_test.rb +0 -23
  104. data/test/crypto_provider_test/sha256_test.rb +0 -14
  105. data/test/crypto_provider_test/sha512_test.rb +0 -14
  106. data/test/fixtures/companies.yml +0 -5
  107. data/test/fixtures/employees.yml +0 -17
  108. data/test/fixtures/projects.yml +0 -3
  109. data/test/fixtures/users.yml +0 -41
  110. data/test/gemfiles/Gemfile.rails-3.2.x +0 -7
  111. data/test/gemfiles/Gemfile.rails-4.0.x +0 -7
  112. data/test/gemfiles/Gemfile.rails-4.1.x +0 -7
  113. data/test/gemfiles/Gemfile.rails-4.2.x +0 -7
  114. data/test/gemfiles/Gemfile.rails-5.0.x +0 -6
  115. data/test/gemfiles/Gemfile.rails-5.1.x +0 -6
  116. data/test/gemfiles/Gemfile.rails-5.2.x +0 -6
  117. data/test/i18n/lol.yml +0 -4
  118. data/test/i18n_test.rb +0 -33
  119. data/test/libs/affiliate.rb +0 -7
  120. data/test/libs/company.rb +0 -6
  121. data/test/libs/employee.rb +0 -7
  122. data/test/libs/employee_session.rb +0 -2
  123. data/test/libs/ldaper.rb +0 -3
  124. data/test/libs/project.rb +0 -3
  125. data/test/libs/user.rb +0 -7
  126. data/test/libs/user_session.rb +0 -25
  127. data/test/random_test.rb +0 -43
  128. data/test/session_test/activation_test.rb +0 -43
  129. data/test/session_test/active_record_trickery_test.rb +0 -75
  130. data/test/session_test/brute_force_protection_test.rb +0 -108
  131. data/test/session_test/callbacks_test.rb +0 -34
  132. data/test/session_test/cookies_test.rb +0 -201
  133. data/test/session_test/credentials_test.rb +0 -0
  134. data/test/session_test/existence_test.rb +0 -75
  135. data/test/session_test/foundation_test.rb +0 -6
  136. data/test/session_test/http_auth_test.rb +0 -56
  137. data/test/session_test/id_test.rb +0 -17
  138. data/test/session_test/klass_test.rb +0 -40
  139. data/test/session_test/magic_columns_test.rb +0 -62
  140. data/test/session_test/magic_states_test.rb +0 -58
  141. data/test/session_test/params_test.rb +0 -53
  142. data/test/session_test/password_test.rb +0 -105
  143. data/test/session_test/perishability_test.rb +0 -15
  144. data/test/session_test/persistence_test.rb +0 -32
  145. data/test/session_test/scopes_test.rb +0 -60
  146. data/test/session_test/session_test.rb +0 -78
  147. data/test/session_test/timeout_test.rb +0 -82
  148. data/test/session_test/unauthorized_record_test.rb +0 -13
  149. data/test/session_test/validation_test.rb +0 -23
  150. 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". 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.
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
- # Change how the perishable token works.
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(:perishable_token_valid_for, (!value.nil? && value.to_i) || value, 10.minutes.to_i)
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
- alias_method :perishable_token_valid_for=, :perishable_token_valid_for
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 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.
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
- alias_method :disable_perishable_token_maintenance=, :disable_perishable_token_maintenance
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 if !klass.column_names.include?("perishable_token")
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, :if => :perishable_token_changed?
55
- before_save :reset_perishable_token, :unless => :disable_perishable_token_maintenance?
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
- # Class level methods for the perishable token
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 = self.perishable_token_valid_for)
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
- # Instance level methods for the perishable token.
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(:validate => false)
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!, :if => :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, :if => :persistence_token_changed?
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, :if => :reset_persistence_token?
33
+ before_validation :reset_persistence_token, if: :reset_persistence_token?
28
34
  end
29
35
  end
30
36
 
31
- # Class level methods for the persistence token.
37
+ # :nodoc:
32
38
  module ClassMethods
33
- # Resets ALL persistence tokens in the database, which will require all users to reauthenticate.
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
- records = nil
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
- # Instance level methods for the persistence token.
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(:validate => false)
57
+ save_without_session_maintenance(validate: false)
57
58
  end
58
- alias_method :forget!, :reset_persistence_token!
59
+ alias forget! reset_persistence_token!
59
60
 
60
61
  private
61
62
 
62
- def reset_persistence_token?
63
- persistence_token.blank?
64
- end
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
- # This is more of a convenience method. In order to turn off automatic
34
- # maintenance of sessions just set this to false, or you can also set
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 maintain_sessions(value = nil)
41
- rw_config(:maintain_sessions, value, true)
42
+ def log_in_after_create(value = nil)
43
+ rw_config(:log_in_after_create, value, true)
42
44
  end
43
- alias_method :maintain_sessions=, :maintain_sessions
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
- alias_method :session_ids=, :session_ids
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 = "#{base_class.name}Session".constantize rescue nil
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
- alias_method :session_class=, :session_class
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, :if => :update_sessions?
73
- before_save :maintain_sessions, :if => :update_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
- def skip_session_maintenance=(value)
88
- @skip_session_maintenance = value
89
- end
105
+ def skip_session_maintenance=(value)
106
+ @skip_session_maintenance = value
107
+ end
90
108
 
91
- def skip_session_maintenance
92
- @skip_session_maintenance ||= false
93
- end
109
+ def skip_session_maintenance
110
+ @skip_session_maintenance ||= false
111
+ end
94
112
 
95
- def update_sessions?
96
- !skip_session_maintenance &&
97
- session_class &&
98
- session_class.activated? &&
99
- self.class.maintain_sessions == true &&
100
- !session_ids.blank? &&
101
- persistence_token_changed?
102
- end
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
- def get_session_information
105
- # Need to determine if we are completely logged out, or logged in as
106
- # another user.
107
- @_sessions = []
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
- session_ids.each do |session_id|
110
- session = session_class.find(session_id, self)
111
- @_sessions << session if session && session.record
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
- def maintain_sessions
116
- if @_sessions.empty?
117
- create_session
118
- else
119
- update_sessions
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
- def create_session
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.
127
- session_id = session_ids.first
128
- session_class.create(*[self, self, session_id].compact)
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
- return true
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
- def update_sessions
134
- # We found sessions above, let's update them with the new info
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
- return true
142
- end
166
+ def session_ids
167
+ self.class.session_ids
168
+ end
143
169
 
144
- def session_ids
145
- self.class.session_ids
146
- end
170
+ def session_class
171
+ self.class.session_class
172
+ end
147
173
 
148
- def session_class
149
- self.class.session_class
150
- end
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 more
4
- # information the single access token and how to use it, see the
5
- # Authlogic::Session::Params module.
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
- alias_method :change_single_access_token_with_password=, :change_single_access_token_with_password
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 if !klass.column_names.include?("single_access_token")
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, :if => :single_access_token_changed?
37
- before_validation :reset_single_access_token, :if => :reset_single_access_token?
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(:reset_single_access_token, :if => :change_single_access_token_with_password?)
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
- def reset_single_access_token?
59
- single_access_token.blank?
60
- end
72
+ def reset_single_access_token?
73
+ single_access_token.blank?
74
+ end
61
75
 
62
- def change_single_access_token_with_password?
63
- self.class.change_single_access_token_with_password == true
64
- end
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
@@ -1,8 +1,21 @@
1
- # encoding: utf-8
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
- # This is a one-liner method to write a config setting, read the config
14
- # setting, and also set a default value for the setting.
15
- def rw_config(key, value, default_value = nil)
16
- if value.nil?
17
- acts_as_authentic_config.include?(key) ? acts_as_authentic_config[key] : default_value
18
- else
19
- self.acts_as_authentic_config = acts_as_authentic_config.merge(key => value)
20
- value
21
- end
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