jwt_keeper 5.0.1 → 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: 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