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,18 +1,24 @@
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
9
+ E_COOKIE_DOMAIN_ADAPTER = "The cookie_domain method has not been " \
10
+ "implemented by the controller adapter"
11
+
6
12
  attr_accessor :controller
7
13
 
8
14
  def initialize(controller)
9
15
  self.controller = controller
10
16
  end
11
17
 
12
- def authenticate_with_http_basic(&block)
18
+ def authenticate_with_http_basic
13
19
  @auth = Rack::Auth::Basic::Request.new(controller.request.env)
14
- if @auth.provided? and @auth.basic?
15
- block.call(*@auth.credentials)
20
+ if @auth.provided? && @auth.basic?
21
+ yield(*@auth.credentials)
16
22
  else
17
23
  false
18
24
  end
@@ -23,7 +29,7 @@ module Authlogic
23
29
  end
24
30
 
25
31
  def cookie_domain
26
- raise NotImplementedError.new("The cookie_domain method has not been implemented by the controller adapter")
32
+ raise NotImplementedError, E_COOKIE_DOMAIN_ADAPTER
27
33
  end
28
34
 
29
35
  def params
@@ -50,19 +56,43 @@ module Authlogic
50
56
  controller.send(:single_access_allowed?)
51
57
  end
52
58
 
53
- def responds_to_last_request_update_allowed?
54
- controller.respond_to?(:last_request_update_allowed?, true)
59
+ # You can disable the updating of `last_request_at`
60
+ # on a per-controller basis.
61
+ #
62
+ # # in your controller
63
+ # def last_request_update_allowed?
64
+ # false
65
+ # end
66
+ #
67
+ # For example, what if you had a javascript function that polled the
68
+ # server updating how much time is left in their session before it
69
+ # times out. Obviously you would want to ignore this request, because
70
+ # then the user would never time out. So you can do something like
71
+ # this in your controller:
72
+ #
73
+ # def last_request_update_allowed?
74
+ # action_name != "update_session_time_left"
75
+ # end
76
+ #
77
+ # See `authlogic/session/magic_columns.rb` to learn more about the
78
+ # `last_request_at` column itself.
79
+ def last_request_update_allowed?
80
+ if controller.respond_to?(:last_request_update_allowed?, true)
81
+ controller.send(:last_request_update_allowed?)
82
+ else
83
+ true
84
+ end
55
85
  end
56
86
 
57
- def last_request_update_allowed?
58
- controller.send(:last_request_update_allowed?)
87
+ def respond_to_missing?(*args)
88
+ super(*args) || controller.respond_to?(*args)
59
89
  end
60
90
 
61
91
  private
62
92
 
63
- def method_missing(id, *args, &block)
64
- controller.send(id, *args, &block)
65
- end
93
+ def method_missing(id, *args, &block)
94
+ controller.send(id, *args, &block)
95
+ end
66
96
  end
67
97
  end
68
98
  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.
@@ -32,7 +34,7 @@ module Authlogic
32
34
  # # Authlogic options go here
33
35
  # end
34
36
  #
35
- # class User < ActiveRecord::Base
37
+ # class User < ApplicationRecord
36
38
  # acts_as_authentic
37
39
  # end
38
40
  #
@@ -48,7 +50,7 @@ module Authlogic
48
50
  end
49
51
 
50
52
  def remote_ip
51
- self.ip
53
+ ip
52
54
  end
53
55
  end
54
56
 
@@ -56,10 +58,14 @@ module Authlogic
56
58
  Authlogic::Session::Base.controller = self
57
59
  end
58
60
 
59
- # Rack Requests stores cookies with not just the value, but also with flags and expire information in the hash.
60
- # Authlogic does not like this, so we drop everything except the cookie value
61
+ # Rack Requests stores cookies with not just the value, but also with
62
+ # flags and expire information in the hash. Authlogic does not like this,
63
+ # so we drop everything except the cookie value.
61
64
  def cookies
62
- controller.cookies.map { |key, value_hash| { key => value_hash[:value] } }.inject(:merge) || {}
65
+ controller
66
+ .cookies
67
+ .map { |key, value_hash| { key => value_hash[:value] } }
68
+ .inject(:merge) || {}
63
69
  end
64
70
  end
65
71
  end
@@ -1,4 +1,4 @@
1
- require 'action_controller'
1
+ # frozen_string_literal: true
2
2
 
3
3
  module Authlogic
4
4
  module ControllerAdapters
@@ -7,19 +7,18 @@ 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
15
13
 
14
+ # Returns a `ActionDispatch::Cookies::CookieJar`. See the AC guide
15
+ # http://guides.rubyonrails.org/action_controller_overview.html#cookies
16
16
  def cookies
17
17
  controller.send(:cookies)
18
18
  end
19
19
 
20
20
  def cookie_domain
21
- @cookie_domain_key ||= Rails::VERSION::STRING >= '2.3' ? :domain : :session_domain
22
- controller.request.session_options[@cookie_domain_key]
21
+ controller.request.session_options[:domain]
23
22
  end
24
23
 
25
24
  def request_content_type
@@ -30,36 +29,19 @@ module Authlogic
30
29
  # "activates" authlogic.
31
30
  module RailsImplementation
32
31
  def self.included(klass) # :nodoc:
33
- if defined?(::ApplicationController)
34
- raise AuthlogicLoadedTooLateError.new(
35
- <<-EOS.strip_heredoc
36
- Authlogic is trying to add a callback to ActionController::Base
37
- but ApplicationController has already been loaded, so the
38
- callback won't be copied into your application. Generally this
39
- is due to another gem or plugin requiring your
40
- ApplicationController prematurely, such as the
41
- resource_controller plugin. Please require Authlogic first,
42
- before these other gems / plugins.
43
- EOS
44
- )
45
- end
46
-
47
- # In Rails 4.0.2, the *_filter methods were renamed to *_action.
48
- if klass.respond_to? :prepend_before_action
49
- klass.prepend_before_action :activate_authlogic
50
- else
51
- klass.prepend_before_filter :activate_authlogic
52
- end
32
+ klass.prepend_before_action :activate_authlogic
53
33
  end
54
34
 
55
35
  private
56
36
 
57
- def activate_authlogic
58
- Authlogic::Session::Base.controller = RailsAdapter.new(self)
59
- end
37
+ def activate_authlogic
38
+ Authlogic::Session::Base.controller = RailsAdapter.new(self)
39
+ end
60
40
  end
61
41
  end
62
42
  end
63
43
  end
64
44
 
65
- ActionController::Base.send(:include, Authlogic::ControllerAdapters::RailsAdapter::RailsImplementation)
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
 
@@ -32,7 +36,7 @@ module Authlogic
32
36
  end
33
37
 
34
38
  def session
35
- env['rack.session']
39
+ env["rack.session"]
36
40
  end
37
41
 
38
42
  def method_missing(meth, *args, &block)
@@ -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
- env['SERVER_NAME']
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
@@ -16,10 +18,18 @@ module Authlogic
16
18
  # require "benchmark"
17
19
  #
18
20
  # Benchmark.bm(18) do |x|
19
- # x.report("BCrypt (cost = 10:") { 100.times { BCrypt::Password.create("mypass", :cost => 10) } }
20
- # x.report("BCrypt (cost = 4:") { 100.times { BCrypt::Password.create("mypass", :cost => 4) } }
21
- # x.report("Sha512:") { 100.times { Digest::SHA512.hexdigest("mypass") } }
22
- # x.report("Sha1:") { 100.times { Digest::SHA1.hexdigest("mypass") } }
21
+ # x.report("BCrypt (cost = 10:") {
22
+ # 100.times { BCrypt::Password.create("mypass", :cost => 10) }
23
+ # }
24
+ # x.report("BCrypt (cost = 4:") {
25
+ # 100.times { BCrypt::Password.create("mypass", :cost => 4) }
26
+ # }
27
+ # x.report("Sha512:") {
28
+ # 100.times { Digest::SHA512.hexdigest("mypass") }
29
+ # }
30
+ # x.report("Sha1:") {
31
+ # 100.times { Digest::SHA1.hexdigest("mypass") }
32
+ # }
23
33
  # end
24
34
  #
25
35
  # user system total real
@@ -56,17 +66,15 @@ module Authlogic
56
66
 
57
67
  def cost=(val)
58
68
  if val < ::BCrypt::Engine::MIN_COST
59
- raise ArgumentError.new(
60
- "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 " \
61
70
  "min cost (#{::BCrypt::Engine::MIN_COST})"
62
- )
63
71
  end
64
72
  @cost = val
65
73
  end
66
74
 
67
75
  # Creates a BCrypt hash for the password passed.
68
76
  def encrypt(*tokens)
69
- ::BCrypt::Password.create(join_tokens(tokens), :cost => cost)
77
+ ::BCrypt::Password.create(join_tokens(tokens), cost: cost)
70
78
  end
71
79
 
72
80
  # Does the hash match the tokens? Uses the same tokens that were used to
@@ -90,17 +98,15 @@ module Authlogic
90
98
 
91
99
  private
92
100
 
93
- def join_tokens(tokens)
94
- tokens.flatten.join
95
- end
101
+ def join_tokens(tokens)
102
+ tokens.flatten.join
103
+ end
96
104
 
97
- def new_from_hash(hash)
98
- begin
99
- ::BCrypt::Password.new(hash)
100
- rescue ::BCrypt::Errors::InvalidHash
101
- return nil
102
- end
103
- end
105
+ def new_from_hash(hash)
106
+ ::BCrypt::Password.new(hash)
107
+ rescue ::BCrypt::Errors::InvalidHash
108
+ nil
109
+ end
104
110
  end
105
111
  end
106
112
  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.unpack("H*")[0]
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,13 +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.
7
+ # A poor choice. There are known attacks against this algorithm.
10
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
+
11
12
  class << self
12
13
  attr_accessor :join_token
13
14
 
@@ -24,7 +25,8 @@ module Authlogic
24
25
  digest
25
26
  end
26
27
 
27
- # Does the crypted password match the tokens? Uses the same tokens that were used to encrypt.
28
+ # Does the crypted password match the tokens? Uses the same tokens that
29
+ # were used to encrypt.
28
30
  def matches?(crypted, *tokens)
29
31
  encrypt(*tokens) == crypted
30
32
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "scrypt"
2
4
 
3
5
  module Authlogic
@@ -19,7 +21,13 @@ module Authlogic
19
21
  # end
20
22
  class SCrypt
21
23
  class << self
22
- DEFAULTS = { :key_len => 32, :salt_size => 8, :max_time => 0.2, :max_mem => 1024 * 1024, :max_memfrac => 0.5 }
24
+ DEFAULTS = {
25
+ key_len: 32,
26
+ salt_size: 8,
27
+ max_time: 0.2,
28
+ max_mem: 1024 * 1024,
29
+ max_memfrac: 0.5
30
+ }.freeze
23
31
 
24
32
  attr_writer :key_len, :salt_size, :max_time, :max_mem, :max_memfrac
25
33
  # Key length - length in bytes of generated key, from 16 to 512.
@@ -42,7 +50,8 @@ module Authlogic
42
50
  @max_mem ||= DEFAULTS[:max_mem]
43
51
  end
44
52
 
45
- # Max memory fraction - maximum memory out of all available. Always greater than zero and <= 0.5.
53
+ # Max memory fraction - maximum memory out of all available. Always
54
+ # greater than zero and <= 0.5.
46
55
  def max_memfrac
47
56
  @max_memfrac ||= DEFAULTS[:max_memfrac]
48
57
  end
@@ -51,11 +60,11 @@ module Authlogic
51
60
  def encrypt(*tokens)
52
61
  ::SCrypt::Password.create(
53
62
  join_tokens(tokens),
54
- :key_len => key_len,
55
- :salt_size => salt_size,
56
- :max_mem => max_mem,
57
- :max_memfrac => max_memfrac,
58
- :max_time => max_time
63
+ key_len: key_len,
64
+ salt_size: salt_size,
65
+ max_mem: max_mem,
66
+ max_memfrac: max_memfrac,
67
+ max_time: max_time
59
68
  )
60
69
  end
61
70
 
@@ -68,17 +77,15 @@ module Authlogic
68
77
 
69
78
  private
70
79
 
71
- def join_tokens(tokens)
72
- tokens.flatten.join
73
- end
80
+ def join_tokens(tokens)
81
+ tokens.flatten.join
82
+ end
74
83
 
75
- def new_from_hash(hash)
76
- begin
77
- ::SCrypt::Password.new(hash)
78
- rescue ::SCrypt::Errors::InvalidHash
79
- return nil
80
- end
81
- end
84
+ def new_from_hash(hash)
85
+ ::SCrypt::Password.new(hash)
86
+ rescue ::SCrypt::Errors::InvalidHash
87
+ nil
88
+ end
82
89
  end
83
90
  end
84
91
  end
@@ -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.unpack("H*")[0]
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,17 +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 restful_authentication. I highly discourage using this
6
- # crypto provider as it is far inferior to your other options. Please use any other provider offered by Authlogic.
7
+ # A poor choice. There are known attacks against this algorithm.
7
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
+
8
12
  class << self
9
13
  def join_token
10
14
  @join_token ||= "--"
11
15
  end
12
16
  attr_writer :join_token
13
17
 
14
- # The number of times to loop through the encryption. This is ten because that is what restful_authentication defaults to.
18
+ # The number of times to loop through the encryption.
15
19
  def stretches
16
20
  @stretches ||= 10
17
21
  end
@@ -21,11 +25,14 @@ module Authlogic
21
25
  def encrypt(*tokens)
22
26
  tokens = tokens.flatten
23
27
  digest = tokens.shift
24
- stretches.times { digest = Digest::SHA1.hexdigest([digest, *tokens].join(join_token)) }
28
+ stretches.times do
29
+ digest = Digest::SHA1.hexdigest([digest, *tokens].join(join_token))
30
+ end
25
31
  digest
26
32
  end
27
33
 
28
- # Does the crypted password match the tokens? Uses the same tokens that were used to encrypt.
34
+ # Does the crypted password match the tokens? Uses the same tokens that
35
+ # were used to encrypt.
29
36
  def matches?(crypted, *tokens)
30
37
  encrypt(*tokens) == crypted
31
38
  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.unpack("H*")[0]
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