model_driven_api 2.3.13 → 2.3.19

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a5497bdb2727e103fa3727595ca62bbaf065b9135dd9bfbc8674f21506929dd0
4
- data.tar.gz: ad09cdae9730b0f5c7983eb478c660ef8cc1c13d1d2c1cb13cd9a143b67f4029
3
+ metadata.gz: d38e64a791f7147bdc145e1767814ac885fcf75ff5031cf30743b96d8717fb32
4
+ data.tar.gz: 213dc7345b1061bca3a93826ac9c52b63e97bee20891aca0569f0e14ce11f565
5
5
  SHA512:
6
- metadata.gz: 719fcf3175dced8eaea5e238551d7d143edc185e9131c44ae9bf5358509de252da07491c27c16f485644c782f73c8f351379744c60f20bc803b074f024ecdbb8
7
- data.tar.gz: ad157de69fbd575e5a9197594901b811a0cb1e74f25eb49146c011fbec9d32ebd6874e8712f2ef8edff4799d9e46cd04e2040c5cbe7c48b3a04e7f428917ab5a
6
+ metadata.gz: 5d435ae0c87967fcdfb1517cf1f353588635efb1df3a657b555f9d622bd7aff36c684c8c8cfaf764926edaf93109ddabc813867dbb62000a7b92d220c1d1a93e
7
+ data.tar.gz: 609644b3be46a961b594e95fc601bc48393095a6bf090679094d5227427856ced680c83d0fb44d489589d3e2433d145473bc080a90a8574040c77cfbb59ab47f
@@ -6,26 +6,43 @@ 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
+ first_arg = args.first
11
+ if !first_arg[:email].blank? && !first_arg[:password].blank?
12
+ @email = first_arg[:email]
13
+ @password = first_arg[:password]
14
+ elsif !first_arg[:access_token].blank?
15
+ @access_token = first_arg[:access_token]
16
+ end
12
17
  end
13
18
 
14
19
  def call
15
- JsonWebToken.encode(user_id: api_user.id) if api_user
20
+ current_u = api_user
21
+ if !current_u.blank? && result = JsonWebToken.encode(user_id: current_u.id)
22
+ # The token is created and the api_user exists => Invalidating all the previous tokens
23
+ # Since this is a new login and I don't care from where it comes, new logins always
24
+ # Invalidate older tokens
25
+ UsedToken.where(user_id: api_user.id).update(is_valid: false) if ENV["ALLOW_MULTISESSIONS"] == "false"
26
+ return result
27
+ end
28
+ nil
16
29
  end
17
30
 
18
31
  private
19
32
 
20
- attr_accessor :email, :password
33
+ attr_accessor :email, :password, :access_token
21
34
 
22
35
  def api_user
23
- user = User.find_by_email(email)
36
+ if !email.blank? && !password.blank?
37
+ user = User.find_by(email: email)
38
+ # Verify the password.
39
+ raise AccessDenied if user.blank? && user.authenticate(password).blank?
40
+ elsif !access_token.blank?
41
+ user = User.find_by(access_token: access_token)
42
+ end
43
+
24
44
  raise AccessDenied unless user.present?
25
45
 
26
- # Verify the password. You can create a blank method for now.
27
- raise AccessDenied if user.authenticate(password).blank?
28
-
29
46
  return user
30
47
  end
31
48
 
@@ -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,3 @@
1
+ class UsedToken < ApplicationRecord
2
+ belongs_to :user, inverse_of: :used_tokens
3
+ end
data/config/routes.rb CHANGED
@@ -12,6 +12,7 @@ Rails.application.routes.draw do
12
12
  get :translations
13
13
  get :schema
14
14
  get :dsl
15
+ get :heartbeat
15
16
  end
16
17
 
17
18
  post "authenticate" => "authentication#authenticate"
@@ -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
@@ -0,0 +1,7 @@
1
+ class RenameValidToIsValidInUsedToken < ActiveRecord::Migration[6.0]
2
+ def change
3
+ change_table :used_tokens do |t|
4
+ t.rename :valid, :is_valid
5
+ end
6
+ end
7
+ 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,20 @@
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).presence||ENV["SECRET_KEY_BASE"])
5
- end
6
-
7
- def decode(token)
8
- body = ::JWT.decode(token, ::Rails.application.credentials.dig(:secret_key_base).presence||ENV["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
+ # In a public environment management, without login, it has no interest, so I don't pollute the DB
7
+ UsedToken.find_or_create_by(token: result, user_id: payload[:user_id]) if ENV["ALLOW_MULTISESSIONS"] == "false"
8
+ result
13
9
  end
14
- end
10
+
11
+ def decode(token)
12
+ # Check if the passed token is present and valid into the UsedToken
13
+ raise "Token is invalidated by new login" unless UsedToken.exists?(token: token, is_valid: true) if ENV["ALLOW_MULTISESSIONS"] == "false"
14
+ body = ::JWT.decode(token, ::Rails.application.credentials.dig(:secret_key_base).presence||ENV["SECRET_KEY_BASE"])[0]
15
+ ::HashWithIndifferentAccess.new body
16
+ rescue
17
+ nil
18
+ end
19
+ end
20
+ 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.13
4
+ version: 2.3.19
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-04-12 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,15 @@ 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
150
+ - db/migrate/20210528111450_rename_valid_to_is_valid_in_used_token.rb
148
151
  - lib/concerns/api_exception_management.rb
149
152
  - lib/concerns/model_driven_api_role.rb
150
153
  - lib/concerns/model_driven_api_user.rb
@@ -173,7 +176,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
173
176
  - !ruby/object:Gem::Version
174
177
  version: '0'
175
178
  requirements: []
176
- rubygems_version: 3.0.3
179
+ rubygems_version: 3.0.3.1
177
180
  signing_key:
178
181
  specification_version: 4
179
182
  summary: Convention based RoR engine which uses DB schema introspection to create