jwtauth 0.2.3 → 0.3.1

Sign up to get free protection for your applications and to get access to all the features.
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