api_engine_base 0.1.1 → 0.1.2

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 (40) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +37 -6
  3. data/app/controllers/api_engine_base/admin_controller.rb +104 -0
  4. data/app/controllers/api_engine_base/application_controller.rb +45 -11
  5. data/app/controllers/api_engine_base/auth/plain_text_controller.rb +1 -1
  6. data/app/controllers/api_engine_base/user_controller.rb +49 -0
  7. data/app/models/api_engine_base/application_record.rb +38 -0
  8. data/app/models/user.rb +13 -4
  9. data/app/services/api_engine_base/README.md +49 -0
  10. data/app/services/api_engine_base/argument_validation/README.md +192 -0
  11. data/app/services/api_engine_base/argument_validation/class_methods.rb +2 -3
  12. data/app/services/api_engine_base/argument_validation/instance_methods.rb +13 -1
  13. data/app/services/api_engine_base/authorize/validate.rb +49 -0
  14. data/app/services/api_engine_base/jwt/authenticate_user.rb +22 -7
  15. data/app/services/api_engine_base/jwt/login_create.rb +1 -1
  16. data/app/services/api_engine_base/service_base.rb +4 -5
  17. data/app/services/api_engine_base/user_attributes/modify.rb +68 -0
  18. data/app/services/api_engine_base/user_attributes/roles.rb +27 -0
  19. data/config/routes.rb +11 -0
  20. data/db/migrate/20241117043720_create_api_engine_base_users.rb +2 -0
  21. data/lib/api_engine_base/authorization/default.yml +34 -0
  22. data/lib/api_engine_base/authorization/entity.rb +101 -0
  23. data/lib/api_engine_base/authorization/role.rb +101 -0
  24. data/lib/api_engine_base/authorization.rb +85 -0
  25. data/lib/api_engine_base/configuration/admin/config.rb +18 -0
  26. data/lib/api_engine_base/configuration/application/config.rb +2 -2
  27. data/lib/api_engine_base/configuration/authorization/config.rb +24 -0
  28. data/lib/api_engine_base/configuration/config.rb +19 -1
  29. data/lib/api_engine_base/configuration/user/config.rb +56 -0
  30. data/lib/api_engine_base/engine.rb +38 -6
  31. data/lib/api_engine_base/error.rb +5 -0
  32. data/lib/api_engine_base/schema/admin/users.rb +15 -0
  33. data/lib/api_engine_base/schema/error/invalid_argument_response.rb +1 -1
  34. data/lib/api_engine_base/schema/page.rb +14 -0
  35. data/lib/api_engine_base/schema/user.rb +28 -0
  36. data/lib/api_engine_base/schema.rb +5 -0
  37. data/lib/api_engine_base/spec_helper.rb +4 -3
  38. data/lib/api_engine_base/version.rb +1 -1
  39. data/lib/api_engine_base.rb +2 -2
  40. metadata +22 -4
@@ -0,0 +1,49 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ApiEngineBase::Authorize
4
+ class Validate < ApiEngineBase::ServiceBase
5
+ on_argument_validation :fail_early
6
+
7
+ validate :user, is_a: User, required: true
8
+ validate :controller, is_a: [ActionController::Base, ActionController::API], required: true
9
+ validate :method, is_a: String, required: true
10
+
11
+ def call
12
+ context.authorization_required = authorization_required?
13
+ unless context.authorization_required
14
+ log_info("controller:#{controller}; method:#{method} -- No Authorization required")
15
+ context.msg = "Authorization not required at this time"
16
+ return
17
+ end
18
+
19
+ # At this point we know authorization on the route is required
20
+ # Iterate through the users roles to find a matching role that allows authorization
21
+ # If at least 1 of the users roles passes validation, we can allow access to the path
22
+ log_info("User Roles: #{user.roles}")
23
+ auhorization_result = user_role_objects.any? do |_role_name, role_object|
24
+ result = role_object.authorized?(controller:, method:, user:)
25
+ log_info("Role:#{result[:role]};Authorized:[#{result[:authorized]}];Reason:[#{result[:reason]}]")
26
+ result[:authorized] == true
27
+ end
28
+
29
+ if auhorization_result
30
+ context.msg = "User is Authorized for action"
31
+ else
32
+ context.fail!(msg: "Unauthorized Access. Incorrect User Privileges")
33
+ end
34
+ end
35
+
36
+ def authorization_required?
37
+ controller_mapping = ApiEngineBase::Authorization.mapped_controllers[controller]
38
+ return false if controller_mapping.nil?
39
+
40
+ controller_mapping.include?(method.to_sym)
41
+ end
42
+
43
+ def user_role_objects
44
+ ApiEngineBase::Authorization::Role.roles.select do |role_name, _|
45
+ user.roles.include?(role_name.to_s)
46
+ end
47
+ end
48
+ end
49
+ end
@@ -5,6 +5,7 @@ module ApiEngineBase::Jwt
5
5
 
6
6
  validate :token, is_a: String, required: true, sensitive: true
7
7
  validate :bypass_email_validation, is_one: [true, false], default: false
8
+ validate :with_reset, is_one: [true, false], default: false
8
9
 
9
10
  def call
10
11
  result = Decode.(token:)
@@ -14,7 +15,7 @@ module ApiEngineBase::Jwt
14
15
  end
15
16
  payload = result.payload
16
17
 
17
- validate_expires_at!(expires_at: payload[:expires_at])
18
+ expires_at = validate_generated_at!(generated_at: payload[:generated_at])
18
19
 
19
20
  user = User.find(payload[:user_id]) rescue nil
20
21
  if user.nil?
@@ -29,25 +30,39 @@ module ApiEngineBase::Jwt
29
30
  end
30
31
 
31
32
  email_validation_required!(user:)
33
+
34
+ if with_reset
35
+ context.generated_token = ApiEngineBase::Jwt::LoginCreate.(user:).token
36
+ expires_at = ApiEngineBase.config.jwt.ttl.from_now.to_time
37
+ end
38
+
39
+ context.expires_at = expires_at.to_s
32
40
  end
33
41
 
34
- def validate_expires_at!(expires_at:)
35
- if expires_at.nil?
36
- log_warn("expires_at payload is missing from the JWT token. Cannot continue")
42
+ def validate_generated_at!(generated_at:)
43
+ if generated_at.nil?
44
+ log_warn("generated_at payload is missing from the JWT token. Cannot continue")
37
45
  context.fail!(msg: "Unauthorized Access. Invalid Authorization token")
38
46
  end
39
47
 
40
- expires_time = Time.at(expires_at) rescue nil
48
+ expires_time = begin
49
+ time = Time.at(generated_at)
50
+ time + ApiEngineBase.config.jwt.ttl
51
+ rescue
52
+ nil
53
+ end
41
54
 
42
55
  if expires_time.nil?
43
- log_warn("expires_at payload cannot be parsed. Cannot continue")
56
+ log_warn("generated_at payload cannot be parsed. Cannot continue")
44
57
  context.fail!(msg: "Unauthorized Access. Invalid Authorization token")
45
58
  end
46
59
 
47
60
  if expires_time < Time.now
48
- log_warn("expires_at is no longer valid. Must request new token")
61
+ log_warn("generated_at is no longer valid. Must request new token")
49
62
  context.fail!(msg: "Unauthorized Access. Invalid Authorization token")
50
63
  end
64
+
65
+ expires_time
51
66
  end
52
67
 
53
68
  def email_validation_required!(user:)
@@ -12,7 +12,7 @@ module ApiEngineBase::Jwt
12
12
 
13
13
  def payload
14
14
  {
15
- expires_at: ApiEngineBase.config.jwt.ttl.from_now.to_i,
15
+ generated_at: Time.now.to_i,
16
16
  user_id: user.id,
17
17
  verifier_token: user.retreive_verifier_token!,
18
18
  }
@@ -41,9 +41,8 @@ class ApiEngineBase::ServiceBase
41
41
  def internal_validate(interactor)
42
42
  # call validate that is overridden from child
43
43
  begin
44
- validate!
45
- # validate_param!
46
- run_validations!
44
+ validate! # custom validations defined on the child class
45
+ run_validations! # ArgumentValidation's based on defined settings on child
47
46
  rescue StandardError => e
48
47
  log_error("Error during validation. #{e.message}")
49
48
  raise
@@ -72,8 +71,8 @@ class ApiEngineBase::ServiceBase
72
71
 
73
72
  # Re-raise to let the core Interactor handle this
74
73
  raise
75
- # Capture exception explicitly to try to logging purposes. Then reraise.
76
- rescue ::Exception => e # rubocop:disable Lint/RescueException
74
+ # Capture exception explicitly for logging purposes, then reraise
75
+ rescue ::Exception => e
77
76
  # set status for use in ensure block
78
77
  status = :error
79
78
 
@@ -0,0 +1,68 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ApiEngineBase::UserAttributes
4
+ class Modify < ApiEngineBase::ServiceBase
5
+ on_argument_validation :fail_early
6
+ DEFAULT = {
7
+ verifier_token: [true, false]
8
+ }
9
+ validate :user, is_a: User, required: true
10
+ validate :admin_user, is_a: User, required: false
11
+
12
+ # Gets assigned during configuration phase via
13
+ # lib/api_engine_base/configuration/user/config.rb
14
+ def self.assign!
15
+ attributes = ApiEngineBase.config.user.default_attributes_for_change + ApiEngineBase.config.user.additional_attributes_for_change
16
+ one_of(:modify_attribute, required: true) do
17
+ attributes.uniq.each do |attribute|
18
+ if metadata = User.attribute_to_type_mapping[attribute]
19
+ arguments = {}
20
+ if default = DEFAULT[attribute.to_sym]
21
+ arguments[:is_one] = default
22
+ else
23
+ if allowed_types = metadata[:allowed_types]
24
+ arguments[:is_one] = allowed_types
25
+ else
26
+ arguments[:is_a] = metadata[:ruby_type]
27
+ end
28
+ end
29
+
30
+ validate(attribute, **arguments)
31
+ end
32
+ end
33
+ end
34
+ end
35
+
36
+ def call
37
+ case modify_attribute_key
38
+ when :email
39
+ unless email =~ URI::MailTo::EMAIL_REGEXP
40
+ inline_argument_failure!(errors: { email: "Invalid email address" })
41
+ end
42
+ when :username
43
+ username_validity = ApiEngineBase::Username::Available.(username:)
44
+ unless username_validity.valid
45
+ inline_argument_failure!(errors: { username: "Username is invalid. #{ApiEngineBase.config.username.username_failure_message}" })
46
+ end
47
+ when :verifier_token
48
+ if verifier_token
49
+ verifier_token!
50
+ else
51
+ inline_argument_failure!(errors: { verifier_token: "verifier_token is invalid. Expected [true] when value present" })
52
+ end
53
+
54
+ return
55
+ end
56
+
57
+ update!
58
+ end
59
+
60
+ def verifier_token!
61
+ user.reset_verifier_token!
62
+ end
63
+
64
+ def update!
65
+ user.update!(modify_attribute_key => modify_attribute)
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ApiEngineBase::UserAttributes
4
+ class Roles < ApiEngineBase::ServiceBase
5
+ on_argument_validation :fail_early
6
+
7
+ validate :user, is_a: User, required: true
8
+ validate :admin_user, is_a: User, required: true
9
+ validate :roles, is_a: Array, required: true
10
+
11
+ def call
12
+ if valid_roles?
13
+ user.update!(roles:)
14
+ return true
15
+ end
16
+
17
+ inline_argument_failure!(errors: { roles: "Invalid roles provided" })
18
+ end
19
+
20
+ def valid_roles?
21
+ return true if roles.empty?
22
+
23
+ available_roles = ApiEngineBase::Authorization::Role.roles.keys
24
+ roles.all? { available_roles.include?(_1) }
25
+ end
26
+ end
27
+ end
data/config/routes.rb CHANGED
@@ -20,4 +20,15 @@ Rails.application.routes.draw do
20
20
  end
21
21
  end
22
22
  end
23
+
24
+ scope "user" do
25
+ get "/", to: "api_engine_base/user#show", as: :"#{append_to_ass}_user_show_get"
26
+ post "/modify", to: "api_engine_base/user#modify", as: :"#{append_to_ass}_user_modify_post"
27
+ end
28
+
29
+ scope "admin" do
30
+ get "/", to: "api_engine_base/admin#show", as: :"#{append_to_ass}_admin_show_get"
31
+ post "/modify", to: "api_engine_base/admin#modify", as: :"#{append_to_ass}_admin_modify_post"
32
+ post "/modify/role", to: "api_engine_base/admin#modify_role", as: :"#{append_to_ass}_admin_modify_role_post"
33
+ end
23
34
  end
@@ -12,6 +12,8 @@ class CreateApiEngineBaseUsers < ActiveRecord::Migration[7.2]
12
12
  t.string :last_login_strategy
13
13
  t.datetime :last_login
14
14
 
15
+ t.string :roles, default: ""
16
+
15
17
  ###
16
18
  # Database token to verify JWT
17
19
  # Token will allow JWT values to expire/reset all devices
@@ -0,0 +1,34 @@
1
+ ---
2
+ groups:
3
+ owner:
4
+ description: The owner of the application will have full access to all components
5
+ entities: true
6
+ admin:
7
+ description: |
8
+ This group defines permissions for Admin Read and Write operations. Users with this role will have
9
+ the ability to view and update other users states.
10
+ entities:
11
+ - admin
12
+ admin-without-impersonation:
13
+ description: |
14
+ This group defines permissions for Admin Read and Write operations. Users with this role will have
15
+ the ability to view and update other users states. However, impersonation is not permitted with this role
16
+ entities:
17
+ - admin-without-impersonate
18
+ admin-read-only:
19
+ description: |
20
+ This group defines permissions for Admin Read interface only.
21
+ entities:
22
+ - read-admin
23
+ entities:
24
+ - name: read-admin
25
+ controller: ApiEngineBase::AdminController
26
+ only: show
27
+ - name: admin
28
+ controller: ApiEngineBase::AdminController
29
+ - name: admin-without-impersonate
30
+ controller: ApiEngineBase::AdminController
31
+ except: impersonate
32
+
33
+
34
+
@@ -0,0 +1,101 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ApiEngineBase
4
+ module Authorization
5
+ class Entity
6
+ class << self
7
+ def create_entity(name:, controller:, only: nil, except: nil)
8
+ if entities[name]
9
+ Rails.logger.warn("Warning: Authorization entity #{name} duplicated. Only the most recent one will persist")
10
+ end
11
+
12
+ entities[name] = new(name:, controller:, only:, except:)
13
+
14
+ entities[name]
15
+ end
16
+
17
+ def entities
18
+ @entities ||= ActiveSupport::HashWithIndifferentAccess.new
19
+ end
20
+
21
+ def entities_reset!
22
+ @entities = ActiveSupport::HashWithIndifferentAccess.new
23
+ end
24
+ end
25
+
26
+ attr_reader :name, :controller, :only, :except
27
+ def initialize(name:, controller:, only: nil, except: nil)
28
+ @controller = controller
29
+ @except = except.nil? ? nil : Array(except).map(&:to_sym)
30
+ @only = only.nil? ? nil : Array(only).map(&:to_sym)
31
+
32
+ validate!
33
+ end
34
+
35
+ def humanize
36
+ "name:[#{name}]; controller:[#{controller}]; only:[#{only}]; except:[#{except}]"
37
+ end
38
+
39
+ # controller will be the class object
40
+ # method will be the string of the route method
41
+ def matches?(controller:, method:)
42
+ # Return early if the controller does not match the existing entity controller
43
+ return nil if @controller != controller
44
+
45
+ # We are in the correct controller
46
+
47
+ # if inclusions are not present, the check is on the entire contoller and we can return true
48
+ if only.nil? && except.nil?
49
+ return true
50
+ end
51
+
52
+ ## `only` or `except` is present at this point
53
+ if only
54
+ # If method is included in only, accept otherwise return reject
55
+ return only.include?(method.to_sym)
56
+ else
57
+ # If method is included in except, reject otherwise return accept
58
+ return !except.include?(method.to_sym)
59
+ end
60
+ end
61
+
62
+ # This is a custom method that can get overridden by a child class for custom
63
+ # authorization logic beyond grouping
64
+ def authorized?(user:)
65
+ true
66
+ end
67
+
68
+ private
69
+
70
+ def validate!
71
+ if @only && @except
72
+ raise Error, "kwargs `only` and `except` passed in. At most 1 can be passed in."
73
+ end
74
+
75
+ validate_controller!
76
+ validate_methods!(@only, :only)
77
+ validate_methods!(@except, :except)
78
+ end
79
+
80
+ def validate_controller!
81
+ return true if Class === @controller
82
+
83
+ @controller = @controller.constantize
84
+ rescue NameError => e
85
+ raise Error, "Controller [#{@controller}] was not found. Please validate spelling or ensure it is loaded earlier"
86
+ end
87
+
88
+ def validate_methods!(array_of_methods, string)
89
+ return if array_of_methods.nil?
90
+
91
+ missing_methods = array_of_methods.select do |method|
92
+ !@controller.instance_methods.include?(method)
93
+ end
94
+
95
+ return true if missing_methods.empty?
96
+
97
+ raise Error, "#{string} parameter is invalid. Controller [#{@controller}] is missing methods:[#{missing_methods}]"
98
+ end
99
+ end
100
+ end
101
+ end
@@ -0,0 +1,101 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ApiEngineBase
4
+ module Authorization
5
+ class Role
6
+ class << self
7
+ def create_role(name:, description:, entities: nil, allow_everything: false)
8
+ if roles[name]
9
+ raise Error, "Role [#{name}] already exists. Must use different name"
10
+ end
11
+
12
+ if allow_everything
13
+ Rails.logger.info { "Authorization Role: #{name} is granted authorization to all roles" }
14
+ else
15
+ unless Array(entities).all? { Entity === _1 }
16
+ raise Error, "Parameter :entities must include objects of or inherited by ApiEngineBase::Authorization::Entity"
17
+ end
18
+ end
19
+
20
+ roles[name] = new(name:, description:, entities:, allow_everything:)
21
+ # A role is `intended` to be immutable (attr_reader)
22
+ # Once the role is defined it will not get changed
23
+ # After it is created, add the mapping to the source of truth list of mapped method names to their controllers
24
+ ApiEngineBase::Authorization.add_mapping!(role: roles[name])
25
+
26
+ roles[name]
27
+ end
28
+
29
+ def roles
30
+ @roles ||= ActiveSupport::HashWithIndifferentAccess.new
31
+ end
32
+
33
+ def roles_reset!
34
+ @roles = ActiveSupport::HashWithIndifferentAccess.new
35
+ end
36
+ end
37
+
38
+ attr_reader :entities, :name, :description, :allow_everything
39
+ def initialize(name:, description:, entities:, allow_everything: false)
40
+ @name = name
41
+ @entities = Array(entities)
42
+ @description = description
43
+ @allow_everything = allow_everything
44
+ end
45
+
46
+ def authorized?(controller:, method:, user:)
47
+ return_value = { role: name, description: }
48
+ return return_value.merge(authorized: true, reason: "#{name} allows all authorizations") if allow_everything
49
+
50
+ matched_controllers = controller_entity_mapping[controller]
51
+ # if Role does not match any of the controllers
52
+ # explicitly return nil here to ensure upstream knows this role does not care about the route
53
+ return return_value.merge(authorized: nil, reason: "#{name} does not match") if matched_controllers.nil?
54
+
55
+ rejected_entities = matched_controllers.map do |entity|
56
+ case entity.matches?(controller:, method:)
57
+ when false, nil
58
+ { authorized: false, entity: entity.name, controller:, readable: entity.humanize, status: "Rejected by inclusion" }
59
+ when true
60
+ # Entity matches all inclusions
61
+ if entity.authorized?(user:)
62
+ # Do nothing! Entity has authorized the user
63
+ else
64
+ { authorized: false, entity: entity.name, controller:, readable: entity.humanize, status: "Rejected via custom Entity Authorization" }
65
+ end
66
+ end
67
+ end.compact
68
+
69
+ # If there were no entities that rejected authorization, return authorized
70
+ return return_value.merge(authorized: true, reason: "All entities approve authorization") if rejected_entities.empty?
71
+
72
+ return_value.merge(authorized: false, reason: "Subset of Entities Rejected authorization", rejected_entities:)
73
+ end
74
+
75
+ def guards
76
+ mapping = {}
77
+ controller_entity_mapping.each do |controller, entities|
78
+ mapping[controller] ||= []
79
+ entities.map do |entity|
80
+ if entity.only
81
+ # We only care about these methods on the controller
82
+ mapping[controller] += entity.only
83
+ elsif entity.except
84
+ # We care about all methods on the controller except these
85
+ mapping[controller] += controller.instance_methods(false) - entity.except
86
+ else
87
+ # We care about all methods on the controller
88
+ mapping[controller] += controller.instance_methods(false)
89
+ end
90
+ end
91
+ end
92
+
93
+ mapping
94
+ end
95
+
96
+ def controller_entity_mapping
97
+ @controller_entity_mapping ||= @entities.group_by(&:controller)
98
+ end
99
+ end
100
+ end
101
+ end
@@ -0,0 +1,85 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "yaml"
4
+ require "set"
5
+ require "api_engine_base/error"
6
+ require "api_engine_base/authorization/entity"
7
+ require "api_engine_base/authorization/role"
8
+
9
+ module ApiEngineBase
10
+ module Authorization
11
+ module_function
12
+
13
+ class Error < ApiEngineBase::Error; end
14
+
15
+ def mapped_controllers
16
+ @mapped_controllers ||= {}
17
+ end
18
+
19
+ def add_mapping!(role:)
20
+ role.guards.each do |controller, methods|
21
+ mapped_controllers[controller] ||= Set.new
22
+ mapped_controllers[controller] += methods
23
+ end
24
+ end
25
+
26
+ def mapped_controllers_reset!
27
+ @mapped_controllers = {}
28
+ end
29
+
30
+ def default_defined!
31
+ provision_rbac_default!
32
+ provision_rbac_user_defined!
33
+ end
34
+
35
+ def provision_rbac_user_defined!
36
+ path = ApiEngineBase.config.authorization.rbac_group_path
37
+ rbac_configuration = load_yaml(path)
38
+ provision_rbac_via_yaml(rbac_configuration)
39
+ end
40
+
41
+ def provision_rbac_default!
42
+ path = ApiEngineBase::Engine.root.join("lib", "api_engine_base", "authorization", "default.yml")
43
+ rbac_configuration = load_yaml(path)
44
+ provision_rbac_via_yaml(rbac_configuration)
45
+ end
46
+
47
+ def load_yaml(path)
48
+ return nil unless File.exist?(path)
49
+
50
+ YAML.load_file(path)
51
+ end
52
+
53
+ def provision_rbac_via_yaml(rbac_configuration)
54
+ return if rbac_configuration.nil?
55
+
56
+ rbac_configuration["entities"].each do |entity|
57
+ ApiEngineBase::Authorization::Entity.create_entity(
58
+ name: entity["name"],
59
+ controller: entity["controller"],
60
+ only: entity["only"],
61
+ except: entity["except"],
62
+ )
63
+ end
64
+
65
+ rbac_configuration["groups"].each do |name, metadata|
66
+ entities = nil
67
+ allow_everything = false
68
+ description = metadata["description"]
69
+
70
+ if metadata["entities"] == true
71
+ allow_everything = true
72
+ else
73
+ entities = ApiEngineBase::Authorization::Entity.entities.map { |k, v| v if metadata["entities"].include?(k) }.compact
74
+ end
75
+
76
+ ApiEngineBase::Authorization::Role.create_role(
77
+ name:,
78
+ entities:,
79
+ description:,
80
+ allow_everything:,
81
+ )
82
+ end
83
+ end
84
+ end
85
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "class_composer"
4
+
5
+ module ApiEngineBase
6
+ module Configuration
7
+ module Admin
8
+ class Config
9
+ include ClassComposer::Generator
10
+
11
+ add_composer :enable,
12
+ desc: "Allow Admin Capabilities for the application. By default, this is enabled",
13
+ allowed: [FalseClass, TrueClass],
14
+ default: true
15
+ end
16
+ end
17
+ end
18
+ end
@@ -27,13 +27,13 @@ module ApiEngineBase
27
27
  add_composer :port,
28
28
  allowed: [String, NilClass],
29
29
  default: ENV.fetch("API_ENGINE_BASE_PORT", nil),
30
- desc: "When composing SSO's or verification URL's, this is the URL for the application"
30
+ desc: "When composing SSO's or verification URL's, this is the PORT for the application"
31
31
 
32
32
  add_composer :composed_url,
33
33
  allowed: String,
34
34
  dynamic_default: ->(instance) { "#{instance.url}#{ ":#{instance.port}" if instance.port }" },
35
35
  desc: "The fully composed URL including the port number when needed. This Config variable is not needed as it is composed of the `url` and `port` composed values",
36
- default_shown: "Composed String of the URL and PORT. Override this with caution"
36
+ default_shown: "# Composed String of the URL and PORT. Override this with caution"
37
37
  end
38
38
  end
39
39
  end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "class_composer"
4
+
5
+ module ApiEngineBase
6
+ module Configuration
7
+ module Authorization
8
+ class Config
9
+ include ClassComposer::Generator
10
+
11
+ add_composer :rbac_default_groups,
12
+ desc: "The default Group Roles defined by this engine.",
13
+ allowed: [TrueClass, FalseClass],
14
+ default: true
15
+
16
+ add_composer :rbac_group_path,
17
+ desc: "If defined, this config points to the users YAML file defining RBAC group roles.",
18
+ allowed: String,
19
+ dynamic_default: ->(_) { Rails.root.join("config","rbac_groups.yml").to_s },
20
+ default_shown: "Rails.root.join(\"config\",\"rbac_groups.yml\")"
21
+ end
22
+ end
23
+ end
24
+ end