api_engine_base 0.1.1 → 0.1.2

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