authlogic 6.0.0 → 6.1.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 +4 -4
- data/lib/authlogic/acts_as_authentic/password.rb +1 -1
- data/lib/authlogic/crypto_providers/md5/v2.rb +1 -1
- data/lib/authlogic/crypto_providers/sha1/v2.rb +1 -1
- data/lib/authlogic/crypto_providers/sha256/v2.rb +1 -1
- data/lib/authlogic/crypto_providers/sha512/v2.rb +1 -1
- data/lib/authlogic/errors.rb +1 -1
- data/lib/authlogic/session/base.rb +98 -43
- data/lib/authlogic/test_case/mock_cookie_jar.rb +35 -0
- data/lib/authlogic/version.rb +1 -1
- metadata +4 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 88e14eb91ceaf33fca0867ad9816d8ee719215bdb9f5ff26c2c4754d84c82dd8
|
4
|
+
data.tar.gz: 1dfbc1800a0fd0766bde87dfaa4a351b4b377e4240ad81aaa7d163c547d4d2a4
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|
-
#
|
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.
|
23
|
+
digest.unpack1("H*")
|
24
24
|
end
|
25
25
|
|
26
26
|
# 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.
|
46
|
+
digest.unpack1("H*")
|
47
47
|
end
|
48
48
|
|
49
49
|
# Does the crypted password match the tokens? Uses the same tokens that
|
data/lib/authlogic/errors.rb
CHANGED
@@ -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
|
-
|
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.
|
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
|
-
|
1642
|
-
|
1656
|
+
define_password_field_writer_method
|
1657
|
+
define_password_field_reader_methods
|
1658
|
+
end
|
1643
1659
|
|
1644
|
-
|
1645
|
-
|
1646
|
-
|
1647
|
-
|
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:
|
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
|
-
|
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
|
data/lib/authlogic/version.rb
CHANGED
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.
|
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-
|
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.
|
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.
|
186
|
+
version: 0.80.1
|
187
187
|
- !ruby/object:Gem::Dependency
|
188
188
|
name: rubocop-performance
|
189
189
|
requirement: !ruby/object:Gem::Requirement
|