authlogic 3.4.6 → 4.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +5 -5
- data/.github/ISSUE_TEMPLATE.md +13 -0
- data/.github/triage.md +87 -0
- data/.gitignore +4 -0
- data/.rubocop.yml +127 -0
- data/.rubocop_todo.yml +65 -0
- data/.travis.yml +18 -10
- data/CHANGELOG.md +156 -6
- data/CONTRIBUTING.md +71 -3
- data/Gemfile +2 -2
- data/README.md +386 -0
- data/Rakefile +13 -7
- data/UPGRADING.md +22 -0
- data/authlogic.gemspec +33 -22
- data/lib/authlogic.rb +60 -52
- data/lib/authlogic/acts_as_authentic/base.rb +40 -26
- data/lib/authlogic/acts_as_authentic/email.rb +96 -32
- data/lib/authlogic/acts_as_authentic/logged_in_status.rb +36 -12
- data/lib/authlogic/acts_as_authentic/login.rb +114 -49
- data/lib/authlogic/acts_as_authentic/magic_columns.rb +17 -6
- data/lib/authlogic/acts_as_authentic/password.rb +296 -139
- data/lib/authlogic/acts_as_authentic/perishable_token.rb +34 -20
- data/lib/authlogic/acts_as_authentic/persistence_token.rb +20 -24
- data/lib/authlogic/acts_as_authentic/queries/find_with_case.rb +67 -0
- data/lib/authlogic/acts_as_authentic/restful_authentication.rb +68 -23
- data/lib/authlogic/acts_as_authentic/session_maintenance.rb +128 -85
- data/lib/authlogic/acts_as_authentic/single_access_token.rb +41 -25
- data/lib/authlogic/acts_as_authentic/validations_scope.rb +8 -8
- data/lib/authlogic/authenticates_many/association.rb +22 -14
- data/lib/authlogic/authenticates_many/base.rb +35 -16
- data/lib/authlogic/config.rb +10 -10
- data/lib/authlogic/controller_adapters/abstract_adapter.rb +40 -12
- data/lib/authlogic/controller_adapters/rack_adapter.rb +15 -8
- data/lib/authlogic/controller_adapters/rails_adapter.rb +42 -22
- data/lib/authlogic/controller_adapters/sinatra_adapter.rb +3 -3
- data/lib/authlogic/crypto_providers.rb +91 -0
- data/lib/authlogic/crypto_providers/aes256.rb +42 -14
- data/lib/authlogic/crypto_providers/bcrypt.rb +35 -20
- data/lib/authlogic/crypto_providers/md5.rb +11 -9
- data/lib/authlogic/crypto_providers/scrypt.rb +26 -13
- data/lib/authlogic/crypto_providers/sha1.rb +14 -8
- data/lib/authlogic/crypto_providers/sha256.rb +16 -12
- data/lib/authlogic/crypto_providers/sha512.rb +8 -24
- data/lib/authlogic/crypto_providers/wordpress.rb +44 -15
- data/lib/authlogic/i18n.rb +33 -20
- data/lib/authlogic/i18n/translator.rb +1 -1
- data/lib/authlogic/random.rb +12 -29
- data/lib/authlogic/regex.rb +59 -27
- data/lib/authlogic/session/activation.rb +36 -23
- data/lib/authlogic/session/active_record_trickery.rb +13 -10
- data/lib/authlogic/session/base.rb +20 -8
- data/lib/authlogic/session/brute_force_protection.rb +87 -56
- data/lib/authlogic/session/callbacks.rb +99 -49
- data/lib/authlogic/session/cookies.rb +128 -59
- data/lib/authlogic/session/existence.rb +29 -19
- data/lib/authlogic/session/foundation.rb +70 -16
- data/lib/authlogic/session/http_auth.rb +39 -31
- data/lib/authlogic/session/id.rb +27 -15
- data/lib/authlogic/session/klass.rb +17 -13
- data/lib/authlogic/session/magic_columns.rb +78 -59
- data/lib/authlogic/session/magic_states.rb +50 -27
- data/lib/authlogic/session/params.rb +79 -50
- data/lib/authlogic/session/password.rb +197 -118
- data/lib/authlogic/session/perishable_token.rb +12 -6
- data/lib/authlogic/session/persistence.rb +20 -14
- data/lib/authlogic/session/priority_record.rb +20 -16
- data/lib/authlogic/session/scopes.rb +63 -33
- data/lib/authlogic/session/session.rb +40 -25
- data/lib/authlogic/session/timeout.rb +51 -34
- data/lib/authlogic/session/unauthorized_record.rb +24 -18
- data/lib/authlogic/session/validation.rb +32 -21
- data/lib/authlogic/test_case.rb +123 -35
- data/lib/authlogic/test_case/mock_controller.rb +14 -13
- data/lib/authlogic/test_case/mock_cookie_jar.rb +14 -5
- data/lib/authlogic/test_case/mock_logger.rb +1 -1
- data/lib/authlogic/test_case/mock_request.rb +9 -4
- data/lib/authlogic/test_case/rails_request_adapter.rb +8 -7
- data/lib/authlogic/version.rb +21 -0
- data/test/acts_as_authentic_test/base_test.rb +1 -1
- data/test/acts_as_authentic_test/email_test.rb +80 -63
- data/test/acts_as_authentic_test/logged_in_status_test.rb +14 -8
- data/test/acts_as_authentic_test/login_test.rb +91 -49
- data/test/acts_as_authentic_test/magic_columns_test.rb +13 -13
- data/test/acts_as_authentic_test/password_test.rb +82 -60
- data/test/acts_as_authentic_test/perishable_token_test.rb +31 -25
- data/test/acts_as_authentic_test/persistence_token_test.rb +9 -5
- data/test/acts_as_authentic_test/restful_authentication_test.rb +18 -9
- data/test/acts_as_authentic_test/session_maintenance_test.rb +86 -22
- data/test/acts_as_authentic_test/single_access_test.rb +15 -15
- data/test/adapter_test.rb +21 -0
- data/test/authenticates_many_test.rb +26 -11
- data/test/config_test.rb +9 -9
- data/test/crypto_provider_test/aes256_test.rb +3 -3
- data/test/crypto_provider_test/bcrypt_test.rb +1 -1
- data/test/crypto_provider_test/scrypt_test.rb +2 -2
- data/test/crypto_provider_test/sha1_test.rb +4 -4
- data/test/crypto_provider_test/sha256_test.rb +2 -2
- data/test/crypto_provider_test/sha512_test.rb +3 -3
- data/test/crypto_provider_test/wordpress_test.rb +24 -0
- data/test/gemfiles/Gemfile.rails-4.2.x +2 -2
- data/test/gemfiles/Gemfile.rails-5.0.x +6 -0
- data/test/gemfiles/Gemfile.rails-5.1.x +6 -0
- data/test/gemfiles/Gemfile.rails-5.2.x +6 -0
- data/test/gemfiles/Gemfile.rails-master +6 -0
- data/test/i18n_test.rb +9 -9
- data/test/libs/affiliate.rb +2 -2
- data/test/libs/company.rb +4 -4
- data/test/libs/employee.rb +2 -2
- data/test/libs/employee_session.rb +1 -1
- data/test/libs/ldaper.rb +1 -1
- data/test/libs/project.rb +1 -1
- data/test/libs/user_session.rb +2 -2
- data/test/random_test.rb +9 -38
- data/test/session_test/activation_test.rb +7 -7
- data/test/session_test/active_record_trickery_test.rb +9 -6
- data/test/session_test/brute_force_protection_test.rb +26 -21
- data/test/session_test/callbacks_test.rb +10 -4
- data/test/session_test/cookies_test.rb +54 -20
- data/test/session_test/existence_test.rb +45 -23
- data/test/session_test/foundation_test.rb +17 -1
- data/test/session_test/http_auth_test.rb +11 -12
- data/test/session_test/id_test.rb +3 -3
- data/test/session_test/klass_test.rb +2 -2
- data/test/session_test/magic_columns_test.rb +15 -17
- data/test/session_test/magic_states_test.rb +17 -19
- data/test/session_test/params_test.rb +26 -20
- data/test/session_test/password_test.rb +11 -12
- data/test/session_test/perishability_test.rb +5 -5
- data/test/session_test/persistence_test.rb +4 -3
- data/test/session_test/scopes_test.rb +15 -9
- data/test/session_test/session_test.rb +7 -6
- data/test/session_test/timeout_test.rb +16 -14
- data/test/session_test/unauthorized_record_test.rb +3 -3
- data/test/session_test/validation_test.rb +5 -5
- data/test/test_helper.rb +115 -49
- metadata +107 -36
- data/README.rdoc +0 -232
- data/test/gemfiles/Gemfile.rails-3.2.x +0 -7
- data/test/gemfiles/Gemfile.rails-4.0.x +0 -7
- data/test/gemfiles/Gemfile.rails-4.1.x +0 -7
@@ -32,7 +32,7 @@ module Authlogic
|
|
32
32
|
end
|
33
33
|
|
34
34
|
def session
|
35
|
-
env[
|
35
|
+
env["rack.session"]
|
36
36
|
end
|
37
37
|
|
38
38
|
def method_missing(meth, *args, &block)
|
@@ -42,7 +42,7 @@ module Authlogic
|
|
42
42
|
|
43
43
|
class Adapter < AbstractAdapter
|
44
44
|
def cookie_domain
|
45
|
-
env[
|
45
|
+
env["SERVER_NAME"]
|
46
46
|
end
|
47
47
|
|
48
48
|
module Implementation
|
@@ -58,4 +58,4 @@ module Authlogic
|
|
58
58
|
end
|
59
59
|
end
|
60
60
|
|
61
|
-
Sinatra::Base.send(:include, Authlogic::ControllerAdapters::SinatraAdapter::Adapter::Implementation)
|
61
|
+
Sinatra::Base.send(:include, Authlogic::ControllerAdapters::SinatraAdapter::Adapter::Implementation)
|
@@ -1,4 +1,25 @@
|
|
1
1
|
module Authlogic
|
2
|
+
# The acts_as_authentic method has a crypto_provider option. This allows you
|
3
|
+
# to use any type of encryption you like. Just create a class with a class
|
4
|
+
# level encrypt and matches? method. See example below.
|
5
|
+
#
|
6
|
+
# === Example
|
7
|
+
#
|
8
|
+
# class MyAwesomeEncryptionMethod
|
9
|
+
# def self.encrypt(*tokens)
|
10
|
+
# # The tokens passed will be an array of objects, what type of object
|
11
|
+
# # is irrelevant, just do what you need to do with them and return a
|
12
|
+
# # single encrypted string. For example, you will most likely join all
|
13
|
+
# # of the objects into a single string and then encrypt that string.
|
14
|
+
# end
|
15
|
+
#
|
16
|
+
# def self.matches?(crypted, *tokens)
|
17
|
+
# # Return true if the crypted string matches the tokens. Depending on
|
18
|
+
# # your algorithm you might decrypt the string then compare it to the
|
19
|
+
# # token, or you might encrypt the tokens and make sure it matches the
|
20
|
+
# # crypted string, its up to you.
|
21
|
+
# end
|
22
|
+
# end
|
2
23
|
module CryptoProviders
|
3
24
|
autoload :MD5, "authlogic/crypto_providers/md5"
|
4
25
|
autoload :Sha1, "authlogic/crypto_providers/sha1"
|
@@ -7,5 +28,75 @@ module Authlogic
|
|
7
28
|
autoload :BCrypt, "authlogic/crypto_providers/bcrypt"
|
8
29
|
autoload :AES256, "authlogic/crypto_providers/aes256"
|
9
30
|
autoload :SCrypt, "authlogic/crypto_providers/scrypt"
|
31
|
+
# crypto_providers/wordpress.rb has never been autoloaded, and now it is
|
32
|
+
# deprecated.
|
33
|
+
|
34
|
+
# Guide users to choose a better crypto provider.
|
35
|
+
class Guidance
|
36
|
+
AES256_DEPRECATED = <<-EOS.strip_heredoc.freeze
|
37
|
+
You have selected AES256 as your authlogic crypto provider. This
|
38
|
+
choice is not suitable for password storage.
|
39
|
+
|
40
|
+
Authlogic will drop its AES256 crypto provider in the next major
|
41
|
+
version. If you're unable to transition away from AES256 please let us
|
42
|
+
know immediately.
|
43
|
+
|
44
|
+
We recommend using a one-way algorithm instead. There are many choices;
|
45
|
+
we recommend scrypt. Use the transition_from_crypto_providers option
|
46
|
+
to make this painless for your users.
|
47
|
+
EOS
|
48
|
+
BUILTIN_PROVIDER_PREFIX = "Authlogic::CryptoProviders::".freeze
|
49
|
+
NONADAPTIVE_ALGORITHM = <<-EOS.strip_heredoc.freeze
|
50
|
+
You have selected %s as your authlogic crypto provider. This algorithm
|
51
|
+
does not have any practical known attacks against it. However, there are
|
52
|
+
better choices.
|
53
|
+
|
54
|
+
Authlogic has no plans yet to deprecate this crypto provider. However,
|
55
|
+
we recommend transitioning to a more secure, adaptive hashing algorithm,
|
56
|
+
like scrypt. Adaptive algorithms are designed to slow down brute force
|
57
|
+
attacks, and over time the iteration count can be increased to make it
|
58
|
+
slower, so it remains resistant to brute-force search attacks even in
|
59
|
+
the face of increasing computation power.
|
60
|
+
|
61
|
+
Use the transition_from_crypto_providers option to make the transition
|
62
|
+
painless for your users.
|
63
|
+
EOS
|
64
|
+
VULNERABLE_ALGORITHM = <<-EOS.strip_heredoc.freeze
|
65
|
+
You have selected %s as your authlogic crypto provider. It is a poor
|
66
|
+
choice because there are known attacks against this algorithm.
|
67
|
+
|
68
|
+
Authlogic has no plans yet to deprecate this crypto provider. However,
|
69
|
+
we recommend transitioning to a secure hashing algorithm. We recommend
|
70
|
+
an adaptive algorithm, like scrypt.
|
71
|
+
|
72
|
+
Use the transition_from_crypto_providers option to make the transition
|
73
|
+
painless for your users.
|
74
|
+
EOS
|
75
|
+
|
76
|
+
def initialize(provider)
|
77
|
+
@provider = provider
|
78
|
+
end
|
79
|
+
|
80
|
+
def impart_wisdom
|
81
|
+
return unless @provider.is_a?(Class)
|
82
|
+
|
83
|
+
# We can only impart wisdom about our own built-in providers.
|
84
|
+
absolute_name = @provider.name
|
85
|
+
return unless absolute_name.start_with?(BUILTIN_PROVIDER_PREFIX)
|
86
|
+
|
87
|
+
# Inspect the string name of the provider, rather than using the
|
88
|
+
# constants in our `when` clauses. If we used the constants, we'd
|
89
|
+
# negate the benefits of the `autoload` above.
|
90
|
+
name = absolute_name.demodulize
|
91
|
+
case name
|
92
|
+
when "AES256"
|
93
|
+
::ActiveSupport::Deprecation.warn(AES256_DEPRECATED)
|
94
|
+
when "MD5", "Sha1"
|
95
|
+
warn(format(VULNERABLE_ALGORITHM, name))
|
96
|
+
when "Sha256", "Sha512"
|
97
|
+
warn(format(NONADAPTIVE_ALGORITHM, name))
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
10
101
|
end
|
11
102
|
end
|
@@ -2,28 +2,33 @@ require "openssl"
|
|
2
2
|
|
3
3
|
module Authlogic
|
4
4
|
module CryptoProviders
|
5
|
-
# This encryption method is reversible if you have the supplied key. So in
|
6
|
-
#
|
5
|
+
# This encryption method is reversible if you have the supplied key. So in
|
6
|
+
# order to use this encryption method you must supply it with a key first.
|
7
|
+
# In an initializer, or before your application initializes, you should do
|
8
|
+
# the following:
|
7
9
|
#
|
8
|
-
# Authlogic::CryptoProviders::AES256.key = "
|
10
|
+
# Authlogic::CryptoProviders::AES256.key = "long, unique, and random key"
|
9
11
|
#
|
10
|
-
# My final comment is that this is a strong encryption method, but its main
|
12
|
+
# My final comment is that this is a strong encryption method, but its main
|
13
|
+
# weakness is that it's reversible. If you do not need to reverse the hash
|
11
14
|
# then you should consider Sha512 or BCrypt instead.
|
12
15
|
#
|
13
|
-
# Keep your key in a safe place, some even say the key should be stored on a
|
14
|
-
# This won't hurt performance because the only time it will
|
15
|
-
#
|
16
|
-
#
|
16
|
+
# Keep your key in a safe place, some even say the key should be stored on a
|
17
|
+
# separate server. This won't hurt performance because the only time it will
|
18
|
+
# try and access the key on the separate server is during initialization,
|
19
|
+
# which only happens once. The reasoning behind this is if someone does
|
20
|
+
# compromise your server they won't have the key also. Basically, you don't
|
21
|
+
# want to store the key with the lock.
|
17
22
|
class AES256
|
18
23
|
class << self
|
19
24
|
attr_writer :key
|
20
|
-
|
25
|
+
|
21
26
|
def encrypt(*tokens)
|
22
27
|
aes.encrypt
|
23
28
|
aes.key = @key
|
24
29
|
[aes.update(tokens.join) + aes.final].pack("m").chomp
|
25
30
|
end
|
26
|
-
|
31
|
+
|
27
32
|
def matches?(crypted, *tokens)
|
28
33
|
aes.decrypt
|
29
34
|
aes.key = @key
|
@@ -31,12 +36,35 @@ module Authlogic
|
|
31
36
|
rescue OpenSSL::CipherError
|
32
37
|
false
|
33
38
|
end
|
34
|
-
|
39
|
+
|
35
40
|
private
|
36
|
-
|
37
|
-
|
38
|
-
|
41
|
+
|
42
|
+
def aes
|
43
|
+
if @key.blank?
|
44
|
+
raise ArgumentError.new(
|
45
|
+
"You must provide a key like #{name}.key = my_key before using the #{name}"
|
46
|
+
)
|
39
47
|
end
|
48
|
+
|
49
|
+
@aes ||= openssl_cipher_class.new("AES-256-ECB")
|
50
|
+
end
|
51
|
+
|
52
|
+
# `::OpenSSL::Cipher::Cipher` has been deprecated since at least 2014,
|
53
|
+
# in favor of `::OpenSSL::Cipher`, but a deprecation warning was not
|
54
|
+
# printed until 2016
|
55
|
+
# (https://github.com/ruby/openssl/commit/5c20a4c014) when openssl
|
56
|
+
# became a gem. Its first release as a gem was 2.0.0, in ruby 2.4.
|
57
|
+
# (See https://github.com/ruby/ruby/blob/v2_4_0/NEWS)
|
58
|
+
#
|
59
|
+
# When we eventually drop support for ruby < 2.4, we can probably also
|
60
|
+
# drop support for openssl gem < 2.
|
61
|
+
def openssl_cipher_class
|
62
|
+
if ::Gem::Version.new(::OpenSSL::VERSION) < ::Gem::Version.new("2.0.0")
|
63
|
+
::OpenSSL::Cipher::Cipher
|
64
|
+
else
|
65
|
+
::OpenSSL::Cipher
|
66
|
+
end
|
67
|
+
end
|
40
68
|
end
|
41
69
|
end
|
42
70
|
end
|
@@ -16,10 +16,18 @@ module Authlogic
|
|
16
16
|
# require "benchmark"
|
17
17
|
#
|
18
18
|
# Benchmark.bm(18) do |x|
|
19
|
-
# x.report("BCrypt (cost = 10:") {
|
20
|
-
#
|
21
|
-
#
|
22
|
-
# x.report("
|
19
|
+
# x.report("BCrypt (cost = 10:") {
|
20
|
+
# 100.times { BCrypt::Password.create("mypass", :cost => 10) }
|
21
|
+
# }
|
22
|
+
# x.report("BCrypt (cost = 4:") {
|
23
|
+
# 100.times { BCrypt::Password.create("mypass", :cost => 4) }
|
24
|
+
# }
|
25
|
+
# x.report("Sha512:") {
|
26
|
+
# 100.times { Digest::SHA512.hexdigest("mypass") }
|
27
|
+
# }
|
28
|
+
# x.report("Sha1:") {
|
29
|
+
# 100.times { Digest::SHA1.hexdigest("mypass") }
|
30
|
+
# }
|
23
31
|
# end
|
24
32
|
#
|
25
33
|
# user system total real
|
@@ -45,32 +53,40 @@ module Authlogic
|
|
45
53
|
# You are good to go!
|
46
54
|
class BCrypt
|
47
55
|
class << self
|
48
|
-
# This is the :cost option for the BCrpyt library. The higher the cost
|
49
|
-
#
|
56
|
+
# This is the :cost option for the BCrpyt library. The higher the cost
|
57
|
+
# the more secure it is and the longer is take the generate a hash. By
|
58
|
+
# default this is 10. Set this to any value >= the engine's minimum
|
59
|
+
# (currently 4), play around with it to get that perfect balance between
|
60
|
+
# security and performance.
|
50
61
|
def cost
|
51
62
|
@cost ||= 10
|
52
63
|
end
|
53
64
|
|
54
65
|
def cost=(val)
|
55
66
|
if val < ::BCrypt::Engine::MIN_COST
|
56
|
-
raise ArgumentError.new(
|
67
|
+
raise ArgumentError.new(
|
68
|
+
"Authlogic's bcrypt cost cannot be set below the engine's " \
|
69
|
+
"min cost (#{::BCrypt::Engine::MIN_COST})"
|
70
|
+
)
|
57
71
|
end
|
58
72
|
@cost = val
|
59
73
|
end
|
60
74
|
|
61
75
|
# Creates a BCrypt hash for the password passed.
|
62
76
|
def encrypt(*tokens)
|
63
|
-
::BCrypt::Password.create(join_tokens(tokens), :
|
77
|
+
::BCrypt::Password.create(join_tokens(tokens), cost: cost)
|
64
78
|
end
|
65
79
|
|
66
|
-
# Does the hash match the tokens? Uses the same tokens that were used to
|
80
|
+
# Does the hash match the tokens? Uses the same tokens that were used to
|
81
|
+
# encrypt.
|
67
82
|
def matches?(hash, *tokens)
|
68
83
|
hash = new_from_hash(hash)
|
69
84
|
return false if hash.blank?
|
70
85
|
hash == join_tokens(tokens)
|
71
86
|
end
|
72
87
|
|
73
|
-
# This method is used as a flag to tell Authlogic to "resave" the
|
88
|
+
# This method is used as a flag to tell Authlogic to "resave" the
|
89
|
+
# password upon a successful login, using the new cost
|
74
90
|
def cost_matches?(hash)
|
75
91
|
hash = new_from_hash(hash)
|
76
92
|
if hash.blank?
|
@@ -81,17 +97,16 @@ module Authlogic
|
|
81
97
|
end
|
82
98
|
|
83
99
|
private
|
84
|
-
def join_tokens(tokens)
|
85
|
-
tokens.flatten.join
|
86
|
-
end
|
87
100
|
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
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
|
95
110
|
end
|
96
111
|
end
|
97
112
|
end
|
@@ -1,34 +1,36 @@
|
|
1
1
|
require "digest/md5"
|
2
|
-
|
2
|
+
|
3
3
|
module Authlogic
|
4
4
|
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
|
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
7
|
# to your other options.
|
8
8
|
#
|
9
|
-
# Please use any other provider offered by Authlogic
|
9
|
+
# Please use any other provider offered by Authlogic (except AES256, that
|
10
|
+
# would be even worse).
|
10
11
|
class MD5
|
11
12
|
class << self
|
12
13
|
attr_accessor :join_token
|
13
|
-
|
14
|
+
|
14
15
|
# The number of times to loop through the encryption.
|
15
16
|
def stretches
|
16
17
|
@stretches ||= 1
|
17
18
|
end
|
18
19
|
attr_writer :stretches
|
19
|
-
|
20
|
+
|
20
21
|
# Turns your raw password into a MD5 hash.
|
21
22
|
def encrypt(*tokens)
|
22
23
|
digest = tokens.flatten.join(join_token)
|
23
24
|
stretches.times { digest = Digest::MD5.hexdigest(digest) }
|
24
25
|
digest
|
25
26
|
end
|
26
|
-
|
27
|
-
# Does the crypted password match the tokens? Uses the same tokens that
|
27
|
+
|
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
|
31
33
|
end
|
32
34
|
end
|
33
35
|
end
|
34
|
-
end
|
36
|
+
end
|
@@ -19,7 +19,13 @@ module Authlogic
|
|
19
19
|
# end
|
20
20
|
class SCrypt
|
21
21
|
class << self
|
22
|
-
DEFAULTS = {
|
22
|
+
DEFAULTS = {
|
23
|
+
key_len: 32,
|
24
|
+
salt_size: 8,
|
25
|
+
max_time: 0.2,
|
26
|
+
max_mem: 1024 * 1024,
|
27
|
+
max_memfrac: 0.5
|
28
|
+
}.freeze
|
23
29
|
|
24
30
|
attr_writer :key_len, :salt_size, :max_time, :max_mem, :max_memfrac
|
25
31
|
# Key length - length in bytes of generated key, from 16 to 512.
|
@@ -42,14 +48,22 @@ module Authlogic
|
|
42
48
|
@max_mem ||= DEFAULTS[:max_mem]
|
43
49
|
end
|
44
50
|
|
45
|
-
# Max memory fraction - maximum memory out of all available. Always
|
51
|
+
# Max memory fraction - maximum memory out of all available. Always
|
52
|
+
# greater than zero and <= 0.5.
|
46
53
|
def max_memfrac
|
47
54
|
@max_memfrac ||= DEFAULTS[:max_memfrac]
|
48
55
|
end
|
49
56
|
|
50
57
|
# Creates an SCrypt hash for the password passed.
|
51
58
|
def encrypt(*tokens)
|
52
|
-
::SCrypt::Password.create(
|
59
|
+
::SCrypt::Password.create(
|
60
|
+
join_tokens(tokens),
|
61
|
+
key_len: key_len,
|
62
|
+
salt_size: salt_size,
|
63
|
+
max_mem: max_mem,
|
64
|
+
max_memfrac: max_memfrac,
|
65
|
+
max_time: max_time
|
66
|
+
)
|
53
67
|
end
|
54
68
|
|
55
69
|
# Does the hash match the tokens? Uses the same tokens that were used to encrypt.
|
@@ -60,17 +74,16 @@ module Authlogic
|
|
60
74
|
end
|
61
75
|
|
62
76
|
private
|
63
|
-
def join_tokens(tokens)
|
64
|
-
tokens.flatten.join
|
65
|
-
end
|
66
77
|
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
78
|
+
def join_tokens(tokens)
|
79
|
+
tokens.flatten.join
|
80
|
+
end
|
81
|
+
|
82
|
+
def new_from_hash(hash)
|
83
|
+
::SCrypt::Password.new(hash)
|
84
|
+
rescue ::SCrypt::Errors::InvalidHash
|
85
|
+
nil
|
86
|
+
end
|
74
87
|
end
|
75
88
|
end
|
76
89
|
end
|
@@ -2,30 +2,36 @@ require "digest/sha1"
|
|
2
2
|
|
3
3
|
module Authlogic
|
4
4
|
module CryptoProviders
|
5
|
-
# This class was made for the users transitioning from
|
6
|
-
#
|
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
9
|
class Sha1
|
8
10
|
class << self
|
9
11
|
def join_token
|
10
12
|
@join_token ||= "--"
|
11
13
|
end
|
12
14
|
attr_writer :join_token
|
13
|
-
|
14
|
-
# The number of times to loop through the encryption. This is ten
|
15
|
+
|
16
|
+
# The number of times to loop through the encryption. This is ten
|
17
|
+
# because that is what restful_authentication defaults to.
|
15
18
|
def stretches
|
16
19
|
@stretches ||= 10
|
17
20
|
end
|
18
21
|
attr_writer :stretches
|
19
|
-
|
22
|
+
|
20
23
|
# Turns your raw password into a Sha1 hash.
|
21
24
|
def encrypt(*tokens)
|
22
25
|
tokens = tokens.flatten
|
23
26
|
digest = tokens.shift
|
24
|
-
stretches.times
|
27
|
+
stretches.times do
|
28
|
+
digest = Digest::SHA1.hexdigest([digest, *tokens].join(join_token))
|
29
|
+
end
|
25
30
|
digest
|
26
31
|
end
|
27
|
-
|
28
|
-
# Does the crypted password match the tokens? Uses the same tokens that
|
32
|
+
|
33
|
+
# Does the crypted password match the tokens? Uses the same tokens that
|
34
|
+
# were used to encrypt.
|
29
35
|
def matches?(crypted, *tokens)
|
30
36
|
encrypt(*tokens) == crypted
|
31
37
|
end
|