jwt-auth 4.2.0 → 5.0.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.
Files changed (76) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +3 -0
  3. data/Gemfile +3 -0
  4. data/README.md +119 -18
  5. data/bin/build +22 -0
  6. data/bin/release +40 -0
  7. data/jwt-auth.gemspec +18 -15
  8. data/lib/jwt/auth.rb +2 -0
  9. data/lib/jwt/auth/access_token.rb +20 -0
  10. data/lib/jwt/auth/authenticatable.rb +16 -0
  11. data/lib/jwt/auth/authentication.rb +63 -22
  12. data/lib/jwt/auth/configuration.rb +4 -1
  13. data/lib/jwt/auth/refresh_token.rb +20 -0
  14. data/lib/jwt/auth/token.rb +49 -41
  15. data/lib/jwt/auth/version.rb +3 -1
  16. data/spec/controllers/content_controller_spec.rb +95 -0
  17. data/spec/controllers/tokens_controller_spec.rb +140 -0
  18. data/spec/dummy/Rakefile +2 -0
  19. data/spec/dummy/app/channels/application_cable/channel.rb +2 -0
  20. data/spec/dummy/app/channels/application_cable/connection.rb +2 -0
  21. data/spec/dummy/app/controllers/application_controller.rb +6 -1
  22. data/spec/dummy/app/controllers/content_controller.rb +29 -0
  23. data/spec/dummy/app/controllers/tokens_controller.rb +53 -0
  24. data/spec/dummy/app/helpers/application_helper.rb +2 -0
  25. data/spec/dummy/app/helpers/authentication_helper.rb +2 -0
  26. data/spec/dummy/app/jobs/application_job.rb +2 -0
  27. data/spec/dummy/app/mailers/application_mailer.rb +3 -1
  28. data/spec/dummy/app/models/application_record.rb +2 -0
  29. data/spec/dummy/app/models/user.rb +3 -6
  30. data/spec/dummy/bin/bundle +2 -0
  31. data/spec/dummy/bin/rails +2 -0
  32. data/spec/dummy/bin/rake +2 -0
  33. data/spec/dummy/bin/setup +2 -0
  34. data/spec/dummy/bin/update +2 -0
  35. data/spec/dummy/bin/yarn +7 -7
  36. data/spec/dummy/config.ru +2 -0
  37. data/spec/dummy/config/application.rb +2 -0
  38. data/spec/dummy/config/boot.rb +3 -1
  39. data/spec/dummy/config/environment.rb +2 -0
  40. data/spec/dummy/config/environments/development.rb +3 -1
  41. data/spec/dummy/config/environments/production.rb +4 -2
  42. data/spec/dummy/config/environments/test.rb +2 -0
  43. data/spec/dummy/config/initializers/application_controller_renderer.rb +2 -0
  44. data/spec/dummy/config/initializers/assets.rb +2 -0
  45. data/spec/dummy/config/initializers/backtrace_silencers.rb +2 -0
  46. data/spec/dummy/config/initializers/content_security_policy.rb +2 -0
  47. data/spec/dummy/config/initializers/cookies_serializer.rb +2 -0
  48. data/spec/dummy/config/initializers/filter_parameter_logging.rb +2 -0
  49. data/spec/dummy/config/initializers/inflections.rb +2 -0
  50. data/spec/dummy/config/initializers/jwt_auth.rb +9 -2
  51. data/spec/dummy/config/initializers/mime_types.rb +2 -0
  52. data/spec/dummy/config/initializers/new_framework_defaults_5_2.rb +2 -0
  53. data/spec/dummy/config/initializers/wrap_parameters.rb +3 -1
  54. data/spec/dummy/config/puma.rb +5 -3
  55. data/spec/dummy/config/routes.rb +5 -4
  56. data/spec/dummy/config/spring.rb +4 -2
  57. data/spec/dummy/db/migrate/20170726110751_create_users.rb +2 -0
  58. data/spec/dummy/db/migrate/20170726110825_add_token_version_to_user.rb +2 -0
  59. data/spec/dummy/db/migrate/20170726112117_add_activated_to_user.rb +2 -0
  60. data/spec/dummy/db/migrate/20190221100103_add_password_to_user.rb +7 -0
  61. data/spec/dummy/db/schema.rb +10 -9
  62. data/spec/jwt/auth/access_token_spec.rb +35 -0
  63. data/spec/jwt/auth/configuration_spec.rb +36 -0
  64. data/spec/jwt/auth/refresh_token_spec.rb +35 -0
  65. data/spec/jwt/auth/token_spec.rb +144 -0
  66. data/spec/models/user_spec.rb +24 -0
  67. data/spec/rails_helper.rb +8 -0
  68. data/spec/spec_helper.rb +51 -53
  69. data/spec/support/database_cleaner.rb +22 -0
  70. data/spec/support/matchers/return_token.rb +33 -0
  71. data/version.yml +1 -0
  72. metadata +119 -54
  73. data/spec/authentication_spec.rb +0 -136
  74. data/spec/configuration_spec.rb +0 -18
  75. data/spec/dummy/app/controllers/authentication_controller.rb +0 -22
  76. data/spec/token_spec.rb +0 -125
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # This file is auto-generated from the current state of the database. Instead
2
4
  # of editing this file, please use the migrations feature of Active Record to
3
5
  # incrementally modify your database, and then regenerate this schema definition.
@@ -10,14 +12,13 @@
10
12
  #
11
13
  # It's strongly recommended that you check this file into your version control system.
12
14
 
13
- ActiveRecord::Schema.define(version: 2017_07_26_112117) do
14
-
15
- create_table "users", force: :cascade do |t|
16
- t.string "email"
17
- t.datetime "created_at", null: false
18
- t.datetime "updated_at", null: false
19
- t.integer "token_version", default: 1, null: false
20
- t.boolean "activated", default: false
15
+ ActiveRecord::Schema.define(:version => 20_190_221_100_103) do
16
+ create_table 'users', :force => :cascade do |t|
17
+ t.string 'email'
18
+ t.datetime 'created_at', :null => false
19
+ t.datetime 'updated_at', :null => false
20
+ t.integer 'token_version', :default => 1, :null => false
21
+ t.boolean 'activated', :default => false
22
+ t.string 'password'
21
23
  end
22
-
23
24
  end
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rails_helper'
4
+
5
+ RSpec.describe JWT::Auth::AccessToken do
6
+ ##
7
+ # Configuration
8
+ #
9
+ ##
10
+ # Test variables
11
+ #
12
+ let(:user) { User.create! :activated => true }
13
+
14
+ ##
15
+ # Subject
16
+ #
17
+ subject(:token) { described_class.new }
18
+
19
+ ##
20
+ # Tests
21
+ #
22
+ describe '#type' do
23
+ it 'returns the correct token type' do
24
+ expect(subject.type).to eq :access
25
+ end
26
+ end
27
+
28
+ describe '#lifetime' do
29
+ it { is_expected.to respond_to :lifetime }
30
+
31
+ it 'returns an integer' do
32
+ expect(subject.lifetime).to be_a_kind_of Integer
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'securerandom'
4
+
5
+ require 'rails_helper'
6
+
7
+ RSpec.describe JWT::Auth do
8
+ ##
9
+ # Configuration
10
+ #
11
+ JWT::Auth.configure do |config|
12
+ config.refresh_token_lifetime = 1.year
13
+ config.access_token_lifetime = 2.hours
14
+ config.secret = 'mysecret'
15
+ end
16
+
17
+ ##
18
+ # Test variables
19
+ #
20
+
21
+ # Ensure the User model is autoloaded, which initializes the JWT::Auth.model configuration entry
22
+ before { User }
23
+
24
+ ##
25
+ # Subject
26
+ #
27
+ subject { JWT::Auth }
28
+
29
+ ##
30
+ # Tests
31
+ #
32
+ it { is_expected.to have_attributes :refresh_token_lifetime => 1.year,
33
+ :access_token_lifetime => 2.hours,
34
+ :secret => 'mysecret',
35
+ :model => 'User' }
36
+ end
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rails_helper'
4
+
5
+ RSpec.describe JWT::Auth::RefreshToken do
6
+ ##
7
+ # Configuration
8
+ #
9
+ ##
10
+ # Test variables
11
+ #
12
+ let(:user) { User.create! :activated => true }
13
+
14
+ ##
15
+ # Subject
16
+ #
17
+ subject(:token) { described_class.new }
18
+
19
+ ##
20
+ # Tests
21
+ #
22
+ describe '#type' do
23
+ it 'returns the correct token type' do
24
+ expect(subject.type).to eq :refresh
25
+ end
26
+ end
27
+
28
+ describe '#lifetime' do
29
+ it { is_expected.to respond_to :lifetime }
30
+
31
+ it 'returns an integer' do
32
+ expect(subject.lifetime).to be_a_kind_of Integer
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,144 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rails_helper'
4
+
5
+ RSpec.describe JWT::Auth::Token do
6
+ ##
7
+ # Configuration
8
+ #
9
+ ##
10
+ # Test variables
11
+ #
12
+ let(:user) { User.create! :activated => true }
13
+
14
+ ##
15
+ # Subject
16
+ #
17
+ subject(:token) { described_class.new }
18
+
19
+ ##
20
+ # Tests
21
+ #
22
+ describe 'properties' do
23
+ it { is_expected.to respond_to :issued_at }
24
+ it { is_expected.to respond_to :subject }
25
+ it { is_expected.to respond_to :version }
26
+
27
+ it { is_expected.to have_attributes :issued_at => nil, :subject => nil, :version => nil }
28
+
29
+ describe 'constructor' do
30
+ subject(:token) { described_class.new :issued_at => 'foo', :subject => 'bar', :version => 'bat' }
31
+
32
+ it { is_expected.to have_attributes :issued_at => 'foo', :subject => 'bar', :version => 'bat' }
33
+ end
34
+ end
35
+
36
+ describe '#valid?' do
37
+ before do
38
+ # Override not implemented methods for test purposes
39
+ allow_any_instance_of(described_class).to receive(:type).and_return :access
40
+ allow_any_instance_of(described_class).to receive(:lifetime).and_return 2.hours.to_i
41
+ end
42
+
43
+ subject(:token) { described_class.new :subject => user,
44
+ :issued_at => Time.now.to_i,
45
+ :version => user.token_version }
46
+
47
+ it { is_expected.to be_valid }
48
+
49
+ context 'when the subject is nil' do
50
+ before { token.subject = nil }
51
+
52
+ it { is_expected.not_to be_valid }
53
+ end
54
+
55
+ context 'when the subject is destroyed' do
56
+ before { user.destroy }
57
+
58
+ it { is_expected.not_to be_valid }
59
+ end
60
+
61
+ context 'when issued_at is nil' do
62
+ before { token.issued_at = nil }
63
+
64
+ it { is_expected.not_to be_valid }
65
+ end
66
+
67
+ context 'when version is nil' do
68
+ before { token.version = nil }
69
+
70
+ it { is_expected.not_to be_valid }
71
+ end
72
+
73
+ context 'when token_version is incremented' do
74
+ # Explicitly call `token` to initialize it with the old token_version
75
+ before { token; user.increment! :token_version }
76
+
77
+ it { is_expected.not_to be_valid }
78
+ end
79
+
80
+ context 'when the token has expired' do
81
+ before { token.issued_at = JWT::Auth.access_token_lifetime.ago.to_i }
82
+
83
+ it { is_expected.not_to be_valid }
84
+ end
85
+
86
+ context 'when the issued_at is in the future' do
87
+ before { token.issued_at = 1.year.from_now.to_i }
88
+
89
+ it { is_expected.not_to be_valid }
90
+ end
91
+ end
92
+
93
+ describe '#to_jwt' do
94
+ before do
95
+ # Override not implemented methods for test purposes
96
+ allow_any_instance_of(described_class).to receive(:type).and_return :access
97
+ end
98
+
99
+ let(:token) { described_class.new :subject => user }
100
+ subject(:payload) { JWT.decode(token.to_jwt, JWT::Auth.secret).first }
101
+
102
+ it { is_expected.to eq 'iat' => Time.now.to_i, 'sub' => user.id, 'ver' => user.token_version, 'typ' => 'access' }
103
+ end
104
+
105
+ describe '.from_jwt' do
106
+ let(:jwt) { JWT.encode({ :iat => Time.now.to_i, :sub => user.id, :ver => user.token_version, :typ => type }, JWT::Auth.secret) }
107
+ let(:type) { :access }
108
+ subject(:token) { described_class.from_jwt jwt }
109
+
110
+ it { is_expected.to have_attributes :issued_at => a_kind_of(Integer), :subject => user, :version => user.token_version }
111
+
112
+ context 'when the jwt cannot be decoded' do
113
+ let(:jwt) { 'rubbish' }
114
+
115
+ it { is_expected.to be_nil }
116
+ end
117
+
118
+ context 'when the typ payload parameter is nil' do
119
+ let(:type) { nil }
120
+
121
+ it { is_expected.to be_nil }
122
+ end
123
+
124
+ context 'when the typ payload parameter is "access"' do
125
+ let(:type) { :access }
126
+
127
+ it { is_expected.to be_an_instance_of JWT::Auth::AccessToken }
128
+ end
129
+
130
+ context 'when the typ payload parameter is "refresh"' do
131
+ let(:type) { :refresh }
132
+
133
+ it { is_expected.to be_an_instance_of JWT::Auth::RefreshToken }
134
+ end
135
+
136
+ it 'calls the User#find_by_token method' do
137
+ expect(User).to receive(:find_by_token)
138
+ .with :id => user.id,
139
+ :token_version => user.token_version
140
+
141
+ described_class.from_jwt jwt
142
+ end
143
+ end
144
+ end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rails_helper'
4
+
5
+ RSpec.describe User do
6
+ ##
7
+ # Configuration
8
+ #
9
+ ##
10
+ # Test variables
11
+ #
12
+ ##
13
+ # Subject
14
+ #
15
+ ##
16
+ # Tests
17
+ #
18
+ it { is_expected.to validate_presence_of :token_version }
19
+ it { is_expected.to respond_to :find_by_token }
20
+
21
+ it 'sets the JWT::Auth configuration model entry to User' do
22
+ expect(JWT::Auth.model).to eq described_class.to_s
23
+ end
24
+ end
@@ -6,6 +6,7 @@ abort('The Rails environment is running in production mode!') if Rails.env.produ
6
6
  require 'spec_helper'
7
7
  require 'rspec/rails'
8
8
  # Add additional requires below this line. Rails is not loaded until this point!
9
+ require 'shoulda/matchers'
9
10
 
10
11
  require 'dummy/config/environment'
11
12
  # ENV['RAILS_ROOT'] ||= File.join File.dirname(__FILE__), 'spec', 'dummy'
@@ -48,3 +49,10 @@ RSpec.configure do |config|
48
49
  # arbitrary gems may also be filtered via:
49
50
  # config.filter_gems_from_backtrace("gem name")
50
51
  end
52
+
53
+ Shoulda::Matchers.configure do |config|
54
+ config.integrate do |with|
55
+ with.test_framework :rspec
56
+ with.library :rails
57
+ end
58
+ end
@@ -57,57 +57,55 @@ RSpec.configure do |config|
57
57
  # triggering implicit auto-inclusion in groups with matching metadata.
58
58
  config.shared_context_metadata_behavior = :apply_to_host_groups
59
59
 
60
- # The settings below are suggested to provide a good initial experience
61
- # with RSpec, but feel free to customize to your heart's content.
62
- =begin
63
- # This allows you to limit a spec run to individual examples or groups
64
- # you care about by tagging them with `:focus` metadata. When nothing
65
- # is tagged with `:focus`, all examples get run. RSpec also provides
66
- # aliases for `it`, `describe`, and `context` that include `:focus`
67
- # metadata: `fit`, `fdescribe` and `fcontext`, respectively.
68
- config.filter_run_when_matching :focus
69
-
70
- # Allows RSpec to persist some state between runs in order to support
71
- # the `--only-failures` and `--next-failure` CLI options. We recommend
72
- # you configure your source control system to ignore this file.
73
- config.example_status_persistence_file_path = "spec/examples.txt"
74
-
75
- # Limits the available syntax to the non-monkey patched syntax that is
76
- # recommended. For more details, see:
77
- # - http://rspec.info/blog/2012/06/rspecs-new-expectation-syntax/
78
- # - http://www.teaisaweso.me/blog/2013/05/27/rspecs-new-message-expectation-syntax/
79
- # - http://rspec.info/blog/2014/05/notable-changes-in-rspec-3/#zero-monkey-patching-mode
80
- config.disable_monkey_patching!
81
-
82
- # This setting enables warnings. It's recommended, but in some cases may
83
- # be too noisy due to issues in dependencies.
84
- config.warnings = true
85
-
86
- # Many RSpec users commonly either run the entire suite or an individual
87
- # file, and it's useful to allow more verbose output when running an
88
- # individual spec file.
89
- if config.files_to_run.one?
90
- # Use the documentation formatter for detailed output,
91
- # unless a formatter has already been configured
92
- # (e.g. via a command-line flag).
93
- config.default_formatter = 'doc'
94
- end
95
-
96
- # Print the 10 slowest examples and example groups at the
97
- # end of the spec run, to help surface which specs are running
98
- # particularly slow.
99
- config.profile_examples = 10
100
-
101
- # Run specs in random order to surface order dependencies. If you find an
102
- # order dependency and want to debug it, you can fix the order by providing
103
- # the seed, which is printed after each run.
104
- # --seed 1234
105
- config.order = :random
106
-
107
- # Seed global randomization in this process using the `--seed` CLI option.
108
- # Setting this allows you to use `--seed` to deterministically reproduce
109
- # test failures related to randomization by passing the same `--seed` value
110
- # as the one that triggered the failure.
111
- Kernel.srand config.seed
112
- =end
60
+ # The settings below are suggested to provide a good initial experience
61
+ # with RSpec, but feel free to customize to your heart's content.
62
+ # # This allows you to limit a spec run to individual examples or groups
63
+ # # you care about by tagging them with `:focus` metadata. When nothing
64
+ # # is tagged with `:focus`, all examples get run. RSpec also provides
65
+ # # aliases for `it`, `describe`, and `context` that include `:focus`
66
+ # # metadata: `fit`, `fdescribe` and `fcontext`, respectively.
67
+ # config.filter_run_when_matching :focus
68
+ #
69
+ # # Allows RSpec to persist some state between runs in order to support
70
+ # # the `--only-failures` and `--next-failure` CLI options. We recommend
71
+ # # you configure your source control system to ignore this file.
72
+ # config.example_status_persistence_file_path = "spec/examples.txt"
73
+ #
74
+ # # Limits the available syntax to the non-monkey patched syntax that is
75
+ # # recommended. For more details, see:
76
+ # # - http://rspec.info/blog/2012/06/rspecs-new-expectation-syntax/
77
+ # # - http://www.teaisaweso.me/blog/2013/05/27/rspecs-new-message-expectation-syntax/
78
+ # # - http://rspec.info/blog/2014/05/notable-changes-in-rspec-3/#zero-monkey-patching-mode
79
+ # config.disable_monkey_patching!
80
+ #
81
+ # # This setting enables warnings. It's recommended, but in some cases may
82
+ # # be too noisy due to issues in dependencies.
83
+ # config.warnings = true
84
+ #
85
+ # # Many RSpec users commonly either run the entire suite or an individual
86
+ # # file, and it's useful to allow more verbose output when running an
87
+ # # individual spec file.
88
+ # if config.files_to_run.one?
89
+ # # Use the documentation formatter for detailed output,
90
+ # # unless a formatter has already been configured
91
+ # # (e.g. via a command-line flag).
92
+ # config.default_formatter = 'doc'
93
+ # end
94
+ #
95
+ # # Print the 10 slowest examples and example groups at the
96
+ # # end of the spec run, to help surface which specs are running
97
+ # # particularly slow.
98
+ # config.profile_examples = 10
99
+ #
100
+ # # Run specs in random order to surface order dependencies. If you find an
101
+ # # order dependency and want to debug it, you can fix the order by providing
102
+ # # the seed, which is printed after each run.
103
+ # # --seed 1234
104
+ # config.order = :random
105
+ #
106
+ # # Seed global randomization in this process using the `--seed` CLI option.
107
+ # # Setting this allows you to use `--seed` to deterministically reproduce
108
+ # # test failures related to randomization by passing the same `--seed` value
109
+ # # as the one that triggered the failure.
110
+ # Kernel.srand config.seed
113
111
  end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'database_cleaner'
4
+
5
+ RSpec.configure do |config|
6
+ # before the entire test suite runs, clear the test database out completely
7
+ config.before(:suite) do
8
+ DatabaseCleaner.clean
9
+ end
10
+
11
+ # Default strategy is transaction (very fast)
12
+ config.before do
13
+ DatabaseCleaner.strategy = :transaction
14
+ end
15
+
16
+ config.before do
17
+ DatabaseCleaner.start
18
+ end
19
+ config.after do
20
+ DatabaseCleaner.clean
21
+ end
22
+ end