model_driven_api 2.3.10 → 2.3.16

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
  SHA256:
3
- metadata.gz: 190f87343976c6c393f9b2c80163ddc403b2575fd2c8fcceb125ef1996e7532a
4
- data.tar.gz: e393facfcd2b11ac2af44df2f5602074e2da1ee48974dbb2fdec6d4f346c837e
3
+ metadata.gz: 6f42b6fcf4138560f8e183c7f02e10854836f7e04247bbe8bb96cdf3b3299324
4
+ data.tar.gz: 1ea8b0e0819840b9f443c06d77f5b175c510085ea435aed509968bf87f2cf2ef
5
5
  SHA512:
6
- metadata.gz: b4f9083c41e709a64d99278f84594d28ac94175983678c01b2b08124facf2ccf3264808034a1c30eac3d2801a763807ffc480bbc4ab17afe929216b3ce096ece
7
- data.tar.gz: 25e8013e5421b51b5fdce2d444fabdb5f66bc9e4805df7c2761646b43a0058dabf70ed7e11d2e36494740c0d5966ea300a4351a4f16754837caf0f23826a7b7e
6
+ metadata.gz: dcb26da2904c349a2749d30ec86011b2712847c0fbfd7577bbc02bcb549e1d2bc05425c5beb609c62784dae0ae3f25a2272a240707ec9647d5e8f3a97c59034a
7
+ data.tar.gz: e4f5477ef79bfe582465ba72a25b984b248d9a2f0b28bf35ad16e4dca4ad104eaa96bd1487df95b0ad7476593544a0fef8c010418b99d6bffc7f8b2012972baa
@@ -6,26 +6,42 @@ class AuthenticateUser
6
6
  end
7
7
  prepend SimpleCommand
8
8
 
9
- def initialize(email, password)
10
- @email = email
11
- @password = password
9
+ def initialize(*args)
10
+ if !args.email.blank? && !args.password.blank?
11
+ @email = args.email
12
+ @password = args.password
13
+ elsif !args.access_token.blank?
14
+ @access_token = args.access_token
15
+ end
12
16
  end
13
17
 
14
18
  def call
15
- JsonWebToken.encode(user_id: api_user.id) if api_user
19
+ if !api_user.blank? && result = JsonWebToken.encode(user_id: api_user.id)
20
+ # The token is created and the api_user exists => Invalidating all the previous tokens
21
+ # Since this is a new login and I don't care from where it comes, new logins always
22
+ # Invalidate older tokens
23
+ UsedToken.where(user_id: api_user.id).update(valid: false)
24
+ return result
25
+ end
26
+ nil
16
27
  end
17
28
 
18
29
  private
19
30
 
20
- attr_accessor :email, :password
31
+ attr_accessor :email, :password, :access_token
21
32
 
22
33
  def api_user
23
- user = User.find_by_email(email)
34
+ if !email.blank? && !password.blank?
35
+ user = User.find_by(email: email)
36
+
37
+ # Verify the password. You can create a blank method for now.
38
+ raise AccessDenied if user.blank? && user.authenticate(password).blank?
39
+ elsif !access_token.blank?
40
+ user = User.find_by(access_token: access_token)
41
+ end
42
+
24
43
  raise AccessDenied unless user.present?
25
44
 
26
- # Verify the password. You can create a blank method for now.
27
- raise AccessDenied if user.authenticate(password).blank?
28
-
29
45
  return user
30
46
  end
31
47
 
@@ -113,7 +113,8 @@ class Api::V2::ApplicationController < ActionController::API
113
113
  resource = "custom_action_#{params[:do]}"
114
114
  raise NoMethodError unless @model.respond_to?(resource)
115
115
  # return true, MultiJson.dump(params[:id].blank? ? @model.send(resource, params) : @model.send(resource, params[:id].to_i, params))
116
- return true, MultiJson.dump(@model.send(resource, params))
116
+ puts json_attrs
117
+ return true, @model.send(resource, params).to_json(json_attrs)
117
118
  end
118
119
  # if it's here there is no custom action in the request querystring
119
120
  return false
@@ -127,15 +128,12 @@ class Api::V2::ApplicationController < ActionController::API
127
128
  end
128
129
 
129
130
  def authenticate_request
130
- # puts request.headers.inspect
131
131
  @current_user = nil
132
- # puts "Are there wbehooks headers to check for? #{Settings.ns(:security).allowed_authorization_headers}"
133
132
  Settings.ns(:security).allowed_authorization_headers.split(",").each do |header|
134
133
  # puts "Found header #{header}: #{request.headers[header.underscore.dasherize]}"
135
134
  check_authorization("Authorize#{header}".constantize.call(request.headers, request.raw_post)) if request.headers[header.underscore.dasherize]
136
135
  end
137
136
 
138
- # This is the default one, if the header doesn't have a valid form for one of the other Auth methods, then use this Auth Class
139
137
  check_authorization AuthorizeApiRequest.call(request.headers) unless @current_user
140
138
  return unauthenticated!(OpenStruct.new({message: @auth_errors})) unless @current_user
141
139
 
@@ -160,7 +158,7 @@ class Api::V2::ApplicationController < ActionController::API
160
158
  # has precedence over if you have setup the json_attrs in the model concern
161
159
  from_params = params[:a].deep_symbolize_keys unless params[:a].blank?
162
160
  from_params = params[:json_attrs].deep_symbolize_keys unless params[:json_attrs].blank?
163
- from_params.presence || @model.json_attrs.presence || @json_attrs.presence || {} rescue {}
161
+ from_params.presence || @json_attrs.presence || @model.json_attrs.presence || {} rescue {}
164
162
  end
165
163
 
166
164
  def extract_model
@@ -2,7 +2,7 @@ class Api::V2::AuthenticationController < ActionController::API
2
2
  include ::ApiExceptionManagement
3
3
 
4
4
  def authenticate
5
- command = AuthenticateUser.call(params[:auth][:email], params[:auth][:password])
5
+ command = !params[:atoken].blank? && User.column_names.include?("access_token") ? AuthenticateUser.call(access_token: params[:atoken]) : AuthenticateUser.call(email: params[:auth][:email], password: params[:auth][:password])
6
6
 
7
7
  if command.success?
8
8
  response.headers['Token'] = command.result
@@ -15,6 +15,13 @@ class Api::V2::InfoController < Api::V2::ApplicationController
15
15
  render json: ::Role.all.to_json, status: 200
16
16
  end
17
17
 
18
+
19
+ # api :GET, '/api/v2/info/heartbeat'
20
+ # Just keeps the session alive by returning a new token
21
+ def heartbeat
22
+ head :ok
23
+ end
24
+
18
25
  # GET '/api/v2/info/translations'
19
26
  def translations
20
27
  render json: I18n.t(".", locale: (params[:locale].presence || :it)).to_json, status: 200
@@ -0,0 +1,7 @@
1
+ class UsedToken < ApplicationRecord
2
+ belongs_to :user, inverse_of: :used_tokens
3
+
4
+ rails_admin do
5
+ visible false
6
+ end
7
+ end
@@ -0,0 +1,12 @@
1
+ class CreateUsedTokens < ActiveRecord::Migration[6.0]
2
+ def change
3
+ create_table :used_tokens do |t|
4
+ t.string :token
5
+ t.references :user, null: false, foreign_key: true
6
+ t.boolean :valid, default: true
7
+
8
+ t.timestamps
9
+ end
10
+ add_index :used_tokens, :token, unique: true
11
+ end
12
+ end
@@ -2,7 +2,7 @@ module ModelDrivenApiUser
2
2
  extend ActiveSupport::Concern
3
3
 
4
4
  included do
5
-
5
+ has_many :used_tokens, inverse_of: :user, dependent: :destroy
6
6
  ## DSL (AKA what to show in the returned JSON)
7
7
  # Use @@json_attrs to drive json rendering for
8
8
  # API model responses (index, show and update ones).
@@ -1,14 +1,19 @@
1
1
  class JsonWebToken
2
- class << self
3
- def encode(payload, expiry = 15.minutes.from_now.to_i)
4
- ::JWT.encode(payload.merge(exp: expiry), ::Rails.application.credentials.dig(:secret_key_base))
5
- end
6
-
7
- def decode(token)
8
- body = ::JWT.decode(token, ::Rails.application.credentials.dig(:secret_key_base))[0]
9
- ::HashWithIndifferentAccess.new body
10
- rescue
11
- nil
12
- end
2
+ class << self
3
+ def encode(payload, expiry = 15.minutes.from_now.to_i)
4
+ result = ::JWT.encode(payload.merge(exp: expiry), ::Rails.application.credentials.dig(:secret_key_base).presence||ENV["SECRET_KEY_BASE"])
5
+ # Store the created token into the DB for later checks if is invalid
6
+ UsedToken.create(token: result, user_id: payload[:user_id])
7
+ result
13
8
  end
14
- end
9
+
10
+ def decode(token)
11
+ # Check if the passed token is present and valid into the UsedToken
12
+ raise "Token is invalidated by new login" unless UsedToken.exists?(token: token, valid: true)
13
+ body = ::JWT.decode(token, ::Rails.application.credentials.dig(:secret_key_base).presence||ENV["SECRET_KEY_BASE"])[0]
14
+ ::HashWithIndifferentAccess.new body
15
+ rescue
16
+ nil
17
+ end
18
+ end
19
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: model_driven_api
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.3.10
4
+ version: 2.3.16
5
5
  platform: ruby
6
6
  authors:
7
7
  - Gabriele Tassoni
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-03-26 00:00:00.000000000 Z
11
+ date: 2021-05-28 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: thecore_backend_commons
@@ -139,12 +139,14 @@ files:
139
139
  - app/controllers/api/v2/authentication_controller.rb
140
140
  - app/controllers/api/v2/info_controller.rb
141
141
  - app/controllers/api/v2/users_controller.rb
142
+ - app/models/used_token.rb
142
143
  - config/initializers/after_initialize_for_model_driven_api.rb
143
144
  - config/initializers/cors_api_thecore.rb
144
145
  - config/initializers/knock.rb
145
146
  - config/initializers/time_with_zone.rb
146
147
  - config/initializers/wrap_parameters.rb
147
148
  - config/routes.rb
149
+ - db/migrate/20210519145438_create_used_tokens.rb
148
150
  - lib/concerns/api_exception_management.rb
149
151
  - lib/concerns/model_driven_api_role.rb
150
152
  - lib/concerns/model_driven_api_user.rb
@@ -173,7 +175,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
173
175
  - !ruby/object:Gem::Version
174
176
  version: '0'
175
177
  requirements: []
176
- rubygems_version: 3.0.3
178
+ rubygems_version: 3.0.3.1
177
179
  signing_key:
178
180
  specification_version: 4
179
181
  summary: Convention based RoR engine which uses DB schema introspection to create