authlogic-nicho 6.5

Sign up to get free protection for your applications and to get access to all the features.
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