jwt-auth 4.2.0 → 5.0.0

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