devise-jwt 0.1.1 → 0.2.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
  SHA1:
3
- metadata.gz: 2ecbf7273869cd4de429e93d195909ba9da9d104
4
- data.tar.gz: 063fd47a63596b94658f9a51ff2dd7bd42f82a8d
3
+ metadata.gz: abe51a448ee1c23ead964f1d3fd53ef1a0f1443d
4
+ data.tar.gz: 7731662d778cc78da4265f7850d071f8632d7d99
5
5
  SHA512:
6
- metadata.gz: 6bc1230d565cf6be101e35461a020980fd65cca899b77f6630f177b6b890c7adfa98f8e2808fd224b1cfdf0c3679965eb8316a5f0962c32b6a75e75f3cfc9994
7
- data.tar.gz: 145836767694dceeb3190bfb98d87c4caaf5fdcf3147567206c92dcba347b14a6246c40ef48804189d0bbdcacbd1af3d54d324be57acd43db5255556e7a2ca07
6
+ metadata.gz: 174b7dc71c02263dc0be659bac3c4cc980b37e80cc735c980845c0a7f9a2732eebfd0956b0b473bc3da0e9e7b14c85365a4465ac243fa75367435bdf7fc8f03a
7
+ data.tar.gz: 6df5de828db92a655a6ecdef225f7bfb3680479c9bcb8ef6769323430f7420371135d7a675992f301b7eb32ee7619ce9f1fc878e9da7454641273cc11e77a098
@@ -4,6 +4,15 @@ 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.2.0] - 2017-02-28
8
+ ### Added
9
+ - Dispatch token on sign up
10
+ - Speed up initialization
11
+ ### Fixed
12
+ - Do not depend on assumed helpers to build default paths
13
+ - Use `sign_out_via` devise option to set revocation request methods
14
+ - Take routes with scopes into account
15
+
7
16
  ## [0.1.1] - 2017-01-26
8
17
  ### Fixed
9
18
  - Request method configuration for Rails < 5
data/README.md CHANGED
@@ -1,5 +1,6 @@
1
1
  # Devise::JWT
2
2
 
3
+ [![Gem Version](https://badge.fury.io/rb/devise-jwt.svg)](https://badge.fury.io/rb/devise-jwt)
3
4
  [![Build Status](https://travis-ci.org/waiting-for-dev/devise-jwt.svg?branch=master)](https://travis-ci.org/waiting-for-dev/devise-jwt)
4
5
  [![Code Climate](https://codeclimate.com/github/waiting-for-dev/devise-jwt/badges/gpa.svg)](https://codeclimate.com/github/waiting-for-dev/devise-jwt)
5
6
  [![Test Coverage](https://codeclimate.com/github/waiting-for-dev/devise-jwt/badges/coverage.svg)](https://codeclimate.com/github/waiting-for-dev/devise-jwt/coverage)
@@ -11,7 +12,7 @@ You can read about which security concerns this library takes into account and a
11
12
  - [Stand Up for JWT Revocation](http://waiting-for-dev.github.io/blog/2017/01/23/stand_up_for_jwt_revocation/)
12
13
  - [JWT Recovation Strategies](http://waiting-for-dev.github.io/blog/2017/01/24/jwt_revocation_strategies/)
13
14
  - [JWT Secure Usage](http://waiting-for-dev.github.io/blog/2017/01/25/jwt_secure_usage/)
14
- - [A secure JWT authentication implementation for Rack and Rails](http://waiting-for-dev.github.io/blog/2017/01/26/a_secure_jwt_authentication_for_rack_and_rails)
15
+ - [A secure JWT authentication implementation for Rack and Rails](http://waiting-for-dev.github.io/blog/2017/01/26/a_secure_jwt_authentication_implementation_for_rack_and_rails/)
15
16
 
16
17
  `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.
17
18
 
@@ -55,7 +56,7 @@ Currently, HS256 algorithm is the one in use.
55
56
  You have to tell which user models you want to be able to authenticate with JWT tokens. For them, the authentication process will be like this:
56
57
 
57
58
  - A user authenticates trough devise create session request (for example, using the standard `:database_authenticatable` module).
58
- - If the authentication succeeds, a JWT token is dispatched to the client in the `Authorization` response header, with format `Bearer #{token}`
59
+ - If the authentication succeeds, a JWT token is dispatched to the client in the `Authorization` response header, with format `Bearer #{token}` (tokens are also dispatched on a successful sign up).
59
60
  - The client can use this token to authenticate following requests for the same user, providing it in the `Authorization` request header, also with format `Bearer #{token}`
60
61
  - When the client visits devise destroy session request, the token is revoked.
61
62
 
@@ -1,9 +1,11 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'forwardable'
3
4
  require 'devise'
4
5
  require 'active_support/core_ext/module/attribute_accessors'
5
6
  require 'warden/jwt_auth'
6
7
  require 'devise/jwt/version'
8
+ require 'devise/jwt/mapping_inspector'
7
9
  require 'devise/jwt/defaults_generator'
8
10
  require 'devise/jwt/railtie'
9
11
  require 'devise/jwt/models'
@@ -15,12 +17,33 @@ module Devise
15
17
  #
16
18
  # @see Warden::JWTAuth
17
19
  def self.jwt
18
- yield(Warden::JWTAuth.config)
20
+ yield(Devise::JWT.config)
19
21
  end
20
22
 
21
23
  add_module(:jwt_authenticatable, strategy: :jwt)
22
24
 
23
25
  # JWT extension for devise
24
26
  module JWT
27
+ extend Dry::Configurable
28
+
29
+ setting(:secret) do |value|
30
+ forward_to_warden(:secret, value)
31
+ end
32
+
33
+ setting(:expiration_time) do |value|
34
+ forward_to_warden(:expiration_time, value)
35
+ end
36
+
37
+ setting(:dispatch_requests) do |value|
38
+ forward_to_warden(:dispatch_requests, value)
39
+ end
40
+
41
+ setting(:revocation_requests) do |value|
42
+ forward_to_warden(:revocation_requests, value)
43
+ end
44
+
45
+ def self.forward_to_warden(setting, value)
46
+ Warden::JWTAuth.config.send("#{setting}=", value)
47
+ end
25
48
  end
26
49
  end
@@ -7,66 +7,91 @@ module Devise
7
7
  #
8
8
  # @see Warden::JWTAuth
9
9
  class DefaultsGenerator
10
- attr_reader :routes, :devise_mappings
10
+ attr_reader :devise_mappings, :defaults
11
+
12
+ def self.call
13
+ new.call
14
+ end
11
15
 
12
16
  def initialize
13
- @routes = Rails.application.routes
14
17
  @devise_mappings = Devise.mappings
18
+ @defaults = {
19
+ mappings: {},
20
+ revocation_strategies: {},
21
+ dispatch_requests: [],
22
+ revocation_requests: []
23
+ }
15
24
  end
16
25
 
17
- def mappings
18
- @mappings ||= devise_mappings.each_with_object({}) do |tuple, hash|
19
- scope, mapping = tuple
20
- modules = mapping.modules
21
- next unless modules.include?(:jwt_authenticatable)
22
- hash[scope] = mapping.to
26
+ def call
27
+ devise_mappings.each_key do |scope|
28
+ inspector = MappingInspector.new(scope)
29
+ next unless inspector.jwt?
30
+ add_defaults(inspector)
23
31
  end
32
+ defaults
24
33
  end
25
34
 
26
- def dispatch_requests
27
- scopes.each_with_object([]) do |scope, array|
28
- named_route = "#{scope}_session"
29
- array << request_for(named_route)
30
- end
35
+ private
36
+
37
+ def add_defaults(inspector)
38
+ add_mapping(inspector)
39
+ add_revocation_strategy(inspector)
40
+ add_dispatch_requests(inspector)
41
+ add_revocation_requests(inspector)
31
42
  end
32
43
 
33
- def revocation_requests
34
- scopes.each_with_object([]) do |scope, array|
35
- named_route = "destroy_#{scope}_session"
36
- array << request_for(named_route)
37
- end
44
+ # :reek:FeatureEnvy
45
+ def add_mapping(inspector)
46
+ scope = inspector.scope
47
+ model = inspector.model
48
+ defaults[:mappings][scope] = model
38
49
  end
39
50
 
40
- def revocation_strategies
41
- mappings.each_with_object({}) do |tuple, hash|
42
- scope, model = tuple
43
- hash[scope] = model.jwt_revocation_strategy
44
- end
51
+ # :reek:FeatureEnvy
52
+ def add_revocation_strategy(inspector)
53
+ scope = inspector.scope
54
+ model = inspector.model
55
+ defaults[:revocation_strategies][scope] = model.jwt_revocation_strategy
45
56
  end
46
57
 
47
- private
58
+ def add_dispatch_requests(inspector)
59
+ add_sign_in_request(inspector)
60
+ add_registration_request(inspector)
61
+ end
48
62
 
49
- def scopes
50
- mappings.keys
63
+ def add_sign_in_request(inspector)
64
+ return unless inspector.session?
65
+ defaults[:dispatch_requests] << sign_in_request(inspector)
51
66
  end
52
67
 
53
- def request_for(named_route)
54
- named_path = "#{named_route}_path"
55
- route = routes.named_routes[named_route]
56
- method = method_for_route(route)
57
- path = /^#{routes.url_helpers.send(named_path)}$/
58
- [method, path]
68
+ def add_registration_request(inspector)
69
+ return unless inspector.registration?
70
+ defaults[:dispatch_requests] << registration_request(inspector)
71
+ end
72
+
73
+ def add_revocation_requests(inspector)
74
+ return unless inspector.session?
75
+ defaults[:revocation_requests] << sign_out_request(inspector)
76
+ end
77
+
78
+ def sign_in_request(inspector)
79
+ request(inspector, :sign_in)
80
+ end
81
+
82
+ def sign_out_request(inspector)
83
+ request(inspector, :sign_out)
84
+ end
85
+
86
+ def registration_request(inspector)
87
+ request(inspector, :registration)
59
88
  end
60
89
 
61
90
  # :reek:UtilityFunction
62
- # @see https://github.com/rails/rails/pull/21849
63
- def method_for_route(route)
64
- verb = route.verb
65
- if Rails.version.to_i < 5
66
- verb.source.match(/\w+/)[0]
67
- else
68
- verb
69
- end
91
+ def request(inspector, name)
92
+ path = inspector.path(name)
93
+ method = inspector.method(name)
94
+ [method, /^#{path}$/]
70
95
  end
71
96
  end
72
97
  end
@@ -0,0 +1,69 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Devise
4
+ module JWT
5
+ # Inspect and extract information from a Devise mapping
6
+ class MappingInspector
7
+ attr_reader :scope, :mapping
8
+
9
+ def initialize(scope)
10
+ @scope = scope
11
+ @mapping = Devise.mappings[scope]
12
+ end
13
+
14
+ def jwt?
15
+ mapping.modules.member?(:jwt_authenticatable)
16
+ end
17
+
18
+ def session?
19
+ routes?(:session)
20
+ end
21
+
22
+ def registration?
23
+ routes?(:registration)
24
+ end
25
+
26
+ def model
27
+ mapping.to
28
+ end
29
+
30
+ def path(name)
31
+ prefix, scope, request = path_parts(name)
32
+ [prefix, scope, request].compact.join('/').prepend('/')
33
+ end
34
+
35
+ # :reek:ControlParameter
36
+ def method(name)
37
+ case name
38
+ when :sign_in
39
+ 'POST'
40
+ when :sign_out
41
+ sign_out_via.to_s.upcase
42
+ when :registration
43
+ 'POST'
44
+ end
45
+ end
46
+
47
+ private
48
+
49
+ def path_parts(name)
50
+ prefix = mapping.instance_variable_get(:@path_prefix)
51
+ path = mapping.path
52
+ path_name = mapping.path_names[name]
53
+ [
54
+ prefix && prefix.gsub(%r{^/}, ''),
55
+ path,
56
+ path_name && !path_name.empty? ? path_name : nil
57
+ ]
58
+ end
59
+
60
+ def routes?(name)
61
+ mapping.routes.member?(name)
62
+ end
63
+
64
+ def sign_out_via
65
+ mapping.sign_out_via.to_s.upcase
66
+ end
67
+ end
68
+ end
69
+ end
@@ -13,12 +13,12 @@ module Devise
13
13
  Rails.application.reload_routes!
14
14
 
15
15
  Warden::JWTAuth.configure do |config|
16
- defaults = DefaultsGenerator.new
16
+ defaults = DefaultsGenerator.call
17
17
 
18
- config.mappings = defaults.mappings
19
- config.dispatch_requests.push(*defaults.dispatch_requests)
20
- config.revocation_requests.push(*defaults.revocation_requests)
21
- config.revocation_strategies = defaults.revocation_strategies
18
+ config.mappings = defaults[:mappings]
19
+ config.dispatch_requests.push(*defaults[:dispatch_requests])
20
+ config.revocation_requests.push(*defaults[:revocation_requests])
21
+ config.revocation_strategies = defaults[:revocation_strategies]
22
22
  end
23
23
  end
24
24
  end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Devise
4
4
  module JWT
5
- VERSION = '0.1.1'
5
+ VERSION = '0.2.0'
6
6
  end
7
7
  end
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.1.1
4
+ version: 0.2.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: 2017-01-26 00:00:00.000000000 Z
11
+ date: 2017-02-28 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: devise
@@ -192,6 +192,7 @@ files:
192
192
  - docker-compose.yml
193
193
  - lib/devise/jwt.rb
194
194
  - lib/devise/jwt/defaults_generator.rb
195
+ - lib/devise/jwt/mapping_inspector.rb
195
196
  - lib/devise/jwt/models.rb
196
197
  - lib/devise/jwt/models/jwt_authenticatable.rb
197
198
  - lib/devise/jwt/railtie.rb
@@ -220,7 +221,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
220
221
  version: '0'
221
222
  requirements: []
222
223
  rubyforge_project:
223
- rubygems_version: 2.6.6
224
+ rubygems_version: 2.6.8
224
225
  signing_key:
225
226
  specification_version: 4
226
227
  summary: JWT authentication for devise