jwt_keeper 3.1.0 → 5.0.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
- SHA1:
3
- metadata.gz: 28d115e2b0772731d3b5fefce241da3f8be40c4a
4
- data.tar.gz: 0507622c05cf4a5b93be4035b77a15424b89e4b1
2
+ SHA256:
3
+ metadata.gz: '0781e4deae7439d13aadad57e1c3fa6dd224cd791c90672ee647815af2ebf70a'
4
+ data.tar.gz: 9be046da200f6d6f6e17c2f747c398e7b5abe13e1fe1517a7b288d9dec468ea8
5
5
  SHA512:
6
- metadata.gz: fd49463a7660666d28507b5b6ae9345cea21c7baec56fdc904d6f683ec8bbcafa354c29113b658798c1531129e34b12e419ff6b1324af9f83b60484341b30c9c
7
- data.tar.gz: 61fcefd218432ca6e2de3e6b6bfde1a0bdda28a8414baefe63ce0ef6a03a1c20e444c9d79b3ad5e95d5e841530d2d1e701a33157d08c468e2dd6f94a6fce2caf
6
+ metadata.gz: a58d6573eb512abce406c8726a15eebac3136d5c05b5305c9b5cd8d040f2facd6c050071d86a8bb885523485ea6217b2596f6bc14771d0e5d0c878278b0bdd66
7
+ data.tar.gz: 6a1086f9933a1daf4fc48e2ea7af4c2fe8c7b26c248a84f096cde00e9e2af3302258a894cdcb88211a281756a2b847713d6a6bd87233b66d1ca10fe64b3b6459
data/.travis.yml CHANGED
@@ -1,19 +1,26 @@
1
1
  language: ruby
2
2
  cache: bundler
3
3
  rvm:
4
- - 2.2.5
5
- - 2.3.1
4
+ - 2.4.5
5
+ - 2.5.3
6
+ - 2.6.1
6
7
  - ruby-head
7
8
  matrix:
8
9
  allow_failures:
9
10
  - rvm: ruby-head
10
- addons:
11
- code_climate:
12
- repo_token: f69bb189f348c1d7992d8ed8690d0a2c9c885c1aac45e2f4d48732034592b37b
13
11
  services:
14
12
  - redis-server
15
13
  env:
16
14
  global:
17
15
  - REDIS_URL=redis://localhost:6379
16
+ - CC_TEST_REPORTER_ID=f69bb189f348c1d7992d8ed8690d0a2c9c885c1aac45e2f4d48732034592b37b
17
+ before_script:
18
+ - curl -L https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64 > ./cc-test-reporter
19
+ - chmod +x ./cc-test-reporter
20
+ - ./cc-test-reporter before-build
21
+ script:
22
+ - bundle exec rspec
23
+ after_script:
24
+ - ./cc-test-reporter after-build --exit-code $TRAVIS_TEST_RESULT
18
25
  notifications:
19
26
  email: false
data/Gemfile CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  source 'https://rubygems.org'
2
4
 
3
5
  gemspec
data/README.md CHANGED
@@ -32,11 +32,13 @@ raw_token_string = token.to_jwt
32
32
  The designed rails token flow is to receive and respond to requests with the token being present in the `Authorization` part of the header. This is to allow us to seamlessly rotate the tokens on the fly without having to rebuff the request as part of the user flow. Automatic rotation happens as part of the `require_authentication` action, meaning that you will always get the latest token data as created by `generate_claims` in your controllers. This new token is added to the response with the `write_authentication_token` action.
33
33
 
34
34
  ```bash
35
- rake generate jwt_keeper:install
35
+ rails generate jwt_keeper:install
36
36
  ```
37
37
 
38
38
  ```ruby
39
39
  class ApplicationController < ActionController::Base
40
+ include JWTKeeper::Controller
41
+
40
42
  before_action :require_authentication
41
43
 
42
44
  def not_authenticated
data/Rakefile CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'bundler/gem_tasks'
2
4
  require 'rspec/core/rake_task'
3
5
 
data/jwt_keeper.gemspec CHANGED
@@ -23,14 +23,14 @@ Gem::Specification.new do |spec|
23
23
  spec.add_development_dependency 'yard'
24
24
  spec.add_development_dependency 'rubocop'
25
25
  spec.add_development_dependency 'dotenv'
26
+ spec.add_development_dependency 'pry'
26
27
 
27
- spec.add_development_dependency 'rspec', '~> 3.4'
28
+ spec.add_development_dependency 'rspec', '~> 3.8'
28
29
  spec.add_development_dependency 'fuubar'
29
30
  spec.add_development_dependency 'simplecov'
30
- spec.add_development_dependency 'codeclimate-test-reporter'
31
31
 
32
- spec.add_dependency 'redis', '~> 3.3'
33
- spec.add_dependency 'rails', '~> 5.0'
34
- spec.add_dependency 'activesupport', '~> 5.0'
35
- spec.add_dependency 'jwt', '~> 1.5'
32
+ spec.add_dependency 'redis'
33
+ spec.add_dependency 'rails'
34
+ spec.add_dependency 'activesupport'
35
+ spec.add_dependency 'jwt', '>= 1.5'
36
36
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  JWTKeeper.configure do |config|
2
4
  # The time to expire for the tokens
3
5
  # config.expiry = 1.hour
@@ -26,6 +28,9 @@ JWTKeeper.configure do |config|
26
28
 
27
29
  # the location of redis config file
28
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
29
34
 
30
35
  # A unique idenfitier for the token version.
31
36
  # config.version = 1
data/lib/jwt_keeper.rb CHANGED
@@ -23,6 +23,4 @@ module JWTKeeper
23
23
 
24
24
  @configuration = new_configuration.freeze
25
25
  end
26
-
27
- require 'jwt_keeper/engine' if defined?(Rails)
28
26
  end
@@ -29,7 +29,7 @@ module JWTKeeper
29
29
  @authentication_token ||=
30
30
  JWTKeeper::Token.find(
31
31
  request.headers['Authorization'].split.last,
32
- cookies.signed['jwt_keeper']
32
+ cookie_secret: defined?(cookies) && cookies.signed['jwt_keeper']
33
33
  )
34
34
  end
35
35
 
@@ -39,7 +39,7 @@ module JWTKeeper
39
39
  def write_authentication_token(token)
40
40
  return clear_authentication_token if token.nil?
41
41
  response.headers['Authorization'] = "Bearer #{token.to_jwt}"
42
- cookies.signed['jwt_keeper'] = token.to_cookie
42
+ defined?(cookies) && cookies.signed['jwt_keeper'] = token.to_cookie
43
43
  @authentication_token = token
44
44
  end
45
45
 
@@ -47,7 +47,7 @@ module JWTKeeper
47
47
  # @return [void]
48
48
  def clear_authentication_token
49
49
  response.headers['Authorization'] = nil
50
- cookies.delete('jwt_keeper')
50
+ defined?(cookies) && cookies.delete('jwt_keeper')
51
51
  @authentication_token = nil
52
52
  end
53
53
 
@@ -27,12 +27,28 @@ module JWTKeeper
27
27
 
28
28
  # @!visibility private
29
29
  def set_with_expiry(jti, seconds, type)
30
- JWTKeeper.configuration.redis_connection.setex(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'
38
+ end
31
39
  end
32
40
 
33
41
  # @!visibility private
34
42
  def get(jti)
35
- JWTKeeper.configuration.redis_connection.get(jti)
43
+ redis = JWTKeeper.configuration.redis_connection
44
+
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) }
49
+ else
50
+ throw 'Bad Redis Connection'
51
+ end
36
52
  end
37
53
  end
38
54
  end
@@ -2,40 +2,47 @@ module JWTKeeper
2
2
  # This class acts as the main interface to wrap the concerns of JWTs. Handling everything from
3
3
  # encoding to invalidation.
4
4
  class Token
5
- attr_accessor :claims, :cookie_secret
5
+ attr_accessor :claims, :secret, :cookie_secret
6
6
 
7
7
  # Initalizes a new web token
8
- # @param private_claims [Hash] the custom claims to encode
9
- # @param cookie_secret [String] the cookie secret to use during encoding
8
+ # @param options [Hash] the custom claims to encode
9
+ # @param secret the secret to use during encoding, defaults to config
10
+ # @param cookie_secret the cookie secret to use during encoding
10
11
  # @return [void]
11
- def initialize(private_claims = {}, cookie_secret = nil)
12
- @cookie_secret = cookie_secret
12
+ def initialize(options = {})
13
+ @secret = options.delete(:secret) || JWTKeeper.configuration.secret
14
+ @cookie_secret = options.delete(:cookie_secret)
13
15
  @claims = {
14
16
  nbf: DateTime.now.to_i, # not before
15
17
  iat: DateTime.now.to_i, # issued at
16
18
  jti: SecureRandom.uuid # JWT ID
17
19
  }
20
+
18
21
  @claims.merge!(JWTKeeper.configuration.base_claims)
19
- @claims.merge!(private_claims)
22
+ @claims.merge!(options)
23
+ @claims[:exp] = @claims[:exp].to_i if @claims[:exp].is_a?(Time)
20
24
  end
21
25
 
22
26
  # Creates a new web token
23
- # @param private_claims [Hash] the custom claims to encode
27
+ # @param options [Hash] the custom claims to encode
28
+ # @param secret the secret to use during encoding, defaults to config
24
29
  # @return [Token] token object
25
- def self.create(private_claims)
30
+ def self.create(options)
26
31
  cookie_secret = SecureRandom.hex(16) if JWTKeeper.configuration.cookie_lock
27
- new(private_claims, cookie_secret)
32
+ new(options.merge(cookie_secret: cookie_secret))
28
33
  end
29
34
 
30
35
  # Decodes and validates an existing token
31
36
  # @param raw_token [String] the raw token
32
37
  # @param cookie_secret [String] the cookie secret
33
38
  # @return [Token] token object
34
- def self.find(raw_token, cookie_secret = nil)
35
- claims = decode(raw_token, cookie_secret)
39
+ def self.find(raw_token, secret: nil, cookie_secret: nil)
40
+ claims = decode(raw_token, secret: secret, cookie_secret: cookie_secret)
36
41
  return nil if claims.nil?
37
42
 
38
- new_token = new(claims, cookie_secret)
43
+ new_token = new(secret: secret, cookie_secret: cookie_secret)
44
+ new_token.claims = claims
45
+
39
46
  return nil if new_token.revoked?
40
47
  new_token
41
48
  end
@@ -110,7 +117,11 @@ module JWTKeeper
110
117
  # Checks if the token invalid?
111
118
  # @return [Boolean]
112
119
  def invalid?
113
- self.class.decode(encode, cookie_secret).nil? || revoked?
120
+ self.class.decode(
121
+ encode,
122
+ secret: secret,
123
+ cookie_secret: cookie_secret
124
+ ).nil? || revoked?
114
125
  end
115
126
 
116
127
  # Encodes the jwt
@@ -130,8 +141,10 @@ module JWTKeeper
130
141
  end
131
142
 
132
143
  # @!visibility private
133
- def self.decode(raw_token, cookie_secret)
134
- JWT.decode(raw_token, JWTKeeper.configuration.secret.to_s + cookie_secret.to_s, true,
144
+ def self.decode(raw_token, secret: nil, cookie_secret: nil)
145
+ secret ||= JWTKeeper.configuration.secret
146
+
147
+ JWT.decode(raw_token, secret.to_s + cookie_secret.to_s, true,
135
148
  algorithm: JWTKeeper.configuration.algorithm,
136
149
  verify_iss: true,
137
150
  verify_aud: true,
@@ -151,8 +164,8 @@ module JWTKeeper
151
164
 
152
165
  # @!visibility private
153
166
  def encode
154
- JWT.encode(claims,
155
- JWTKeeper.configuration.secret.to_s + cookie_secret.to_s,
167
+ JWT.encode(claims.compact,
168
+ secret.to_s + cookie_secret.to_s,
156
169
  JWTKeeper.configuration.algorithm
157
170
  )
158
171
  end
@@ -1,4 +1,4 @@
1
1
  # Gem Version
2
2
  module JWTKeeper
3
- VERSION = '3.1.0'.freeze
3
+ VERSION = '5.0.0'.freeze
4
4
  end
@@ -4,7 +4,8 @@ RSpec.describe JWTKeeper do
4
4
  describe 'Controller' do
5
5
  include_context 'initialize config'
6
6
 
7
- let(:token) { JWTKeeper::Token.create(claim: "Jet fuel can't melt steel beams") }
7
+ let(:token) { JWTKeeper::Token.create(claim: "The Earth is Flat") }
8
+
8
9
  subject(:test_controller) do
9
10
  cookies_klass = Class.new(Hash) do
10
11
  def signed
@@ -3,7 +3,7 @@ require 'spec_helper'
3
3
  module JWTKeeper
4
4
  RSpec.describe Token do
5
5
  include_context 'initialize config'
6
- let(:private_claims) { { claim: "Jet fuel can't melt steel beams" } }
6
+ let(:private_claims) { { claim: "The Earth is Flat" } }
7
7
  let(:token) { described_class.create(private_claims) }
8
8
  let(:raw_token) { token.to_jwt }
9
9
 
@@ -24,6 +24,15 @@ module JWTKeeper
24
24
  it { is_expected.to be_instance_of described_class }
25
25
  it { expect(subject.claims[:exp]).to eql private_claims[:exp] }
26
26
  end
27
+
28
+ context 'when overriding default secret' do
29
+ subject { described_class.create(**private_claims, secret: secret) }
30
+
31
+ let(:secret) { SecureRandom.uuid }
32
+
33
+ it { is_expected.to be_instance_of described_class }
34
+ it { expect(subject.claims[:claim]).to eql private_claims[:claim] }
35
+ end
27
36
  end
28
37
 
29
38
  describe '.find' do
@@ -42,16 +51,33 @@ module JWTKeeper
42
51
  it { is_expected.to be nil }
43
52
  end
44
53
 
45
- context 'with bad cookie' do
46
- subject { described_class.find(raw_token, 'BAD_COOKIE') }
47
- it { is_expected.to be nil }
54
+ context 'describe with cookie locking' do
55
+ before { JWTKeeper.configure(JWTKeeper::Configuration.new(config.merge(cookie_lock: true))) }
56
+
57
+ context 'with no cookie' do
58
+ subject { described_class.find(raw_token, cookie_secret: nil) }
59
+ it { is_expected.to be nil }
60
+ end
61
+
62
+ context 'with bad cookie' do
63
+ subject { described_class.find(raw_token, cookie_secret: 'BAD_COOKIE') }
64
+ it { is_expected.to be nil }
65
+ end
66
+
67
+ context 'with valid cookie' do
68
+ subject { described_class.find(raw_token, cookie_secret: token.cookie_secret) }
69
+ it { is_expected.to be_instance_of described_class }
70
+ end
48
71
  end
49
72
 
50
- context 'with valid cookie' do
51
- before { JWTKeeper.configure(JWTKeeper::Configuration.new(config.merge(cookie_lock: true))) }
52
- subject { described_class.find(raw_token, token.cookie_secret) }
73
+ context 'when overriding default secret' do
74
+ subject { described_class.find(raw_token, secret: secret) }
75
+
76
+ let(:token) { described_class.create(**private_claims, secret: secret) }
77
+ let(:secret) { SecureRandom.uuid }
53
78
 
54
79
  it { is_expected.to be_instance_of described_class }
80
+ it { expect(subject.claims[:claim]).to eql private_claims[:claim] }
55
81
  end
56
82
  end
57
83
 
@@ -187,6 +213,16 @@ module JWTKeeper
187
213
  context 'when valid' do
188
214
  it { is_expected.to be_valid }
189
215
  end
216
+
217
+ context 'with overriden secret' do
218
+ subject { described_class.create(**private_claims, secret: secret) }
219
+
220
+ let(:secret) { SecureRandom.uuid }
221
+
222
+ context 'when valid' do
223
+ it { is_expected.to be_valid }
224
+ end
225
+ end
190
226
  end
191
227
 
192
228
  describe '#invalid?' do
data/spec/spec_helper.rb CHANGED
@@ -1,14 +1,10 @@
1
+ require 'pry'
1
2
  require 'dotenv'
2
3
  Dotenv.load
3
4
 
4
5
  require 'simplecov'
5
- require 'codeclimate-test-reporter'
6
6
 
7
- SimpleCov.formatter =
8
- SimpleCov::Formatter::MultiFormatter.new([
9
- SimpleCov::Formatter::HTMLFormatter,
10
- CodeClimate::TestReporter::Formatter
11
- ])
7
+ SimpleCov.formatter = SimpleCov::Formatter::HTMLFormatter
12
8
  SimpleCov.start do
13
9
  add_filter '/spec/'
14
10
  end
metadata CHANGED
@@ -1,15 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: jwt_keeper
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.1.0
4
+ version: 5.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - David Rivera
8
8
  - Zane Wolfgang Pickett
9
- autorequire:
9
+ autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2016-07-01 00:00:00.000000000 Z
12
+ date: 2021-02-28 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: bundler
@@ -82,35 +82,35 @@ dependencies:
82
82
  - !ruby/object:Gem::Version
83
83
  version: '0'
84
84
  - !ruby/object:Gem::Dependency
85
- name: rspec
85
+ name: pry
86
86
  requirement: !ruby/object:Gem::Requirement
87
87
  requirements:
88
- - - "~>"
88
+ - - ">="
89
89
  - !ruby/object:Gem::Version
90
- version: '3.4'
90
+ version: '0'
91
91
  type: :development
92
92
  prerelease: false
93
93
  version_requirements: !ruby/object:Gem::Requirement
94
94
  requirements:
95
- - - "~>"
95
+ - - ">="
96
96
  - !ruby/object:Gem::Version
97
- version: '3.4'
97
+ version: '0'
98
98
  - !ruby/object:Gem::Dependency
99
- name: fuubar
99
+ name: rspec
100
100
  requirement: !ruby/object:Gem::Requirement
101
101
  requirements:
102
- - - ">="
102
+ - - "~>"
103
103
  - !ruby/object:Gem::Version
104
- version: '0'
104
+ version: '3.8'
105
105
  type: :development
106
106
  prerelease: false
107
107
  version_requirements: !ruby/object:Gem::Requirement
108
108
  requirements:
109
- - - ">="
109
+ - - "~>"
110
110
  - !ruby/object:Gem::Version
111
- version: '0'
111
+ version: '3.8'
112
112
  - !ruby/object:Gem::Dependency
113
- name: simplecov
113
+ name: fuubar
114
114
  requirement: !ruby/object:Gem::Requirement
115
115
  requirements:
116
116
  - - ">="
@@ -124,7 +124,7 @@ dependencies:
124
124
  - !ruby/object:Gem::Version
125
125
  version: '0'
126
126
  - !ruby/object:Gem::Dependency
127
- name: codeclimate-test-reporter
127
+ name: simplecov
128
128
  requirement: !ruby/object:Gem::Requirement
129
129
  requirements:
130
130
  - - ">="
@@ -141,56 +141,56 @@ dependencies:
141
141
  name: redis
142
142
  requirement: !ruby/object:Gem::Requirement
143
143
  requirements:
144
- - - "~>"
144
+ - - ">="
145
145
  - !ruby/object:Gem::Version
146
- version: '3.3'
146
+ version: '0'
147
147
  type: :runtime
148
148
  prerelease: false
149
149
  version_requirements: !ruby/object:Gem::Requirement
150
150
  requirements:
151
- - - "~>"
151
+ - - ">="
152
152
  - !ruby/object:Gem::Version
153
- version: '3.3'
153
+ version: '0'
154
154
  - !ruby/object:Gem::Dependency
155
155
  name: rails
156
156
  requirement: !ruby/object:Gem::Requirement
157
157
  requirements:
158
- - - "~>"
158
+ - - ">="
159
159
  - !ruby/object:Gem::Version
160
- version: '5.0'
160
+ version: '0'
161
161
  type: :runtime
162
162
  prerelease: false
163
163
  version_requirements: !ruby/object:Gem::Requirement
164
164
  requirements:
165
- - - "~>"
165
+ - - ">="
166
166
  - !ruby/object:Gem::Version
167
- version: '5.0'
167
+ version: '0'
168
168
  - !ruby/object:Gem::Dependency
169
169
  name: activesupport
170
170
  requirement: !ruby/object:Gem::Requirement
171
171
  requirements:
172
- - - "~>"
172
+ - - ">="
173
173
  - !ruby/object:Gem::Version
174
- version: '5.0'
174
+ version: '0'
175
175
  type: :runtime
176
176
  prerelease: false
177
177
  version_requirements: !ruby/object:Gem::Requirement
178
178
  requirements:
179
- - - "~>"
179
+ - - ">="
180
180
  - !ruby/object:Gem::Version
181
- version: '5.0'
181
+ version: '0'
182
182
  - !ruby/object:Gem::Dependency
183
183
  name: jwt
184
184
  requirement: !ruby/object:Gem::Requirement
185
185
  requirements:
186
- - - "~>"
186
+ - - ">="
187
187
  - !ruby/object:Gem::Version
188
188
  version: '1.5'
189
189
  type: :runtime
190
190
  prerelease: false
191
191
  version_requirements: !ruby/object:Gem::Requirement
192
192
  requirements:
193
- - - "~>"
193
+ - - ">="
194
194
  - !ruby/object:Gem::Version
195
195
  version: '1.5'
196
196
  description: A managing interface layer for handling the creation and validation of
@@ -234,7 +234,7 @@ homepage: https://github.com/sirwolfgang/jwt_keeper
234
234
  licenses:
235
235
  - MIT
236
236
  metadata: {}
237
- post_install_message:
237
+ post_install_message:
238
238
  rdoc_options: []
239
239
  require_paths:
240
240
  - lib
@@ -249,9 +249,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
249
249
  - !ruby/object:Gem::Version
250
250
  version: '0'
251
251
  requirements: []
252
- rubyforge_project:
253
- rubygems_version: 2.5.1
254
- signing_key:
252
+ rubygems_version: 3.2.3
253
+ signing_key:
255
254
  specification_version: 4
256
255
  summary: JWT for Rails made easy
257
256
  test_files:
@@ -261,4 +260,3 @@ test_files:
261
260
  - spec/lib/jwt_keeper/token_spec.rb
262
261
  - spec/lib/jwt_keeper_spec.rb
263
262
  - spec/spec_helper.rb
264
- has_rdoc: