jwtauth 0.2.3 → 0.3.1

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.
Files changed (4) hide show
  1. checksums.yaml +4 -4
  2. data/lib/jwtauth.rb +299 -3
  3. data/lib/jwtauth/user.rb +6 -1
  4. metadata +1 -1
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 133c62c21f3825c7cceedbad5395dae11cb4dcdc
4
- data.tar.gz: 5e4cec0830accd1b2b93c730d998914a4cb8daae
3
+ metadata.gz: 001dd1412a0f2ff8431611490222199d76e1b366
4
+ data.tar.gz: 54182546254c2cbb51b20b6c65d0ce8a09f4cde1
5
5
  SHA512:
6
- metadata.gz: e7b5c770cd442cdad5a0f1daba2b928bc0f53c19928cbd236ffa5ae2ae8349c6f327ff0f96fa835644caf5e1c8586d461a384744ad7add01cbf6c47506fef635
7
- data.tar.gz: ad3a53e8b6de9daa8bcd8ee2d916a4c169bae14c0b3843507ec3d6c0e410c141615da1d027c53a8bf9d2b52f00a925c5c6c35e237458c115f76e6e0427154888
6
+ metadata.gz: e2f6e0cf4784ef59b4c4e98db8ee820ae9c0e326cd9bc83488c90bfb6b27ea5a0cc6be28b7a52f18caeb0faeda7af1009747e593df36ae577c04c7f9a14f1703
7
+ data.tar.gz: bc3ba8325a68ac19c3772bb325a7adfc0be4c7d78dbe65a9ba93cfbf71c821a1666158bc386439682501471f7bd96e922b7a19f10701d39d6d365fa310bd3522
data/lib/jwtauth.rb CHANGED
@@ -17,6 +17,14 @@ module Jwtauth
17
17
  # mattr_accessor :session_path
18
18
  @@session_path = nil
19
19
 
20
+ # Define current service contain entities
21
+ # mattr_accessor :service_name
22
+ @@service_name = nil
23
+
24
+ # Define namespace (String | Array) include +current service+ for service
25
+ # mattr_accessor :namespace
26
+ @@namespace = nil
27
+
20
28
  # Algorithm, JWT use to encode
21
29
  # mattr_accessor :algorithm
22
30
  @@algorithm = 'RS256'
@@ -57,6 +65,22 @@ module Jwtauth
57
65
  @@session_path = session_path
58
66
  end
59
67
 
68
+ def self.service_name
69
+ @@service_name
70
+ end
71
+
72
+ def self.service_name=(service_name)
73
+ @@service_name = service_name
74
+ end
75
+
76
+ def self.namespace
77
+ @@namespace
78
+ end
79
+
80
+ def self.namespace=(namespace)
81
+ @@namespace = namespace
82
+ end
83
+
60
84
  def self.algorithm
61
85
  @@algorithm
62
86
  end
@@ -116,7 +140,9 @@ module Jwtauth
116
140
  uri.query = CGI.unescape({
117
141
  'uid' => origin_request.headers['uid'],
118
142
  'client' => origin_request.headers['client'],
119
- 'access-token' => origin_request.headers['access-token'],}.to_query)
143
+ 'access-token' => origin_request.headers['access-token'],
144
+ 'namespace' => Jwtauth.namespace,
145
+ }.to_query)
120
146
 
121
147
  Net::HTTP.start(uri.host, uri.port,
122
148
  :use_ssl => uri.scheme == 'https') do |http|
@@ -165,7 +191,7 @@ module Jwtauth
165
191
  end
166
192
 
167
193
  # Handle for user not authorized
168
- def user_not_authorized(exception)
194
+ def user_not_authenticated(exception)
169
195
  status = :forbidden
170
196
 
171
197
  case exception
@@ -185,7 +211,277 @@ module Jwtauth
185
211
 
186
212
  base.class_eval do
187
213
  attr_reader :current_user
188
- rescue_from Jwtauth::AuthorizedError, with: :user_not_authorized
214
+ rescue_from Jwtauth::AuthorizedError, with: :user_not_authenticated
215
+ end
216
+ end
217
+
218
+ module ClassMethods
219
+ end
220
+ end
221
+
222
+ module Model
223
+ module ForeignKeys
224
+ COMPANY_ID = :company_id
225
+ DEPARTMENT_ID = :department_id
226
+ USER_ID = :user_id
227
+ end
228
+
229
+ def self.included(base)
230
+ base.extend ClassMethods
231
+
232
+ base.class_eval do
233
+ end
234
+ end
235
+
236
+ module ClassMethods
237
+ def new2nd params, current_user
238
+ _record = self.new(params)
239
+
240
+ _record[self::ForeignKeys::USER_ID] = current_user.id if _record[self::ForeignKeys::USER_ID].blank?
241
+ _record[self::ForeignKeys::DEPARTMENT_ID] = current_user.department_id if _record[self::ForeignKeys::DEPARTMENT_ID].blank?
242
+ _record[self::ForeignKeys::COMPANY_ID] = current_user.company_id if _record[self::ForeignKeys::COMPANY_ID].blank?
243
+
244
+ _record
245
+ end
246
+ end
247
+ end
248
+
249
+ # require include Pundit (gem <<pundit>>)
250
+ module Apiv01Controller
251
+ # Require define entity class name
252
+ def define_entity
253
+ send_json_error(['entity model is not defined'], :internal_server_error)
254
+ end
255
+
256
+ # Send error messages with status
257
+ def send_json_error(errors = [], status = :unprocessable_entity)
258
+ render json: errors, status: status
259
+ end
260
+
261
+ # Handle for user not authorized
262
+ def user_not_authorized(exception)
263
+ policy_name = exception.policy.class.to_s.underscore
264
+ error_message = I18n.t("#{policy_name}.#{exception.query}", scope: "pundit", default: :default)
265
+
266
+ if request.format.symbol == :json
267
+ send_json_error [error_message], :forbidden
268
+ else
269
+ render template: 'errors/401', locals: { message: error_message }
270
+ end
271
+ end
272
+
273
+ # GET /api/v02/entity_name(s)
274
+ def index
275
+ authorize @entity_model
276
+ @records = core_index_filter(policy_scope(@entity_model))
277
+
278
+ render json: { filters: filter_jsons, records: records_as_json(@records) }
279
+ end
280
+
281
+ # GET /api/v02/entity_names(s)/1
282
+ def show
283
+ authorize @record
284
+
285
+ render json: record_as_json(@record)
286
+ end
287
+
288
+ # POST /api/v02/entity_names(s)
289
+ def create
290
+ @record = @entity_model.new2nd(entity_params, current_user)
291
+ authorize @record
292
+
293
+ if @record.save
294
+ render json: record_as_json(@record), status: :created
295
+ else
296
+ render json: @record.errors.full_messages, status: :unprocessable_entity
297
+ end
298
+ end
299
+
300
+ # PATCH/PUT /api/v02/entity_names(s)/1
301
+ def update
302
+ authorize @record
303
+ @record.assign_attributes(entity_params)
304
+ authorize @record
305
+
306
+ if @record.save
307
+ render json: record_as_json(@record), status: :ok
308
+ else
309
+ render json: @record.errors.full_messages, status: :unprocessable_entity
310
+ end
311
+ end
312
+
313
+ # DELETE /api/v02/entity_names(s)/1
314
+ def destroy
315
+ authorize @record
316
+
317
+ @record.destroy
318
+ end
319
+
320
+ protected
321
+ # Use callbacks to share common setup or constraints between actions.
322
+ def set_entity
323
+ @record = @entity_model.find(params[:id])
324
+ end
325
+
326
+ # Only allow a trusted parameter "white list" through.
327
+ def entity_params
328
+ params.require(:record).permit(:created_at)
329
+ end
330
+
331
+ # Strong parameters for default search query
332
+ def search_params
333
+ params.permit(:id)
334
+ end
335
+
336
+ # Strong parameters for default advanced search query
337
+ def advanced_search_params
338
+ params.permit(:created_at)
339
+ end
340
+
341
+ def self.included(base)
342
+ base.extend ClassMethods
343
+
344
+ base.class_eval do
345
+ # Define entity model before action
346
+ before_action :authorize_user!
347
+ before_action :define_entity
348
+ before_action :set_entity, only: [:show, :update, :destroy]
349
+ rescue_from Pundit::NotAuthorizedError, with: :user_not_authorized
350
+
351
+ attr_reader :entity_model
352
+ end
353
+ end
354
+
355
+ module ClassMethods
356
+ end
357
+ end
358
+
359
+ # require use Pundit (gem <<pundit>>)
360
+ module Policy
361
+ # Reference from authservice/models/role.rb
362
+ module Privileges
363
+ CREATE = 'create'.freeze
364
+ READ = 'read'.freeze
365
+ UPDATE = 'update'.freeze
366
+ DELETE = 'delete'.freeze
367
+ end
368
+
369
+ # Reference from authservice/models/role.rb
370
+ module LevelsOfAccess
371
+ NONE = 'none'.freeze
372
+ USER = 'user'.freeze
373
+ BUSINESS_UNIT = 'bu'.freeze
374
+ FAMILY_BU_TREE = 'fbu'.freeze
375
+ ORGANIZATION = 'org'.freeze
376
+ end
377
+
378
+ attr_reader :user, :record
379
+
380
+ def initialize(user, record)
381
+ @user = user
382
+ @record = record
383
+ end
384
+
385
+ def index?
386
+ get_level_of_access(Privileges::READ) != LevelsOfAccess::NONE
387
+ end
388
+
389
+ def show?
390
+ record_action?(get_level_of_access(Privileges::READ))
391
+ end
392
+
393
+ def create?
394
+ record_action?(get_level_of_access(Privileges::CREATE))
395
+ end
396
+
397
+ def new?
398
+ create?
399
+ end
400
+
401
+ def update?
402
+ record_action?(get_level_of_access(Privileges::UPDATE))
403
+ end
404
+
405
+ def edit?
406
+ update?
407
+ end
408
+
409
+ def destroy?
410
+ record_action?(get_level_of_access(Privileges::DELETE))
411
+ end
412
+
413
+ def scope
414
+ Pundit.policy_scope!(user, record.class)
415
+ end
416
+
417
+ def _entity_class
418
+ @record.is_a?(Class) ? @record.name.underscore : @record.class.name.underscore
419
+ end
420
+
421
+ protected
422
+ def get_level_of_access(method_name, service_name = Jwtauth.service_name)
423
+ level_of_access = nil
424
+
425
+ if @user.role_permissions.is_a?(Hash)
426
+ level_of_access = @user.role_permissions.dig(service_name, _entity_class, method_name)
427
+ end
428
+
429
+ level_of_access ? level_of_access : LevelsOfAccess::NONE
430
+ end
431
+
432
+ def record_action?(level_of_access)
433
+ case level_of_access
434
+ when LevelsOfAccess::USER
435
+ @user.id == @record[@record.class::ForeignKeys::USER_ID]
436
+ when LevelsOfAccess::BUSINESS_UNIT
437
+ @user.departments[LevelsOfAccess::BUSINESS_UNIT].include?(@record[@record.class::ForeignKeys::USER_ID])
438
+ when LevelsOfAccess::FAMILY_BU_TREE
439
+ @user.departments[LevelsOfAccess::FAMILY_BU_TREE].include?(@record[@record.class::ForeignKeys::DEPARTMENT_ID])
440
+ when LevelsOfAccess::ORGANIZATION
441
+ @user.company_id == @record[@record.class::ForeignKeys::COMPANY_ID]
442
+ else
443
+ false
444
+ end
445
+ end
446
+
447
+ class Scope
448
+ attr_reader :user, :scope
449
+
450
+ def initialize(user, scope)
451
+ @user = user
452
+ @scope = scope
453
+ end
454
+
455
+ def resolve
456
+ case get_level_of_access(Privileges::READ)
457
+ when LevelsOfAccess::BUSINESS_UNIT
458
+ scope.where(scope::ForeignKeys::DEPARTMENT_ID => @user.departments[LevelsOfAccess::BUSINESS_UNIT])
459
+ when LevelsOfAccess::FAMILY_BU_TREE
460
+ scope.where(scope::ForeignKeys::DEPARTMENT_ID => @user.departments[LevelsOfAccess::FAMILY_BU_TREE])
461
+ when LevelsOfAccess::ORGANIZATION
462
+ scope.where(scope::ForeignKeys::COMPANY_ID => @user.company_id)
463
+ else
464
+ scope.where(scope::ForeignKeys::USER_ID => @user.id)
465
+ end
466
+ end
467
+
468
+ protected
469
+ # Reference from Policy.instance.get_level_of_access
470
+ def get_level_of_access(method_name, service_name = Jwtauth.service_name)
471
+ level_of_access = nil
472
+
473
+ if @user.role_permissions.is_a?(Hash)
474
+ level_of_access = @user.role_permissions.dig(service_name, scope.name.downcase, method_name)
475
+ end
476
+
477
+ level_of_access ? level_of_access : LevelsOfAccess::NONE
478
+ end
479
+ end
480
+
481
+ def self.included(base)
482
+ base.extend ClassMethods
483
+
484
+ base.class_eval do
189
485
  end
190
486
  end
191
487
 
data/lib/jwtauth/user.rb CHANGED
@@ -1,11 +1,16 @@
1
1
  module Jwtauth
2
2
  class User
3
- attr_reader :id, :uid, :role
3
+ attr_reader :id, :uid, :role, :department_id, :company_id
4
+ attr_reader :role_permissions, :departments
4
5
 
5
6
  def initialize attrs
6
7
  @id = attrs['id']
7
8
  @uid = attrs['uid']
8
9
  @role = attrs['role']
10
+ @department_id = attrs['department_id']
11
+ @company_id = attrs['company_id']
12
+ @role_permissions = attrs['role_permissions']
13
+ @departments = attrs['departments']
9
14
  end
10
15
  end
11
16
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: jwtauth
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.3
4
+ version: 0.3.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dieu Pham