authlogic 5.2.0 → 6.0.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 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
  - - ">="