solidus_jwt 0.1.0 → 1.2.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
data/bin/console
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
# frozen_string_literal: true
|
4
|
+
|
5
|
+
require "bundler/setup"
|
6
|
+
require "solidus_jwt"
|
7
|
+
|
8
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
9
|
+
# with your gem easier. You can also use a different console, if you like.
|
10
|
+
$LOAD_PATH.unshift(*Dir["#{__dir__}/../app/*"])
|
11
|
+
|
12
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
13
|
+
# require "pry"
|
14
|
+
# Pry.start
|
15
|
+
|
16
|
+
require "irb"
|
17
|
+
IRB.start(__FILE__)
|
data/bin/r
ADDED
data/bin/rails
ADDED
data/bin/rails-engine
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
# This command will automatically be run when you run "rails" with Rails gems
|
5
|
+
# installed from the root of your application.
|
6
|
+
|
7
|
+
ENGINE_ROOT = File.expand_path('..', __dir__)
|
8
|
+
ENGINE_PATH = File.expand_path('../lib/solidus_jwt/engine', __dir__)
|
9
|
+
|
10
|
+
# Set up gems listed in the Gemfile.
|
11
|
+
ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../Gemfile', __dir__)
|
12
|
+
require 'bundler/setup' if File.exist?(ENV['BUNDLE_GEMFILE'])
|
13
|
+
|
14
|
+
require 'rails/all'
|
15
|
+
require 'rails/engine/commands'
|
data/bin/rails-sandbox
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
app_root = 'sandbox'
|
5
|
+
|
6
|
+
unless File.exist? "#{app_root}/bin/rails"
|
7
|
+
warn 'Creating the sandbox app...'
|
8
|
+
Dir.chdir "#{__dir__}/.." do
|
9
|
+
system "#{__dir__}/sandbox" or begin # rubocop:disable Style/AndOr
|
10
|
+
warn 'Automatic creation of the sandbox app failed'
|
11
|
+
exit 1
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
Dir.chdir app_root
|
17
|
+
exec 'bin/rails', *ARGV
|
data/bin/rake
ADDED
data/bin/sandbox
ADDED
@@ -0,0 +1,84 @@
|
|
1
|
+
#!/usr/bin/env bash
|
2
|
+
|
3
|
+
set -e
|
4
|
+
|
5
|
+
case "$DB" in
|
6
|
+
postgres|postgresql)
|
7
|
+
RAILSDB="postgresql"
|
8
|
+
;;
|
9
|
+
mysql)
|
10
|
+
RAILSDB="mysql"
|
11
|
+
;;
|
12
|
+
sqlite|'')
|
13
|
+
RAILSDB="sqlite3"
|
14
|
+
;;
|
15
|
+
*)
|
16
|
+
echo "Invalid DB specified: $DB"
|
17
|
+
exit 1
|
18
|
+
;;
|
19
|
+
esac
|
20
|
+
|
21
|
+
if [ ! -z $SOLIDUS_BRANCH ]
|
22
|
+
then
|
23
|
+
BRANCH=$SOLIDUS_BRANCH
|
24
|
+
else
|
25
|
+
BRANCH="master"
|
26
|
+
fi
|
27
|
+
|
28
|
+
extension_name="solidus_jwt"
|
29
|
+
|
30
|
+
# Stay away from the bundler env of the containing extension.
|
31
|
+
function unbundled {
|
32
|
+
ruby -rbundler -e'b = proc {system *ARGV}; Bundler.respond_to?(:with_unbundled_env) ? Bundler.with_unbundled_env(&b) : Bundler.with_clean_env(&b)' -- $@
|
33
|
+
}
|
34
|
+
|
35
|
+
rm -rf ./sandbox
|
36
|
+
unbundled bundle exec rails new sandbox --database="$RAILSDB" \
|
37
|
+
--skip-bundle \
|
38
|
+
--skip-git \
|
39
|
+
--skip-keeps \
|
40
|
+
--skip-rc \
|
41
|
+
--skip-spring \
|
42
|
+
--skip-test \
|
43
|
+
--skip-javascript
|
44
|
+
|
45
|
+
if [ ! -d "sandbox" ]; then
|
46
|
+
echo 'sandbox rails application failed'
|
47
|
+
exit 1
|
48
|
+
fi
|
49
|
+
|
50
|
+
cd ./sandbox
|
51
|
+
cat <<RUBY >> Gemfile
|
52
|
+
gem 'solidus', github: 'solidusio/solidus', branch: '$BRANCH'
|
53
|
+
gem 'solidus_auth_devise', '>= 2.1.0'
|
54
|
+
gem 'rails-i18n'
|
55
|
+
gem 'solidus_i18n'
|
56
|
+
|
57
|
+
gem '$extension_name', path: '..'
|
58
|
+
|
59
|
+
group :test, :development do
|
60
|
+
platforms :mri do
|
61
|
+
gem 'pry-byebug'
|
62
|
+
end
|
63
|
+
end
|
64
|
+
RUBY
|
65
|
+
|
66
|
+
unbundled bundle install --gemfile Gemfile
|
67
|
+
|
68
|
+
unbundled bundle exec rake db:drop db:create
|
69
|
+
|
70
|
+
unbundled bundle exec rails generate spree:install \
|
71
|
+
--auto-accept \
|
72
|
+
--user_class=Spree::User \
|
73
|
+
--enforce_available_locales=true \
|
74
|
+
--with-authentication=false \
|
75
|
+
$@
|
76
|
+
|
77
|
+
unbundled bundle exec rails generate solidus:auth:install
|
78
|
+
|
79
|
+
echo
|
80
|
+
echo "🚀 Sandbox app successfully created for $extension_name!"
|
81
|
+
echo "🚀 Using $RAILSDB and Solidus $BRANCH"
|
82
|
+
echo "🚀 Use 'export DB=[postgres|mysql|sqlite]' to control the DB adapter"
|
83
|
+
echo "🚀 Use 'export SOLIDUS_BRANCH=<BRANCH-NAME>' to control the Solidus version"
|
84
|
+
echo "🚀 This app is intended for test purposes."
|
data/bin/sandbox_rails
ADDED
data/bin/setup
ADDED
data/config/locales/en.yml
CHANGED
data/config/routes.rb
CHANGED
@@ -0,0 +1,14 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class CreateSolidusJwtTokens < ActiveRecord::Migration[5.2]
|
4
|
+
def change
|
5
|
+
create_table :solidus_jwt_tokens do |t|
|
6
|
+
t.string :token, index: true
|
7
|
+
t.integer :auth_type, default: 0, null: false
|
8
|
+
t.integer :user_id, index: true
|
9
|
+
t.boolean :active, default: true, null: false
|
10
|
+
|
11
|
+
t.timestamps null: false
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Spree
|
4
|
+
module Api
|
5
|
+
class OauthsController < BaseController
|
6
|
+
skip_before_action :authenticate_user
|
7
|
+
|
8
|
+
def token
|
9
|
+
result = catch(:warden) do
|
10
|
+
try_authenticate_user
|
11
|
+
end
|
12
|
+
|
13
|
+
case result
|
14
|
+
when Spree::User
|
15
|
+
render json: token_response_json(result)
|
16
|
+
when Hash
|
17
|
+
render status: :unauthorized, json: { error: I18n.t(result[:message], scope: 'devise.failure') }
|
18
|
+
else
|
19
|
+
render status: :unauthorized, json: { error: I18n.t(:invalid_credentials, scope: 'solidus_jwt') }
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def token_response_json(user)
|
26
|
+
expires_in = SolidusJwt::Config.jwt_expiration
|
27
|
+
|
28
|
+
{
|
29
|
+
token_type: 'bearer',
|
30
|
+
access_token: user.generate_jwt(expires_in: expires_in),
|
31
|
+
expires_in: expires_in,
|
32
|
+
refresh_token: generate_refresh_token_for(user)
|
33
|
+
}
|
34
|
+
end
|
35
|
+
|
36
|
+
def try_authenticate_user
|
37
|
+
warden.authenticate(:solidus_jwt_password) ||
|
38
|
+
warden.authenticate(:solidus_jwt_refresh_token)
|
39
|
+
end
|
40
|
+
|
41
|
+
def generate_refresh_token_for(user)
|
42
|
+
token_resource = user.auth_tokens.create!
|
43
|
+
token_resource.token
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -1,18 +1,10 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module SolidusJwt
|
2
4
|
module Generators
|
3
5
|
class InstallGenerator < Rails::Generators::Base
|
4
6
|
class_option :auto_run_migrations, type: :boolean, default: false
|
5
7
|
|
6
|
-
def add_javascripts
|
7
|
-
append_file 'vendor/assets/javascripts/spree/frontend/all.js', "//= require spree/frontend/solidus_jwt\n"
|
8
|
-
append_file 'vendor/assets/javascripts/spree/backend/all.js', "//= require spree/backend/solidus_jwt\n"
|
9
|
-
end
|
10
|
-
|
11
|
-
def add_stylesheets
|
12
|
-
inject_into_file 'vendor/assets/stylesheets/spree/frontend/all.css', " *= require spree/frontend/solidus_jwt\n", before: /\*\//, verbose: true
|
13
|
-
inject_into_file 'vendor/assets/stylesheets/spree/backend/all.css', " *= require spree/backend/solidus_jwt\n", before: /\*\//, verbose: true
|
14
|
-
end
|
15
|
-
|
16
8
|
def add_migrations
|
17
9
|
run 'bundle exec rake railties:install:migrations FROM=solidus_jwt'
|
18
10
|
end
|
@@ -22,7 +14,7 @@ module SolidusJwt
|
|
22
14
|
if run_migrations
|
23
15
|
run 'bundle exec rake db:migrate'
|
24
16
|
else
|
25
|
-
puts 'Skipping rake db:migrate, don\'t forget to run it!'
|
17
|
+
puts 'Skipping rake db:migrate, don\'t forget to run it!' # rubocop:disable Rails/Output
|
26
18
|
end
|
27
19
|
end
|
28
20
|
end
|
data/lib/solidus_jwt.rb
CHANGED
@@ -1,8 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'jwt'
|
2
4
|
|
3
5
|
require 'solidus_core'
|
6
|
+
require 'solidus_support'
|
7
|
+
require 'solidus_auth_devise'
|
4
8
|
require 'solidus_jwt/engine'
|
5
9
|
|
10
|
+
require 'solidus_jwt/devise_strategies/base'
|
11
|
+
require 'solidus_jwt/devise_strategies/password'
|
12
|
+
require 'solidus_jwt/devise_strategies/refresh_token'
|
13
|
+
|
6
14
|
require 'solidus_jwt/version'
|
7
15
|
require 'solidus_jwt/config'
|
8
16
|
require 'solidus_jwt/concerns/decodeable'
|
@@ -1,15 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module SolidusJwt
|
2
4
|
module Decodeable
|
3
5
|
##
|
4
6
|
# Decode a token generated by SolidusJwt
|
5
7
|
# @see https://github.com/jwt/ruby-jwt
|
6
8
|
#
|
9
|
+
# @example decode a token.
|
10
|
+
# SolidusJwt.decode('abc.123.efg')
|
11
|
+
# #=> [{"sub"=>"1234567890", "name"=>"John Doe", "iat"=>1516239022}, {"alg"=>"HS256", "typ"=>"JWT"}]
|
12
|
+
#
|
7
13
|
# @param token [String] The token to decode
|
8
14
|
# @return [Array<Hash>]
|
9
15
|
#
|
10
16
|
def decode(token)
|
11
17
|
JWT.decode(token, SolidusJwt::Config.jwt_secret, true,
|
12
|
-
|
18
|
+
algorithm: SolidusJwt::Config.jwt_algorithm)
|
13
19
|
end
|
14
20
|
end
|
15
21
|
end
|
@@ -1,9 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module SolidusJwt
|
2
4
|
module Encodeable
|
3
5
|
##
|
4
6
|
# Encode a specified payload
|
5
7
|
# @see https://github.com/jwt/ruby-jwt
|
6
8
|
#
|
9
|
+
# @example encode data into token
|
10
|
+
# payload = {
|
11
|
+
# sub: 1,
|
12
|
+
# iat: DateTime.current.to_i,
|
13
|
+
# exp: 1.hour.from_now.to_i
|
14
|
+
# }
|
15
|
+
#
|
16
|
+
# SolidusJwt.encode payload: payload
|
17
|
+
# #=> 'eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOjEsImlhdCI6MTU4NDEzMjExOCwiZXhwIjoxNTg0MTM1NzE4LCJpc3MiOiJzb2xpZHVzIn0.OKZOGlawx435GdgKp2AGD8SKxW7sqn0h-Ef2qdVSxqQ'
|
18
|
+
#
|
7
19
|
# @param payload [Hash] Attributes to place within the jwt
|
8
20
|
# @param expires_in [Integer] How long until token expires in Seconds (*Optional*).
|
9
21
|
# Note that if no expires at is set, then the token will last forever.
|
@@ -15,12 +27,12 @@ module SolidusJwt
|
|
15
27
|
current_time = Time.current.to_i
|
16
28
|
|
17
29
|
# @see https://github.com/jwt/ruby-jwt#support-for-reserved-claim-names
|
18
|
-
jwt_payload[:exp] ||= current_time + expires_in if expires_in.present?
|
30
|
+
jwt_payload[:exp] ||= current_time + expires_in.to_i if expires_in.present?
|
19
31
|
jwt_payload[:iat] ||= current_time
|
20
32
|
jwt_payload[:iss] ||= 'solidus'
|
21
33
|
|
22
34
|
JWT.encode(jwt_payload, SolidusJwt::Config.jwt_secret,
|
23
|
-
|
35
|
+
SolidusJwt::Config.jwt_algorithm)
|
24
36
|
end
|
25
37
|
end
|
26
38
|
end
|
data/lib/solidus_jwt/config.rb
CHANGED
@@ -0,0 +1,25 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module SolidusJwt
|
4
|
+
module DeviseStrategies
|
5
|
+
class Base < Devise::Strategies::Authenticatable
|
6
|
+
def valid?
|
7
|
+
valid_grant_type? && valid_params?
|
8
|
+
end
|
9
|
+
|
10
|
+
private
|
11
|
+
|
12
|
+
def grant_type
|
13
|
+
params[:grant_type]
|
14
|
+
end
|
15
|
+
|
16
|
+
def valid_grant_type?
|
17
|
+
raise NotImplementedError
|
18
|
+
end
|
19
|
+
|
20
|
+
def valid_params?
|
21
|
+
raise NotImplementedError
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module SolidusJwt
|
4
|
+
module DeviseStrategies
|
5
|
+
class Password < Base
|
6
|
+
def authenticate!
|
7
|
+
block = proc { resource.valid_password?(password) }
|
8
|
+
|
9
|
+
if resource&.valid_for_authentication?(&block)
|
10
|
+
resource.after_database_authentication
|
11
|
+
return success!(resource)
|
12
|
+
end
|
13
|
+
|
14
|
+
fail!(:invalid)
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
def resource
|
20
|
+
@resource ||= mapping.to.find_for_database_authentication(auth_hash)
|
21
|
+
end
|
22
|
+
|
23
|
+
def auth_hash
|
24
|
+
{ email: username }
|
25
|
+
end
|
26
|
+
|
27
|
+
def username
|
28
|
+
params[:username]
|
29
|
+
end
|
30
|
+
|
31
|
+
def password
|
32
|
+
params[:password]
|
33
|
+
end
|
34
|
+
|
35
|
+
def valid_grant_type?
|
36
|
+
grant_type == 'password'
|
37
|
+
end
|
38
|
+
|
39
|
+
def valid_params?
|
40
|
+
username.present? && password.present?
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
Warden::Strategies.add(:solidus_jwt_password, SolidusJwt::DeviseStrategies::Password)
|