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.
- checksums.yaml +4 -4
- data/lib/jwtauth.rb +299 -3
- data/lib/jwtauth/user.rb +6 -1
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 001dd1412a0f2ff8431611490222199d76e1b366
|
4
|
+
data.tar.gz: 54182546254c2cbb51b20b6c65d0ce8a09f4cde1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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'],
|
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
|
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: :
|
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
|