jwt_keeper 5.0.1 → 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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 4ce4912150544b5d9944105ef36f43022c480578eb922d6a5f001c2044a53de6
4
- data.tar.gz: 8f1ef7fa13008c88133aac5babbf8622070db55ac3ea49eb45ef515c23e1751b
3
+ metadata.gz: d6ad212dc01831b9bae31adab98ba2edbe1fd803923e32eb9817e2b96515c706
4
+ data.tar.gz: c6ef8deb150ffeed569d4da108ac745a907c8bfc065c5564cd49b6aff978f00e
5
5
  SHA512:
6
- metadata.gz: df62c535a49f323772ee6b7fe995ada5a1906c1ac3d80916949a30c7030c058eea47105368edc97351c1853bdf11cf6f561452e21d71d2d79f32246964acf3b5
7
- data.tar.gz: b03abb09f142d3d5b27706b9792be412ea8c5698b4c7c385a343f15cd147cf9b71202c32b24b7dbbd892a9ac054be6918b9562498f7f8a347d30d054d54ddc19
6
+ metadata.gz: 87f73d56ceb956a78337d4df685ac8fb86b6eda03046ba137f92f689eb10b5485103f9ea003ccdb7643149b4e74722d674571ec698e8eed40eb0a2d3b1b2feb2
7
+ data.tar.gz: 7695c3ce514f9e150d492766b90e7b76e04cb5c496e422aa265d6f255a311e72d986319f169fc0bb5919a42fbe4cb364da700bfeb42fb947bfdb9a6841c5c280
data/README.md CHANGED
@@ -40,6 +40,7 @@ class ApplicationController < ActionController::Base
40
40
  include JWTKeeper::Controller
41
41
 
42
42
  before_action :require_authentication
43
+ rescue_from JWTKeeper::NotAuthenticatedError, with: :not_authenticated
43
44
 
44
45
  def not_authenticated
45
46
  # Overload to return status 401
data/jwt_keeper.gemspec CHANGED
@@ -28,8 +28,9 @@ Gem::Specification.new do |spec|
28
28
  spec.add_development_dependency 'rspec', '~> 3.8'
29
29
  spec.add_development_dependency 'fuubar'
30
30
  spec.add_development_dependency 'simplecov'
31
+ spec.add_development_dependency 'redis-client'
32
+ spec.add_development_dependency 'redis'
31
33
 
32
- spec.add_dependency 'redis'
33
34
  spec.add_dependency 'rails'
34
35
  spec.add_dependency 'activesupport'
35
36
  spec.add_dependency 'jwt', '>= 1.5'
@@ -27,10 +27,8 @@ JWTKeeper.configure do |config|
27
27
  # config.audience = 'example.com'
28
28
 
29
29
  # the location of redis config file
30
- # config.redis_connection = Redis.new(connection_options)
31
- # config.redis_connection = ConnectionPool.new(size: ENV.fetch('RAILS_MAX_THREADS', 5)) do
32
- # Redis.new(url: ENV['REDISCLOUD_URL'] || 'redis://localhost:6379/')
33
- # end
30
+ # config.redis_connection = RedisClient.new(connection_options)
31
+ # config.redis_connection = RedisClient.config(connection_options).new_pool(size: ENV.fetch('RAILS_MAX_THREADS', 5))
34
32
 
35
33
  # A unique idenfitier for the token version.
36
34
  # config.version = 1
@@ -10,7 +10,7 @@ module JWTKeeper
10
10
 
11
11
  if token.nil?
12
12
  clear_authentication_token
13
- return not_authenticated
13
+ raise JWTKeeper::NotAuthenticatedError
14
14
  end
15
15
 
16
16
  if token.version_mismatch? || token.pending?
@@ -51,13 +51,6 @@ module JWTKeeper
51
51
  @authentication_token = nil
52
52
  end
53
53
 
54
- # The default action for denying non-authenticated connections.
55
- # You can override this method in your controllers
56
- # @return [void]
57
- def not_authenticated
58
- redirect_to root_path
59
- end
60
-
61
54
  # The default action for accepting authenticated connections.
62
55
  # You can override this method in your controllers
63
56
  # @return [void]
@@ -27,27 +27,40 @@ module JWTKeeper
27
27
 
28
28
  # @!visibility private
29
29
  def set_with_expiry(jti, seconds, type)
30
- redis = JWTKeeper.configuration.redis_connection
31
-
32
- if redis.is_a?(Redis)
33
- redis.setex(jti, seconds, type)
34
- elsif defined?(ConnectionPool) && redis.is_a?(ConnectionPool)
35
- redis.with { |conn| conn.setex(jti, seconds, type) }
36
- else
37
- throw 'Bad Redis Connection'
30
+ with_redis do |redis|
31
+ if redis.respond_to?(:call) # For RedisClient
32
+ redis.call('SETEX', jti, seconds, type)
33
+ elsif redis.respond_to?(:setex) # For Redis
34
+ redis.setex(jti, seconds, type)
35
+ else
36
+ throw 'Bad Redis Connection'
37
+ end
38
38
  end
39
39
  end
40
40
 
41
41
  # @!visibility private
42
42
  def get(jti)
43
+ with_redis do |redis|
44
+ if redis.respond_to?(:call) # For RedisClient
45
+ redis.call('GET', jti)
46
+ elsif redis.respond_to?(:get) # For Redis
47
+ redis.get(jti)
48
+ else
49
+ throw 'Bad Redis Connection'
50
+ end
51
+ end
52
+ end
53
+
54
+ # @!visibility private
55
+ def with_redis
43
56
  redis = JWTKeeper.configuration.redis_connection
44
57
 
45
- if redis.is_a?(Redis)
46
- redis.get(jti)
47
- elsif defined?(ConnectionPool) && redis.is_a?(ConnectionPool)
48
- redis.with { |conn| conn.get(jti) }
58
+ if redis.respond_to?(:with)
59
+ redis.with do |conn|
60
+ yield conn
61
+ end
49
62
  else
50
- throw 'Bad Redis Connection'
63
+ yield(redis)
51
64
  end
52
65
  end
53
66
  end
@@ -1,4 +1,7 @@
1
1
  module JWTKeeper
2
+ # the session is invalid
3
+ class NotAuthenticatedError < StandardError; end
4
+
2
5
  # The token is invalid
3
6
  class InvalidTokenError < StandardError; end
4
7
 
@@ -1,4 +1,4 @@
1
1
  # Gem Version
2
2
  module JWTKeeper
3
- VERSION = '5.0.1'.freeze
3
+ VERSION = '6.1.0'.freeze
4
4
  end
@@ -52,7 +52,6 @@ RSpec.describe JWTKeeper do
52
52
  it { is_expected.to respond_to(:read_authentication_token) }
53
53
  it { is_expected.to respond_to(:write_authentication_token) }
54
54
  it { is_expected.to respond_to(:clear_authentication_token) }
55
- it { is_expected.to respond_to(:not_authenticated) }
56
55
  it { is_expected.to respond_to(:authenticated) }
57
56
  it { is_expected.to respond_to(:regenerate_claims) }
58
57
  end
@@ -77,13 +76,9 @@ RSpec.describe JWTKeeper do
77
76
 
78
77
  context 'with expired token' do
79
78
  let(:token) { JWTKeeper::Token.create(exp: 3.hours.ago) }
80
- before do
81
- allow(test_controller).to receive(:not_authenticated)
82
- end
83
79
 
84
- it 'calls not_authenticated' do
85
- subject.require_authentication
86
- expect(subject).to have_received(:not_authenticated).once
80
+ it 'raises NotAuthenticated' do
81
+ expect { subject.require_authentication }.to raise_error(JWTKeeper::NotAuthenticatedError)
87
82
  end
88
83
  end
89
84
 
@@ -162,16 +157,5 @@ RSpec.describe JWTKeeper do
162
157
  expect(subject.response.headers['Authorization']).to be_nil
163
158
  end
164
159
  end
165
-
166
- describe '#not_authenticated' do
167
- before do
168
- allow(test_controller).to receive(:redirect_to)
169
- end
170
-
171
- it 'it calls redirect_to' do
172
- subject.not_authenticated
173
- expect(subject).to have_received(:redirect_to).with('/')
174
- end
175
- end
176
160
  end
177
161
  end
@@ -1,70 +1,107 @@
1
1
  RSpec.describe JWTKeeper::Datastore do
2
- include_context 'initialize config'
3
2
  let(:jti) { SecureRandom.uuid }
4
3
 
5
- describe '.rotate' do
6
- before { described_class.rotate(jti, 30) }
4
+ shared_examples 'Datastore Specs' do
5
+ describe '.rotate' do
6
+ before { described_class.rotate(jti, 30) }
7
7
 
8
- it 'stores a token_id with a soft expiry' do
9
- expect(described_class.send(:get, jti)).to eq 'soft'
8
+ it 'stores a token_id with a soft expiry' do
9
+ expect(described_class.send(:get, jti)).to eq 'soft'
10
+ end
10
11
  end
11
- end
12
12
 
13
- describe '.pending?' do
14
- context 'with a missing token' do
15
- it 'returns false' do
16
- expect(described_class.pending?(jti)).to be false
13
+ describe '.pending?' do
14
+ context 'with a missing token' do
15
+ it 'returns false' do
16
+ expect(described_class.pending?(jti)).to be false
17
+ end
17
18
  end
18
- end
19
19
 
20
- context 'with a revoked token' do
21
- before { described_class.revoke(jti, 30) }
20
+ context 'with a revoked token' do
21
+ before { described_class.revoke(jti, 30) }
22
22
 
23
- it 'returns false' do
24
- expect(described_class.pending?(jti)).to be false
23
+ it 'returns false' do
24
+ expect(described_class.pending?(jti)).to be false
25
+ end
25
26
  end
26
- end
27
27
 
28
- context 'with a pending token' do
29
- before { described_class.rotate(jti, 30) }
28
+ context 'with a pending token' do
29
+ before { described_class.rotate(jti, 30) }
30
30
 
31
- it 'returns true' do
32
- expect(described_class.pending?(jti)).to be true
31
+ it 'returns true' do
32
+ expect(described_class.pending?(jti)).to be true
33
+ end
33
34
  end
34
35
  end
35
- end
36
36
 
37
- describe '.revoke' do
38
- before do
39
- described_class.revoke(jti, 30)
40
- end
37
+ describe '.revoke' do
38
+ before do
39
+ described_class.revoke(jti, 30)
40
+ end
41
41
 
42
- it 'stores a token_id with a hard expiry' do
43
- expect(described_class.send(:get, jti)).to eq 'hard'
42
+ it 'stores a token_id with a hard expiry' do
43
+ expect(described_class.send(:get, jti)).to eq 'hard'
44
+ end
44
45
  end
45
- end
46
46
 
47
- describe '.revoked?' do
48
- context 'with a missing token' do
49
- it 'returns false' do
50
- expect(described_class.revoked?(jti)).to be false
47
+ describe '.revoked?' do
48
+ context 'with a missing token' do
49
+ it 'returns false' do
50
+ expect(described_class.revoked?(jti)).to be false
51
+ end
52
+ end
53
+
54
+ context 'with a revoked token' do
55
+ before { described_class.revoke(jti, 30) }
56
+
57
+ it 'returns true' do
58
+ expect(described_class.revoked?(jti)).to be true
59
+ end
51
60
  end
52
- end
53
61
 
54
- context 'with a revoked token' do
55
- before { described_class.revoke(jti, 30) }
62
+ context 'with a pending token' do
63
+ before { described_class.rotate(jti, 30) }
56
64
 
57
- it 'returns true' do
58
- expect(described_class.revoked?(jti)).to be true
65
+ it 'returns false' do
66
+ expect(described_class.revoked?(jti)).to be false
67
+ end
59
68
  end
60
69
  end
70
+ end
61
71
 
62
- context 'with a pending token' do
63
- before { described_class.rotate(jti, 30) }
72
+ context 'with Redis' do
73
+ include_context 'initialize config'
74
+
75
+ let(:redis_connection) { Redis.new(url: ENV['REDIS_URL']) }
76
+
77
+ include_examples 'Datastore Specs'
78
+ end
79
+
80
+ context 'with Redis Connection Pool' do
81
+ include_context 'initialize config'
64
82
 
65
- it 'returns false' do
66
- expect(described_class.revoked?(jti)).to be false
83
+ let(:redis_connection) do
84
+ ConnectionPool.new(size: ENV.fetch('RAILS_MAX_THREADS', 5)) do
85
+ Redis.new(url: ENV['REDISCLOUD_URL'] || 'redis://localhost:6379/')
67
86
  end
68
87
  end
88
+
89
+ include_examples 'Datastore Specs'
90
+ end
91
+
92
+ context 'with RedisClient' do
93
+ include_context 'initialize config'
94
+
95
+ let(:redis_connection) { RedisClient.new(url: ENV['REDIS_URL']) }
96
+
97
+ include_examples 'Datastore Specs'
98
+ end
99
+
100
+ context 'with RedisClient Pool' do
101
+ include_context 'initialize config'
102
+
103
+ let(:redis_connection) { RedisClient.config(url: ENV['REDIS_URL']).new_pool(size: ENV.fetch('RAILS_MAX_THREADS', 5)) }
104
+
105
+ include_examples 'Datastore Specs'
69
106
  end
70
107
  end
data/spec/spec_helper.rb CHANGED
@@ -39,6 +39,7 @@ RSpec.configure do |config|
39
39
  end
40
40
 
41
41
  RSpec.shared_context 'initialize config' do
42
+ let(:redis_connection) { RedisClient.new(url: ENV['REDIS_URL']) }
42
43
  let(:config) do
43
44
  {
44
45
  algorithm: 'HS256',
@@ -46,12 +47,13 @@ RSpec.shared_context 'initialize config' do
46
47
  expiry: 24.hours,
47
48
  issuer: 'api.example.com',
48
49
  audience: 'example.com',
49
- redis_connection: Redis.new(url: ENV['REDIS_URL']),
50
+ redis_connection: redis_connection,
50
51
  version: nil,
51
52
  cookie_lock: false
52
53
  }
53
54
  end
54
55
 
56
+
55
57
  before(:each) do
56
58
  JWTKeeper.configure(JWTKeeper::Configuration.new(config))
57
59
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: jwt_keeper
3
3
  version: !ruby/object:Gem::Version
4
- version: 5.0.1
4
+ version: 6.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - David Rivera
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2021-03-02 00:00:00.000000000 Z
12
+ date: 2023-02-09 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: bundler
@@ -137,6 +137,20 @@ dependencies:
137
137
  - - ">="
138
138
  - !ruby/object:Gem::Version
139
139
  version: '0'
140
+ - !ruby/object:Gem::Dependency
141
+ name: redis-client
142
+ requirement: !ruby/object:Gem::Requirement
143
+ requirements:
144
+ - - ">="
145
+ - !ruby/object:Gem::Version
146
+ version: '0'
147
+ type: :development
148
+ prerelease: false
149
+ version_requirements: !ruby/object:Gem::Requirement
150
+ requirements:
151
+ - - ">="
152
+ - !ruby/object:Gem::Version
153
+ version: '0'
140
154
  - !ruby/object:Gem::Dependency
141
155
  name: redis
142
156
  requirement: !ruby/object:Gem::Requirement
@@ -144,7 +158,7 @@ dependencies:
144
158
  - - ">="
145
159
  - !ruby/object:Gem::Version
146
160
  version: '0'
147
- type: :runtime
161
+ type: :development
148
162
  prerelease: false
149
163
  version_requirements: !ruby/object:Gem::Requirement
150
164
  requirements:
@@ -249,7 +263,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
249
263
  - !ruby/object:Gem::Version
250
264
  version: '0'
251
265
  requirements: []
252
- rubygems_version: 3.2.3
266
+ rubygems_version: 3.4.1
253
267
  signing_key:
254
268
  specification_version: 4
255
269
  summary: JWT for Rails made easy