devise-jwt 0.5.7 → 0.8.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 +5 -5
- data/.codeclimate.yml +1 -2
- data/.rubocop.yml +40 -1
- data/.travis.yml +10 -11
- data/CHANGELOG.md +20 -0
- data/LICENSE.txt +1 -1
- data/README.md +53 -30
- data/bin/console +5 -4
- data/devise-jwt.gemspec +11 -8
- data/issue_template.md +1 -0
- data/lib/devise/jwt.rb +15 -9
- data/lib/devise/jwt/defaults_generator.rb +4 -4
- data/lib/devise/jwt/mapping_inspector.rb +0 -2
- data/lib/devise/jwt/revocation_strategies.rb +2 -2
- data/lib/devise/jwt/revocation_strategies/{whitelist.rb → allowlist.rb} +8 -9
- data/lib/devise/jwt/revocation_strategies/{blacklist.rb → denylist.rb} +1 -1
- data/lib/devise/jwt/test_helpers.rb +6 -3
- data/lib/devise/jwt/version.rb +1 -1
- metadata +54 -29
- data/.overcommit.yml +0 -56
- data/.overcommit_gems.rb +0 -15
- data/.reek +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: dbd6de3011149a0bca3be6b3658cd5a9556b0be78581f3cd22c3aec9cbfd4cf0
|
4
|
+
data.tar.gz: 6ce928fe9ccbf54f7b119a815ffe97eb72c02a321e618a7f60018c00fabe7e5c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7460b663f7639978e6021f52b1de8e0f4c20ebc9ca33375cc11d630e379fb82cd48d1e61a5ee7fc72335ec1088112a75e02b4bae60935f8439878d2f81b8bd5e
|
7
|
+
data.tar.gz: a572ab50a87f8254bce00685a248dea9ff16181bbdcc70f2f70e7b65a97cfc1d0c0a11dd8ef966a0e80bd7327e5fb5e4e0ed54aef227448960d22c5a5b2aec46
|
data/.codeclimate.yml
CHANGED
data/.rubocop.yml
CHANGED
@@ -1,6 +1,11 @@
|
|
1
1
|
require: rubocop-rspec
|
2
2
|
AllCops:
|
3
|
-
TargetRubyVersion: 2.
|
3
|
+
TargetRubyVersion: 2.7
|
4
|
+
Exclude:
|
5
|
+
- Gemfile
|
6
|
+
- devise-jwt.gemspec
|
7
|
+
- spec/fixtures/rails_app/**/*
|
8
|
+
- vendor/**/*
|
4
9
|
RSpec/NestedGroups:
|
5
10
|
Max: 3
|
6
11
|
RSpec/MessageExpectation:
|
@@ -14,3 +19,37 @@ Metrics/BlockLength:
|
|
14
19
|
- "spec/**/*.rb"
|
15
20
|
Style/SafeNavigation:
|
16
21
|
Enabled: false
|
22
|
+
Layout/EmptyLinesAroundAttributeAccessor:
|
23
|
+
Enabled: true
|
24
|
+
Layout/SpaceAroundMethodCallOperator:
|
25
|
+
Enabled: true
|
26
|
+
Lint/DeprecatedOpenSSLConstant:
|
27
|
+
Enabled: true
|
28
|
+
Lint/MixedRegexpCaptureTypes:
|
29
|
+
Enabled: true
|
30
|
+
Lint/RaiseException:
|
31
|
+
Enabled: true
|
32
|
+
Lint/StructNewOverride:
|
33
|
+
Enabled: true
|
34
|
+
Style/AccessorGrouping:
|
35
|
+
Enabled: true
|
36
|
+
Style/BisectedAttrAccessor:
|
37
|
+
Enabled: true
|
38
|
+
Style/ExponentialNotation:
|
39
|
+
Enabled: true
|
40
|
+
Style/HashEachMethods:
|
41
|
+
Enabled: true
|
42
|
+
Style/HashTransformKeys:
|
43
|
+
Enabled: true
|
44
|
+
Style/HashTransformValues:
|
45
|
+
Enabled: true
|
46
|
+
Style/RedundantAssignment:
|
47
|
+
Enabled: true
|
48
|
+
Style/RedundantFetchBlock:
|
49
|
+
Enabled: true
|
50
|
+
Style/RedundantRegexpCharacterClass:
|
51
|
+
Enabled: true
|
52
|
+
Style/RedundantRegexpEscape:
|
53
|
+
Enabled: true
|
54
|
+
Style/SlicingWithRange:
|
55
|
+
Enabled: true
|
data/.travis.yml
CHANGED
@@ -1,21 +1,20 @@
|
|
1
|
-
sudo: false
|
2
1
|
language: ruby
|
2
|
+
cache: bundler
|
3
3
|
rvm:
|
4
|
-
- 2.
|
5
|
-
- 2.
|
6
|
-
- 2.
|
7
|
-
-
|
4
|
+
- 2.5
|
5
|
+
- 2.6
|
6
|
+
- 2.7
|
7
|
+
- ruby-head
|
8
8
|
before_install:
|
9
9
|
- gem update --system --no-doc
|
10
|
-
-
|
11
|
-
before_script:
|
12
|
-
- git config --global user.email 'travis@travis.ci'
|
13
|
-
- git config --global user.name 'Travis CI'
|
10
|
+
- gem install bundler
|
14
11
|
script:
|
15
12
|
- bundle exec rspec
|
13
|
+
- bundle exec rubocop
|
16
14
|
- bundle exec codeclimate-test-reporter
|
17
|
-
|
18
|
-
|
15
|
+
jobs:
|
16
|
+
allow_failures:
|
17
|
+
- rvm: ruby-head
|
19
18
|
addons:
|
20
19
|
code_climate:
|
21
20
|
repo_token:
|
data/CHANGELOG.md
CHANGED
@@ -4,6 +4,26 @@ All notable changes to this project will be documented in this file.
|
|
4
4
|
The format is based on [Keep a Changelog](http://keepachangelog.com/)
|
5
5
|
and this project adheres to [Semantic Versioning](http://semver.org/).
|
6
6
|
|
7
|
+
## [0.8.0] - 2020-07-06
|
8
|
+
### Fixed
|
9
|
+
- Fix compatibility with last version of dry-configurable
|
10
|
+
|
11
|
+
## [0.7.0] - 2020-06-03
|
12
|
+
### Fixed
|
13
|
+
- Replace whitelist/blacklist terminology with allowlist/denylist
|
14
|
+
|
15
|
+
## [0.6.0] - 2019-08-01
|
16
|
+
### Fixed
|
17
|
+
- Update warden-jwt_auth dependency to v0.4.0 so that now it is possible to configure algorithm.
|
18
|
+
|
19
|
+
## [0.5.9] - 2019-03-29
|
20
|
+
### Fixed
|
21
|
+
- Update dependencies.
|
22
|
+
|
23
|
+
## [0.5.8] - 2018-09-07
|
24
|
+
### Fixed
|
25
|
+
- Fix test helper to persist whitelisted tokens.
|
26
|
+
|
7
27
|
## [0.5.7] - 2018-06-22
|
8
28
|
### Added
|
9
29
|
- Use `primary_key` instead of `id` to fetch resource.
|
data/LICENSE.txt
CHANGED
data/README.md
CHANGED
@@ -21,12 +21,34 @@ You can read about which security concerns this library takes into account and a
|
|
21
21
|
|
22
22
|
`devise-jwt` is just a thin layer on top of [`warden-jwt_auth`](https://github.com/waiting-for-dev/warden-jwt_auth) that configures it to be used out of the box with devise and Rails.
|
23
23
|
|
24
|
+
## Upgrade notes
|
25
|
+
|
26
|
+
### v0.7.0
|
27
|
+
|
28
|
+
Since version v0.7.0 `Blacklist` revocation strategy has been renamed to `Denylist` while `Whitelist` has been renamed to `Allowlist`.
|
29
|
+
|
30
|
+
For `Denylist`, you only need to update the `include` line you're using in your revocation strategy model:
|
31
|
+
|
32
|
+
```ruby
|
33
|
+
# include Devise::JWT::RevocationStrategies::Blacklist # before
|
34
|
+
include Devise::JWT::RevocationStrategies::Denylist
|
35
|
+
```
|
36
|
+
|
37
|
+
For `Whitelist`, you need to update the `include` line you're using in your user model:
|
38
|
+
|
39
|
+
```ruby
|
40
|
+
# include Devise::JWT::RevocationStrategies::Whitelist # before
|
41
|
+
include Devise::JWT::RevocationStrategies::Allowlist
|
42
|
+
```
|
43
|
+
|
44
|
+
You also have to rename your `WhitelistedJwt` model to `AllowlistedJwt` and change the underlying database table to `allowlisted_jwts` (or configure the model to keep using the old name).
|
45
|
+
|
24
46
|
## Installation
|
25
47
|
|
26
48
|
Add this line to your application's Gemfile:
|
27
49
|
|
28
50
|
```ruby
|
29
|
-
gem 'devise-jwt', '~> 0.
|
51
|
+
gem 'devise-jwt', '~> 0.6.0'
|
30
52
|
```
|
31
53
|
|
32
54
|
And then execute:
|
@@ -76,7 +98,7 @@ An example configuration:
|
|
76
98
|
```ruby
|
77
99
|
class User < ApplicationRecord
|
78
100
|
devise :database_authenticatable,
|
79
|
-
:jwt_authenticatable, jwt_revocation_strategy:
|
101
|
+
:jwt_authenticatable, jwt_revocation_strategy: Denylist
|
80
102
|
end
|
81
103
|
```
|
82
104
|
|
@@ -132,7 +154,7 @@ This is so because of the following default devise workflow:
|
|
132
154
|
in the session without even reaching to any strategy (`:jwt_authenticatable`
|
133
155
|
in our case).
|
134
156
|
|
135
|
-
So, if you want to avoid this caveat you have
|
157
|
+
So, if you want to avoid this caveat you have three options:
|
136
158
|
|
137
159
|
- Disable the session. If you are developing an API, probably you don't need
|
138
160
|
it. In order to disable it, change `config/initializers/session_store.rb` to:
|
@@ -146,6 +168,15 @@ So, if you want to avoid this caveat you have two options:
|
|
146
168
|
```ruby
|
147
169
|
config.skip_session_storage = [:http_auth, :params_auth]
|
148
170
|
```
|
171
|
+
- If you are using Devise for another model (e.g. `AdminUser`) and doesn't want
|
172
|
+
to disable session storage for devise entirely, you can disable it on a
|
173
|
+
per-model basis:
|
174
|
+
```ruby
|
175
|
+
class User < ApplicationRecord
|
176
|
+
devise :database_authenticatable #, your other enabled modules...
|
177
|
+
self.skip_session_storage = [:http_auth, :params_auth]
|
178
|
+
end
|
179
|
+
```
|
149
180
|
|
150
181
|
### Revocation strategies
|
151
182
|
|
@@ -157,7 +188,7 @@ Here, the model class acts itself as the revocation strategy. It needs a new str
|
|
157
188
|
|
158
189
|
It works like the following:
|
159
190
|
|
160
|
-
-
|
191
|
+
- When a token is dispatched for a user, the `jti` claim is taken from the `jti` column in the model (which has been initialized when the record has been created).
|
161
192
|
- At every authenticated action, the incoming token `jti` claim is matched against the `jti` column for that user. The authentication only succeeds if they are the same.
|
162
193
|
- When the user requests to sign out its `jti` column changes, so that provided token won't be valid anymore.
|
163
194
|
|
@@ -196,29 +227,29 @@ def jwt_payload
|
|
196
227
|
end
|
197
228
|
```
|
198
229
|
|
199
|
-
####
|
230
|
+
#### Denylist
|
200
231
|
|
201
|
-
In this strategy, a database table is used as a
|
232
|
+
In this strategy, a database table is used as a list of revoked JWT tokens. The `jti` claim, which uniquely identifies a token, is persisted. The `exp` claim is also stored to allow the clean-up of staled tokens.
|
202
233
|
|
203
|
-
In order to use it, you need to create the
|
234
|
+
In order to use it, you need to create the denylist table in a migration:
|
204
235
|
|
205
236
|
```ruby
|
206
237
|
def change
|
207
|
-
create_table :
|
238
|
+
create_table :jwt_denylist do |t|
|
208
239
|
t.string :jti, null: false
|
209
240
|
t.datetime :exp, null: false
|
210
241
|
end
|
211
|
-
add_index :
|
242
|
+
add_index :jwt_denylist, :jti
|
212
243
|
end
|
213
244
|
```
|
214
245
|
For performance reasons, it is better if the `jti` column is an index.
|
215
246
|
|
216
|
-
Note: if you used the
|
247
|
+
Note: if you used the denylist strategy before vesion 0.4.0 you may not have the field *exp.* If not, run the following migration:
|
217
248
|
|
218
249
|
```ruby
|
219
|
-
class
|
250
|
+
class AddExpirationTimeToJWTDenylist < ActiveRecord::Migration
|
220
251
|
def change
|
221
|
-
add_column :
|
252
|
+
add_column :jwt_denylist, :exp, :datetime, null: false
|
222
253
|
end
|
223
254
|
end
|
224
255
|
|
@@ -227,10 +258,10 @@ end
|
|
227
258
|
Then, you need to create the corresponding model and include the strategy:
|
228
259
|
|
229
260
|
```ruby
|
230
|
-
class
|
231
|
-
include Devise::JWT::RevocationStrategies::
|
261
|
+
class JwtDenylist < ApplicationRecord
|
262
|
+
include Devise::JWT::RevocationStrategies::Denylist
|
232
263
|
|
233
|
-
self.table_name = '
|
264
|
+
self.table_name = 'jwt_denylist'
|
234
265
|
end
|
235
266
|
```
|
236
267
|
|
@@ -239,11 +270,11 @@ Last, configure the user model to use it:
|
|
239
270
|
```ruby
|
240
271
|
class User < ApplicationRecord
|
241
272
|
devise :database_authenticatable,
|
242
|
-
:jwt_authenticatable, jwt_revocation_strategy:
|
273
|
+
:jwt_authenticatable, jwt_revocation_strategy: JwtDenylist
|
243
274
|
end
|
244
275
|
```
|
245
276
|
|
246
|
-
####
|
277
|
+
#### Allowlist
|
247
278
|
|
248
279
|
Here, the model itself acts also as a revocation strategy, but it needs to have
|
249
280
|
a one-to-many association with another table which stores the tokens (in fact
|
@@ -266,11 +297,11 @@ devices for the same user.
|
|
266
297
|
The `exp` claim is also stored to allow the clean-up of staled tokens.
|
267
298
|
|
268
299
|
In order to use it, you have to create yourself the associated table and model.
|
269
|
-
The association table must be called `
|
300
|
+
The association table must be called `allowlisted_jwts`:
|
270
301
|
|
271
302
|
```ruby
|
272
303
|
def change
|
273
|
-
create_table :
|
304
|
+
create_table :allowlisted_jwts do |t|
|
274
305
|
t.string :jti, null: false
|
275
306
|
t.string :aud
|
276
307
|
# If you want to leverage the `aud` claim, add to it a `NOT NULL` constraint:
|
@@ -279,7 +310,7 @@ def change
|
|
279
310
|
t.references :your_user_table, foreign_key: { on_delete: :cascade }, null: false
|
280
311
|
end
|
281
312
|
|
282
|
-
add_index :
|
313
|
+
add_index :allowlisted_jwts, :jti, unique: true
|
283
314
|
end
|
284
315
|
```
|
285
316
|
Important: You are encouraged to set a unique index in the jti column. This way we can be sure at the database level that there aren't two valid tokens with same jti at the same time. Definining `foreign_key: { on_delete: :cascade }, null: false` on `t.references :your_user_table` helps to keep referential integrity of your database.
|
@@ -287,7 +318,7 @@ Important: You are encouraged to set a unique index in the jti column. This way
|
|
287
318
|
And then, the model:
|
288
319
|
|
289
320
|
```ruby
|
290
|
-
class
|
321
|
+
class AllowlistedJwt < ApplicationRecord
|
291
322
|
end
|
292
323
|
```
|
293
324
|
|
@@ -295,7 +326,7 @@ Finally, include the strategy in the model and configure it:
|
|
295
326
|
|
296
327
|
```ruby
|
297
328
|
class User < ApplicationRecord
|
298
|
-
include Devise::JWT::RevocationStrategies::
|
329
|
+
include Devise::JWT::RevocationStrategies::Allowlist
|
299
330
|
|
300
331
|
devise :database_authenticatable,
|
301
332
|
:jwt_authenticatable, jwt_revocation_strategy: self
|
@@ -490,14 +521,6 @@ An then, for example:
|
|
490
521
|
|
491
522
|
`docker-compose exec app rspec`
|
492
523
|
|
493
|
-
This gem uses [overcommit](https://github.com/brigade/overcommit) to execute some code review engines. If you submit a pull request, it will be executed in the CI process. In order to set it up, you need to do:
|
494
|
-
|
495
|
-
```ruby
|
496
|
-
bundle install --gemfile=.overcommit_gems.rb
|
497
|
-
overcommit --sign
|
498
|
-
overcommit --run # To test if it works
|
499
|
-
```
|
500
|
-
|
501
524
|
## Contributing
|
502
525
|
|
503
526
|
Bug reports and pull requests are welcome on GitHub at https://github.com/waiting-for-dev/devise-jwt. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
|
data/bin/console
CHANGED
@@ -1,14 +1,15 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
2
3
|
|
3
|
-
require
|
4
|
-
require
|
4
|
+
require 'bundler/setup'
|
5
|
+
require 'devise/jwt'
|
5
6
|
|
6
7
|
# You can add fixtures and/or initialization code here to make experimenting
|
7
8
|
# with your gem easier. You can also use a different console, if you like.
|
8
9
|
|
9
10
|
# (If you use this, don't forget to add pry to your Gemfile!)
|
10
|
-
# require
|
11
|
+
# require 'pry'
|
11
12
|
# Pry.start
|
12
13
|
|
13
|
-
require
|
14
|
+
require 'irb'
|
14
15
|
IRB.start
|
data/devise-jwt.gemspec
CHANGED
@@ -22,17 +22,20 @@ Gem::Specification.new do |spec|
|
|
22
22
|
spec.require_paths = ["lib"]
|
23
23
|
|
24
24
|
spec.add_dependency 'devise', '~> 4.0'
|
25
|
-
spec.add_dependency 'warden-jwt_auth', '~> 0.
|
25
|
+
spec.add_dependency 'warden-jwt_auth', '~> 0.5'
|
26
26
|
|
27
|
-
spec.add_development_dependency "bundler", "
|
28
|
-
spec.add_development_dependency "rake", "~>
|
29
|
-
spec.add_development_dependency "rspec"
|
30
|
-
spec.add_development_dependency "pry-byebug", "~> 3.
|
27
|
+
spec.add_development_dependency "bundler", "> 1"
|
28
|
+
spec.add_development_dependency "rake", "~> 13.0"
|
29
|
+
spec.add_development_dependency "rspec"
|
30
|
+
spec.add_development_dependency "pry-byebug", "~> 3.7"
|
31
31
|
# Needed to test the rails fixture application
|
32
|
-
spec.add_development_dependency 'rails', '~>
|
32
|
+
spec.add_development_dependency 'rails', '~> 6.0'
|
33
33
|
spec.add_development_dependency 'sqlite3', '~> 1.3'
|
34
|
-
spec.add_development_dependency 'rspec-rails', '~>
|
34
|
+
spec.add_development_dependency 'rspec-rails', '~> 4.0'
|
35
|
+
# Cops
|
36
|
+
spec.add_development_dependency 'rubocop', '~> 0.87'
|
37
|
+
spec.add_development_dependency 'rubocop-rspec', '~> 1.42'
|
35
38
|
# Test reporting
|
36
|
-
spec.add_development_dependency 'simplecov', '
|
39
|
+
spec.add_development_dependency 'simplecov', '0.17'
|
37
40
|
spec.add_development_dependency 'codeclimate-test-reporter', '~> 1.0'
|
38
41
|
end
|
data/issue_template.md
CHANGED
@@ -18,6 +18,7 @@ Provide following information. Please, format pasted output as code. Feel free t
|
|
18
18
|
|
19
19
|
- Version of `devise-jwt` in use
|
20
20
|
- Version of `rails` in use
|
21
|
+
- Version of `warden-jwt_auth` in use
|
21
22
|
- Output of `Devise::JWT.config`
|
22
23
|
- Output of `Warden::JWTAuth.config`
|
23
24
|
- Output of `Devise.mappings`
|
data/lib/devise/jwt.rb
CHANGED
@@ -17,7 +17,9 @@ module Devise
|
|
17
17
|
#
|
18
18
|
# @see Warden::JWTAuth
|
19
19
|
def self.jwt
|
20
|
+
Warden::JWTAuth.config.to_h
|
20
21
|
yield(Devise::JWT.config)
|
22
|
+
Devise::JWT.config.to_h
|
21
23
|
end
|
22
24
|
|
23
25
|
add_module(:jwt_authenticatable, strategy: :jwt)
|
@@ -26,23 +28,31 @@ module Devise
|
|
26
28
|
module JWT
|
27
29
|
extend Dry::Configurable
|
28
30
|
|
29
|
-
setting
|
31
|
+
def self.forward_to_warden(setting, value)
|
32
|
+
default = Warden::JWTAuth.config.send(setting)
|
33
|
+
Warden::JWTAuth.config.send("#{setting}=", value || default)
|
34
|
+
Warden::JWTAuth.config.send(setting)
|
35
|
+
end
|
36
|
+
|
37
|
+
setting(:secret, Warden::JWTAuth.config.secret) do |value|
|
30
38
|
forward_to_warden(:secret, value)
|
31
39
|
end
|
32
40
|
|
33
|
-
setting(:expiration_time) do |value|
|
41
|
+
setting(:expiration_time, Warden::JWTAuth.config.expiration_time) do |value|
|
34
42
|
forward_to_warden(:expiration_time, value)
|
35
43
|
end
|
36
44
|
|
37
|
-
setting(:dispatch_requests
|
45
|
+
setting(:dispatch_requests,
|
46
|
+
Warden::JWTAuth.config.dispatch_requests) do |value|
|
38
47
|
forward_to_warden(:dispatch_requests, value)
|
39
48
|
end
|
40
49
|
|
41
|
-
setting(:revocation_requests
|
50
|
+
setting(:revocation_requests,
|
51
|
+
Warden::JWTAuth.config.revocation_requests) do |value|
|
42
52
|
forward_to_warden(:revocation_requests, value)
|
43
53
|
end
|
44
54
|
|
45
|
-
setting(:aud_header) do |value|
|
55
|
+
setting(:aud_header, Warden::JWTAuth.config.aud_header) do |value|
|
46
56
|
forward_to_warden(:aud_header, value)
|
47
57
|
end
|
48
58
|
|
@@ -60,9 +70,5 @@ module Devise
|
|
60
70
|
# admin_user: [nil, :xml]
|
61
71
|
# }
|
62
72
|
setting :request_formats, {}
|
63
|
-
|
64
|
-
def self.forward_to_warden(setting, value)
|
65
|
-
Warden::JWTAuth.config.send("#{setting}=", value)
|
66
|
-
end
|
67
73
|
end
|
68
74
|
end
|
@@ -27,6 +27,7 @@ module Devise
|
|
27
27
|
devise_mappings.each_key do |scope|
|
28
28
|
inspector = MappingInspector.new(scope)
|
29
29
|
next unless inspector.jwt?
|
30
|
+
|
30
31
|
add_defaults(inspector)
|
31
32
|
end
|
32
33
|
defaults
|
@@ -41,14 +42,12 @@ module Devise
|
|
41
42
|
add_revocation_requests(inspector)
|
42
43
|
end
|
43
44
|
|
44
|
-
# :reek:FeatureEnvy
|
45
45
|
def add_mapping(inspector)
|
46
46
|
scope = inspector.scope
|
47
47
|
model = inspector.model
|
48
48
|
defaults[:mappings][scope] = model.name
|
49
49
|
end
|
50
50
|
|
51
|
-
# :reek:FeatureEnvy
|
52
51
|
def add_revocation_strategy(inspector)
|
53
52
|
scope = inspector.scope
|
54
53
|
strategy = inspector.model.jwt_revocation_strategy
|
@@ -62,16 +61,19 @@ module Devise
|
|
62
61
|
|
63
62
|
def add_sign_in_request(inspector)
|
64
63
|
return unless inspector.session?
|
64
|
+
|
65
65
|
defaults[:dispatch_requests].push(*sign_in_requests(inspector))
|
66
66
|
end
|
67
67
|
|
68
68
|
def add_registration_request(inspector)
|
69
69
|
return unless inspector.registration?
|
70
|
+
|
70
71
|
defaults[:dispatch_requests].push(*registration_requests(inspector))
|
71
72
|
end
|
72
73
|
|
73
74
|
def add_revocation_requests(inspector)
|
74
75
|
return unless inspector.session?
|
76
|
+
|
75
77
|
defaults[:revocation_requests].push(*sign_out_requests(inspector))
|
76
78
|
end
|
77
79
|
|
@@ -87,7 +89,6 @@ module Devise
|
|
87
89
|
requests(inspector, :registration)
|
88
90
|
end
|
89
91
|
|
90
|
-
# :reek:FeatureEnvy
|
91
92
|
def requests(inspector, name)
|
92
93
|
path = inspector.path(name)
|
93
94
|
methods = inspector.methods(name)
|
@@ -96,7 +97,6 @@ module Devise
|
|
96
97
|
end
|
97
98
|
end
|
98
99
|
|
99
|
-
# :reek:UtilityFunction
|
100
100
|
def requests_for_format(path, methods, format)
|
101
101
|
path_regexp = format ? /^#{path}.#{format}$/ : /^#{path}$/
|
102
102
|
methods.map do |method|
|
@@ -27,7 +27,6 @@ module Devise
|
|
27
27
|
mapping.to
|
28
28
|
end
|
29
29
|
|
30
|
-
# :reek:FeatureEnvy
|
31
30
|
def path(name)
|
32
31
|
prefix, scope, request = path_parts(name)
|
33
32
|
[prefix, scope, request].delete_if do |item|
|
@@ -35,7 +34,6 @@ module Devise
|
|
35
34
|
end.join('/').prepend('/').gsub('//', '/')
|
36
35
|
end
|
37
36
|
|
38
|
-
# :reek:ControlParameter
|
39
37
|
def methods(name)
|
40
38
|
method = case name
|
41
39
|
when :sign_in then 'POST'
|
@@ -1,8 +1,8 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require 'devise/jwt/revocation_strategies/jti_matcher'
|
4
|
-
require 'devise/jwt/revocation_strategies/
|
5
|
-
require 'devise/jwt/revocation_strategies/
|
4
|
+
require 'devise/jwt/revocation_strategies/denylist'
|
5
|
+
require 'devise/jwt/revocation_strategies/allowlist'
|
6
6
|
require 'devise/jwt/revocation_strategies/null'
|
7
7
|
|
8
8
|
module Devise
|
@@ -7,40 +7,39 @@ module Devise
|
|
7
7
|
module RevocationStrategies
|
8
8
|
# This strategy must be included in the user model.
|
9
9
|
#
|
10
|
-
# The
|
10
|
+
# The JwtAllowlist table must include `jti`, `aud`, `exp` and `user_id`
|
11
11
|
# columns
|
12
12
|
#
|
13
13
|
# In order to tell whether a token is revoked, it just tries to find the
|
14
|
-
# `jti` and `aud` values from the token on the `
|
14
|
+
# `jti` and `aud` values from the token on the `allowlisted_jwts`
|
15
15
|
# table for the respective user.
|
16
16
|
#
|
17
17
|
# If the values don't exist means the token was revoked.
|
18
18
|
# On revocation, it deletes the matching record from the
|
19
|
-
# `
|
19
|
+
# `allowlisted_jwts` table.
|
20
20
|
#
|
21
21
|
# On sign in, it creates a new record with the `jti` and `aud` values.
|
22
|
-
module
|
22
|
+
module Allowlist
|
23
23
|
extend ActiveSupport::Concern
|
24
24
|
|
25
25
|
included do
|
26
|
-
has_many :
|
26
|
+
has_many :allowlisted_jwts, dependent: :destroy
|
27
27
|
|
28
28
|
# @see Warden::JWTAuth::Interfaces::RevocationStrategy#jwt_revoked?
|
29
29
|
def self.jwt_revoked?(payload, user)
|
30
|
-
!user.
|
30
|
+
!user.allowlisted_jwts.exists?(payload.slice('jti', 'aud'))
|
31
31
|
end
|
32
32
|
|
33
33
|
# @see Warden::JWTAuth::Interfaces::RevocationStrategy#revoke_jwt
|
34
34
|
def self.revoke_jwt(payload, user)
|
35
|
-
jwt = user.
|
35
|
+
jwt = user.allowlisted_jwts.find_by(payload.slice('jti', 'aud'))
|
36
36
|
jwt.destroy! if jwt
|
37
37
|
end
|
38
38
|
end
|
39
39
|
|
40
40
|
# Warden::JWTAuth::Interfaces::User#on_jwt_dispatch
|
41
|
-
# :reek:FeatureEnvy
|
42
41
|
def on_jwt_dispatch(_token, payload)
|
43
|
-
|
42
|
+
allowlisted_jwts.create!(
|
44
43
|
jti: payload['jti'],
|
45
44
|
aud: payload['aud'],
|
46
45
|
exp: Time.at(payload['exp'].to_i)
|
@@ -7,6 +7,10 @@ module Devise
|
|
7
7
|
# Returns headers with a valid token in the `Authorization` header
|
8
8
|
# added.
|
9
9
|
#
|
10
|
+
# Side effects could happen if you have implemented
|
11
|
+
# `on_jwt_dispatch` method on the user model (as it happens in
|
12
|
+
# the allowlist revocation strategy).
|
13
|
+
#
|
10
14
|
# Be aware that a fresh copy of `headers` is returned with the new
|
11
15
|
# key/value pair added, instead of modifying given argument.
|
12
16
|
#
|
@@ -16,14 +20,13 @@ module Devise
|
|
16
20
|
# autodetected.
|
17
21
|
# @param aud [String] The aud claim. If `nil` it will be autodetected from
|
18
22
|
# the header name configured in `Devise::JWT.config.aud_header`.
|
19
|
-
#
|
20
|
-
# :reek:LongParameterList
|
21
23
|
def self.auth_headers(headers, user, scope: nil, aud: nil)
|
22
24
|
scope ||= Devise::Mapping.find_scope!(user)
|
23
25
|
aud ||= headers[Warden::JWTAuth.config.aud_header]
|
24
|
-
token,
|
26
|
+
token, payload = Warden::JWTAuth::UserEncoder.new.call(
|
25
27
|
user, scope, aud
|
26
28
|
)
|
29
|
+
user.on_jwt_dispatch(token, payload) if user.respond_to?(:on_jwt_dispatch)
|
27
30
|
Warden::JWTAuth::HeaderParser.to_headers(headers, token)
|
28
31
|
end
|
29
32
|
end
|
data/lib/devise/jwt/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: devise-jwt
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.8.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Marc Busqué
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2020-07-11 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: devise
|
@@ -30,84 +30,84 @@ dependencies:
|
|
30
30
|
requirements:
|
31
31
|
- - "~>"
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version: 0.
|
33
|
+
version: '0.5'
|
34
34
|
type: :runtime
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
38
|
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version: 0.
|
40
|
+
version: '0.5'
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: bundler
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
44
44
|
requirements:
|
45
|
-
- - "
|
45
|
+
- - ">"
|
46
46
|
- !ruby/object:Gem::Version
|
47
|
-
version: '1
|
47
|
+
version: '1'
|
48
48
|
type: :development
|
49
49
|
prerelease: false
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
52
|
-
- - "
|
52
|
+
- - ">"
|
53
53
|
- !ruby/object:Gem::Version
|
54
|
-
version: '1
|
54
|
+
version: '1'
|
55
55
|
- !ruby/object:Gem::Dependency
|
56
56
|
name: rake
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
58
58
|
requirements:
|
59
59
|
- - "~>"
|
60
60
|
- !ruby/object:Gem::Version
|
61
|
-
version: '
|
61
|
+
version: '13.0'
|
62
62
|
type: :development
|
63
63
|
prerelease: false
|
64
64
|
version_requirements: !ruby/object:Gem::Requirement
|
65
65
|
requirements:
|
66
66
|
- - "~>"
|
67
67
|
- !ruby/object:Gem::Version
|
68
|
-
version: '
|
68
|
+
version: '13.0'
|
69
69
|
- !ruby/object:Gem::Dependency
|
70
70
|
name: rspec
|
71
71
|
requirement: !ruby/object:Gem::Requirement
|
72
72
|
requirements:
|
73
|
-
- - "
|
73
|
+
- - ">="
|
74
74
|
- !ruby/object:Gem::Version
|
75
|
-
version: '
|
75
|
+
version: '0'
|
76
76
|
type: :development
|
77
77
|
prerelease: false
|
78
78
|
version_requirements: !ruby/object:Gem::Requirement
|
79
79
|
requirements:
|
80
|
-
- - "
|
80
|
+
- - ">="
|
81
81
|
- !ruby/object:Gem::Version
|
82
|
-
version: '
|
82
|
+
version: '0'
|
83
83
|
- !ruby/object:Gem::Dependency
|
84
84
|
name: pry-byebug
|
85
85
|
requirement: !ruby/object:Gem::Requirement
|
86
86
|
requirements:
|
87
87
|
- - "~>"
|
88
88
|
- !ruby/object:Gem::Version
|
89
|
-
version: '3.
|
89
|
+
version: '3.7'
|
90
90
|
type: :development
|
91
91
|
prerelease: false
|
92
92
|
version_requirements: !ruby/object:Gem::Requirement
|
93
93
|
requirements:
|
94
94
|
- - "~>"
|
95
95
|
- !ruby/object:Gem::Version
|
96
|
-
version: '3.
|
96
|
+
version: '3.7'
|
97
97
|
- !ruby/object:Gem::Dependency
|
98
98
|
name: rails
|
99
99
|
requirement: !ruby/object:Gem::Requirement
|
100
100
|
requirements:
|
101
101
|
- - "~>"
|
102
102
|
- !ruby/object:Gem::Version
|
103
|
-
version: '
|
103
|
+
version: '6.0'
|
104
104
|
type: :development
|
105
105
|
prerelease: false
|
106
106
|
version_requirements: !ruby/object:Gem::Requirement
|
107
107
|
requirements:
|
108
108
|
- - "~>"
|
109
109
|
- !ruby/object:Gem::Version
|
110
|
-
version: '
|
110
|
+
version: '6.0'
|
111
111
|
- !ruby/object:Gem::Dependency
|
112
112
|
name: sqlite3
|
113
113
|
requirement: !ruby/object:Gem::Requirement
|
@@ -128,28 +128,56 @@ dependencies:
|
|
128
128
|
requirements:
|
129
129
|
- - "~>"
|
130
130
|
- !ruby/object:Gem::Version
|
131
|
-
version: '
|
131
|
+
version: '4.0'
|
132
132
|
type: :development
|
133
133
|
prerelease: false
|
134
134
|
version_requirements: !ruby/object:Gem::Requirement
|
135
135
|
requirements:
|
136
136
|
- - "~>"
|
137
137
|
- !ruby/object:Gem::Version
|
138
|
-
version: '
|
138
|
+
version: '4.0'
|
139
139
|
- !ruby/object:Gem::Dependency
|
140
|
-
name:
|
140
|
+
name: rubocop
|
141
|
+
requirement: !ruby/object:Gem::Requirement
|
142
|
+
requirements:
|
143
|
+
- - "~>"
|
144
|
+
- !ruby/object:Gem::Version
|
145
|
+
version: '0.87'
|
146
|
+
type: :development
|
147
|
+
prerelease: false
|
148
|
+
version_requirements: !ruby/object:Gem::Requirement
|
149
|
+
requirements:
|
150
|
+
- - "~>"
|
151
|
+
- !ruby/object:Gem::Version
|
152
|
+
version: '0.87'
|
153
|
+
- !ruby/object:Gem::Dependency
|
154
|
+
name: rubocop-rspec
|
141
155
|
requirement: !ruby/object:Gem::Requirement
|
142
156
|
requirements:
|
143
157
|
- - "~>"
|
144
158
|
- !ruby/object:Gem::Version
|
145
|
-
version: '
|
159
|
+
version: '1.42'
|
146
160
|
type: :development
|
147
161
|
prerelease: false
|
148
162
|
version_requirements: !ruby/object:Gem::Requirement
|
149
163
|
requirements:
|
150
164
|
- - "~>"
|
151
165
|
- !ruby/object:Gem::Version
|
152
|
-
version: '
|
166
|
+
version: '1.42'
|
167
|
+
- !ruby/object:Gem::Dependency
|
168
|
+
name: simplecov
|
169
|
+
requirement: !ruby/object:Gem::Requirement
|
170
|
+
requirements:
|
171
|
+
- - '='
|
172
|
+
- !ruby/object:Gem::Version
|
173
|
+
version: '0.17'
|
174
|
+
type: :development
|
175
|
+
prerelease: false
|
176
|
+
version_requirements: !ruby/object:Gem::Requirement
|
177
|
+
requirements:
|
178
|
+
- - '='
|
179
|
+
- !ruby/object:Gem::Version
|
180
|
+
version: '0.17'
|
153
181
|
- !ruby/object:Gem::Dependency
|
154
182
|
name: codeclimate-test-reporter
|
155
183
|
requirement: !ruby/object:Gem::Requirement
|
@@ -173,9 +201,6 @@ extra_rdoc_files: []
|
|
173
201
|
files:
|
174
202
|
- ".codeclimate.yml"
|
175
203
|
- ".gitignore"
|
176
|
-
- ".overcommit.yml"
|
177
|
-
- ".overcommit_gems.rb"
|
178
|
-
- ".reek"
|
179
204
|
- ".rspec"
|
180
205
|
- ".rubocop.yml"
|
181
206
|
- ".travis.yml"
|
@@ -198,10 +223,10 @@ files:
|
|
198
223
|
- lib/devise/jwt/models/jwt_authenticatable.rb
|
199
224
|
- lib/devise/jwt/railtie.rb
|
200
225
|
- lib/devise/jwt/revocation_strategies.rb
|
201
|
-
- lib/devise/jwt/revocation_strategies/
|
226
|
+
- lib/devise/jwt/revocation_strategies/allowlist.rb
|
227
|
+
- lib/devise/jwt/revocation_strategies/denylist.rb
|
202
228
|
- lib/devise/jwt/revocation_strategies/jti_matcher.rb
|
203
229
|
- lib/devise/jwt/revocation_strategies/null.rb
|
204
|
-
- lib/devise/jwt/revocation_strategies/whitelist.rb
|
205
230
|
- lib/devise/jwt/test_helpers.rb
|
206
231
|
- lib/devise/jwt/version.rb
|
207
232
|
homepage: https://github.com/waiting-for-dev/devise-jwt
|
@@ -224,7 +249,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
224
249
|
version: '0'
|
225
250
|
requirements: []
|
226
251
|
rubyforge_project:
|
227
|
-
rubygems_version: 2.
|
252
|
+
rubygems_version: 2.7.8
|
228
253
|
signing_key:
|
229
254
|
specification_version: 4
|
230
255
|
summary: JWT authentication for devise
|
data/.overcommit.yml
DELETED
@@ -1,56 +0,0 @@
|
|
1
|
-
#
|
2
|
-
# Select version of overcommit and the other tools from Gemfile
|
3
|
-
#
|
4
|
-
gemfile: .overcommit_gems.rb
|
5
|
-
|
6
|
-
#
|
7
|
-
# Hooks that are run against every commit message after a user has written it.
|
8
|
-
#
|
9
|
-
CommitMsg:
|
10
|
-
ALL:
|
11
|
-
required: true
|
12
|
-
exclude: &default_excludes
|
13
|
-
- Gemfile
|
14
|
-
- devise-jwt.gemspec
|
15
|
-
- spec/fixtures/rails_app/**/*
|
16
|
-
- README.md
|
17
|
-
- CHANGELOG.md
|
18
|
-
|
19
|
-
HardTabs:
|
20
|
-
enabled: true
|
21
|
-
|
22
|
-
SingleLineSubject:
|
23
|
-
enabled: true
|
24
|
-
|
25
|
-
#
|
26
|
-
# Hooks that are run after `git commit` is executed, before the commit message
|
27
|
-
# editor is displayed.
|
28
|
-
#
|
29
|
-
PreCommit:
|
30
|
-
ALL:
|
31
|
-
required: true
|
32
|
-
exclude: *default_excludes
|
33
|
-
|
34
|
-
BundleAudit:
|
35
|
-
enabled: true
|
36
|
-
|
37
|
-
BundleCheck:
|
38
|
-
enabled: true
|
39
|
-
|
40
|
-
LocalPathsInGemfile:
|
41
|
-
enabled: true
|
42
|
-
|
43
|
-
ExecutePermissions:
|
44
|
-
enabled: true
|
45
|
-
exclude:
|
46
|
-
- *default_excludes
|
47
|
-
- bin/*
|
48
|
-
|
49
|
-
Reek:
|
50
|
-
enabled: true
|
51
|
-
|
52
|
-
RuboCop:
|
53
|
-
enabled: true
|
54
|
-
|
55
|
-
TrailingWhitespace:
|
56
|
-
enabled: true
|
data/.overcommit_gems.rb
DELETED
@@ -1,15 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
source 'https://rubygems.org'
|
4
|
-
|
5
|
-
gem 'overcommit', '~> 0.36'
|
6
|
-
|
7
|
-
# Patch-level verification for Bundled apps
|
8
|
-
gem 'bundler-audit', '~> 0.5'
|
9
|
-
|
10
|
-
# Ruby code smell reporter
|
11
|
-
gem 'reek', '~> 4.5'
|
12
|
-
|
13
|
-
# Ruby code style checking
|
14
|
-
gem 'rubocop', '~> 0.47'
|
15
|
-
gem 'rubocop-rspec', '~> 1.10'
|
data/.reek
DELETED
File without changes
|