jwt_sessions 2.7.0 → 2.7.4
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/CHANGELOG.md +25 -0
- data/README.md +5 -5
- data/lib/jwt_sessions/refresh_token.rb +1 -1
- data/lib/jwt_sessions/session.rb +2 -2
- data/lib/jwt_sessions/store_adapters/redis_store_adapter.rb +19 -3
- data/lib/jwt_sessions/token.rb +1 -1
- data/lib/jwt_sessions/version.rb +1 -1
- data/lib/jwt_sessions.rb +1 -3
- data/test/units/jwt_sessions/store_adapters/test_redis_store_adapter.rb +0 -2
- data/test/units/jwt_sessions/test_session.rb +4 -4
- data/test/units/jwt_sessions/test_token.rb +5 -5
- metadata +24 -10
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8d8719e8f8b113faf2af6b40f1912d2cf4819527634411ec946a909c67833d31
|
4
|
+
data.tar.gz: f4e46db88c68b110dc78034925fce8193deab286d5703ea81ccfd2740bca9225
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6edb6fb526941fda66abcf0cea4a69904e08f4ca0be03ff7514d8c73e9b9f94cb86cb74a948612d62f3a20a2f91c123bce8c5e342b2600c959f0da90f4e0a918
|
7
|
+
data.tar.gz: b49c7a27800f9b7621565c9e9206a30f547e837668fb0fd683073ff75b062479bb0d51630f28cd165a70ecd767fc44f736795d4d12b480183fe7395b239696ac
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,28 @@
|
|
1
|
+
## 2.7.4 (August 31, 2022)
|
2
|
+
|
3
|
+
Support:
|
4
|
+
|
5
|
+
- compatibility with redis 5.0
|
6
|
+
|
7
|
+
## 2.7.3 (August 26, 2022)
|
8
|
+
|
9
|
+
Support:
|
10
|
+
|
11
|
+
- compatibility with jwt 2.5
|
12
|
+
- add rspec to development deps
|
13
|
+
|
14
|
+
## 2.7.2 (January 24, 2022)
|
15
|
+
|
16
|
+
Bugfixes:
|
17
|
+
|
18
|
+
- 2.7.1 version didn't include the correct patch
|
19
|
+
|
20
|
+
## 2.7.1 (January 22, 2022)
|
21
|
+
|
22
|
+
Bugfixes:
|
23
|
+
|
24
|
+
- Correctly init namespaced refresh tokens when fetching all tokens from Redis
|
25
|
+
|
1
26
|
## 2.7.0 (October 05, 2021)
|
2
27
|
|
3
28
|
Features:
|
data/README.md
CHANGED
@@ -409,11 +409,11 @@ jwt_sessions only uses `exp` claim by default when it decodes tokens and you can
|
|
409
409
|
setting `jwt_options`. You can also specify leeway to account for clock skew.
|
410
410
|
|
411
411
|
```ruby
|
412
|
-
JWTSessions.jwt_options
|
413
|
-
JWTSessions.jwt_options
|
414
|
-
JWTSessions.jwt_options
|
415
|
-
JWTSessions.jwt_options
|
416
|
-
JWTSessions.jwt_options
|
412
|
+
JWTSessions.jwt_options[:verify_iss] = true
|
413
|
+
JWTSessions.jwt_options[:verify_sub] = true
|
414
|
+
JWTSessions.jwt_options[:verify_iat] = true
|
415
|
+
JWTSessions.jwt_options[:verify_aud] = true
|
416
|
+
JWTSessions.jwt_options[:leeway] = 30 # seconds
|
417
417
|
```
|
418
418
|
|
419
419
|
To pass options like `sub`, `aud`, `iss`, or leeways you should specify a method called `token_claims` in your controller.
|
data/lib/jwt_sessions/session.rb
CHANGED
@@ -89,7 +89,7 @@ module JWTSessions
|
|
89
89
|
tokens.each do |token|
|
90
90
|
AccessToken.destroy(token.access_uid, store)
|
91
91
|
# unlink refresh token from the current access token
|
92
|
-
token.update(
|
92
|
+
token.update(0, 0, token.csrf)
|
93
93
|
end.count
|
94
94
|
end
|
95
95
|
|
@@ -208,7 +208,7 @@ module JWTSessions
|
|
208
208
|
def check_access_uid_within_refresh_token
|
209
209
|
uid = retrieve_val_from(payload, :access, "uid", "access uid")
|
210
210
|
access_uid = @_refresh.access_uid
|
211
|
-
return if access_uid
|
211
|
+
return if access_uid == "0"
|
212
212
|
yield @_refresh.uid, @_refresh.access_expiration if access_uid != uid
|
213
213
|
end
|
214
214
|
|
@@ -37,10 +37,15 @@ module JWTSessions
|
|
37
37
|
|
38
38
|
def fetch_refresh(uid, namespace, first_match = false)
|
39
39
|
key = first_match ? first_refresh_key(uid) : full_refresh_key(uid, namespace)
|
40
|
-
|
40
|
+
return {} if key.nil?
|
41
41
|
|
42
|
+
values = storage.hmget(key, *REFRESH_KEYS).compact
|
42
43
|
return {} if values.length != REFRESH_KEYS.length
|
43
|
-
|
44
|
+
|
45
|
+
REFRESH_KEYS
|
46
|
+
.each_with_index
|
47
|
+
.each_with_object({}) { |(key, index), acc| acc[key] = values[index] }
|
48
|
+
.merge({ namespace: namespace })
|
44
49
|
end
|
45
50
|
|
46
51
|
def persist_refresh(uid:, access_expiration:, access_uid:, csrf:, expiration:, namespace: nil)
|
@@ -69,7 +74,10 @@ module JWTSessions
|
|
69
74
|
keys_in_namespace = scan_keys(refresh_key("*", namespace))
|
70
75
|
(keys_in_namespace || []).each_with_object({}) do |key, acc|
|
71
76
|
uid = uid_from_key(key)
|
72
|
-
|
77
|
+
# to be able to properly initialize namespaced tokens extract their namespaces
|
78
|
+
# and pass down to fetch_refresh
|
79
|
+
token_namespace = namespace.to_s.empty? ? namespace_from_key(key) : namespace
|
80
|
+
acc[uid] = fetch_refresh(uid, token_namespace)
|
73
81
|
end
|
74
82
|
end
|
75
83
|
|
@@ -131,6 +139,14 @@ module JWTSessions
|
|
131
139
|
key.split("_").last
|
132
140
|
end
|
133
141
|
|
142
|
+
def namespace_from_key(key)
|
143
|
+
ns_regexp.match(key)&.[](:namespace)
|
144
|
+
end
|
145
|
+
|
146
|
+
def ns_regexp
|
147
|
+
@ns_regexp ||= Regexp.new("#{prefix}_(?<namespace>.+)_refresh")
|
148
|
+
end
|
149
|
+
|
134
150
|
def scan_keys(key_pattern)
|
135
151
|
cursor = 0
|
136
152
|
all_keys = []
|
data/lib/jwt_sessions/token.rb
CHANGED
@@ -13,7 +13,7 @@ module JWTSessions
|
|
13
13
|
end
|
14
14
|
|
15
15
|
def decode(token, claims = {})
|
16
|
-
decode_options = { algorithm: JWTSessions.algorithm }.merge(JWTSessions.jwt_options
|
16
|
+
decode_options = { algorithm: JWTSessions.algorithm }.merge(JWTSessions.jwt_options).merge(claims)
|
17
17
|
JWT.decode(token, JWTSessions.public_key, JWTSessions.validate?, decode_options)
|
18
18
|
rescue JWT::ExpiredSignature => e
|
19
19
|
raise Errors::Expired, e.message
|
data/lib/jwt_sessions/version.rb
CHANGED
data/lib/jwt_sessions.rb
CHANGED
@@ -21,8 +21,6 @@ module JWTSessions
|
|
21
21
|
|
22
22
|
NONE = "none"
|
23
23
|
|
24
|
-
JWTOptions = Struct.new(*JWT::DefaultOptions::DEFAULT_OPTIONS.keys)
|
25
|
-
|
26
24
|
DEFAULT_SETTINGS_KEYS = %i[access_cookie
|
27
25
|
access_exp_time
|
28
26
|
access_header
|
@@ -66,7 +64,7 @@ module JWTSessions
|
|
66
64
|
end
|
67
65
|
|
68
66
|
def jwt_options
|
69
|
-
@jwt_options ||=
|
67
|
+
@jwt_options ||= JWT::Configuration::Container.new.decode.to_h
|
70
68
|
end
|
71
69
|
|
72
70
|
def algorithm=(algo)
|
@@ -24,13 +24,11 @@ class TestRedisStoreAdapter < Minitest::Test
|
|
24
24
|
adapter = JWTSessions::StoreAdapters::RedisStoreAdapter.new(
|
25
25
|
redis_url: "redis://127.0.0.1:6379",
|
26
26
|
ssl_params: { verify_mode: OpenSSL::SSL::VERIFY_NONE },
|
27
|
-
reconnect_delay: 2,
|
28
27
|
timeout: 8
|
29
28
|
)
|
30
29
|
options = adapter.storage.instance_variable_get(:@options)
|
31
30
|
|
32
31
|
assert_equal 8, options[:timeout]
|
33
|
-
assert_equal 2, options[:reconnect_delay]
|
34
32
|
assert_equal 0, options[:ssl_params][:verify_mode]
|
35
33
|
end
|
36
34
|
|
@@ -309,8 +309,8 @@ class TestSession < Minitest::Test
|
|
309
309
|
session.flush_namespaced_access_tokens
|
310
310
|
ruid = session.instance_variable_get(:"@_refresh").uid
|
311
311
|
refresh_token = JWTSessions::RefreshToken.find(ruid, JWTSessions.token_store, namespace)
|
312
|
-
assert_equal "", refresh_token.access_uid
|
313
|
-
assert_equal "", refresh_token.access_expiration
|
312
|
+
assert_equal "0", refresh_token.access_uid
|
313
|
+
assert_equal "0", refresh_token.access_expiration
|
314
314
|
|
315
315
|
# allows to refresh with un-expired but flushed access token payload
|
316
316
|
session.refresh_by_access_payload do
|
@@ -320,8 +320,8 @@ class TestSession < Minitest::Test
|
|
320
320
|
access_token = JWTSessions::AccessToken.find(auid, JWTSessions.token_store)
|
321
321
|
refresh_token = JWTSessions::RefreshToken.find(ruid, JWTSessions.token_store, namespace)
|
322
322
|
|
323
|
-
|
324
|
-
|
323
|
+
assert "0" != access_token.uid
|
324
|
+
assert "0" != access_token.expiration
|
325
325
|
assert_equal access_token.uid.to_s, refresh_token.access_uid
|
326
326
|
assert_equal access_token.expiration.to_s, refresh_token.access_expiration
|
327
327
|
end
|
@@ -24,7 +24,7 @@ class TestToken < Minitest::Test
|
|
24
24
|
|
25
25
|
def teardown
|
26
26
|
JWTSessions.algorithm = JWTSessions::DEFAULT_ALGORITHM
|
27
|
-
JWTSessions.instance_variable_set(:"@jwt_options",
|
27
|
+
JWTSessions.instance_variable_set(:"@jwt_options", JWT::Configuration::Container.new.decode.to_h)
|
28
28
|
end
|
29
29
|
|
30
30
|
def test_rsa_token_decode
|
@@ -73,7 +73,7 @@ class TestToken < Minitest::Test
|
|
73
73
|
|
74
74
|
def test_token_sub_claim
|
75
75
|
JWTSessions.encryption_key = "abcdefghijklmnopqrstuvwxyzABCDEF"
|
76
|
-
JWTSessions.jwt_options
|
76
|
+
JWTSessions.jwt_options[:verify_sub] = true
|
77
77
|
token = JWTSessions::Token.encode(payload.merge(sub: "subject"))
|
78
78
|
decoded = JWTSessions::Token.decode(token, { sub: "subject" }).first
|
79
79
|
assert_equal payload["user_id"], decoded["user_id"]
|
@@ -85,7 +85,7 @@ class TestToken < Minitest::Test
|
|
85
85
|
|
86
86
|
def test_token_iss_claim
|
87
87
|
JWTSessions.encryption_key = "abcdefghijklmnopqrstuvwxyzABCDEF"
|
88
|
-
JWTSessions.jwt_options
|
88
|
+
JWTSessions.jwt_options[:verify_iss] = true
|
89
89
|
token = JWTSessions::Token.encode(payload.merge(iss: "Me"))
|
90
90
|
decoded = JWTSessions::Token.decode(token, { iss: "Me" }).first
|
91
91
|
assert_equal payload["user_id"], decoded["user_id"]
|
@@ -97,7 +97,7 @@ class TestToken < Minitest::Test
|
|
97
97
|
|
98
98
|
def test_token_aud_claim
|
99
99
|
JWTSessions.encryption_key = "abcdefghijklmnopqrstuvwxyzABCDEF"
|
100
|
-
JWTSessions.jwt_options
|
100
|
+
JWTSessions.jwt_options[:verify_aud] = true
|
101
101
|
token = JWTSessions::Token.encode(payload.merge(aud: ["young", "old"]))
|
102
102
|
decoded = JWTSessions::Token.decode(token, { aud: ["young"] }).first
|
103
103
|
assert_equal payload["user_id"], decoded["user_id"]
|
@@ -109,7 +109,7 @@ class TestToken < Minitest::Test
|
|
109
109
|
|
110
110
|
def test_token_leeway_decode
|
111
111
|
JWTSessions.encryption_key = "abcdefghijklmnopqrstuvwxyzABCDEF"
|
112
|
-
JWTSessions.jwt_options
|
112
|
+
JWTSessions.jwt_options[:leeway] = 50
|
113
113
|
token = JWTSessions::Token.encode(payload.merge("exp" => Time.now.to_i - 20))
|
114
114
|
decoded = JWTSessions::Token.decode(token).first
|
115
115
|
assert_equal payload["user_id"], decoded["user_id"]
|
metadata
CHANGED
@@ -1,22 +1,22 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: jwt_sessions
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.7.
|
4
|
+
version: 2.7.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Yulia Oletskaya
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2022-08-31 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: jwt
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- - "
|
17
|
+
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: 2.
|
19
|
+
version: '2.5'
|
20
20
|
- - "<"
|
21
21
|
- !ruby/object:Gem::Version
|
22
22
|
version: '3'
|
@@ -24,9 +24,9 @@ dependencies:
|
|
24
24
|
prerelease: false
|
25
25
|
version_requirements: !ruby/object:Gem::Requirement
|
26
26
|
requirements:
|
27
|
-
- - "
|
27
|
+
- - "~>"
|
28
28
|
- !ruby/object:Gem::Version
|
29
|
-
version: 2.
|
29
|
+
version: '2.5'
|
30
30
|
- - "<"
|
31
31
|
- !ruby/object:Gem::Version
|
32
32
|
version: '3'
|
@@ -58,6 +58,20 @@ dependencies:
|
|
58
58
|
- - "~>"
|
59
59
|
- !ruby/object:Gem::Version
|
60
60
|
version: '12.3'
|
61
|
+
- !ruby/object:Gem::Dependency
|
62
|
+
name: rspec
|
63
|
+
requirement: !ruby/object:Gem::Requirement
|
64
|
+
requirements:
|
65
|
+
- - "~>"
|
66
|
+
- !ruby/object:Gem::Version
|
67
|
+
version: '3.11'
|
68
|
+
type: :development
|
69
|
+
prerelease: false
|
70
|
+
version_requirements: !ruby/object:Gem::Requirement
|
71
|
+
requirements:
|
72
|
+
- - "~>"
|
73
|
+
- !ruby/object:Gem::Version
|
74
|
+
version: '3.11'
|
61
75
|
description: XSS/CSRF safe JWT auth designed for SPA
|
62
76
|
email: yulia.oletskaya@gmail.com
|
63
77
|
executables: []
|
@@ -98,7 +112,7 @@ metadata:
|
|
98
112
|
changelog_uri: https://github.com/tuwukee/jwt_sessions/blob/master/CHANGELOG.md
|
99
113
|
source_code_uri: https://github.com/tuwukee/jwt_sessions
|
100
114
|
bug_tracker_uri: https://github.com/tuwukee/jwt_sessions/issues
|
101
|
-
post_install_message:
|
115
|
+
post_install_message:
|
102
116
|
rdoc_options: []
|
103
117
|
require_paths:
|
104
118
|
- lib
|
@@ -113,8 +127,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
113
127
|
- !ruby/object:Gem::Version
|
114
128
|
version: '0'
|
115
129
|
requirements: []
|
116
|
-
rubygems_version: 3.
|
117
|
-
signing_key:
|
130
|
+
rubygems_version: 3.0.3.1
|
131
|
+
signing_key:
|
118
132
|
specification_version: 4
|
119
133
|
summary: JWT Sessions
|
120
134
|
test_files:
|