authlogic 5.2.0 → 6.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c4ede36ceee21501805105c66349d58ba6c6d9d483d5fefc41b8d4cbd5189944
4
- data.tar.gz: f323b446e8f8e2a722bb9d896249170596f64ebf8ff441b2740cb834c2b085b8
3
+ metadata.gz: 755961398552a88cf3761088e4521e71e243249b3a131632e281679d723c82fe
4
+ data.tar.gz: 2b739ad482ecdaad8218065a4c03882e730c86825bc7140691e451fc26032815
5
5
  SHA512:
6
- metadata.gz: 26cda51c7c8e2b5a8be9395ef13e3d39d9ee1c73429542d107bb229747b9a004800771a96b8f516e4f994c8926b1d0ef2fb1bf45e38102646451c48a3e4fb453
7
- data.tar.gz: 971d54be27f18e12d8d7eafad90e50627098c689b34e047c0ddea4a96f82abf8c80e45766f49fdd82a9efb45fd3508ca312ee4b0cc0508d06a37887d45f9fcb0
6
+ metadata.gz: 52e998e1210ac287f2bc91d01d2afba9416f5b0eee54cff13d89c6c9affdd2ff2a88ac1a80e78ce100c2a43dcbcf777a5f22dd3d72ff3571bc69c5242a89d97c
7
+ data.tar.gz: 6152232cf873d2c9be4fa24584b3d8bf8013f95ae58a8117f4494c3a6632df814e36b85d02c67efc0e2b73849a43333c0b9bcf9cb1d379f10587147aa69f808e
@@ -13,6 +13,7 @@ require "active_record"
13
13
  path = File.dirname(__FILE__) + "/authlogic/"
14
14
 
15
15
  [
16
+ "errors",
16
17
  "i18n",
17
18
  "random",
18
19
  "config",
@@ -109,13 +109,23 @@ module Authlogic
109
109
  # transition to a better crypto provider without causing your users any
110
110
  # pain.
111
111
  #
112
- # * <tt>Default:</tt> CryptoProviders::SCrypt
112
+ # * <tt>Default:</tt> There is no longer a default value. Prior to
113
+ # Authlogic 6, the default was `CryptoProviders::SCrypt`. If you try
114
+ # to read this config option before setting it, it will raise a
115
+ # `NilCryptoProvider` error. See that error's message for further
116
+ # details, and rationale for this change.
113
117
  # * <tt>Accepts:</tt> Class
114
- def crypto_provider(value = nil)
118
+ def crypto_provider
119
+ acts_as_authentic_config[:crypto_provider].tap { |provider|
120
+ raise NilCryptoProvider if provider.nil?
121
+ }
122
+ end
123
+
124
+ def crypto_provider=(value)
125
+ raise NilCryptoProvider if value.nil?
115
126
  CryptoProviders::Guidance.new(value).impart_wisdom
116
- rw_config(:crypto_provider, value, CryptoProviders::SCrypt)
127
+ rw_config(:crypto_provider, value)
117
128
  end
118
- alias crypto_provider= crypto_provider
119
129
 
120
130
  # Let's say you originally encrypted your passwords with Sha1. Sha1 is
121
131
  # starting to join the party with MD5 and you want to switch to
@@ -176,7 +176,9 @@ module Authlogic
176
176
  end
177
177
 
178
178
  def log_in_after_password_change?
179
- will_save_change_to_persistence_token? && self.class.log_in_after_password_change
179
+ persisted? &&
180
+ will_save_change_to_persistence_token? &&
181
+ self.class.log_in_after_password_change
180
182
  end
181
183
  end
182
184
  end
@@ -6,6 +6,9 @@ module Authlogic
6
6
  module CryptoProviders
7
7
  # A poor choice. There are known attacks against this algorithm.
8
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
+
9
12
  class << self
10
13
  attr_accessor :join_token
11
14
 
@@ -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
@@ -6,6 +6,9 @@ module Authlogic
6
6
  module CryptoProviders
7
7
  # A poor choice. There are known attacks against this algorithm.
8
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
+
9
12
  class << self
10
13
  def join_token
11
14
  @join_token ||= "--"
@@ -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
@@ -29,6 +29,9 @@ module Authlogic
29
29
  #
30
30
  # Uses the Sha256 hash algorithm to encrypt passwords.
31
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
+
32
35
  class << self
33
36
  attr_accessor :join_token
34
37
 
@@ -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
@@ -8,6 +8,9 @@ module Authlogic
8
8
  # there are better choices. We recommend transitioning to a more secure,
9
9
  # adaptive hashing algorithm, like scrypt.
10
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
+
11
14
  class << self
12
15
  attr_accessor :join_token
13
16
 
@@ -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.unpack("H*")[0]
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,35 @@
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 |config|
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
+ end
@@ -8,7 +8,7 @@ module Authlogic
8
8
  # arguments, else returns +options[:default]+.
9
9
  def translate(key, options = {})
10
10
  if defined?(::I18n)
11
- ::I18n.translate key, options
11
+ ::I18n.translate key, **options
12
12
  else
13
13
  options[:default]
14
14
  end
@@ -198,7 +198,7 @@ module Authlogic
198
198
  # 2. Enable logging out on timeouts
199
199
  #
200
200
  # class UserSession < Authlogic::Session::Base
201
- # logout_on_timeout true # default if false
201
+ # logout_on_timeout true # default is false
202
202
  # end
203
203
  #
204
204
  # This will require a user to log back in if they are inactive for more than
@@ -472,14 +472,9 @@ module Authlogic
472
472
  !controller.nil?
473
473
  end
474
474
 
475
- # Do you want to allow your users to log in via HTTP basic auth?
475
+ # Allow users to log in via HTTP basic authentication.
476
476
  #
477
- # I recommend keeping this enabled. The only time I feel this should be
478
- # disabled is if you are not comfortable having your users provide their
479
- # raw username and password. Whatever the reason, you can disable it
480
- # here.
481
- #
482
- # * <tt>Default:</tt> true
477
+ # * <tt>Default:</tt> false
483
478
  # * <tt>Accepts:</tt> Boolean
484
479
  def allow_http_basic_auth(value = nil)
485
480
  rw_config(:allow_http_basic_auth, value, false)
@@ -961,20 +956,6 @@ module Authlogic
961
956
  end
962
957
  alias sign_cookie= sign_cookie
963
958
 
964
- # Should the cookie be encrypted? If the controller adapter supports it, this is a
965
- # measure to hide the contents of the cookie (e.g. persistence_token)
966
- def encrypt_cookie(value = nil)
967
- if value && !controller.cookies.respond_to?(:encrypted)
968
- raise "Encrypted cookies not supported with #{controller.class}!"
969
- end
970
- if value && sign_cookie
971
- raise "It is recommended to use encrypt_cookie instead of sign_cookie. " \
972
- "You may not enable both options."
973
- end
974
- rw_config(:encrypt_cookie, value, false)
975
- end
976
- alias_method :encrypt_cookie=, :encrypt_cookie
977
-
978
959
  # Works exactly like cookie_key, but for sessions. See cookie_key for more info.
979
960
  #
980
961
  # * <tt>Default:</tt> cookie_key
@@ -1494,23 +1475,6 @@ module Authlogic
1494
1475
  sign_cookie == true || sign_cookie == "true" || sign_cookie == "1"
1495
1476
  end
1496
1477
 
1497
- # If the cookie should be encrypted
1498
- def encrypt_cookie
1499
- return @encrypt_cookie if defined?(@encrypt_cookie)
1500
- @encrypt_cookie = self.class.encrypt_cookie
1501
- end
1502
-
1503
- # Accepts a boolean as to whether the cookie should be encrypted. If true
1504
- # the cookie will be saved in an encrypted state.
1505
- def encrypt_cookie=(value)
1506
- @encrypt_cookie = value
1507
- end
1508
-
1509
- # See encrypt_cookie
1510
- def encrypt_cookie?
1511
- encrypt_cookie == true || encrypt_cookie == "true" || encrypt_cookie == "1"
1512
- end
1513
-
1514
1478
  # The scope of the current object
1515
1479
  def scope
1516
1480
  @scope ||= {}
@@ -1654,9 +1618,7 @@ module Authlogic
1654
1618
  end
1655
1619
 
1656
1620
  def cookie_jar
1657
- if self.class.encrypt_cookie
1658
- controller.cookies.encrypted
1659
- elsif self.class.sign_cookie
1621
+ if self.class.sign_cookie
1660
1622
  controller.cookies.signed
1661
1623
  else
1662
1624
  controller.cookies
@@ -1738,8 +1700,13 @@ module Authlogic
1738
1700
 
1739
1701
  # @api private
1740
1702
  def generate_cookie_for_saving
1703
+ creds = ::Authlogic::CookieCredentials.new(
1704
+ record.persistence_token,
1705
+ record.send(record.class.primary_key),
1706
+ remember_me? ? remember_me_until : nil
1707
+ )
1741
1708
  {
1742
- value: generate_cookie_value.to_s,
1709
+ value: creds.to_s,
1743
1710
  expires: remember_me_until,
1744
1711
  secure: secure,
1745
1712
  httponly: httponly,
@@ -1748,14 +1715,6 @@ module Authlogic
1748
1715
  }
1749
1716
  end
1750
1717
 
1751
- def generate_cookie_value
1752
- ::Authlogic::CookieCredentials.new(
1753
- record.persistence_token,
1754
- record.send(record.class.primary_key),
1755
- remember_me? ? remember_me_until : nil
1756
- )
1757
- end
1758
-
1759
1718
  # Returns a Proc to be executed by
1760
1719
  # `ActionController::HttpAuthentication::Basic` when credentials are
1761
1720
  # present in the HTTP request.
@@ -1971,7 +1930,11 @@ module Authlogic
1971
1930
  end
1972
1931
 
1973
1932
  def save_cookie
1974
- cookie_jar[cookie_key] = generate_cookie_for_saving
1933
+ if sign_cookie?
1934
+ controller.cookies.signed[cookie_key] = generate_cookie_for_saving
1935
+ else
1936
+ controller.cookies[cookie_key] = generate_cookie_for_saving
1937
+ end
1975
1938
  end
1976
1939
 
1977
1940
  # @api private
@@ -23,10 +23,6 @@ module Authlogic
23
23
  def signed
24
24
  @signed ||= MockSignedCookieJar.new(self)
25
25
  end
26
-
27
- def encrypted
28
- @encrypted ||= MockEncryptedCookieJar.new(self)
29
- end
30
26
  end
31
27
 
32
28
  # A mock of `ActionDispatch::Cookies::SignedKeyRotatingCookieJar`
@@ -39,7 +35,6 @@ module Authlogic
39
35
 
40
36
  def initialize(parent_jar)
41
37
  @parent_jar = parent_jar
42
- parent_jar.each { |k, v| self[k] = v }
43
38
  end
44
39
 
45
40
  def [](val)
@@ -56,35 +51,5 @@ module Authlogic
56
51
  @parent_jar[key] = options
57
52
  end
58
53
  end
59
-
60
- class MockEncryptedCookieJar < MockCookieJar
61
- attr_reader :parent_jar # helper for testing
62
-
63
- def initialize(parent_jar)
64
- @parent_jar = parent_jar
65
- parent_jar.each { |k, v| self[k] = v }
66
- end
67
-
68
- def [](val)
69
- encrypted_message = @parent_jar[val]
70
- if encrypted_message
71
- self.class.decrypt(encrypted_message)
72
- end
73
- end
74
-
75
- def []=(key, options)
76
- options[:value] = self.class.encrypt(options[:value])
77
- @parent_jar[key] = options
78
- end
79
-
80
- # simple caesar cipher for testing
81
- def self.encrypt(str)
82
- str.unpack("U*").map(&:succ).pack("U*")
83
- end
84
-
85
- def self.decrypt(str)
86
- str.unpack("U*").map(&:pred).pack("U*")
87
- end
88
- end
89
54
  end
90
55
  end
@@ -17,6 +17,6 @@ module Authlogic
17
17
  #
18
18
  # @api public
19
19
  def self.gem_version
20
- ::Gem::Version.new("5.2.0")
20
+ ::Gem::Version.new("6.0.0")
21
21
  end
22
22
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: authlogic
3
3
  version: !ruby/object:Gem::Version
4
- version: 5.2.0
4
+ version: 6.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ben Johnson
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2020-05-08 00:00:00.000000000 Z
13
+ date: 2020-03-24 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: activemodel
@@ -86,26 +86,6 @@ dependencies:
86
86
  - - "~>"
87
87
  - !ruby/object:Gem::Version
88
88
  version: '1.0'
89
- - !ruby/object:Gem::Dependency
90
- name: scrypt
91
- requirement: !ruby/object:Gem::Requirement
92
- requirements:
93
- - - ">="
94
- - !ruby/object:Gem::Version
95
- version: '1.2'
96
- - - "<"
97
- - !ruby/object:Gem::Version
98
- version: '4.0'
99
- type: :runtime
100
- prerelease: false
101
- version_requirements: !ruby/object:Gem::Requirement
102
- requirements:
103
- - - ">="
104
- - !ruby/object:Gem::Version
105
- version: '1.2'
106
- - - "<"
107
- - !ruby/object:Gem::Version
108
- version: '4.0'
109
89
  - !ruby/object:Gem::Dependency
110
90
  name: bcrypt
111
91
  requirement: !ruby/object:Gem::Requirement
@@ -218,6 +198,26 @@ dependencies:
218
198
  - - "~>"
219
199
  - !ruby/object:Gem::Version
220
200
  version: '1.1'
201
+ - !ruby/object:Gem::Dependency
202
+ name: scrypt
203
+ requirement: !ruby/object:Gem::Requirement
204
+ requirements:
205
+ - - ">="
206
+ - !ruby/object:Gem::Version
207
+ version: '1.2'
208
+ - - "<"
209
+ - !ruby/object:Gem::Version
210
+ version: '4.0'
211
+ type: :development
212
+ prerelease: false
213
+ version_requirements: !ruby/object:Gem::Requirement
214
+ requirements:
215
+ - - ">="
216
+ - !ruby/object:Gem::Version
217
+ version: '1.2'
218
+ - - "<"
219
+ - !ruby/object:Gem::Version
220
+ version: '4.0'
221
221
  - !ruby/object:Gem::Dependency
222
222
  name: simplecov
223
223
  requirement: !ruby/object:Gem::Requirement
@@ -252,14 +252,14 @@ dependencies:
252
252
  requirements:
253
253
  - - "~>"
254
254
  - !ruby/object:Gem::Version
255
- version: 1.3.13
255
+ version: 1.4.0
256
256
  type: :development
257
257
  prerelease: false
258
258
  version_requirements: !ruby/object:Gem::Requirement
259
259
  requirements:
260
260
  - - "~>"
261
261
  - !ruby/object:Gem::Version
262
- version: 1.3.13
262
+ version: 1.4.0
263
263
  - !ruby/object:Gem::Dependency
264
264
  name: timecop
265
265
  requirement: !ruby/object:Gem::Requirement
@@ -305,10 +305,15 @@ files:
305
305
  - lib/authlogic/crypto_providers.rb
306
306
  - lib/authlogic/crypto_providers/bcrypt.rb
307
307
  - lib/authlogic/crypto_providers/md5.rb
308
+ - lib/authlogic/crypto_providers/md5/v2.rb
308
309
  - lib/authlogic/crypto_providers/scrypt.rb
309
310
  - lib/authlogic/crypto_providers/sha1.rb
311
+ - lib/authlogic/crypto_providers/sha1/v2.rb
310
312
  - lib/authlogic/crypto_providers/sha256.rb
313
+ - lib/authlogic/crypto_providers/sha256/v2.rb
311
314
  - lib/authlogic/crypto_providers/sha512.rb
315
+ - lib/authlogic/crypto_providers/sha512/v2.rb
316
+ - lib/authlogic/errors.rb
312
317
  - lib/authlogic/i18n.rb
313
318
  - lib/authlogic/i18n/translator.rb
314
319
  - lib/authlogic/random.rb
@@ -333,7 +338,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
333
338
  requirements:
334
339
  - - ">="
335
340
  - !ruby/object:Gem::Version
336
- version: 2.3.0
341
+ version: 2.4.0
337
342
  required_rubygems_version: !ruby/object:Gem::Requirement
338
343
  requirements:
339
344
  - - ">="