authlogic 4.4.2 → 5.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.
Files changed (146) hide show
  1. checksums.yaml +4 -4
  2. data/lib/authlogic/acts_as_authentic/base.rb +3 -18
  3. data/lib/authlogic/acts_as_authentic/email.rb +3 -170
  4. data/lib/authlogic/acts_as_authentic/logged_in_status.rb +3 -1
  5. data/lib/authlogic/acts_as_authentic/login.rb +7 -174
  6. data/lib/authlogic/acts_as_authentic/magic_columns.rb +7 -4
  7. data/lib/authlogic/acts_as_authentic/password.rb +54 -253
  8. data/lib/authlogic/acts_as_authentic/perishable_token.rb +7 -5
  9. data/lib/authlogic/acts_as_authentic/persistence_token.rb +9 -4
  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 +17 -22
  12. data/lib/authlogic/acts_as_authentic/session_maintenance.rb +8 -6
  13. data/lib/authlogic/acts_as_authentic/single_access_token.rb +9 -8
  14. data/lib/authlogic/config.rb +9 -1
  15. data/lib/authlogic/controller_adapters/abstract_adapter.rb +7 -4
  16. data/lib/authlogic/controller_adapters/rack_adapter.rb +2 -0
  17. data/lib/authlogic/controller_adapters/rails_adapter.rb +17 -14
  18. data/lib/authlogic/controller_adapters/sinatra_adapter.rb +6 -0
  19. data/lib/authlogic/crypto_providers/bcrypt.rb +3 -3
  20. data/lib/authlogic/crypto_providers/md5.rb +3 -6
  21. data/lib/authlogic/crypto_providers/scrypt.rb +2 -0
  22. data/lib/authlogic/crypto_providers/sha1.rb +4 -6
  23. data/lib/authlogic/crypto_providers/sha256.rb +2 -0
  24. data/lib/authlogic/crypto_providers/sha512.rb +6 -5
  25. data/lib/authlogic/crypto_providers.rb +5 -20
  26. data/lib/authlogic/i18n/translator.rb +3 -0
  27. data/lib/authlogic/i18n.rb +3 -1
  28. data/lib/authlogic/random.rb +2 -0
  29. data/lib/authlogic/session/base.rb +2089 -39
  30. data/lib/authlogic/session/magic_column/assigns_last_request_at.rb +46 -0
  31. data/lib/authlogic/test_case/mock_controller.rb +2 -0
  32. data/lib/authlogic/test_case/mock_cookie_jar.rb +7 -0
  33. data/lib/authlogic/test_case/mock_logger.rb +2 -0
  34. data/lib/authlogic/test_case/mock_request.rb +2 -0
  35. data/lib/authlogic/test_case/rails_request_adapter.rb +2 -0
  36. data/lib/authlogic/test_case.rb +4 -0
  37. data/lib/authlogic/version.rb +2 -1
  38. data/lib/authlogic.rb +3 -28
  39. metadata +36 -180
  40. data/.github/ISSUE_TEMPLATE/bug_report.md +0 -28
  41. data/.github/ISSUE_TEMPLATE/feature_proposal.md +0 -32
  42. data/.github/triage.md +0 -86
  43. data/.gitignore +0 -15
  44. data/.rubocop.yml +0 -133
  45. data/.rubocop_todo.yml +0 -74
  46. data/.travis.yml +0 -24
  47. data/CHANGELOG.md +0 -326
  48. data/CONTRIBUTING.md +0 -91
  49. data/Gemfile +0 -6
  50. data/LICENSE +0 -20
  51. data/README.md +0 -439
  52. data/Rakefile +0 -21
  53. data/UPGRADING.md +0 -22
  54. data/authlogic.gemspec +0 -40
  55. data/doc/use_normal_rails_validation.md +0 -82
  56. data/gemfiles/Gemfile.rails-4.2.x +0 -6
  57. data/gemfiles/Gemfile.rails-5.1.x +0 -6
  58. data/gemfiles/Gemfile.rails-5.2.x +0 -6
  59. data/lib/authlogic/acts_as_authentic/restful_authentication.rb +0 -106
  60. data/lib/authlogic/acts_as_authentic/validations_scope.rb +0 -35
  61. data/lib/authlogic/authenticates_many/association.rb +0 -50
  62. data/lib/authlogic/authenticates_many/base.rb +0 -81
  63. data/lib/authlogic/crypto_providers/aes256.rb +0 -71
  64. data/lib/authlogic/crypto_providers/wordpress.rb +0 -72
  65. data/lib/authlogic/regex.rb +0 -79
  66. data/lib/authlogic/session/activation.rb +0 -73
  67. data/lib/authlogic/session/active_record_trickery.rb +0 -65
  68. data/lib/authlogic/session/brute_force_protection.rb +0 -127
  69. data/lib/authlogic/session/callbacks.rb +0 -153
  70. data/lib/authlogic/session/cookies.rb +0 -296
  71. data/lib/authlogic/session/existence.rb +0 -103
  72. data/lib/authlogic/session/foundation.rb +0 -105
  73. data/lib/authlogic/session/http_auth.rb +0 -107
  74. data/lib/authlogic/session/id.rb +0 -53
  75. data/lib/authlogic/session/klass.rb +0 -73
  76. data/lib/authlogic/session/magic_columns.rb +0 -119
  77. data/lib/authlogic/session/magic_states.rb +0 -82
  78. data/lib/authlogic/session/params.rb +0 -130
  79. data/lib/authlogic/session/password.rb +0 -318
  80. data/lib/authlogic/session/perishable_token.rb +0 -24
  81. data/lib/authlogic/session/persistence.rb +0 -77
  82. data/lib/authlogic/session/priority_record.rb +0 -38
  83. data/lib/authlogic/session/scopes.rb +0 -138
  84. data/lib/authlogic/session/session.rb +0 -77
  85. data/lib/authlogic/session/timeout.rb +0 -103
  86. data/lib/authlogic/session/unauthorized_record.rb +0 -56
  87. data/lib/authlogic/session/validation.rb +0 -93
  88. data/test/acts_as_authentic_test/base_test.rb +0 -27
  89. data/test/acts_as_authentic_test/email_test.rb +0 -241
  90. data/test/acts_as_authentic_test/logged_in_status_test.rb +0 -64
  91. data/test/acts_as_authentic_test/login_test.rb +0 -153
  92. data/test/acts_as_authentic_test/magic_columns_test.rb +0 -29
  93. data/test/acts_as_authentic_test/password_test.rb +0 -263
  94. data/test/acts_as_authentic_test/perishable_token_test.rb +0 -98
  95. data/test/acts_as_authentic_test/persistence_token_test.rb +0 -62
  96. data/test/acts_as_authentic_test/restful_authentication_test.rb +0 -48
  97. data/test/acts_as_authentic_test/session_maintenance_test.rb +0 -150
  98. data/test/acts_as_authentic_test/single_access_test.rb +0 -46
  99. data/test/adapter_test.rb +0 -23
  100. data/test/authenticates_many_test.rb +0 -33
  101. data/test/config_test.rb +0 -38
  102. data/test/crypto_provider_test/aes256_test.rb +0 -16
  103. data/test/crypto_provider_test/bcrypt_test.rb +0 -16
  104. data/test/crypto_provider_test/scrypt_test.rb +0 -16
  105. data/test/crypto_provider_test/sha1_test.rb +0 -25
  106. data/test/crypto_provider_test/sha256_test.rb +0 -16
  107. data/test/crypto_provider_test/sha512_test.rb +0 -16
  108. data/test/crypto_provider_test/wordpress_test.rb +0 -26
  109. data/test/fixtures/companies.yml +0 -5
  110. data/test/fixtures/employees.yml +0 -17
  111. data/test/fixtures/projects.yml +0 -3
  112. data/test/fixtures/users.yml +0 -41
  113. data/test/i18n/lol.yml +0 -4
  114. data/test/i18n_test.rb +0 -35
  115. data/test/libs/affiliate.rb +0 -9
  116. data/test/libs/company.rb +0 -8
  117. data/test/libs/employee.rb +0 -9
  118. data/test/libs/employee_session.rb +0 -4
  119. data/test/libs/ldaper.rb +0 -5
  120. data/test/libs/project.rb +0 -5
  121. data/test/libs/user.rb +0 -9
  122. data/test/libs/user_session.rb +0 -27
  123. data/test/random_test.rb +0 -15
  124. data/test/session_test/activation_test.rb +0 -45
  125. data/test/session_test/active_record_trickery_test.rb +0 -78
  126. data/test/session_test/brute_force_protection_test.rb +0 -110
  127. data/test/session_test/callbacks_test.rb +0 -42
  128. data/test/session_test/cookies_test.rb +0 -226
  129. data/test/session_test/credentials_test.rb +0 -0
  130. data/test/session_test/existence_test.rb +0 -88
  131. data/test/session_test/foundation_test.rb +0 -24
  132. data/test/session_test/http_auth_test.rb +0 -60
  133. data/test/session_test/id_test.rb +0 -19
  134. data/test/session_test/klass_test.rb +0 -42
  135. data/test/session_test/magic_columns_test.rb +0 -62
  136. data/test/session_test/magic_states_test.rb +0 -60
  137. data/test/session_test/params_test.rb +0 -61
  138. data/test/session_test/password_test.rb +0 -107
  139. data/test/session_test/perishability_test.rb +0 -17
  140. data/test/session_test/persistence_test.rb +0 -35
  141. data/test/session_test/scopes_test.rb +0 -68
  142. data/test/session_test/session_test.rb +0 -80
  143. data/test/session_test/timeout_test.rb +0 -84
  144. data/test/session_test/unauthorized_record_test.rb +0 -15
  145. data/test/session_test/validation_test.rb +0 -25
  146. data/test/test_helper.rb +0 -272
@@ -1,127 +0,0 @@
1
- module Authlogic
2
- module Session
3
- # A brute force attacks is executed by hammering a login with as many password
4
- # combinations as possible, until one works. A brute force attacked is generally
5
- # combated with a slow hashing algorithm such as BCrypt. You can increase the cost,
6
- # which makes the hash generation slower, and ultimately increases the time it takes
7
- # to execute a brute force attack. Just to put this into perspective, if a hacker was
8
- # to gain access to your server and execute a brute force attack locally, meaning
9
- # there is no network lag, it would probably take decades to complete. Now throw in
10
- # network lag and it would take MUCH longer.
11
- #
12
- # But for those that are extra paranoid and can't get enough protection, why not stop
13
- # them as soon as you realize something isn't right? That's what this module is all
14
- # about. By default the consecutive_failed_logins_limit configuration option is set to
15
- # 50, if someone consecutively fails to login after 50 attempts their account will be
16
- # suspended. This is a very liberal number and at this point it should be obvious that
17
- # something is not right. If you wish to lower this number just set the configuration
18
- # to a lower number:
19
- #
20
- # class UserSession < Authlogic::Session::Base
21
- # consecutive_failed_logins_limit 10
22
- # end
23
- module BruteForceProtection
24
- def self.included(klass)
25
- klass.class_eval do
26
- extend Config
27
- include InstanceMethods
28
- validate :reset_failed_login_count, if: :reset_failed_login_count?
29
- validate :validate_failed_logins, if: :being_brute_force_protected?
30
- end
31
- end
32
-
33
- # Configuration for the brute force protection feature.
34
- module Config
35
- # To help protect from brute force attacks you can set a limit on the
36
- # allowed number of consecutive failed logins. By default this is 50,
37
- # this is a very liberal number, and if someone fails to login after 50
38
- # tries it should be pretty obvious that it's a machine trying to login
39
- # in and very likely a brute force attack.
40
- #
41
- # In order to enable this field your model MUST have a
42
- # failed_login_count (integer) field.
43
- #
44
- # If you don't know what a brute force attack is, it's when a machine
45
- # tries to login into a system using every combination of character
46
- # possible. Thus resulting in possibly millions of attempts to log into
47
- # an account.
48
- #
49
- # * <tt>Default:</tt> 50
50
- # * <tt>Accepts:</tt> Integer, set to 0 to disable
51
- def consecutive_failed_logins_limit(value = nil)
52
- rw_config(:consecutive_failed_logins_limit, value, 50)
53
- end
54
- alias_method :consecutive_failed_logins_limit=, :consecutive_failed_logins_limit
55
-
56
- # Once the failed logins limit has been exceed, how long do you want to
57
- # ban the user? This can be a temporary or permanent ban.
58
- #
59
- # * <tt>Default:</tt> 2.hours
60
- # * <tt>Accepts:</tt> Fixnum, set to 0 for permanent ban
61
- def failed_login_ban_for(value = nil)
62
- rw_config(:failed_login_ban_for, (!value.nil? && value) || value, 2.hours.to_i)
63
- end
64
- alias_method :failed_login_ban_for=, :failed_login_ban_for
65
- end
66
-
67
- # The methods available for an Authlogic::Session::Base object that make
68
- # up the brute force protection feature.
69
- module InstanceMethods
70
- # Returns true when the consecutive_failed_logins_limit has been
71
- # exceeded and is being temporarily banned. Notice the word temporary,
72
- # the user will not be permanently banned unless you choose to do so
73
- # with configuration. By default they will be banned for 2 hours. During
74
- # that 2 hour period this method will return true.
75
- def being_brute_force_protected?
76
- exceeded_failed_logins_limit? &&
77
- (
78
- failed_login_ban_for <= 0 ||
79
- attempted_record.respond_to?(:updated_at) &&
80
- attempted_record.updated_at >= failed_login_ban_for.seconds.ago
81
- )
82
- end
83
-
84
- private
85
-
86
- def exceeded_failed_logins_limit?
87
- !attempted_record.nil? &&
88
- attempted_record.respond_to?(:failed_login_count) &&
89
- consecutive_failed_logins_limit > 0 &&
90
- attempted_record.failed_login_count &&
91
- attempted_record.failed_login_count >= consecutive_failed_logins_limit
92
- end
93
-
94
- def reset_failed_login_count?
95
- exceeded_failed_logins_limit? && !being_brute_force_protected?
96
- end
97
-
98
- def reset_failed_login_count
99
- attempted_record.failed_login_count = 0
100
- end
101
-
102
- def validate_failed_logins
103
- # Clear all other error messages, as they are irrelevant at this point and can
104
- # only provide additional information that is not needed
105
- errors.clear
106
- errors.add(
107
- :base,
108
- I18n.t(
109
- "error_messages.consecutive_failed_logins_limit_exceeded",
110
- default: "Consecutive failed logins limit exceeded, account has been" +
111
- (failed_login_ban_for.zero? ? "" : " temporarily") +
112
- " disabled."
113
- )
114
- )
115
- end
116
-
117
- def consecutive_failed_logins_limit
118
- self.class.consecutive_failed_logins_limit
119
- end
120
-
121
- def failed_login_ban_for
122
- self.class.failed_login_ban_for
123
- end
124
- end
125
- end
126
- end
127
- end
@@ -1,153 +0,0 @@
1
- module Authlogic
2
- module Session
3
- # Between these callbacks and the configuration, this is the contract between me and
4
- # you to safely modify Authlogic's behavior. I will do everything I can to make sure
5
- # these do not change.
6
- #
7
- # Check out the sub modules of Authlogic::Session. They are very concise, clear, and
8
- # to the point. More importantly they use the same API that you would use to extend
9
- # Authlogic. That being said, they are great examples of how to extend Authlogic and
10
- # add / modify behavior to Authlogic. These modules could easily be pulled out into
11
- # their own plugin and become an "add on" without any change.
12
- #
13
- # Now to the point of this module. Just like in ActiveRecord you have before_save,
14
- # before_validation, etc. You have similar callbacks with Authlogic, see the METHODS
15
- # constant below. The order of execution is as follows:
16
- #
17
- # before_persisting
18
- # persist
19
- # after_persisting
20
- # [save record if record.changed?]
21
- #
22
- # before_validation
23
- # before_validation_on_create
24
- # before_validation_on_update
25
- # validate
26
- # after_validation_on_update
27
- # after_validation_on_create
28
- # after_validation
29
- # [save record if record.changed?]
30
- #
31
- # before_save
32
- # before_create
33
- # before_update
34
- # after_update
35
- # after_create
36
- # after_save
37
- # [save record if record.changed?]
38
- #
39
- # before_destroy
40
- # [save record if record.changed?]
41
- # destroy
42
- # after_destroy
43
- #
44
- # Notice the "save record if changed?" lines above. This helps with performance. If
45
- # you need to make changes to the associated record, there is no need to save the
46
- # record, Authlogic will do it for you. This allows multiple modules to modify the
47
- # record and execute as few queries as possible.
48
- #
49
- # **WARNING**: unlike ActiveRecord, these callbacks must be set up on the class level:
50
- #
51
- # class UserSession < Authlogic::Session::Base
52
- # before_validation :my_method
53
- # validate :another_method
54
- # # ..etc
55
- # end
56
- #
57
- # You can NOT define a "before_validation" method, this is bad practice and does not
58
- # allow Authlogic to extend properly with multiple extensions. Please ONLY use the
59
- # method above.
60
- module Callbacks
61
- METHODS = %w[
62
- before_persisting
63
- persist
64
- after_persisting
65
- before_validation
66
- before_validation_on_create
67
- before_validation_on_update
68
- validate
69
- after_validation_on_update
70
- after_validation_on_create
71
- after_validation
72
- before_save
73
- before_create
74
- before_update
75
- after_update
76
- after_create
77
- after_save
78
- before_destroy
79
- after_destroy
80
- ].freeze
81
-
82
- class << self
83
- def included(base) #:nodoc:
84
- base.send :include, ActiveSupport::Callbacks
85
- define_session_callbacks(base)
86
- define_session_callback_installation_methods(base)
87
- end
88
-
89
- private
90
-
91
- # Defines the "callback installation methods". Other modules will use
92
- # these class methods to install their callbacks. Examples:
93
- #
94
- # ```
95
- # # session/timeout.rb, in `included`
96
- # before_persisting :reset_stale_state
97
- #
98
- # # session/password.rb, in `included`
99
- # validate :validate_by_password, if: :authenticating_with_password?
100
- # ```
101
- def define_session_callback_installation_methods(base)
102
- METHODS.each do |method|
103
- base.class_eval <<-EOS, __FILE__, __LINE__ + 1
104
- def self.#{method}(*filter_list, &block)
105
- set_callback(:#{method}, *filter_list, &block)
106
- end
107
- EOS
108
- end
109
- end
110
-
111
- # Defines session life cycle events that support callbacks.
112
- def define_session_callbacks(base)
113
- if Gem::Version.new(ActiveSupport::VERSION::STRING) >= Gem::Version.new("5")
114
- base.define_callbacks(
115
- *METHODS,
116
- terminator: ->(_target, result_lambda) { result_lambda.call == false }
117
- )
118
- base.define_callbacks(
119
- "persist",
120
- terminator: ->(_target, result_lambda) { result_lambda.call == true }
121
- )
122
- else
123
- base.define_callbacks(
124
- *METHODS,
125
- terminator: ->(_target, result) { result == false }
126
- )
127
- base.define_callbacks(
128
- "persist",
129
- terminator: ->(_target, result) { result == true }
130
- )
131
- end
132
- end
133
- end
134
-
135
- METHODS.each do |method|
136
- class_eval(
137
- <<-EOS, __FILE__, __LINE__ + 1
138
- def #{method}
139
- run_callbacks(:#{method})
140
- end
141
- EOS
142
- )
143
- end
144
-
145
- def save_record(alternate_record = nil)
146
- r = alternate_record || record
147
- if r&.changed? && !r.readonly?
148
- r.save_without_session_maintenance(validate: false)
149
- end
150
- end
151
- end
152
- end
153
- end
@@ -1,296 +0,0 @@
1
- module Authlogic
2
- module Session
3
- # Handles all authentication that deals with cookies, such as persisting,
4
- # saving, and destroying.
5
- module Cookies
6
- VALID_SAME_SITE_VALUES = [nil, "Lax", "Strict"].freeze
7
-
8
- def self.included(klass)
9
- klass.class_eval do
10
- extend Config
11
- include InstanceMethods
12
- persist :persist_by_cookie
13
- after_save :save_cookie
14
- after_destroy :destroy_cookie
15
- end
16
- end
17
-
18
- # Configuration for the cookie feature set.
19
- module Config
20
- # The name of the cookie or the key in the cookies hash. Be sure and use
21
- # a unique name. If you have multiple sessions and they use the same
22
- # cookie it will cause problems. Also, if a id is set it will be
23
- # inserted into the beginning of the string. Example:
24
- #
25
- # session = UserSession.new
26
- # session.cookie_key => "user_credentials"
27
- #
28
- # session = UserSession.new(:super_high_secret)
29
- # session.cookie_key => "super_high_secret_user_credentials"
30
- #
31
- # * <tt>Default:</tt> "#{klass_name.underscore}_credentials"
32
- # * <tt>Accepts:</tt> String
33
- def cookie_key(value = nil)
34
- rw_config(:cookie_key, value, "#{klass_name.underscore}_credentials")
35
- end
36
- alias_method :cookie_key=, :cookie_key
37
-
38
- # If sessions should be remembered by default or not.
39
- #
40
- # * <tt>Default:</tt> false
41
- # * <tt>Accepts:</tt> Boolean
42
- def remember_me(value = nil)
43
- rw_config(:remember_me, value, false)
44
- end
45
- alias_method :remember_me=, :remember_me
46
-
47
- # The length of time until the cookie expires.
48
- #
49
- # * <tt>Default:</tt> 3.months
50
- # * <tt>Accepts:</tt> Integer, length of time in seconds, such as 60 or 3.months
51
- def remember_me_for(value = nil)
52
- rw_config(:remember_me_for, value, 3.months)
53
- end
54
- alias_method :remember_me_for=, :remember_me_for
55
-
56
- # Should the cookie be set as secure? If true, the cookie will only be sent over
57
- # SSL connections
58
- #
59
- # * <tt>Default:</tt> true
60
- # * <tt>Accepts:</tt> Boolean
61
- def secure(value = nil)
62
- rw_config(:secure, value, true)
63
- end
64
- alias_method :secure=, :secure
65
-
66
- # Should the cookie be set as httponly? If true, the cookie will not be
67
- # accessible from javascript
68
- #
69
- # * <tt>Default:</tt> true
70
- # * <tt>Accepts:</tt> Boolean
71
- def httponly(value = nil)
72
- rw_config(:httponly, value, true)
73
- end
74
- alias_method :httponly=, :httponly
75
-
76
- # Should the cookie be prevented from being send along with cross-site
77
- # requests?
78
- #
79
- # * <tt>Default:</tt> nil
80
- # * <tt>Accepts:</tt> String, one of nil, 'Lax' or 'Strict'
81
- def same_site(value = nil)
82
- unless VALID_SAME_SITE_VALUES.include?(value)
83
- msg = "Invalid same_site value: #{value}. Valid: #{VALID_SAME_SITE_VALUES.inspect}"
84
- raise ArgumentError.new(msg)
85
- end
86
- rw_config(:same_site, value)
87
- end
88
- alias_method :same_site=, :same_site
89
-
90
- # Should the cookie be signed? If the controller adapter supports it, this is a
91
- # measure against cookie tampering.
92
- def sign_cookie(value = nil)
93
- if value && !controller.cookies.respond_to?(:signed)
94
- raise "Signed cookies not supported with #{controller.class}!"
95
- end
96
- rw_config(:sign_cookie, value, false)
97
- end
98
- alias_method :sign_cookie=, :sign_cookie
99
- end
100
-
101
- # The methods available for an Authlogic::Session::Base object that make up the
102
- # cookie feature set.
103
- module InstanceMethods
104
- # Allows you to set the remember_me option when passing credentials.
105
- def credentials=(value)
106
- super
107
- values = value.is_a?(Array) ? value : [value]
108
- case values.first
109
- when Hash
110
- if values.first.with_indifferent_access.key?(:remember_me)
111
- self.remember_me = values.first.with_indifferent_access[:remember_me]
112
- end
113
- else
114
- r = values.find { |val| val.is_a?(TrueClass) || val.is_a?(FalseClass) }
115
- self.remember_me = r unless r.nil?
116
- end
117
- end
118
-
119
- # Is the cookie going to expire after the session is over, or will it stick around?
120
- def remember_me
121
- return @remember_me if defined?(@remember_me)
122
- @remember_me = self.class.remember_me
123
- end
124
-
125
- # Accepts a boolean as a flag to remember the session or not. Basically
126
- # to expire the cookie at the end of the session or keep it for
127
- # "remember_me_until".
128
- def remember_me=(value)
129
- @remember_me = value
130
- end
131
-
132
- # See remember_me
133
- def remember_me?
134
- remember_me == true || remember_me == "true" || remember_me == "1"
135
- end
136
-
137
- # How long to remember the user if remember_me is true. This is based on the class
138
- # level configuration: remember_me_for
139
- def remember_me_for
140
- return unless remember_me?
141
- self.class.remember_me_for
142
- end
143
-
144
- # When to expire the cookie. See remember_me_for configuration option to change
145
- # this.
146
- def remember_me_until
147
- return unless remember_me?
148
- remember_me_for.from_now
149
- end
150
-
151
- # Has the cookie expired due to current time being greater than remember_me_until.
152
- def remember_me_expired?
153
- return unless remember_me?
154
- (Time.parse(cookie_credentials[2]) < Time.now)
155
- end
156
-
157
- # If the cookie should be marked as secure (SSL only)
158
- def secure
159
- return @secure if defined?(@secure)
160
- @secure = self.class.secure
161
- end
162
-
163
- # Accepts a boolean as to whether the cookie should be marked as secure. If true
164
- # the cookie will only ever be sent over an SSL connection.
165
- def secure=(value)
166
- @secure = value
167
- end
168
-
169
- # See secure
170
- def secure?
171
- secure == true || secure == "true" || secure == "1"
172
- end
173
-
174
- # If the cookie should be marked as httponly (not accessible via javascript)
175
- def httponly
176
- return @httponly if defined?(@httponly)
177
- @httponly = self.class.httponly
178
- end
179
-
180
- # Accepts a boolean as to whether the cookie should be marked as
181
- # httponly. If true, the cookie will not be accessible from javascript
182
- def httponly=(value)
183
- @httponly = value
184
- end
185
-
186
- # See httponly
187
- def httponly?
188
- httponly == true || httponly == "true" || httponly == "1"
189
- end
190
-
191
- # If the cookie should be marked as SameSite with 'Lax' or 'Strict' flag.
192
- def same_site
193
- return @same_site if defined?(@same_site)
194
- @same_site = self.class.same_site(nil)
195
- end
196
-
197
- # Accepts nil, 'Lax' or 'Strict' as possible flags.
198
- def same_site=(value)
199
- unless VALID_SAME_SITE_VALUES.include?(value)
200
- msg = "Invalid same_site value: #{value}. Valid: #{VALID_SAME_SITE_VALUES.inspect}"
201
- raise ArgumentError.new(msg)
202
- end
203
- @same_site = value
204
- end
205
-
206
- # If the cookie should be signed
207
- def sign_cookie
208
- return @sign_cookie if defined?(@sign_cookie)
209
- @sign_cookie = self.class.sign_cookie
210
- end
211
-
212
- # Accepts a boolean as to whether the cookie should be signed. If true
213
- # the cookie will be saved and verified using a signature.
214
- def sign_cookie=(value)
215
- @sign_cookie = value
216
- end
217
-
218
- # See sign_cookie
219
- def sign_cookie?
220
- sign_cookie == true || sign_cookie == "true" || sign_cookie == "1"
221
- end
222
-
223
- private
224
-
225
- def cookie_key
226
- build_key(self.class.cookie_key)
227
- end
228
-
229
- # Returns an array of cookie elements. See cookie format in
230
- # `generate_cookie_for_saving`. If no cookie is found, returns nil.
231
- def cookie_credentials
232
- cookie = cookie_jar[cookie_key]
233
- cookie&.split("::")
234
- end
235
-
236
- # The third element of the cookie indicates whether the user wanted
237
- # to be remembered (Actually, it's a timestamp, `remember_me_until`)
238
- # See cookie format in `generate_cookie_for_saving`.
239
- def cookie_credentials_remember_me?
240
- !cookie_credentials.nil? && !cookie_credentials[2].nil?
241
- end
242
-
243
- def cookie_jar
244
- if self.class.sign_cookie
245
- controller.cookies.signed
246
- else
247
- controller.cookies
248
- end
249
- end
250
-
251
- # Tries to validate the session from information in the cookie
252
- def persist_by_cookie
253
- persistence_token, record_id = cookie_credentials
254
- if persistence_token.present?
255
- record = search_for_record("find_by_#{klass.primary_key}", record_id)
256
- if record && record.persistence_token == persistence_token
257
- self.unauthorized_record = record
258
- end
259
- valid?
260
- else
261
- false
262
- end
263
- end
264
-
265
- def save_cookie
266
- if sign_cookie?
267
- controller.cookies.signed[cookie_key] = generate_cookie_for_saving
268
- else
269
- controller.cookies[cookie_key] = generate_cookie_for_saving
270
- end
271
- end
272
-
273
- def generate_cookie_for_saving
274
- value = format(
275
- "%s::%s%s",
276
- record.persistence_token,
277
- record.send(record.class.primary_key),
278
- remember_me? ? "::#{remember_me_until.iso8601}" : ""
279
- )
280
- {
281
- value: value,
282
- expires: remember_me_until,
283
- secure: secure,
284
- httponly: httponly,
285
- same_site: same_site,
286
- domain: controller.cookie_domain
287
- }
288
- end
289
-
290
- def destroy_cookie
291
- controller.cookies.delete cookie_key, domain: controller.cookie_domain
292
- end
293
- end
294
- end
295
- end
296
- end
@@ -1,103 +0,0 @@
1
- module Authlogic
2
- module Session
3
- # Provides methods to create and destroy objects. Basically controls their
4
- # "existence".
5
- module Existence
6
- class SessionInvalidError < ::StandardError # :nodoc:
7
- def initialize(session)
8
- message = I18n.t(
9
- "error_messages.session_invalid",
10
- default: "Your session is invalid and has the following errors:"
11
- )
12
- message += " #{session.errors.full_messages.to_sentence}"
13
- super message
14
- end
15
- end
16
-
17
- def self.included(klass)
18
- klass.class_eval do
19
- extend ClassMethods
20
- include InstanceMethods
21
- attr_accessor :new_session, :record
22
- end
23
- end
24
-
25
- module ClassMethods
26
- # A convenience method. The same as:
27
- #
28
- # session = UserSession.new(*args)
29
- # session.save
30
- #
31
- # Instead you can do:
32
- #
33
- # UserSession.create(*args)
34
- def create(*args, &block)
35
- session = new(*args)
36
- session.save(&block)
37
- session
38
- end
39
-
40
- # Same as create but calls create!, which raises an exception when validation fails.
41
- def create!(*args)
42
- session = new(*args)
43
- session.save!
44
- session
45
- end
46
- end
47
-
48
- module InstanceMethods
49
- # Clears all errors and the associated record, you should call this
50
- # terminate a session, thus requiring the user to authenticate again if
51
- # it is needed.
52
- def destroy
53
- before_destroy
54
- save_record
55
- errors.clear
56
- @record = nil
57
- after_destroy
58
- true
59
- end
60
-
61
- # Returns true if the session is new, meaning no action has been taken
62
- # on it and a successful save has not taken place.
63
- def new_session?
64
- new_session != false
65
- end
66
-
67
- # After you have specified all of the details for your session you can
68
- # try to save it. This will run validation checks and find the
69
- # associated record, if all validation passes. If validation does not
70
- # pass, the save will fail and the errors will be stored in the errors
71
- # object.
72
- def save
73
- result = nil
74
- if valid?
75
- self.record = attempted_record
76
-
77
- before_save
78
- new_session? ? before_create : before_update
79
- new_session? ? after_create : after_update
80
- after_save
81
-
82
- save_record
83
- self.new_session = false
84
- result = true
85
- else
86
- result = false
87
- end
88
-
89
- yield result if block_given?
90
- result
91
- end
92
-
93
- # Same as save but raises an exception of validation errors when
94
- # validation fails
95
- def save!
96
- result = save
97
- raise SessionInvalidError.new(self) unless result
98
- result
99
- end
100
- end
101
- end
102
- end
103
- end