devise-jwt 0.5.7 → 0.8.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|