authlogic 6.0.0 → 6.1.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: 755961398552a88cf3761088e4521e71e243249b3a131632e281679d723c82fe
4
- data.tar.gz: 2b739ad482ecdaad8218065a4c03882e730c86825bc7140691e451fc26032815
3
+ metadata.gz: 88e14eb91ceaf33fca0867ad9816d8ee719215bdb9f5ff26c2c4754d84c82dd8
4
+ data.tar.gz: 1dfbc1800a0fd0766bde87dfaa4a351b4b377e4240ad81aaa7d163c547d4d2a4
5
5
  SHA512:
6
- metadata.gz: 52e998e1210ac287f2bc91d01d2afba9416f5b0eee54cff13d89c6c9affdd2ff2a88ac1a80e78ce100c2a43dcbcf777a5f22dd3d72ff3571bc69c5242a89d97c
7
- data.tar.gz: 6152232cf873d2c9be4fa24584b3d8bf8013f95ae58a8117f4494c3a6632df814e36b85d02c67efc0e2b73849a43333c0b9bcf9cb1d379f10587147aa69f808e
6
+ metadata.gz: a9e01562988e0b0a1660b7fa51009d71a76c01bca17711d278fd9d5e7271c3ef0e165da9622a7049b15f45d994d108e51c6fff0689ad4afe063df62525ddc572
7
+ data.tar.gz: b0930fa9bc9d370cb71b1e502ece7885319429aff8f49039a8150621f9eb79bd9301c6e028933e156eb28f50a571a0586c23c918280a23f681bc7f45e440aa4f
@@ -102,7 +102,7 @@ module Authlogic
102
102
  # The family of adaptive hash functions (BCrypt, SCrypt, PBKDF2) is the
103
103
  # best choice for password storage today. We recommend SCrypt. Other
104
104
  # one-way functions like SHA512 are inferior, but widely used.
105
- # Reverisbile functions like AES256 are the worst choice, and we no
105
+ # Reversible functions like AES256 are the worst choice, and we no
106
106
  # longer support them.
107
107
  #
108
108
  # You can use the `transition_from_crypto_providers` option to gradually
@@ -20,7 +20,7 @@ module Authlogic
20
20
  def encrypt(*tokens)
21
21
  digest = tokens.flatten.join(join_token)
22
22
  stretches.times { digest = Digest::MD5.digest(digest) }
23
- digest.unpack("H*")[0]
23
+ digest.unpack1("H*")
24
24
  end
25
25
 
26
26
  # Does the crypted password match the tokens? Uses the same tokens that
@@ -26,7 +26,7 @@ module Authlogic
26
26
  stretches.times do
27
27
  digest = Digest::SHA1.digest([digest, *tokens].join(join_token))
28
28
  end
29
- digest.unpack("H*")[0]
29
+ digest.unpack1("H*")
30
30
  end
31
31
 
32
32
  # Does the crypted password match the tokens? Uses the same tokens that
@@ -43,7 +43,7 @@ module Authlogic
43
43
  def encrypt(*tokens)
44
44
  digest = tokens.flatten.join(join_token)
45
45
  stretches.times { digest = Digest::SHA256.digest(digest) }
46
- digest.unpack("H*")[0]
46
+ digest.unpack1("H*")
47
47
  end
48
48
 
49
49
  # Does the crypted password match the tokens? Uses the same tokens that
@@ -24,7 +24,7 @@ module Authlogic
24
24
  stretches.times do
25
25
  digest = Digest::SHA512.digest(digest)
26
26
  end
27
- digest.unpack("H*")[0]
27
+ digest.unpack1("H*")
28
28
  end
29
29
 
30
30
  # Does the crypted password match the tokens? Uses the same tokens that
@@ -18,7 +18,7 @@ module Authlogic
18
18
  this default, then, in your User model (or equivalent), please set the
19
19
  following:
20
20
 
21
- acts_as_authentic do |config|
21
+ acts_as_authentic do |c|
22
22
  c.crypto_provider = ::Authlogic::CryptoProviders::SCrypt
23
23
  end
24
24
 
@@ -438,8 +438,7 @@ module Authlogic
438
438
 
439
439
  class << self
440
440
  attr_accessor(
441
- :configured_password_methods,
442
- :configured_klass_methods
441
+ :configured_password_methods
443
442
  )
444
443
  end
445
444
  attr_accessor(
@@ -956,6 +955,20 @@ module Authlogic
956
955
  end
957
956
  alias sign_cookie= sign_cookie
958
957
 
958
+ # Should the cookie be encrypted? If the controller adapter supports it, this is a
959
+ # measure to hide the contents of the cookie (e.g. persistence_token)
960
+ def encrypt_cookie(value = nil)
961
+ if value && !controller.cookies.respond_to?(:encrypted)
962
+ raise "Encrypted cookies not supported with #{controller.class}!"
963
+ end
964
+ if value && sign_cookie
965
+ raise "It is recommended to use encrypt_cookie instead of sign_cookie. " \
966
+ "You may not enable both options."
967
+ end
968
+ rw_config(:encrypt_cookie, value, false)
969
+ end
970
+ alias_method :encrypt_cookie=, :encrypt_cookie
971
+
959
972
  # Works exactly like cookie_key, but for sessions. See cookie_key for more info.
960
973
  #
961
974
  # * <tt>Default:</tt> cookie_key
@@ -1060,24 +1073,10 @@ module Authlogic
1060
1073
  # Constructor
1061
1074
  # ===========
1062
1075
 
1063
- # rubocop:disable Metrics/AbcSize
1064
1076
  def initialize(*args)
1065
1077
  @id = nil
1066
1078
  self.scope = self.class.scope
1067
-
1068
- # Creating an alias method for the "record" method based on the klass
1069
- # name, so that we can do:
1070
- #
1071
- # session.user
1072
- #
1073
- # instead of:
1074
- #
1075
- # session.record
1076
- unless self.class.configured_klass_methods
1077
- self.class.send(:alias_method, klass_name.demodulize.underscore.to_sym, :record)
1078
- self.class.configured_klass_methods = true
1079
- end
1080
-
1079
+ define_record_alias_method
1081
1080
  raise Activation::NotActivatedError unless self.class.activated?
1082
1081
  unless self.class.configured_password_methods
1083
1082
  configure_password_methods
@@ -1086,7 +1085,6 @@ module Authlogic
1086
1085
  instance_variable_set("@#{password_field}", nil)
1087
1086
  self.credentials = args
1088
1087
  end
1089
- # rubocop:enable Metrics/AbcSize
1090
1088
 
1091
1089
  # Public instance methods
1092
1090
  # =======================
@@ -1475,6 +1473,23 @@ module Authlogic
1475
1473
  sign_cookie == true || sign_cookie == "true" || sign_cookie == "1"
1476
1474
  end
1477
1475
 
1476
+ # If the cookie should be encrypted
1477
+ def encrypt_cookie
1478
+ return @encrypt_cookie if defined?(@encrypt_cookie)
1479
+ @encrypt_cookie = self.class.encrypt_cookie
1480
+ end
1481
+
1482
+ # Accepts a boolean as to whether the cookie should be encrypted. If true
1483
+ # the cookie will be saved in an encrypted state.
1484
+ def encrypt_cookie=(value)
1485
+ @encrypt_cookie = value
1486
+ end
1487
+
1488
+ # See encrypt_cookie
1489
+ def encrypt_cookie?
1490
+ encrypt_cookie == true || encrypt_cookie == "true" || encrypt_cookie == "1"
1491
+ end
1492
+
1478
1493
  # The scope of the current object
1479
1494
  def scope
1480
1495
  @scope ||= {}
@@ -1492,24 +1507,21 @@ module Authlogic
1492
1507
  # Determines if the information you provided for authentication is valid
1493
1508
  # or not. If there is a problem with the information provided errors will
1494
1509
  # be added to the errors object and this method will return false.
1510
+ #
1511
+ # @api public
1495
1512
  def valid?
1496
1513
  errors.clear
1497
1514
  self.attempted_record = nil
1498
-
1499
- run_callbacks(:before_validation)
1500
- run_callbacks(new_session? ? :before_validation_on_create : :before_validation_on_update)
1515
+ run_the_before_validation_callbacks
1501
1516
 
1502
1517
  # Run the `validate` callbacks, eg. `validate_by_password`.
1503
1518
  # This is when `attempted_record` is set.
1504
1519
  run_callbacks(:validate)
1505
1520
 
1506
1521
  ensure_authentication_attempted
1507
-
1508
1522
  if errors.empty?
1509
- run_callbacks(new_session? ? :after_validation_on_create : :after_validation_on_update)
1510
- run_callbacks(:after_validation)
1523
+ run_the_after_validation_callbacks
1511
1524
  end
1512
-
1513
1525
  save_record(attempted_record)
1514
1526
  errors.empty?
1515
1527
  end
@@ -1618,7 +1630,9 @@ module Authlogic
1618
1630
  end
1619
1631
 
1620
1632
  def cookie_jar
1621
- if self.class.sign_cookie
1633
+ if self.class.encrypt_cookie
1634
+ controller.cookies.encrypted
1635
+ elsif self.class.sign_cookie
1622
1636
  controller.cookies.signed
1623
1637
  else
1624
1638
  controller.cookies
@@ -1636,15 +1650,23 @@ module Authlogic
1636
1650
  self.class.send(:attr_reader, login_field) unless respond_to?(login_field)
1637
1651
  end
1638
1652
 
1653
+ # @api private
1639
1654
  def define_password_field_methods
1640
1655
  return unless password_field
1641
- self.class.send(:attr_writer, password_field) unless respond_to?("#{password_field}=")
1642
- self.class.send(:define_method, password_field) {} unless respond_to?(password_field)
1656
+ define_password_field_writer_method
1657
+ define_password_field_reader_methods
1658
+ end
1643
1659
 
1644
- # The password should not be accessible publicly. This way forms
1645
- # using form_for don't fill the password with the attempted
1646
- # password. To prevent this we just create this method that is
1647
- # private.
1660
+ # The password should not be accessible publicly. This way forms using
1661
+ # form_for don't fill the password with the attempted password. To prevent
1662
+ # this we just create this method that is private.
1663
+ #
1664
+ # @api private
1665
+ def define_password_field_reader_methods
1666
+ unless respond_to?(password_field)
1667
+ # Deliberate no-op method, see rationale above.
1668
+ self.class.send(:define_method, password_field) {}
1669
+ end
1648
1670
  self.class.class_eval(
1649
1671
  <<-EOS, __FILE__, __LINE__ + 1
1650
1672
  private
@@ -1655,6 +1677,28 @@ module Authlogic
1655
1677
  )
1656
1678
  end
1657
1679
 
1680
+ def define_password_field_writer_method
1681
+ unless respond_to?("#{password_field}=")
1682
+ self.class.send(:attr_writer, password_field)
1683
+ end
1684
+ end
1685
+
1686
+ # Creating an alias method for the "record" method based on the klass
1687
+ # name, so that we can do:
1688
+ #
1689
+ # session.user
1690
+ #
1691
+ # instead of:
1692
+ #
1693
+ # session.record
1694
+ #
1695
+ # @api private
1696
+ def define_record_alias_method
1697
+ noun = klass_name.demodulize.underscore.to_sym
1698
+ return if respond_to?(noun)
1699
+ self.class.send(:alias_method, noun, :record)
1700
+ end
1701
+
1658
1702
  def destroy_cookie
1659
1703
  controller.cookies.delete cookie_key, domain: controller.cookie_domain
1660
1704
  end
@@ -1700,13 +1744,8 @@ module Authlogic
1700
1744
 
1701
1745
  # @api private
1702
1746
  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
- )
1708
1747
  {
1709
- value: creds.to_s,
1748
+ value: generate_cookie_value.to_s,
1710
1749
  expires: remember_me_until,
1711
1750
  secure: secure,
1712
1751
  httponly: httponly,
@@ -1715,6 +1754,14 @@ module Authlogic
1715
1754
  }
1716
1755
  end
1717
1756
 
1757
+ def generate_cookie_value
1758
+ ::Authlogic::CookieCredentials.new(
1759
+ record.persistence_token,
1760
+ record.send(record.class.primary_key),
1761
+ remember_me? ? remember_me_until : nil
1762
+ )
1763
+ end
1764
+
1718
1765
  # Returns a Proc to be executed by
1719
1766
  # `ActionController::HttpAuthentication::Basic` when credentials are
1720
1767
  # present in the HTTP request.
@@ -1893,6 +1940,18 @@ module Authlogic
1893
1940
  attempted_record.failed_login_count = 0
1894
1941
  end
1895
1942
 
1943
+ # @api private
1944
+ def run_the_after_validation_callbacks
1945
+ run_callbacks(new_session? ? :after_validation_on_create : :after_validation_on_update)
1946
+ run_callbacks(:after_validation)
1947
+ end
1948
+
1949
+ # @api private
1950
+ def run_the_before_validation_callbacks
1951
+ run_callbacks(:before_validation)
1952
+ run_callbacks(new_session? ? :before_validation_on_create : :before_validation_on_update)
1953
+ end
1954
+
1896
1955
  # `args[0]` is the name of a model method, like
1897
1956
  # `find_by_single_access_token` or `find_by_smart_case_login_field`.
1898
1957
  def search_for_record(*args)
@@ -1930,11 +1989,7 @@ module Authlogic
1930
1989
  end
1931
1990
 
1932
1991
  def save_cookie
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
1992
+ cookie_jar[cookie_key] = generate_cookie_for_saving
1938
1993
  end
1939
1994
 
1940
1995
  # @api private
@@ -23,6 +23,10 @@ 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
26
30
  end
27
31
 
28
32
  # A mock of `ActionDispatch::Cookies::SignedKeyRotatingCookieJar`
@@ -35,6 +39,7 @@ module Authlogic
35
39
 
36
40
  def initialize(parent_jar)
37
41
  @parent_jar = parent_jar
42
+ parent_jar.each { |k, v| self[k] = v }
38
43
  end
39
44
 
40
45
  def [](val)
@@ -51,5 +56,35 @@ module Authlogic
51
56
  @parent_jar[key] = options
52
57
  end
53
58
  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
54
89
  end
55
90
  end
@@ -17,6 +17,6 @@ module Authlogic
17
17
  #
18
18
  # @api public
19
19
  def self.gem_version
20
- ::Gem::Version.new("6.0.0")
20
+ ::Gem::Version.new("6.1.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: 6.0.0
4
+ version: 6.1.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-03-24 00:00:00.000000000 Z
13
+ date: 2020-05-08 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: activemodel
@@ -176,14 +176,14 @@ dependencies:
176
176
  requirements:
177
177
  - - "~>"
178
178
  - !ruby/object:Gem::Version
179
- version: 0.67.2
179
+ version: 0.80.1
180
180
  type: :development
181
181
  prerelease: false
182
182
  version_requirements: !ruby/object:Gem::Requirement
183
183
  requirements:
184
184
  - - "~>"
185
185
  - !ruby/object:Gem::Version
186
- version: 0.67.2
186
+ version: 0.80.1
187
187
  - !ruby/object:Gem::Dependency
188
188
  name: rubocop-performance
189
189
  requirement: !ruby/object:Gem::Requirement