model_driven_api 2.3.11 → 2.3.17

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: f318cd8434ed86ff9045ec0a2849774d2d4232f9b057ea70c2313f2255011ff6
4
- data.tar.gz: b587c4fee867ea15389db03d191c899061856fc8a53beea17bf7b88f0aa86cf3
3
+ metadata.gz: aa5e1a3c1035f1a2c765dfc5969845af3c80d70a2e0063e2f42b140b636b751a
4
+ data.tar.gz: 461d22a194727f614e60227f2ed886b0f8fe92e27a984ed13e8b33f5e73db2e8
5
5
  SHA512:
6
- metadata.gz: d92b432a32ee4a23c2209f66ab40eb6d2f56bb3fc9b7229da63eba8a105aacdfcfea36b21cb2739f879077e9f736e1b0ba3e5c4d0602b070cc388aaec684cefa
7
- data.tar.gz: 330b5cbc65fed482fc7af84368967ae3987047d6235f68b5f8fa1b8757c626dbfcde0f6bdde13d3f644666850f24be6cd9a793ffe6ea528ed78b35d9dc8cb933
6
+ metadata.gz: a401038c58d3bf9386e5020b4552040a013c5c6867c2df16ae831ebaf90ae7c22a0ed75187bd2f09fcadf00d48958ec314e288fe74767471d2432eaef6f95e39
7
+ data.tar.gz: 4b03ebfbc44d9158198f1a455a5a294a5436e31af3488714b0a0fd153771aa38f2907d613a4b76a552dcbf463a6c6969821bac3a79a77e4777fd0be5b86dc745
@@ -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
 
@@ -128,15 +128,12 @@ class Api::V2::ApplicationController < ActionController::API
128
128
  end
129
129
 
130
130
  def authenticate_request
131
- # puts request.headers.inspect
132
131
  @current_user = nil
133
- # puts "Are there wbehooks headers to check for? #{Settings.ns(:security).allowed_authorization_headers}"
134
132
  Settings.ns(:security).allowed_authorization_headers.split(",").each do |header|
135
133
  # puts "Found header #{header}: #{request.headers[header.underscore.dasherize]}"
136
134
  check_authorization("Authorize#{header}".constantize.call(request.headers, request.raw_post)) if request.headers[header.underscore.dasherize]
137
135
  end
138
136
 
139
- # 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
140
137
  check_authorization AuthorizeApiRequest.call(request.headers) unless @current_user
141
138
  return unauthenticated!(OpenStruct.new({message: @auth_errors})) unless @current_user
142
139
 
@@ -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,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, is_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.11
4
+ version: 2.3.17
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-01 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