jwt_sessions 2.6.0 → 2.7.3

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: 8a485796c7aa19c00c79992111ed0135c0ec93af6e88aff80b233be779bb2301
4
- data.tar.gz: d0b89a924589aa8450cfcaefb2061674db4d61cb32ed5ace92f1cab021db1fb1
3
+ metadata.gz: ed69732617f15f4c07c0fb37d3ad938807224b729f136d24755a90f58b7b28ab
4
+ data.tar.gz: 27bee3f1c2bd4b099b0dadea703143d70e6abf1aaa6e5556f67515dfbc6f2e5b
5
5
  SHA512:
6
- metadata.gz: e0bef3934719502d51f1299b210fad2df87360ef91cc3471384c3840870f3d548f43c5c5c1ff89a33e9e8847b706f9b7e1d2c240f288a21a16533369d8b0fce5
7
- data.tar.gz: cd8b450b1a09e13290e3ac6ec5bcd17cf52c7314f01044ca1c2888321816585ff27eb7ae7b3935f5aa388fec3c11d9b8ebb0fe2c5fdde5a99cbc390932c4a646
6
+ metadata.gz: a0a81d8d8013a1393b441ddd15ec34fb57ceb0bd3198f9ee4a2554dff653efbe4379ad6992d1a8678895e0391f45626068a2f16b422ad8c658b7a086a08241d3
7
+ data.tar.gz: 46e744a4512da3d90b54f6552c42f35c7b3b3d25a9d73292058ac5782102ed9d9c77ac6a734a865b40e2fcccd675257cc5c41d27be45bd5fde758e8d6c97537f
data/CHANGELOG.md CHANGED
@@ -1,3 +1,31 @@
1
+ ## 2.7.3 (August 26, 2022)
2
+
3
+ Bugfixes:
4
+
5
+ - compatibility with jwt 2.5
6
+
7
+ Support:
8
+
9
+ - add rspec to development deps
10
+
11
+ ## 2.7.2 (January 24, 2022)
12
+
13
+ Bugfixes:
14
+
15
+ - 2.7.1 version didn't include the correct patch
16
+
17
+ ## 2.7.1 (January 22, 2022)
18
+
19
+ Bugfixes:
20
+
21
+ - Correctly init namespaced refresh tokens when fetching all tokens from Redis
22
+
23
+ ## 2.7.0 (October 05, 2021)
24
+
25
+ Features:
26
+
27
+ - added redis_client setting to JWTSessions::StoreAdapters::RedisStoreAdapter
28
+
1
29
  ## 2.6.0 (June 01, 2021)
2
30
 
3
31
  Features:
data/README.md CHANGED
@@ -153,11 +153,11 @@ end
153
153
  ```
154
154
 
155
155
  Specify an encryption key for JSON Web Tokens in `config/initializers/jwt_session.rb` \
156
- It is advisable to store the key itself within the app secrets.
156
+ It is advisable to store the key itself in a secure way, f.e. within app credentials.
157
157
 
158
158
  ```ruby
159
159
  JWTSessions.algorithm = "HS256"
160
- JWTSessions.encryption_key = Rails.application.secrets.secret_jwt_encryption_key
160
+ JWTSessions.encryption_key = Rails.application.credentials.secret_jwt_encryption_key
161
161
  ```
162
162
 
163
163
  Most of the encryption algorithms require private and public keys to sign a token. However, HMAC requires only a single key and you can use the `encryption_key` shortcut to sign the token. For other algorithms you must specify private and public keys separately.
@@ -378,6 +378,12 @@ JWTSessions.token_store = :redis, {
378
378
  }
379
379
  ```
380
380
 
381
+ If you already have a configured Redis client, you can pass it among the options to reduce opened connections to a Redis server:
382
+
383
+ ```ruby
384
+ JWTSessions.token_store = :redis, {redis_client: Redis.current}
385
+ ```
386
+
381
387
  ##### JWT signature
382
388
 
383
389
  ```ruby
@@ -61,7 +61,7 @@ module JWTSessions
61
61
  token_attrs[:access_uid],
62
62
  token_attrs[:access_expiration],
63
63
  store,
64
- namespace: namespace,
64
+ namespace: token_attrs[:namespace] || namespace,
65
65
  payload: {},
66
66
  uid: uid,
67
67
  expiration: token_attrs[:expiration]
@@ -7,16 +7,20 @@ module JWTSessions
7
7
 
8
8
  REFRESH_KEYS = %i[csrf access_uid access_expiration expiration].freeze
9
9
 
10
- def initialize(token_prefix: JWTSessions.token_prefix, **options)
10
+ def initialize(token_prefix: JWTSessions.token_prefix, redis_client: nil, **options)
11
11
  @prefix = token_prefix
12
12
 
13
- begin
14
- require "redis"
15
- @storage = configure_redis_client(**options)
16
- rescue LoadError => e
17
- msg = "Could not load the 'redis' gem, please add it to your gemfile or " \
18
- "configure a different adapter (e.g. JWTSessions.store_adapter = :memory)"
19
- raise e.class, msg, e.backtrace
13
+ if redis_client
14
+ @storage = redis_client
15
+ else
16
+ begin
17
+ require "redis"
18
+ @storage = configure_redis_client(**options)
19
+ rescue LoadError => e
20
+ msg = "Could not load the 'redis' gem, please add it to your gemfile or " \
21
+ "configure a different adapter (e.g. JWTSessions.store_adapter = :memory)"
22
+ raise e.class, msg, e.backtrace
23
+ end
20
24
  end
21
25
  end
22
26
 
@@ -36,7 +40,10 @@ module JWTSessions
36
40
  values = storage.hmget(key, *REFRESH_KEYS).compact
37
41
 
38
42
  return {} if values.length != REFRESH_KEYS.length
39
- REFRESH_KEYS.each_with_index.each_with_object({}) { |(key, index), acc| acc[key] = values[index] }
43
+ REFRESH_KEYS
44
+ .each_with_index
45
+ .each_with_object({}) { |(key, index), acc| acc[key] = values[index] }
46
+ .merge({ namespace: namespace })
40
47
  end
41
48
 
42
49
  def persist_refresh(uid:, access_expiration:, access_uid:, csrf:, expiration:, namespace: nil)
@@ -65,7 +72,10 @@ module JWTSessions
65
72
  keys_in_namespace = scan_keys(refresh_key("*", namespace))
66
73
  (keys_in_namespace || []).each_with_object({}) do |key, acc|
67
74
  uid = uid_from_key(key)
68
- acc[uid] = fetch_refresh(uid, namespace)
75
+ # to be able to properly initialize namespaced tokens extract their namespaces
76
+ # and pass down to fetch_refresh
77
+ token_namespace = namespace.to_s.empty? ? namespace_from_key(key) : namespace
78
+ acc[uid] = fetch_refresh(uid, token_namespace)
69
79
  end
70
80
  end
71
81
 
@@ -127,6 +137,14 @@ module JWTSessions
127
137
  key.split("_").last
128
138
  end
129
139
 
140
+ def namespace_from_key(key)
141
+ ns_regexp.match(key)&.[](:namespace)
142
+ end
143
+
144
+ def ns_regexp
145
+ @ns_regexp ||= Regexp.new("#{prefix}_(?<namespace>.+)_refresh")
146
+ end
147
+
130
148
  def scan_keys(key_pattern)
131
149
  cursor = 0
132
150
  all_keys = []
@@ -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.to_h).merge(claims)
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
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module JWTSessions
4
- VERSION = "2.6.0"
4
+ VERSION = "2.7.3"
5
5
  end
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 ||= JWTOptions.new(*JWT::DefaultOptions::DEFAULT_OPTIONS.values)
67
+ @jwt_options ||= JWT::Configuration::Container.new.decode.to_h
70
68
  end
71
69
 
72
70
  def algorithm=(algo)
@@ -77,4 +77,10 @@ class TestRedisStoreAdapter < Minitest::Test
77
77
  adapter = JWTSessions::StoreAdapters::RedisStoreAdapter.new
78
78
  assert_equal "redis://127.0.0.2:6322/0", adapter.storage.connection[:id]
79
79
  end
80
+
81
+ def test_configuration_via_redis_client
82
+ client = Object.new
83
+ adapter = JWTSessions::StoreAdapters::RedisStoreAdapter.new(redis_client: client)
84
+ assert_equal client, adapter.storage
85
+ end
80
86
  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", JWTSessions::JWTOptions.new(*JWT::DefaultOptions::DEFAULT_OPTIONS.values))
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.verify_sub = true
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.verify_iss = true
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.verify_aud = true
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.leeway = 50
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.6.0
4
+ version: 2.7.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Yulia Oletskaya
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-06-01 00:00:00.000000000 Z
11
+ date: 2022-08-26 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.2.3
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.2.3
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: []
@@ -113,7 +127,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
113
127
  - !ruby/object:Gem::Version
114
128
  version: '0'
115
129
  requirements: []
116
- rubygems_version: 3.0.3
130
+ rubygems_version: 3.0.3.1
117
131
  signing_key:
118
132
  specification_version: 4
119
133
  summary: JWT Sessions