authlogic 4.5.0 → 6.4.2

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 (153) hide show
  1. checksums.yaml +4 -4
  2. data/lib/authlogic/acts_as_authentic/base.rb +19 -19
  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 +67 -256
  8. data/lib/authlogic/acts_as_authentic/perishable_token.rb +8 -5
  9. data/lib/authlogic/acts_as_authentic/persistence_token.rb +10 -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 +36 -20
  12. data/lib/authlogic/acts_as_authentic/session_maintenance.rb +12 -8
  13. data/lib/authlogic/acts_as_authentic/single_access_token.rb +10 -8
  14. data/lib/authlogic/config.rb +9 -1
  15. data/lib/authlogic/controller_adapters/abstract_adapter.rb +28 -4
  16. data/lib/authlogic/controller_adapters/rack_adapter.rb +2 -0
  17. data/lib/authlogic/controller_adapters/rails_adapter.rb +7 -30
  18. data/lib/authlogic/controller_adapters/sinatra_adapter.rb +6 -0
  19. data/lib/authlogic/cookie_credentials.rb +63 -0
  20. data/lib/authlogic/crypto_providers/bcrypt.rb +3 -3
  21. data/lib/authlogic/crypto_providers/md5/v2.rb +35 -0
  22. data/lib/authlogic/crypto_providers/md5.rb +6 -6
  23. data/lib/authlogic/crypto_providers/scrypt.rb +2 -0
  24. data/lib/authlogic/crypto_providers/sha1/v2.rb +41 -0
  25. data/lib/authlogic/crypto_providers/sha1.rb +7 -6
  26. data/lib/authlogic/crypto_providers/sha256/v2.rb +58 -0
  27. data/lib/authlogic/crypto_providers/sha256.rb +5 -0
  28. data/lib/authlogic/crypto_providers/sha512/v2.rb +39 -0
  29. data/lib/authlogic/crypto_providers/sha512.rb +9 -5
  30. data/lib/authlogic/crypto_providers.rb +5 -20
  31. data/lib/authlogic/errors.rb +50 -0
  32. data/lib/authlogic/i18n/translator.rb +4 -1
  33. data/lib/authlogic/i18n.rb +3 -1
  34. data/lib/authlogic/random.rb +2 -0
  35. data/lib/authlogic/session/base.rb +2197 -39
  36. data/lib/authlogic/session/magic_column/assigns_last_request_at.rb +46 -0
  37. data/lib/authlogic/test_case/mock_api_controller.rb +52 -0
  38. data/lib/authlogic/test_case/mock_controller.rb +3 -1
  39. data/lib/authlogic/test_case/mock_cookie_jar.rb +32 -6
  40. data/lib/authlogic/test_case/mock_logger.rb +2 -0
  41. data/lib/authlogic/test_case/mock_request.rb +12 -0
  42. data/lib/authlogic/test_case/rails_request_adapter.rb +9 -1
  43. data/lib/authlogic/test_case.rb +5 -0
  44. data/lib/authlogic/version.rb +2 -1
  45. data/lib/authlogic.rb +5 -28
  46. metadata +175 -200
  47. data/.github/ISSUE_TEMPLATE/bug_report.md +0 -28
  48. data/.github/ISSUE_TEMPLATE/feature_proposal.md +0 -32
  49. data/.github/triage.md +0 -86
  50. data/.gitignore +0 -15
  51. data/.rubocop.yml +0 -133
  52. data/.rubocop_todo.yml +0 -74
  53. data/.travis.yml +0 -24
  54. data/CHANGELOG.md +0 -348
  55. data/CONTRIBUTING.md +0 -91
  56. data/Gemfile +0 -6
  57. data/LICENSE +0 -20
  58. data/README.md +0 -448
  59. data/Rakefile +0 -21
  60. data/UPGRADING.md +0 -22
  61. data/authlogic.gemspec +0 -40
  62. data/doc/use_normal_rails_validation.md +0 -82
  63. data/gemfiles/Gemfile.rails-4.2.x +0 -6
  64. data/gemfiles/Gemfile.rails-5.1.x +0 -6
  65. data/gemfiles/Gemfile.rails-5.2.x +0 -6
  66. data/lib/authlogic/acts_as_authentic/restful_authentication.rb +0 -106
  67. data/lib/authlogic/acts_as_authentic/validations_scope.rb +0 -35
  68. data/lib/authlogic/authenticates_many/association.rb +0 -50
  69. data/lib/authlogic/authenticates_many/base.rb +0 -81
  70. data/lib/authlogic/crypto_providers/aes256.rb +0 -71
  71. data/lib/authlogic/crypto_providers/wordpress.rb +0 -72
  72. data/lib/authlogic/regex.rb +0 -79
  73. data/lib/authlogic/session/activation.rb +0 -73
  74. data/lib/authlogic/session/active_record_trickery.rb +0 -65
  75. data/lib/authlogic/session/brute_force_protection.rb +0 -127
  76. data/lib/authlogic/session/callbacks.rb +0 -153
  77. data/lib/authlogic/session/cookies.rb +0 -329
  78. data/lib/authlogic/session/existence.rb +0 -103
  79. data/lib/authlogic/session/foundation.rb +0 -105
  80. data/lib/authlogic/session/http_auth.rb +0 -107
  81. data/lib/authlogic/session/id.rb +0 -53
  82. data/lib/authlogic/session/klass.rb +0 -73
  83. data/lib/authlogic/session/magic_columns.rb +0 -119
  84. data/lib/authlogic/session/magic_states.rb +0 -82
  85. data/lib/authlogic/session/params.rb +0 -130
  86. data/lib/authlogic/session/password.rb +0 -318
  87. data/lib/authlogic/session/perishable_token.rb +0 -24
  88. data/lib/authlogic/session/persistence.rb +0 -77
  89. data/lib/authlogic/session/priority_record.rb +0 -38
  90. data/lib/authlogic/session/scopes.rb +0 -138
  91. data/lib/authlogic/session/session.rb +0 -77
  92. data/lib/authlogic/session/timeout.rb +0 -103
  93. data/lib/authlogic/session/unauthorized_record.rb +0 -56
  94. data/lib/authlogic/session/validation.rb +0 -93
  95. data/test/acts_as_authentic_test/base_test.rb +0 -27
  96. data/test/acts_as_authentic_test/email_test.rb +0 -241
  97. data/test/acts_as_authentic_test/logged_in_status_test.rb +0 -64
  98. data/test/acts_as_authentic_test/login_test.rb +0 -153
  99. data/test/acts_as_authentic_test/magic_columns_test.rb +0 -29
  100. data/test/acts_as_authentic_test/password_test.rb +0 -263
  101. data/test/acts_as_authentic_test/perishable_token_test.rb +0 -98
  102. data/test/acts_as_authentic_test/persistence_token_test.rb +0 -62
  103. data/test/acts_as_authentic_test/restful_authentication_test.rb +0 -48
  104. data/test/acts_as_authentic_test/session_maintenance_test.rb +0 -150
  105. data/test/acts_as_authentic_test/single_access_test.rb +0 -46
  106. data/test/adapter_test.rb +0 -23
  107. data/test/authenticates_many_test.rb +0 -33
  108. data/test/config_test.rb +0 -38
  109. data/test/crypto_provider_test/aes256_test.rb +0 -16
  110. data/test/crypto_provider_test/bcrypt_test.rb +0 -16
  111. data/test/crypto_provider_test/scrypt_test.rb +0 -16
  112. data/test/crypto_provider_test/sha1_test.rb +0 -25
  113. data/test/crypto_provider_test/sha256_test.rb +0 -16
  114. data/test/crypto_provider_test/sha512_test.rb +0 -16
  115. data/test/crypto_provider_test/wordpress_test.rb +0 -26
  116. data/test/fixtures/companies.yml +0 -5
  117. data/test/fixtures/employees.yml +0 -17
  118. data/test/fixtures/projects.yml +0 -3
  119. data/test/fixtures/users.yml +0 -41
  120. data/test/i18n/lol.yml +0 -4
  121. data/test/i18n_test.rb +0 -35
  122. data/test/libs/affiliate.rb +0 -9
  123. data/test/libs/company.rb +0 -8
  124. data/test/libs/employee.rb +0 -9
  125. data/test/libs/employee_session.rb +0 -4
  126. data/test/libs/ldaper.rb +0 -5
  127. data/test/libs/project.rb +0 -5
  128. data/test/libs/user.rb +0 -9
  129. data/test/libs/user_session.rb +0 -27
  130. data/test/random_test.rb +0 -15
  131. data/test/session_test/activation_test.rb +0 -45
  132. data/test/session_test/active_record_trickery_test.rb +0 -78
  133. data/test/session_test/brute_force_protection_test.rb +0 -110
  134. data/test/session_test/callbacks_test.rb +0 -42
  135. data/test/session_test/cookies_test.rb +0 -244
  136. data/test/session_test/credentials_test.rb +0 -0
  137. data/test/session_test/existence_test.rb +0 -88
  138. data/test/session_test/foundation_test.rb +0 -24
  139. data/test/session_test/http_auth_test.rb +0 -60
  140. data/test/session_test/id_test.rb +0 -19
  141. data/test/session_test/klass_test.rb +0 -42
  142. data/test/session_test/magic_columns_test.rb +0 -62
  143. data/test/session_test/magic_states_test.rb +0 -60
  144. data/test/session_test/params_test.rb +0 -61
  145. data/test/session_test/password_test.rb +0 -107
  146. data/test/session_test/perishability_test.rb +0 -17
  147. data/test/session_test/persistence_test.rb +0 -35
  148. data/test/session_test/scopes_test.rb +0 -68
  149. data/test/session_test/session_test.rb +0 -80
  150. data/test/session_test/timeout_test.rb +0 -84
  151. data/test/session_test/unauthorized_record_test.rb +0 -15
  152. data/test/session_test/validation_test.rb +0 -25
  153. data/test/test_helper.rb +0 -272
@@ -4,12 +4,25 @@ module Authlogic
4
4
  module ActsAsAuthentic
5
5
  module Queries
6
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
+ #
7
20
  # @api private
8
21
  class FindWithCase
9
22
  # Dup ActiveRecord.gem_version before freezing, in case someone
10
23
  # else wants to modify it. Freezing modifies an object in place.
11
24
  # https://github.com/binarylogic/authlogic/pull/590
12
- AR_GEM_VERSION = ActiveRecord.gem_version.dup.freeze
25
+ AR_GEM_VERSION = ::ActiveRecord.gem_version.dup.freeze
13
26
 
14
27
  # @api private
15
28
  def initialize(model_class, field, value, sensitive)
@@ -21,44 +34,47 @@ module Authlogic
21
34
 
22
35
  # @api private
23
36
  def execute
24
- bind(relation).first
37
+ @model_class.where(comparison).first
25
38
  end
26
39
 
27
40
  private
28
41
 
29
42
  # @api private
30
- def bind(relation)
31
- if AR_GEM_VERSION >= Gem::Version.new("5")
32
- bind = ActiveRecord::Relation::QueryAttribute.new(
33
- @field,
34
- @value,
35
- ActiveRecord::Type::Value.new
36
- )
37
- @model_class.where(relation, bind)
38
- else
39
- @model_class.where(relation)
40
- end
43
+ # @return Arel::Nodes::Equality
44
+ def comparison
45
+ @sensitive ? sensitive_comparison : insensitive_comparison
41
46
  end
42
47
 
43
48
  # @api private
44
- def relation
45
- if !@sensitive
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
46
55
  @model_class.connection.case_insensitive_comparison(
47
56
  @model_class.arel_table,
48
57
  @field,
49
58
  @model_class.columns_hash[@field],
50
59
  @value
51
60
  )
52
- elsif AR_GEM_VERSION >= Gem::Version.new("5.0")
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
53
72
  @model_class.connection.case_sensitive_comparison(
54
73
  @model_class.arel_table,
55
74
  @field,
56
75
  @model_class.columns_hash[@field],
57
- @value
76
+ bound_value
58
77
  )
59
- else
60
- value = @model_class.connection.case_sensitive_modifier(@value, @field)
61
- @model_class.arel_table[@field].eq(value)
62
78
  end
63
79
  end
64
80
  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
@@ -40,7 +42,7 @@ module Authlogic
40
42
  def log_in_after_create(value = nil)
41
43
  rw_config(:log_in_after_create, value, true)
42
44
  end
43
- alias_method :log_in_after_create=, :log_in_after_create
45
+ alias log_in_after_create= log_in_after_create
44
46
 
45
47
  # In order to turn off automatic maintenance of sessions when updating
46
48
  # the password, just set this to false.
@@ -50,7 +52,7 @@ module Authlogic
50
52
  def log_in_after_password_change(value = nil)
51
53
  rw_config(:log_in_after_password_change, value, true)
52
54
  end
53
- alias_method :log_in_after_password_change=, :log_in_after_password_change
55
+ alias log_in_after_password_change= log_in_after_password_change
54
56
 
55
57
  # As you may know, authlogic sessions can be separate by id (See
56
58
  # Authlogic::Session::Base#id). You can specify here what session ids
@@ -62,7 +64,7 @@ module Authlogic
62
64
  def session_ids(value = nil)
63
65
  rw_config(:session_ids, value, [nil])
64
66
  end
65
- alias_method :session_ids=, :session_ids
67
+ alias session_ids= session_ids
66
68
 
67
69
  # The name of the associated session class. This is inferred by the name
68
70
  # of the model.
@@ -77,7 +79,7 @@ module Authlogic
77
79
  end
78
80
  rw_config(:session_class, value, const)
79
81
  end
80
- alias_method :session_class=, :session_class
82
+ alias session_class= session_class
81
83
  end
82
84
 
83
85
  # This module, as one of the `acts_as_authentic_modules`, is only included
@@ -91,9 +93,9 @@ module Authlogic
91
93
  end
92
94
 
93
95
  # Save the record and skip session maintenance all together.
94
- def save_without_session_maintenance(*args)
96
+ def save_without_session_maintenance(**options)
95
97
  self.skip_session_maintenance = true
96
- result = save(*args)
98
+ result = save(**options)
97
99
  self.skip_session_maintenance = false
98
100
  result
99
101
  end
@@ -114,7 +116,7 @@ module Authlogic
114
116
  session_class.activated? &&
115
117
  maintain_session? &&
116
118
  !session_ids.blank? &&
117
- persistence_token_changed?
119
+ will_save_change_to_persistence_token?
118
120
  end
119
121
 
120
122
  def maintain_session?
@@ -174,7 +176,9 @@ module Authlogic
174
176
  end
175
177
 
176
178
  def log_in_after_password_change?
177
- persistence_token_changed? && self.class.log_in_after_password_change
179
+ persisted? &&
180
+ will_save_change_to_persistence_token? &&
181
+ self.class.log_in_after_password_change
178
182
  end
179
183
  end
180
184
  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
@@ -25,10 +27,7 @@ module Authlogic
25
27
  def change_single_access_token_with_password(value = nil)
26
28
  rw_config(:change_single_access_token_with_password, value, false)
27
29
  end
28
- alias_method(
29
- :change_single_access_token_with_password=,
30
- :change_single_access_token_with_password
31
- )
30
+ alias change_single_access_token_with_password= change_single_access_token_with_password
32
31
  end
33
32
 
34
33
  # All method, for the single_access token aspect of acts_as_authentic.
@@ -41,7 +40,10 @@ module Authlogic
41
40
 
42
41
  klass.class_eval do
43
42
  include InstanceMethods
44
- validates_uniqueness_of :single_access_token, if: :single_access_token_changed?
43
+ validates_uniqueness_of :single_access_token,
44
+ case_sensitive: true,
45
+ if: :will_save_change_to_single_access_token?
46
+
45
47
  before_validation :reset_single_access_token, if: :reset_single_access_token?
46
48
  if respond_to?(:after_password_set)
47
49
  after_password_set(
@@ -1,6 +1,10 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Authlogic
4
+ # Mixed into `Authlogic::ActsAsAuthentic::Base` and
5
+ # `Authlogic::Session::Base`.
2
6
  module Config
3
- E_USE_NORMAL_RAILS_VALIDATION = <<~EOS.freeze
7
+ E_USE_NORMAL_RAILS_VALIDATION = <<~EOS
4
8
  This Authlogic configuration option (%s) is deprecated. Use normal
5
9
  ActiveRecord validation instead. Detailed instructions:
6
10
  https://github.com/binarylogic/authlogic/blob/master/doc/use_normal_rails_validation.md
@@ -8,6 +12,10 @@ module Authlogic
8
12
 
9
13
  def self.extended(klass)
10
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?
11
19
  class_attribute :acts_as_authentic_config
12
20
  self.acts_as_authentic_config ||= {}
13
21
  end
@@ -1,10 +1,14 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Authlogic
2
4
  module ControllerAdapters # :nodoc:
3
- # Allows you to use Authlogic in any framework you want, not just rails. See the RailsAdapter
4
- # for an example of how to adapt Authlogic to work with your framework.
5
+ # Allows you to use Authlogic in any framework you want, not just rails. See
6
+ # the RailsAdapter for an example of how to adapt Authlogic to work with
7
+ # your framework.
5
8
  class AbstractAdapter
6
9
  E_COOKIE_DOMAIN_ADAPTER = "The cookie_domain method has not been " \
7
- "implemented by the controller adapter".freeze
10
+ "implemented by the controller adapter"
11
+ ENV_SESSION_OPTIONS = "rack.session.options"
8
12
 
9
13
  attr_accessor :controller
10
14
 
@@ -26,7 +30,7 @@ module Authlogic
26
30
  end
27
31
 
28
32
  def cookie_domain
29
- raise NotImplementedError.new(E_COOKIE_DOMAIN_ADAPTER)
33
+ raise NotImplementedError, E_COOKIE_DOMAIN_ADAPTER
30
34
  end
31
35
 
32
36
  def params
@@ -41,6 +45,26 @@ module Authlogic
41
45
  request.content_type
42
46
  end
43
47
 
48
+ # Inform Rack that we would like a new session ID to be assigned. Changes
49
+ # the ID, but not the contents of the session.
50
+ #
51
+ # The `:renew` option is read by `rack/session/abstract/id.rb`.
52
+ #
53
+ # This is how Devise (via warden) implements defense against Session
54
+ # Fixation. Our implementation is copied directly from the warden gem
55
+ # (set_user in warden/proxy.rb)
56
+ def renew_session_id
57
+ env = request.env
58
+ options = env[ENV_SESSION_OPTIONS]
59
+ if options
60
+ if options.frozen?
61
+ env[ENV_SESSION_OPTIONS] = options.merge(renew: true).freeze
62
+ else
63
+ options[:renew] = true
64
+ end
65
+ end
66
+ end
67
+
44
68
  def session
45
69
  controller.session
46
70
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Authlogic
2
4
  module ControllerAdapters
3
5
  # Adapter for authlogic to make it function as a Rack middleware.
@@ -1,4 +1,4 @@
1
- require "action_controller"
1
+ # frozen_string_literal: true
2
2
 
3
3
  module Authlogic
4
4
  module ControllerAdapters
@@ -7,8 +7,6 @@ module Authlogic
7
7
  # Similar to how ActiveRecord has an adapter for MySQL, PostgreSQL, SQLite,
8
8
  # etc.
9
9
  class RailsAdapter < AbstractAdapter
10
- class AuthlogicLoadedTooLateError < StandardError; end
11
-
12
10
  def authenticate_with_http_basic(&block)
13
11
  controller.authenticate_with_http_basic(&block)
14
12
  end
@@ -16,12 +14,11 @@ module Authlogic
16
14
  # Returns a `ActionDispatch::Cookies::CookieJar`. See the AC guide
17
15
  # http://guides.rubyonrails.org/action_controller_overview.html#cookies
18
16
  def cookies
19
- controller.send(:cookies)
17
+ controller.respond_to?(:cookies, true) ? controller.send(:cookies) : nil
20
18
  end
21
19
 
22
20
  def cookie_domain
23
- @cookie_domain_key ||= Rails::VERSION::STRING >= "2.3" ? :domain : :session_domain
24
- controller.request.session_options[@cookie_domain_key]
21
+ controller.request.session_options[:domain]
25
22
  end
26
23
 
27
24
  def request_content_type
@@ -32,26 +29,7 @@ module Authlogic
32
29
  # "activates" authlogic.
33
30
  module RailsImplementation
34
31
  def self.included(klass) # :nodoc:
35
- if defined?(::ApplicationController)
36
- raise AuthlogicLoadedTooLateError.new(
37
- <<~EOS.squish
38
- Authlogic is trying to add a callback to ActionController::Base
39
- but ApplicationController has already been loaded, so the
40
- callback won't be copied into your application. Generally this
41
- is due to another gem or plugin requiring your
42
- ApplicationController prematurely, such as the
43
- resource_controller plugin. Please require Authlogic first,
44
- before these other gems / plugins.
45
- EOS
46
- )
47
- end
48
-
49
- # In Rails 4.0.2, the *_filter methods were renamed to *_action.
50
- if klass.respond_to? :prepend_before_action
51
- klass.prepend_before_action :activate_authlogic
52
- else
53
- klass.prepend_before_filter :activate_authlogic
54
- end
32
+ klass.prepend_before_action :activate_authlogic
55
33
  end
56
34
 
57
35
  private
@@ -64,7 +42,6 @@ module Authlogic
64
42
  end
65
43
  end
66
44
 
67
- ActionController::Base.send(
68
- :include,
69
- Authlogic::ControllerAdapters::RailsAdapter::RailsImplementation
70
- )
45
+ ActiveSupport.on_load(:action_controller) do
46
+ include Authlogic::ControllerAdapters::RailsAdapter::RailsImplementation
47
+ end
@@ -1,7 +1,10 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # Authlogic bridge for Sinatra
2
4
  module Authlogic
3
5
  module ControllerAdapters
4
6
  module SinatraAdapter
7
+ # Cookie management functions
5
8
  class Cookies
6
9
  attr_reader :request, :response
7
10
 
@@ -23,6 +26,7 @@ module Authlogic
23
26
  end
24
27
  end
25
28
 
29
+ # Thin wrapper around request and response.
26
30
  class Controller
27
31
  attr_reader :request, :response, :cookies
28
32
 
@@ -40,11 +44,13 @@ module Authlogic
40
44
  end
41
45
  end
42
46
 
47
+ # Sinatra controller adapter
43
48
  class Adapter < AbstractAdapter
44
49
  def cookie_domain
45
50
  env["SERVER_NAME"]
46
51
  end
47
52
 
53
+ # Mixed into `Sinatra::Base`
48
54
  module Implementation
49
55
  def self.included(klass)
50
56
  klass.send :before do
@@ -0,0 +1,63 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Authlogic
4
+ # Represents the credentials *in* the cookie. The value of the cookie.
5
+ # This is primarily a data object. It doesn't interact with controllers.
6
+ # It doesn't know about eg. cookie expiration.
7
+ #
8
+ # @api private
9
+ class CookieCredentials
10
+ # @api private
11
+ class ParseError < RuntimeError
12
+ end
13
+
14
+ DELIMITER = "::"
15
+
16
+ attr_reader :persistence_token, :record_id, :remember_me_until
17
+
18
+ # @api private
19
+ # @param persistence_token [String]
20
+ # @param record_id [String, Numeric]
21
+ # @param remember_me_until [ActiveSupport::TimeWithZone]
22
+ def initialize(persistence_token, record_id, remember_me_until)
23
+ @persistence_token = persistence_token
24
+ @record_id = record_id
25
+ @remember_me_until = remember_me_until
26
+ end
27
+
28
+ class << self
29
+ # @api private
30
+ def parse(string)
31
+ parts = string.split(DELIMITER)
32
+ unless (1..3).cover?(parts.length)
33
+ raise ParseError, format("Expected 1..3 parts, got %d", parts.length)
34
+ end
35
+ new(parts[0], parts[1], parse_time(parts[2]))
36
+ end
37
+
38
+ private
39
+
40
+ # @api private
41
+ def parse_time(string)
42
+ return if string.nil?
43
+ ::Time.parse(string)
44
+ rescue ::ArgumentError => e
45
+ raise ParseError, format("Found cookie, cannot parse remember_me_until: #{e}")
46
+ end
47
+ end
48
+
49
+ # @api private
50
+ def remember_me?
51
+ !@remember_me_until.nil?
52
+ end
53
+
54
+ # @api private
55
+ def to_s
56
+ [
57
+ @persistence_token,
58
+ @record_id.to_s,
59
+ @remember_me_until&.iso8601
60
+ ].compact.join(DELIMITER)
61
+ end
62
+ end
63
+ end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "bcrypt"
2
4
 
3
5
  module Authlogic
@@ -64,10 +66,8 @@ module Authlogic
64
66
 
65
67
  def cost=(val)
66
68
  if val < ::BCrypt::Engine::MIN_COST
67
- raise ArgumentError.new(
68
- "Authlogic's bcrypt cost cannot be set below the engine's " \
69
+ raise ArgumentError, "Authlogic's bcrypt cost cannot be set below the engine's " \
69
70
  "min cost (#{::BCrypt::Engine::MIN_COST})"
70
- )
71
71
  end
72
72
  @cost = val
73
73
  end
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "digest/md5"
4
+
5
+ module Authlogic
6
+ module CryptoProviders
7
+ class MD5
8
+ # A poor choice. There are known attacks against this algorithm.
9
+ class V2
10
+ class << self
11
+ attr_accessor :join_token
12
+
13
+ # The number of times to loop through the encryption.
14
+ def stretches
15
+ @stretches ||= 1
16
+ end
17
+ attr_writer :stretches
18
+
19
+ # Turns your raw password into a MD5 hash.
20
+ def encrypt(*tokens)
21
+ digest = tokens.flatten.join(join_token)
22
+ stretches.times { digest = Digest::MD5.digest(digest) }
23
+ digest.unpack1("H*")
24
+ end
25
+
26
+ # Does the crypted password match the tokens? Uses the same tokens that
27
+ # were used to encrypt.
28
+ def matches?(crypted, *tokens)
29
+ encrypt(*tokens) == crypted
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
@@ -1,14 +1,14 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "digest/md5"
2
4
 
3
5
  module Authlogic
4
6
  module CryptoProviders
5
- # This class was made for the users transitioning from md5 based systems.
6
- # I highly discourage using this crypto provider as it superbly inferior
7
- # to your other options.
8
- #
9
- # Please use any other provider offered by Authlogic (except AES256, that
10
- # would be even worse).
7
+ # A poor choice. There are known attacks against this algorithm.
11
8
  class MD5
9
+ # V2 hashes the digest bytes in repeated stretches instead of hex characters.
10
+ autoload :V2, File.join(__dir__, "md5", "v2")
11
+
12
12
  class << self
13
13
  attr_accessor :join_token
14
14
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "scrypt"
2
4
 
3
5
  module Authlogic
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "digest/sha1"
4
+
5
+ module Authlogic
6
+ module CryptoProviders
7
+ class Sha1
8
+ # A poor choice. There are known attacks against this algorithm.
9
+ class V2
10
+ class << self
11
+ def join_token
12
+ @join_token ||= "--"
13
+ end
14
+ attr_writer :join_token
15
+
16
+ # The number of times to loop through the encryption.
17
+ def stretches
18
+ @stretches ||= 10
19
+ end
20
+ attr_writer :stretches
21
+
22
+ # Turns your raw password into a Sha1 hash.
23
+ def encrypt(*tokens)
24
+ tokens = tokens.flatten
25
+ digest = tokens.shift
26
+ stretches.times do
27
+ digest = Digest::SHA1.digest([digest, *tokens].join(join_token))
28
+ end
29
+ digest.unpack1("H*")
30
+ end
31
+
32
+ # Does the crypted password match the tokens? Uses the same tokens that
33
+ # were used to encrypt.
34
+ def matches?(crypted, *tokens)
35
+ encrypt(*tokens) == crypted
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
@@ -1,20 +1,21 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "digest/sha1"
2
4
 
3
5
  module Authlogic
4
6
  module CryptoProviders
5
- # This class was made for the users transitioning from
6
- # restful_authentication. Use of this crypto provider is highly discouraged.
7
- # It is far inferior to your other options. Please use any other provider
8
- # offered by Authlogic.
7
+ # A poor choice. There are known attacks against this algorithm.
9
8
  class Sha1
9
+ # V2 hashes the digest bytes in repeated stretches instead of hex characters.
10
+ autoload :V2, File.join(__dir__, "sha1", "v2")
11
+
10
12
  class << self
11
13
  def join_token
12
14
  @join_token ||= "--"
13
15
  end
14
16
  attr_writer :join_token
15
17
 
16
- # The number of times to loop through the encryption. This is ten
17
- # because that is what restful_authentication defaults to.
18
+ # The number of times to loop through the encryption.
18
19
  def stretches
19
20
  @stretches ||= 10
20
21
  end
@@ -0,0 +1,58 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "digest/sha2"
4
+
5
+ module Authlogic
6
+ # The acts_as_authentic method has a crypto_provider option. This allows you
7
+ # to use any type of encryption you like. Just create a class with a class
8
+ # level encrypt and matches? method. See example below.
9
+ #
10
+ # === Example
11
+ #
12
+ # class MyAwesomeEncryptionMethod
13
+ # def self.encrypt(*tokens)
14
+ # # the tokens passed will be an array of objects, what type of object
15
+ # # is irrelevant, just do what you need to do with them and return a
16
+ # # single encrypted string. for example, you will most likely join all
17
+ # # of the objects into a single string and then encrypt that string
18
+ # end
19
+ #
20
+ # def self.matches?(crypted, *tokens)
21
+ # # return true if the crypted string matches the tokens. Depending on
22
+ # # your algorithm you might decrypt the string then compare it to the
23
+ # # token, or you might encrypt the tokens and make sure it matches the
24
+ # # crypted string, its up to you.
25
+ # end
26
+ # end
27
+ module CryptoProviders
28
+ class Sha256
29
+ # = Sha256
30
+ #
31
+ # Uses the Sha256 hash algorithm to encrypt passwords.
32
+ class V2
33
+ class << self
34
+ attr_accessor :join_token
35
+
36
+ # The number of times to loop through the encryption.
37
+ def stretches
38
+ @stretches ||= 20
39
+ end
40
+ attr_writer :stretches
41
+
42
+ # Turns your raw password into a Sha256 hash.
43
+ def encrypt(*tokens)
44
+ digest = tokens.flatten.join(join_token)
45
+ stretches.times { digest = Digest::SHA256.digest(digest) }
46
+ digest.unpack1("H*")
47
+ end
48
+
49
+ # Does the crypted password match the tokens? Uses the same tokens that
50
+ # were used to encrypt.
51
+ def matches?(crypted, *tokens)
52
+ encrypt(*tokens) == crypted
53
+ end
54
+ end
55
+ end
56
+ end
57
+ end
58
+ end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "digest/sha2"
2
4
 
3
5
  module Authlogic
@@ -27,6 +29,9 @@ module Authlogic
27
29
  #
28
30
  # Uses the Sha256 hash algorithm to encrypt passwords.
29
31
  class Sha256
32
+ # V2 hashes the digest bytes in repeated stretches instead of hex characters.
33
+ autoload :V2, File.join(__dir__, "sha256", "v2")
34
+
30
35
  class << self
31
36
  attr_accessor :join_token
32
37