solidus_jwt 0.1.0 → 1.2.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 +4 -4
- data/.circleci/config.yml +35 -0
- data/.gem_release.yml +5 -0
- data/.github/CODEOWNERS +4 -0
- data/.github/stale.yml +17 -0
- data/.gitignore +19 -0
- data/.rspec +1 -0
- data/.rubocop.yml +16 -0
- data/.ruby-gemset +1 -0
- data/.ruby-version +1 -0
- data/Gemfile +33 -0
- data/README.md +71 -2
- data/Rakefile +4 -28
- data/_config.yml +1 -0
- data/app/decorators/controllers/solidus_jwt/spree/api/base_controller_decorator.rb +41 -0
- data/app/decorators/models/solidus_jwt/spree/user_decorator.rb +58 -0
- data/app/models/solidus_jwt/base_record.rb +13 -0
- data/app/models/solidus_jwt/token.rb +63 -0
- data/bin/console +17 -0
- data/bin/r +9 -0
- data/bin/rails +8 -0
- data/bin/rails-engine +15 -0
- data/bin/rails-sandbox +17 -0
- data/bin/rake +7 -0
- data/bin/sandbox +84 -0
- data/bin/sandbox_rails +9 -0
- data/bin/setup +8 -0
- data/config/locales/en.yml +2 -1
- data/config/routes.rb +3 -0
- data/db/migrate/20190222220038_create_solidus_jwt_tokens.rb +14 -0
- data/db/migrate/20191212083655_add_foreign_key_to_users_table.rb +7 -0
- data/lib/controllers/api/spree/api/oauths_controller.rb +47 -0
- data/lib/generators/solidus_jwt/install/install_generator.rb +3 -11
- data/lib/solidus_jwt.rb +8 -0
- data/lib/solidus_jwt/concerns/decodeable.rb +7 -1
- data/lib/solidus_jwt/concerns/encodeable.rb +14 -2
- data/lib/solidus_jwt/config.rb +2 -0
- data/lib/solidus_jwt/devise_strategies/base.rb +25 -0
- data/lib/solidus_jwt/devise_strategies/password.rb +46 -0
- data/lib/solidus_jwt/devise_strategies/refresh_token.rb +48 -0
- data/lib/solidus_jwt/distributor/devise.rb +3 -1
- data/lib/solidus_jwt/engine.rb +8 -12
- data/lib/solidus_jwt/factories.rb +13 -0
- data/lib/solidus_jwt/preferences.rb +8 -0
- data/lib/solidus_jwt/version.rb +3 -9
- data/solidus_jwt.gemspec +38 -0
- data/spec/lib/solidus_jwt/concerns/decodeable_spec.rb +0 -0
- data/spec/lib/solidus_jwt/concerns/encodeable_spec.rb +0 -0
- data/spec/lib/solidus_jwt/config_spec.rb +7 -0
- data/spec/lib/solidus_jwt/devise_strategies/password_spec.rb +78 -0
- data/spec/lib/solidus_jwt/devise_strategies/refresh_token_spec.rb +74 -0
- data/spec/lib/solidus_jwt/preferences_spec.rb +39 -0
- data/spec/lib/solidus_jwt_spec.rb +8 -0
- data/spec/models/solidus_jwt/token_spec.rb +43 -0
- data/spec/requests/spree/api/json_web_tokens_spec.rb +77 -0
- data/spec/requests/spree/api/oauths_spec.rb +122 -0
- data/spec/spec_helper.rb +26 -0
- data/spec/support/shared_examples/decodeable_examples.rb +23 -0
- data/spec/support/shared_examples/encodeable_examples.rb +29 -0
- metadata +86 -222
- data/app/assets/javascripts/spree/backend/solidus_jwt.js +0 -2
- data/app/assets/javascripts/spree/frontend/solidus_jwt.js +0 -2
- data/app/assets/stylesheets/spree/backend/solidus_jwt.css +0 -4
- data/app/assets/stylesheets/spree/frontend/solidus_jwt.css +0 -4
- data/app/controllers/spree/api/base_controller/json_web_tokens.rb +0 -22
- data/app/controllers/spree/api/base_controller_decorator.rb +0 -17
- data/app/models/spree/user_decorator.rb +0 -30
@@ -0,0 +1,48 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module SolidusJwt
|
4
|
+
module DeviseStrategies
|
5
|
+
class RefreshToken < Base
|
6
|
+
def authenticate!
|
7
|
+
return fail!(:invalid) if resource.nil? || resource.user.nil?
|
8
|
+
|
9
|
+
block = proc do
|
10
|
+
# If we honor then mark the refresh token as stale for one time use
|
11
|
+
# rubocop:disable Rails/SkipsModelValidations
|
12
|
+
resource.honor? && resource.update_columns(active: false)
|
13
|
+
# rubocop:enable Rails/SkipsModelValidations
|
14
|
+
end
|
15
|
+
|
16
|
+
if resource.user.valid_for_authentication?(&block)
|
17
|
+
return success!(resource.user)
|
18
|
+
end
|
19
|
+
|
20
|
+
fail!(:invalid)
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def resource
|
26
|
+
@resource ||= SolidusJwt::Token.find_by(auth_hash)
|
27
|
+
end
|
28
|
+
|
29
|
+
def auth_hash
|
30
|
+
{ auth_type: :refresh, token: refresh_token }
|
31
|
+
end
|
32
|
+
|
33
|
+
def refresh_token
|
34
|
+
params[:refresh_token]
|
35
|
+
end
|
36
|
+
|
37
|
+
def valid_grant_type?
|
38
|
+
grant_type == 'refresh_token'
|
39
|
+
end
|
40
|
+
|
41
|
+
def valid_params?
|
42
|
+
refresh_token.present?
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
Warden::Strategies.add(:solidus_jwt_refresh_token, SolidusJwt::DeviseStrategies::RefreshToken)
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module SolidusJwt
|
2
4
|
module Distributor
|
3
5
|
module Devise
|
@@ -5,7 +7,7 @@ module SolidusJwt
|
|
5
7
|
# Send back json web token in redirect header
|
6
8
|
if try_spree_current_user
|
7
9
|
response.headers['X-SPREE-TOKEN'] = try_spree_current_user.
|
8
|
-
|
10
|
+
generate_jwt_token(expires_in: SolidusJwt::Config.jwt_expiration)
|
9
11
|
end
|
10
12
|
|
11
13
|
super
|
data/lib/solidus_jwt/engine.rb
CHANGED
@@ -1,22 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'spree/core'
|
4
|
+
|
1
5
|
module SolidusJwt
|
2
6
|
class Engine < Rails::Engine
|
3
|
-
|
4
|
-
|
7
|
+
include SolidusSupport::EngineExtensions
|
8
|
+
|
9
|
+
isolate_namespace ::Spree
|
10
|
+
|
5
11
|
engine_name 'solidus_jwt'
|
6
12
|
|
7
13
|
# use rspec for tests
|
8
14
|
config.generators do |g|
|
9
15
|
g.test_framework :rspec
|
10
16
|
end
|
11
|
-
|
12
|
-
def self.activate
|
13
|
-
decorator_pattern = File.join(__dir__, '../../app/**/*_decorator*.rb')
|
14
|
-
|
15
|
-
Dir.glob(decorator_pattern) do |c|
|
16
|
-
Rails.configuration.cache_classes ? require(c) : load(c)
|
17
|
-
end
|
18
|
-
end
|
19
|
-
|
20
|
-
config.to_prepare(&method(:activate).to_proc)
|
21
17
|
end
|
22
18
|
end
|
@@ -1,6 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
FactoryBot.define do
|
2
4
|
# Define your Spree extensions Factories within this file to enable applications, and other extensions to use and override them.
|
3
5
|
#
|
4
6
|
# Example adding this to your spec_helper will load these Factories for use:
|
5
7
|
# require 'solidus_jwt/factories'
|
8
|
+
factory :token, class: SolidusJwt::Token do
|
9
|
+
association :user
|
10
|
+
|
11
|
+
trait :expired do
|
12
|
+
created_at { 1.year.ago }
|
13
|
+
end
|
14
|
+
|
15
|
+
trait :inactive do
|
16
|
+
active { false }
|
17
|
+
end
|
18
|
+
end
|
6
19
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'spree/preferences/configuration'
|
2
4
|
|
3
5
|
module SolidusJwt
|
@@ -34,6 +36,12 @@ module SolidusJwt
|
|
34
36
|
#
|
35
37
|
preference :jwt_options, :hash, default: { only: %i[email first_name id last_name] }
|
36
38
|
|
39
|
+
# @!attribute [rw] refresh_expriation
|
40
|
+
# @return [String] How long until the refresh token expires in seconds
|
41
|
+
# (default: +2592000+)
|
42
|
+
#
|
43
|
+
preference :refresh_expiration, :integer, default: 2_592_000
|
44
|
+
|
37
45
|
##
|
38
46
|
# Get the secret token to encrypt json web tokens with.
|
39
47
|
# @return [String] The secret used to encrypt json web tokens
|
data/lib/solidus_jwt/version.rb
CHANGED
@@ -1,11 +1,5 @@
|
|
1
|
-
|
2
|
-
MAJOR = 0
|
3
|
-
MINOR = 1
|
4
|
-
PATCH = 0
|
5
|
-
PRERELEASE = nil
|
1
|
+
# frozen_string_literal: true
|
6
2
|
|
7
|
-
|
8
|
-
|
9
|
-
[version, PRERELEASE].compact.join('.')
|
10
|
-
end
|
3
|
+
module SolidusJwt
|
4
|
+
VERSION = '1.2.0'
|
11
5
|
end
|
data/solidus_jwt.gemspec
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'lib/solidus_jwt/version'
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = 'solidus_jwt'
|
7
|
+
s.version = SolidusJwt::VERSION
|
8
|
+
s.summary = 'Add Json Web Tokens to Solidus API'
|
9
|
+
s.description = 'Add Json Web Tokens to Solidus API'
|
10
|
+
s.license = 'BSD-3-Clause'
|
11
|
+
|
12
|
+
s.author = 'Taylor Scott'
|
13
|
+
s.email = 't.skukx@gmail.com'
|
14
|
+
s.homepage = 'https://github.com/skukx/solidus_jwt'
|
15
|
+
|
16
|
+
s.metadata['homepage_uri'] = s.homepage
|
17
|
+
s.metadata['source_code_uri'] = s.homepage
|
18
|
+
|
19
|
+
s.required_ruby_version = Gem::Requirement.new('~> 2.4')
|
20
|
+
|
21
|
+
# Specify which files should be added to the gem when it is released.
|
22
|
+
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
|
23
|
+
files = Dir.chdir(__dir__) { `git ls-files -z`.split("\x0") }
|
24
|
+
|
25
|
+
s.files = files.grep_v(%r{^(test|spec|features)/})
|
26
|
+
s.test_files = files.grep(%r{^(test|spec|features)/})
|
27
|
+
s.bindir = "exe"
|
28
|
+
s.executables = files.grep(%r{^exe/}) { |f| File.basename(f) }
|
29
|
+
s.require_paths = ["lib"]
|
30
|
+
|
31
|
+
s.add_dependency 'jwt'
|
32
|
+
s.add_dependency 'solidus_auth_devise'
|
33
|
+
s.add_dependency 'solidus_core', ['>= 2.0.0', '< 3']
|
34
|
+
s.add_dependency 'solidus_support', '~> 0.5.0'
|
35
|
+
|
36
|
+
s.add_development_dependency 'byebug'
|
37
|
+
s.add_development_dependency 'solidus_dev_support'
|
38
|
+
end
|
File without changes
|
File without changes
|
@@ -0,0 +1,78 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
require 'spree/testing_support/factories/user_factory'
|
5
|
+
|
6
|
+
RSpec.describe SolidusJwt::DeviseStrategies::Password do
|
7
|
+
let(:request) { instance_double('ActionController::Request') }
|
8
|
+
let(:strategy) { described_class.new(nil, :spree_user) }
|
9
|
+
|
10
|
+
let(:params) do
|
11
|
+
{
|
12
|
+
username: user.email,
|
13
|
+
password: password,
|
14
|
+
grant_type: 'password'
|
15
|
+
}
|
16
|
+
end
|
17
|
+
|
18
|
+
let(:headers) { {} }
|
19
|
+
let(:user) { FactoryBot.create(:user, password: password) }
|
20
|
+
let(:password) { 'secret' }
|
21
|
+
|
22
|
+
before do
|
23
|
+
allow(request).to receive(:headers).and_return(:headers)
|
24
|
+
|
25
|
+
allow(strategy).to receive(:request).and_return(request)
|
26
|
+
allow(strategy).to receive(:params).and_return(params)
|
27
|
+
end
|
28
|
+
|
29
|
+
describe '#valid?' do
|
30
|
+
subject { strategy.valid? }
|
31
|
+
|
32
|
+
it { is_expected.to be true }
|
33
|
+
|
34
|
+
context 'when username is missing' do
|
35
|
+
before { params.delete(:username) }
|
36
|
+
|
37
|
+
it { is_expected.to be false }
|
38
|
+
end
|
39
|
+
|
40
|
+
context 'when password is missing' do
|
41
|
+
before { params.delete(:password) }
|
42
|
+
|
43
|
+
it { is_expected.to be false }
|
44
|
+
end
|
45
|
+
|
46
|
+
context 'when grant_type is not password' do
|
47
|
+
before { params[:grant_type] = 'invalid' }
|
48
|
+
|
49
|
+
it { is_expected.to be false }
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
describe '#authenticate!' do
|
54
|
+
subject { strategy.authenticate! }
|
55
|
+
|
56
|
+
it { is_expected.to be :success }
|
57
|
+
|
58
|
+
context 'when auth is invalid' do
|
59
|
+
let(:params) do
|
60
|
+
{
|
61
|
+
username: user.email,
|
62
|
+
password: 'invalid',
|
63
|
+
grant_type: password
|
64
|
+
}
|
65
|
+
end
|
66
|
+
|
67
|
+
it { is_expected.to be :failure }
|
68
|
+
end
|
69
|
+
|
70
|
+
context 'when user is not valid for authentication' do
|
71
|
+
before do
|
72
|
+
allow_any_instance_of(Spree::User).to receive(:valid_for_authentication?).and_return(false) # rubocop:disable RSpec/AnyInstance
|
73
|
+
end
|
74
|
+
|
75
|
+
it { is_expected.to be :failure }
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
require 'spree/testing_support/factories/user_factory'
|
5
|
+
|
6
|
+
RSpec.describe SolidusJwt::DeviseStrategies::RefreshToken do
|
7
|
+
let(:request) { instance_double('ActionController::Request') }
|
8
|
+
let(:strategy) { described_class.new(nil, :spree_user) }
|
9
|
+
|
10
|
+
let(:params) do
|
11
|
+
{
|
12
|
+
refresh_token: token.token,
|
13
|
+
grant_type: 'refresh_token'
|
14
|
+
}
|
15
|
+
end
|
16
|
+
|
17
|
+
let(:headers) { {} }
|
18
|
+
let(:user) { FactoryBot.create(:user, password: password) }
|
19
|
+
let(:password) { 'secret' }
|
20
|
+
let(:token) { user.auth_tokens.create! }
|
21
|
+
|
22
|
+
before do
|
23
|
+
allow(request).to receive(:headers).and_return(:headers)
|
24
|
+
|
25
|
+
allow(strategy).to receive(:request).and_return(request)
|
26
|
+
allow(strategy).to receive(:params).and_return(params)
|
27
|
+
end
|
28
|
+
|
29
|
+
describe '#valid?' do
|
30
|
+
subject { strategy.valid? }
|
31
|
+
|
32
|
+
it { is_expected.to be true }
|
33
|
+
|
34
|
+
context 'when refresh_token is missing' do
|
35
|
+
before { params.delete(:refresh_token) }
|
36
|
+
|
37
|
+
it { is_expected.to be false }
|
38
|
+
end
|
39
|
+
|
40
|
+
context 'when grant_type is not refresh_token' do
|
41
|
+
before { params[:grant_type] = 'invalid' }
|
42
|
+
|
43
|
+
it { is_expected.to be false }
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
describe '#authenticate!' do
|
48
|
+
subject { strategy.authenticate! }
|
49
|
+
|
50
|
+
it { is_expected.to be :success }
|
51
|
+
|
52
|
+
context 'when token is not honorable' do
|
53
|
+
before do
|
54
|
+
allow_any_instance_of(SolidusJwt::Token).to receive(:honor?).and_return false # rubocop:disable RSpec/AnyInstance
|
55
|
+
end
|
56
|
+
|
57
|
+
it { is_expected.to be :failure }
|
58
|
+
end
|
59
|
+
|
60
|
+
context 'when user is not valid for authentication' do
|
61
|
+
before do
|
62
|
+
allow_any_instance_of(Spree::User).to receive(:valid_for_authentication?).and_return(false) # rubocop:disable RSpec/AnyInstance
|
63
|
+
end
|
64
|
+
|
65
|
+
it { is_expected.to be :failure }
|
66
|
+
end
|
67
|
+
|
68
|
+
context 'when token is used more than once' do
|
69
|
+
before { strategy.authenticate! }
|
70
|
+
|
71
|
+
it { is_expected.to be :failure }
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
RSpec.describe SolidusJwt::Preferences do
|
6
|
+
let(:instance) { described_class.new }
|
7
|
+
|
8
|
+
it { is_expected.to be_kind_of(Spree::Preferences::Configuration) }
|
9
|
+
|
10
|
+
describe '#jwt_secret' do
|
11
|
+
subject { instance.jwt_secret }
|
12
|
+
|
13
|
+
it { is_expected.to eql Rails.application.secret_key_base }
|
14
|
+
end
|
15
|
+
|
16
|
+
describe '#allow_spree_api_key' do
|
17
|
+
subject { instance.allow_spree_api_key }
|
18
|
+
|
19
|
+
it { is_expected.to be true }
|
20
|
+
end
|
21
|
+
|
22
|
+
describe '#jwt_algorithm' do
|
23
|
+
subject { instance.jwt_algorithm }
|
24
|
+
|
25
|
+
it { is_expected.to eql 'HS256' }
|
26
|
+
end
|
27
|
+
|
28
|
+
describe '#jwt_expiration' do
|
29
|
+
subject { instance.jwt_expiration }
|
30
|
+
|
31
|
+
it { is_expected.to be 3600 }
|
32
|
+
end
|
33
|
+
|
34
|
+
describe '#jwt_options' do
|
35
|
+
subject { instance.jwt_options }
|
36
|
+
|
37
|
+
it { is_expected.to be_kind_of Hash }
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
RSpec.describe SolidusJwt::Token, type: :model do
|
6
|
+
subject { instance }
|
7
|
+
|
8
|
+
let(:instance) { FactoryBot.create(:token) }
|
9
|
+
|
10
|
+
it { is_expected.to be_valid }
|
11
|
+
it { is_expected.to be_active }
|
12
|
+
it { is_expected.not_to be_expired }
|
13
|
+
|
14
|
+
context 'when token is nil' do
|
15
|
+
let(:instance) { FactoryBot.build(:token, token: nil) }
|
16
|
+
|
17
|
+
it 'generates one automatically' do
|
18
|
+
expect(instance.token).to be_nil
|
19
|
+
instance.save
|
20
|
+
expect(instance.token).to be_present
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
describe '.honor?' do
|
25
|
+
subject { described_class.honor?(token) }
|
26
|
+
|
27
|
+
let(:token) { instance.token }
|
28
|
+
|
29
|
+
it { is_expected.to be true }
|
30
|
+
|
31
|
+
context 'when token is inactive' do
|
32
|
+
let(:instance) { FactoryBot.create(:token, :inactive) }
|
33
|
+
|
34
|
+
it { is_expected.to be false }
|
35
|
+
end
|
36
|
+
|
37
|
+
context 'when token is expired' do
|
38
|
+
let(:instance) { FactoryBot.create(:token, :expired) }
|
39
|
+
|
40
|
+
it { is_expected.to be false }
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|