authlogic-nicho 6.5

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 (46) hide show
  1. checksums.yaml +7 -0
  2. data/lib/authlogic/acts_as_authentic/base.rb +116 -0
  3. data/lib/authlogic/acts_as_authentic/email.rb +30 -0
  4. data/lib/authlogic/acts_as_authentic/logged_in_status.rb +85 -0
  5. data/lib/authlogic/acts_as_authentic/login.rb +63 -0
  6. data/lib/authlogic/acts_as_authentic/magic_columns.rb +38 -0
  7. data/lib/authlogic/acts_as_authentic/password.rb +357 -0
  8. data/lib/authlogic/acts_as_authentic/perishable_token.rb +122 -0
  9. data/lib/authlogic/acts_as_authentic/persistence_token.rb +70 -0
  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 +186 -0
  13. data/lib/authlogic/acts_as_authentic/single_access_token.rb +83 -0
  14. data/lib/authlogic/config.rb +43 -0
  15. data/lib/authlogic/controller_adapters/abstract_adapter.rb +119 -0
  16. data/lib/authlogic/controller_adapters/rack_adapter.rb +72 -0
  17. data/lib/authlogic/controller_adapters/rails_adapter.rb +47 -0
  18. data/lib/authlogic/controller_adapters/sinatra_adapter.rb +67 -0
  19. data/lib/authlogic/cookie_credentials.rb +63 -0
  20. data/lib/authlogic/crypto_providers/bcrypt.rb +113 -0
  21. data/lib/authlogic/crypto_providers/md5/v2.rb +35 -0
  22. data/lib/authlogic/crypto_providers/md5.rb +36 -0
  23. data/lib/authlogic/crypto_providers/scrypt.rb +92 -0
  24. data/lib/authlogic/crypto_providers/sha1/v2.rb +41 -0
  25. data/lib/authlogic/crypto_providers/sha1.rb +42 -0
  26. data/lib/authlogic/crypto_providers/sha256/v2.rb +58 -0
  27. data/lib/authlogic/crypto_providers/sha256.rb +59 -0
  28. data/lib/authlogic/crypto_providers/sha512/v2.rb +39 -0
  29. data/lib/authlogic/crypto_providers/sha512.rb +38 -0
  30. data/lib/authlogic/crypto_providers.rb +87 -0
  31. data/lib/authlogic/errors.rb +50 -0
  32. data/lib/authlogic/i18n/translator.rb +18 -0
  33. data/lib/authlogic/i18n.rb +100 -0
  34. data/lib/authlogic/random.rb +18 -0
  35. data/lib/authlogic/session/base.rb +2207 -0
  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 +58 -0
  39. data/lib/authlogic/test_case/mock_cookie_jar.rb +109 -0
  40. data/lib/authlogic/test_case/mock_logger.rb +12 -0
  41. data/lib/authlogic/test_case/mock_request.rb +35 -0
  42. data/lib/authlogic/test_case/rails_request_adapter.rb +39 -0
  43. data/lib/authlogic/test_case.rb +215 -0
  44. data/lib/authlogic/version.rb +22 -0
  45. data/lib/authlogic.rb +44 -0
  46. metadata +382 -0
@@ -0,0 +1,113 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "bcrypt"
4
+
5
+ module Authlogic
6
+ module CryptoProviders
7
+ # The family of adaptive hash functions (BCrypt, SCrypt, PBKDF2)
8
+ # is the best choice for password storage today. They have the
9
+ # three properties of password hashing that are desirable. They
10
+ # are one-way, unique, and slow. While a salted SHA or MD5 hash is
11
+ # one-way and unique, preventing rainbow table attacks, they are
12
+ # still lightning fast and attacks on the stored passwords are
13
+ # much more effective. This benchmark demonstrates the effective
14
+ # slowdown that BCrypt provides:
15
+ #
16
+ # require "bcrypt"
17
+ # require "digest"
18
+ # require "benchmark"
19
+ #
20
+ # Benchmark.bm(18) do |x|
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
+ # }
33
+ # end
34
+ #
35
+ # user system total real
36
+ # BCrypt (cost = 10): 37.360000 0.020000 37.380000 ( 37.558943)
37
+ # BCrypt (cost = 4): 0.680000 0.000000 0.680000 ( 0.677460)
38
+ # Sha512: 0.000000 0.000000 0.000000 ( 0.000672)
39
+ # Sha1: 0.000000 0.000000 0.000000 ( 0.000454)
40
+ #
41
+ # You can play around with the cost to get that perfect balance
42
+ # between performance and security. A default cost of 10 is the
43
+ # best place to start.
44
+ #
45
+ # Decided BCrypt is for you? Just install the bcrypt gem:
46
+ #
47
+ # gem install bcrypt
48
+ #
49
+ # Tell acts_as_authentic to use it:
50
+ #
51
+ # acts_as_authentic do |c|
52
+ # c.crypto_provider = Authlogic::CryptoProviders::BCrypt
53
+ # end
54
+ #
55
+ # You are good to go!
56
+ class BCrypt
57
+ class << self
58
+ # This is the :cost option for the BCrpyt library. The higher the cost
59
+ # the more secure it is and the longer is take the generate a hash. By
60
+ # default this is 10. Set this to any value >= the engine's minimum
61
+ # (currently 4), play around with it to get that perfect balance between
62
+ # security and performance.
63
+ def cost
64
+ @cost ||= 10
65
+ end
66
+
67
+ def cost=(val)
68
+ if val < ::BCrypt::Engine::MIN_COST
69
+ raise ArgumentError, "Authlogic's bcrypt cost cannot be set below the engine's " \
70
+ "min cost (#{::BCrypt::Engine::MIN_COST})"
71
+ end
72
+ @cost = val
73
+ end
74
+
75
+ # Creates a BCrypt hash for the password passed.
76
+ def encrypt(*tokens)
77
+ ::BCrypt::Password.create(join_tokens(tokens), cost: cost)
78
+ end
79
+
80
+ # Does the hash match the tokens? Uses the same tokens that were used to
81
+ # encrypt.
82
+ def matches?(hash, *tokens)
83
+ hash = new_from_hash(hash)
84
+ return false if hash.blank?
85
+ hash == join_tokens(tokens)
86
+ end
87
+
88
+ # This method is used as a flag to tell Authlogic to "resave" the
89
+ # password upon a successful login, using the new cost
90
+ def cost_matches?(hash)
91
+ hash = new_from_hash(hash)
92
+ if hash.blank?
93
+ false
94
+ else
95
+ hash.cost == cost
96
+ end
97
+ end
98
+
99
+ private
100
+
101
+ def join_tokens(tokens)
102
+ tokens.flatten.join
103
+ end
104
+
105
+ def new_from_hash(hash)
106
+ ::BCrypt::Password.new(hash)
107
+ rescue ::BCrypt::Errors::InvalidHash
108
+ nil
109
+ end
110
+ end
111
+ end
112
+ end
113
+ 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
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "digest/md5"
4
+
5
+ module Authlogic
6
+ module CryptoProviders
7
+ # A poor choice. There are known attacks against this algorithm.
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
+ class << self
13
+ attr_accessor :join_token
14
+
15
+ # The number of times to loop through the encryption.
16
+ def stretches
17
+ @stretches ||= 1
18
+ end
19
+ attr_writer :stretches
20
+
21
+ # Turns your raw password into a MD5 hash.
22
+ def encrypt(*tokens)
23
+ digest = tokens.flatten.join(join_token)
24
+ stretches.times { digest = Digest::MD5.hexdigest(digest) }
25
+ digest
26
+ end
27
+
28
+ # Does the crypted password match the tokens? Uses the same tokens that
29
+ # were used to encrypt.
30
+ def matches?(crypted, *tokens)
31
+ encrypt(*tokens) == crypted
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,92 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "scrypt"
4
+
5
+ module Authlogic
6
+ module CryptoProviders
7
+ # SCrypt is the default provider for Authlogic. It is the only
8
+ # choice in the adaptive hash family that accounts for hardware
9
+ # based attacks by compensating with memory bound as well as cpu
10
+ # bound computational constraints. It offers the same guarantees
11
+ # as BCrypt in the way of one-way, unique and slow.
12
+ #
13
+ # Decided SCrypt is for you? Just install the scrypt gem:
14
+ #
15
+ # gem install scrypt
16
+ #
17
+ # Tell acts_as_authentic to use it:
18
+ #
19
+ # acts_as_authentic do |c|
20
+ # c.crypto_provider = Authlogic::CryptoProviders::SCrypt
21
+ # end
22
+ class SCrypt
23
+ class << self
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
31
+
32
+ attr_writer :key_len, :salt_size, :max_time, :max_mem, :max_memfrac
33
+ # Key length - length in bytes of generated key, from 16 to 512.
34
+ def key_len
35
+ @key_len ||= DEFAULTS[:key_len]
36
+ end
37
+
38
+ # Salt size - size in bytes of random salt, from 8 to 32
39
+ def salt_size
40
+ @salt_size ||= DEFAULTS[:salt_size]
41
+ end
42
+
43
+ # Max time - maximum time spent in computation
44
+ def max_time
45
+ @max_time ||= DEFAULTS[:max_time]
46
+ end
47
+
48
+ # Max memory - maximum memory usage. The minimum is always 1MB
49
+ def max_mem
50
+ @max_mem ||= DEFAULTS[:max_mem]
51
+ end
52
+
53
+ # Max memory fraction - maximum memory out of all available. Always
54
+ # greater than zero and <= 0.5.
55
+ def max_memfrac
56
+ @max_memfrac ||= DEFAULTS[:max_memfrac]
57
+ end
58
+
59
+ # Creates an SCrypt hash for the password passed.
60
+ def encrypt(*tokens)
61
+ ::SCrypt::Password.create(
62
+ join_tokens(tokens),
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
68
+ )
69
+ end
70
+
71
+ # Does the hash match the tokens? Uses the same tokens that were used to encrypt.
72
+ def matches?(hash, *tokens)
73
+ hash = new_from_hash(hash)
74
+ return false if hash.blank?
75
+ hash == join_tokens(tokens)
76
+ end
77
+
78
+ private
79
+
80
+ def join_tokens(tokens)
81
+ tokens.flatten.join
82
+ end
83
+
84
+ def new_from_hash(hash)
85
+ ::SCrypt::Password.new(hash)
86
+ rescue ::SCrypt::Errors::InvalidHash
87
+ nil
88
+ end
89
+ end
90
+ end
91
+ end
92
+ 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.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
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "digest/sha1"
4
+
5
+ module Authlogic
6
+ module CryptoProviders
7
+ # A poor choice. There are known attacks against this algorithm.
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
+
12
+ class << self
13
+ def join_token
14
+ @join_token ||= "--"
15
+ end
16
+ attr_writer :join_token
17
+
18
+ # The number of times to loop through the encryption.
19
+ def stretches
20
+ @stretches ||= 10
21
+ end
22
+ attr_writer :stretches
23
+
24
+ # Turns your raw password into a Sha1 hash.
25
+ def encrypt(*tokens)
26
+ tokens = tokens.flatten
27
+ digest = tokens.shift
28
+ stretches.times do
29
+ digest = Digest::SHA1.hexdigest([digest, *tokens].join(join_token))
30
+ end
31
+ digest
32
+ end
33
+
34
+ # Does the crypted password match the tokens? Uses the same tokens that
35
+ # were used to encrypt.
36
+ def matches?(crypted, *tokens)
37
+ encrypt(*tokens) == crypted
38
+ end
39
+ end
40
+ end
41
+ end
42
+ 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
@@ -0,0 +1,59 @@
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
+ # = Sha256
29
+ #
30
+ # Uses the Sha256 hash algorithm to encrypt passwords.
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
+
35
+ class << self
36
+ attr_accessor :join_token
37
+
38
+ # The number of times to loop through the encryption.
39
+ def stretches
40
+ @stretches ||= 20
41
+ end
42
+ attr_writer :stretches
43
+
44
+ # Turns your raw password into a Sha256 hash.
45
+ def encrypt(*tokens)
46
+ digest = tokens.flatten.join(join_token)
47
+ stretches.times { digest = Digest::SHA256.hexdigest(digest) }
48
+ digest
49
+ end
50
+
51
+ # Does the crypted password match the tokens? Uses the same tokens that
52
+ # were used to encrypt.
53
+ def matches?(crypted, *tokens)
54
+ encrypt(*tokens) == crypted
55
+ end
56
+ end
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "digest/sha2"
4
+
5
+ module Authlogic
6
+ module CryptoProviders
7
+ class Sha512
8
+ # SHA-512 does not have any practical known attacks against it. However,
9
+ # there are better choices. We recommend transitioning to a more secure,
10
+ # adaptive hashing algorithm, like scrypt.
11
+ class V2
12
+ class << self
13
+ attr_accessor :join_token
14
+
15
+ # The number of times to loop through the encryption.
16
+ def stretches
17
+ @stretches ||= 20
18
+ end
19
+ attr_writer :stretches
20
+
21
+ # Turns your raw password into a Sha512 hash.
22
+ def encrypt(*tokens)
23
+ digest = tokens.flatten.join(join_token)
24
+ stretches.times do
25
+ digest = Digest::SHA512.digest(digest)
26
+ end
27
+ digest.unpack1("H*")
28
+ end
29
+
30
+ # Does the crypted password match the tokens? Uses the same tokens that
31
+ # were used to encrypt.
32
+ def matches?(crypted, *tokens)
33
+ encrypt(*tokens) == crypted
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "digest/sha2"
4
+
5
+ module Authlogic
6
+ module CryptoProviders
7
+ # SHA-512 does not have any practical known attacks against it. However,
8
+ # there are better choices. We recommend transitioning to a more secure,
9
+ # adaptive hashing algorithm, like scrypt.
10
+ class Sha512
11
+ # V2 hashes the digest bytes in repeated stretches instead of hex characters.
12
+ autoload :V2, File.join(__dir__, "sha512", "v2")
13
+
14
+ class << self
15
+ attr_accessor :join_token
16
+
17
+ # The number of times to loop through the encryption.
18
+ def stretches
19
+ @stretches ||= 20
20
+ end
21
+ attr_writer :stretches
22
+
23
+ # Turns your raw password into a Sha512 hash.
24
+ def encrypt(*tokens)
25
+ digest = tokens.flatten.join(join_token)
26
+ stretches.times { digest = Digest::SHA512.hexdigest(digest) }
27
+ digest
28
+ end
29
+
30
+ # Does the crypted password match the tokens? Uses the same tokens that
31
+ # were used to encrypt.
32
+ def matches?(crypted, *tokens)
33
+ encrypt(*tokens) == crypted
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,87 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Authlogic
4
+ # The acts_as_authentic method has a crypto_provider option. This allows you
5
+ # to use any type of encryption you like. Just create a class with a class
6
+ # level encrypt and matches? method. See example below.
7
+ #
8
+ # === Example
9
+ #
10
+ # class MyAwesomeEncryptionMethod
11
+ # def self.encrypt(*tokens)
12
+ # # The tokens passed will be an array of objects, what type of object
13
+ # # is irrelevant, just do what you need to do with them and return a
14
+ # # single encrypted string. For example, you will most likely join all
15
+ # # of the objects into a single string and then encrypt that string.
16
+ # end
17
+ #
18
+ # def self.matches?(crypted, *tokens)
19
+ # # Return true if the crypted string matches the tokens. Depending on
20
+ # # your algorithm you might decrypt the string then compare it to the
21
+ # # token, or you might encrypt the tokens and make sure it matches the
22
+ # # crypted string, its up to you.
23
+ # end
24
+ # end
25
+ module CryptoProviders
26
+ autoload :MD5, "authlogic/crypto_providers/md5"
27
+ autoload :Sha1, "authlogic/crypto_providers/sha1"
28
+ autoload :Sha256, "authlogic/crypto_providers/sha256"
29
+ autoload :Sha512, "authlogic/crypto_providers/sha512"
30
+ autoload :BCrypt, "authlogic/crypto_providers/bcrypt"
31
+ autoload :SCrypt, "authlogic/crypto_providers/scrypt"
32
+
33
+ # Guide users to choose a better crypto provider.
34
+ class Guidance
35
+ BUILTIN_PROVIDER_PREFIX = "Authlogic::CryptoProviders::"
36
+ NONADAPTIVE_ALGORITHM = <<~EOS
37
+ You have selected %s as your authlogic crypto provider. This algorithm
38
+ does not have any practical known attacks against it. However, there are
39
+ better choices.
40
+
41
+ Authlogic has no plans yet to deprecate this crypto provider. However,
42
+ we recommend transitioning to a more secure, adaptive hashing algorithm,
43
+ like scrypt. Adaptive algorithms are designed to slow down brute force
44
+ attacks, and over time the iteration count can be increased to make it
45
+ slower, so it remains resistant to brute-force search attacks even in
46
+ the face of increasing computation power.
47
+
48
+ Use the transition_from_crypto_providers option to make the transition
49
+ painless for your users.
50
+ EOS
51
+ VULNERABLE_ALGORITHM = <<~EOS
52
+ You have selected %s as your authlogic crypto provider. It is a poor
53
+ choice because there are known attacks against this algorithm.
54
+
55
+ Authlogic has no plans yet to deprecate this crypto provider. However,
56
+ we recommend transitioning to a secure hashing algorithm. We recommend
57
+ an adaptive algorithm, like scrypt.
58
+
59
+ Use the transition_from_crypto_providers option to make the transition
60
+ painless for your users.
61
+ EOS
62
+
63
+ def initialize(provider)
64
+ @provider = provider
65
+ end
66
+
67
+ def impart_wisdom
68
+ return unless @provider.is_a?(Class)
69
+
70
+ # We can only impart wisdom about our own built-in providers.
71
+ absolute_name = @provider.name
72
+ return unless absolute_name.start_with?(BUILTIN_PROVIDER_PREFIX)
73
+
74
+ # Inspect the string name of the provider, rather than using the
75
+ # constants in our `when` clauses. If we used the constants, we'd
76
+ # negate the benefits of the `autoload` above.
77
+ name = absolute_name.demodulize
78
+ case name
79
+ when "MD5", "Sha1"
80
+ warn(format(VULNERABLE_ALGORITHM, name))
81
+ when "Sha256", "Sha512"
82
+ warn(format(NONADAPTIVE_ALGORITHM, name))
83
+ end
84
+ end
85
+ end
86
+ end
87
+ end
@@ -0,0 +1,50 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Authlogic
4
+ # Parent class of all Authlogic errors.
5
+ class Error < StandardError
6
+ end
7
+
8
+ # :nodoc:
9
+ class InvalidCryptoProvider < Error
10
+ end
11
+
12
+ # :nodoc:
13
+ class NilCryptoProvider < InvalidCryptoProvider
14
+ def message
15
+ <<~EOS
16
+ In version 5, Authlogic used SCrypt by default. As of version 6, there
17
+ is no default. We still recommend SCrypt. If you previously relied on
18
+ this default, then, in your User model (or equivalent), please set the
19
+ following:
20
+
21
+ acts_as_authentic do |c|
22
+ c.crypto_provider = ::Authlogic::CryptoProviders::SCrypt
23
+ end
24
+
25
+ Furthermore, the authlogic gem no longer depends on the scrypt gem. In
26
+ your Gemfile, please add scrypt.
27
+
28
+ gem "scrypt", "~> 3.0"
29
+
30
+ We have made this change in Authlogic 6 so that users of other crypto
31
+ providers no longer need to install the scrypt gem.
32
+ EOS
33
+ end
34
+ end
35
+
36
+ # :nodoc:
37
+ class ModelSetupError < Error
38
+ def message
39
+ <<-EOS
40
+ You must establish a database connection and run the migrations before
41
+ using acts_as_authentic. If you need to load the User model before the
42
+ database is set up correctly, please set the following:
43
+
44
+ acts_as_authentic do |c|
45
+ c.raise_on_model_setup_error = false
46
+ end
47
+ EOS
48
+ end
49
+ end
50
+ end