class Casbin::CoreEnforcer

CoreEnforcer defines the core functionality of an enforcer. get_attr/set_attr methods is ported from Python as attr/attr=

Attributes

adapter[RW]
auto_motify_watcher[RW]
auto_save[RW]
effector[RW]
enabled[RW]
enabled?[RW]
fm[RW]
matcher_map[RW]
model[R]
model_path[RW]
rm_map[RW]
watcher[R]

Public Class Methods

new(model = nil, adapter = nil, watcher = nil) click to toggle source
# File lib/casbin-ruby/core_enforcer.rb, line 19
def initialize(model = nil, adapter = nil, watcher = nil)
  model ||= Config.model
  adapter ||= Config.adapter
  @watcher = watcher || Config.watcher

  if model.is_a? String
    if adapter.is_a? String
      init_with_file(model, adapter)
    else
      init_with_adapter(model, adapter)
    end
  elsif adapter.is_a? String
    raise 'Invalid parameters for enforcer.'
  else
    init_with_model_and_adapter(model, adapter)
  end
end
new_model(path = '', text = '') click to toggle source

creates a model.

# File lib/casbin-ruby/core_enforcer.rb, line 73
def self.new_model(path = '', text = '')
  m = Model::Model.new
  if path.length.positive?
    m.load_model(path)
  else
    m.load_model_from_text(text)
  end

  m
end

Public Instance Methods

add_named_domain_matching_func(ptype, fn) click to toggle source

add_named_domain_matching_func add MatchingFunc by ptype to RoleManager

# File lib/casbin-ruby/core_enforcer.rb, line 193
def add_named_domain_matching_func(ptype, fn)
  rm_map[ptype]&.add_domain_matching_func(fn)
end
add_named_matching_func(ptype, fn) click to toggle source

add_named_matching_func add MatchingFunc by ptype RoleManager

# File lib/casbin-ruby/core_enforcer.rb, line 188
def add_named_matching_func(ptype, fn)
  rm_map[ptype]&.add_matching_func(fn)
end
clear_policy() click to toggle source

clears all policy.

# File lib/casbin-ruby/core_enforcer.rb, line 115
def clear_policy
  model.clear_policy
end
enable_auto_save(auto_save) click to toggle source

controls whether to save a policy rule automatically to the adapter when it is added or removed.

# File lib/casbin-ruby/core_enforcer.rb, line 172
def enable_auto_save(auto_save)
  self.auto_save = auto_save
end
enable_enforce(enabled = true) click to toggle source

changes the enforcing state of Casbin, when Casbin is disabled, all access will be allowed by the Enforce() function.

# File lib/casbin-ruby/core_enforcer.rb, line 167
def enable_enforce(enabled = true)
  self.enabled = enabled
end
enforce(*rvals) click to toggle source

decides whether a “subject” can access a “object” with the operation “action”, input parameters are usually: (sub, obj, act).

# File lib/casbin-ruby/core_enforcer.rb, line 199
def enforce(*rvals)
  enforce_ex(*rvals)[0]
end
enforce_ex(*rvals) click to toggle source

decides whether a “subject” can access a “object” with the operation “action”, input parameters are usually: (sub, obj, act). return judge result with reason

# File lib/casbin-ruby/core_enforcer.rb, line 206
def enforce_ex(*rvals)
  return [false, []] unless enabled?

  raise 'model is undefined' unless model.model&.key?('m')
  raise 'model is undefined' unless model.model['m']&.key?('m')

  r_tokens = model.model['r']['r'].tokens
  p_tokens = model.model['p']['p'].tokens
  raise StandardError, 'invalid request size' unless r_tokens.size == rvals.size

  exp_string = model.model['m']['m'].value
  has_eval = Util.has_eval(exp_string)
  expression = exp_string
  policy_effects = Set.new
  r_parameters = load_params(r_tokens, rvals)
  policy_len = model.model['p']['p'].policy.size
  explain_index = -1
  if policy_len.positive?
    model.model['p']['p'].policy.each_with_index do |pvals, i|
      raise StandardError, 'invalid policy size' unless p_tokens.size == pvals.size

      p_parameters = load_params(p_tokens, pvals)
      parameters = r_parameters.merge(p_parameters)

      if has_eval
        rule_names = Util.get_eval_value(exp_string)
        rules = rule_names.map { |rule_name| Util.escape_assertion(p_parameters[rule_name]) }
        expression = Util.replace_eval(exp_string, rules)
      end

      result = evaluate(expression, functions, parameters)
      case result
      when TrueClass, FalseClass
        unless result
          policy_effects.add(Effect::Effector::INDETERMINATE)
          next
        end
      when Numeric
        if result.zero?
          policy_effects.add(Effect::Effector::INDETERMINATE)
          next
        end
      else
        raise 'matcher result should be true, false or a number'
      end

      if parameters.keys.include?('p_eft')
        case parameters['p_eft']
        when 'allow'
          policy_effects.add(Effect::Effector::ALLOW)
        when 'deny'
          policy_effects.add(Effect::Effector::DENY)
        else
          policy_effects.add(Effect::Effector::INDETERMINATE)
        end
      else
        policy_effects.add(Effect::Effector::ALLOW)
      end

      if effector.intermediate_effect(policy_effects) != Effect::Effector::INDETERMINATE
        explain_index = i
        break
      end
    end

  else
    raise 'please make sure rule exists in policy when using eval() in matcher' if has_eval

    parameters = r_parameters.clone
    model.model['p']['p'].tokens.each { |token| parameters[token] = '' }
    result = evaluate(expression, functions, parameters)
    if result
      policy_effects.add(Effect::Effector::ALLOW)
    else
      policy_effects.add(Effect::Effector::INDETERMINATE)
    end
  end

  final_effect = effector.final_effect(policy_effects)
  result = Effect::DefaultEffector.effect_to_bool(final_effect)

  # Log request.
  log_request(rvals, result)

  explain_rule = []
  explain_rule = model.model['p']['p'].policy[explain_index] if explain_index != -1 && explain_index < policy_len
  [result, explain_rule]
end
filtered?() click to toggle source

returns true if the loaded policy has been filtered.

# File lib/casbin-ruby/core_enforcer.rb, line 151
def filtered?
  adapter.respond_to?(:filtered?) && adapter.filtered?
end
init_with_adapter(model_path, adapter = nil) click to toggle source

initializes an enforcer with a database adapter.

# File lib/casbin-ruby/core_enforcer.rb, line 47
def init_with_adapter(model_path, adapter = nil)
  m = new_model(model_path)
  init_with_model_and_adapter(m, adapter)

  self.model_path = model_path
end
init_with_file(model_path, policy_path) click to toggle source

initializes an enforcer with a model file and a policy file.

# File lib/casbin-ruby/core_enforcer.rb, line 41
def init_with_file(model_path, policy_path)
  a = Persist::Adapters::FileAdapter.new(policy_path)
  init_with_adapter(model_path, a)
end
init_with_model_and_adapter(m, adapter = nil) click to toggle source

initializes an enforcer with a model and a database adapter.

# File lib/casbin-ruby/core_enforcer.rb, line 55
def init_with_model_and_adapter(m, adapter = nil)
  if !m.is_a?(Model::Model) || (!adapter.nil? && !adapter.is_a?(Persist::Adapter))
    raise StandardError, 'Invalid parameters for enforcer.'
  end

  self.adapter = adapter

  self.model = m
  model.print_model
  self.fm = Model::FunctionMap.load_function_map

  init

  # Do not initialize the full policy when using a filtered adapter
  load_policy if adapter && !filtered?
end
load_filtered_policy(filter) click to toggle source

reloads a filtered policy from file/database.

# File lib/casbin-ruby/core_enforcer.rb, line 130
def load_filtered_policy(filter)
  model.clear_policy

  raise ArgumentError, 'filtered policies are not supported by this adapter' unless adapter.respond_to?(:filtered?)

  adapter.load_filtered_policy(model, filter)
  init_rm_map
  model.print_policy
  build_role_links if auto_build_role_links
end
load_increment_filtered_policy(filter) click to toggle source

appends a filtered policy from file/database.

# File lib/casbin-ruby/core_enforcer.rb, line 142
def load_increment_filtered_policy(filter)
  raise ArgumentError, 'filtered policies are not supported by this adapter' unless adapter.respond_to?(:filtered?)

  adapter.load_filtered_policy(model, filter)
  model.print_policy
  build_role_links if auto_build_role_links
end
load_model() click to toggle source

reloads the model from the model CONF file. Because the policy is attached to a model, so the policy is invalidated and needs to be reloaded by calling load_policy.

# File lib/casbin-ruby/core_enforcer.rb, line 91
def load_model
  self.model = new_model
  model.load_model model_path
  model.print_model
  self.fm = Model::FunctionMap.load_function_map
end
load_policy() click to toggle source

reloads the policy from file/database.

# File lib/casbin-ruby/core_enforcer.rb, line 120
def load_policy
  model.clear_policy
  adapter.load_policy model

  init_rm_map
  model.print_policy
  build_role_links if auto_build_role_links
end
model=(m) click to toggle source

sets the current model.

# File lib/casbin-ruby/core_enforcer.rb, line 99
def model=(m)
  @model = m
  self.fm = Model::FunctionMap.load_function_map
end
new_model(*args) click to toggle source
# File lib/casbin-ruby/core_enforcer.rb, line 84
def new_model(*args)
  self.class.new_model(*args)
end
role_manager() click to toggle source

gets the current role manager.

# File lib/casbin-ruby/core_enforcer.rb, line 105
def role_manager
  rm_map['g']
end
role_manager=(rm) click to toggle source

sets the current role manager.

# File lib/casbin-ruby/core_enforcer.rb, line 110
def role_manager=(rm)
  rm_map['g'] = rm
end
save_policy() click to toggle source
# File lib/casbin-ruby/core_enforcer.rb, line 155
def save_policy
  raise 'cannot save a filtered policy' if filtered?

  adapter.save_policy(model)

  watcher&.update
end

Private Instance Methods

evaluate(expr, funcs = {}, params = {}) click to toggle source
# File lib/casbin-ruby/core_enforcer.rb, line 315
def evaluate(expr, funcs = {}, params = {})
  Util::Evaluator.eval(expr, funcs, params)
end
functions() click to toggle source
# File lib/casbin-ruby/core_enforcer.rb, line 326
def functions
  functions = fm.get_functions

  if model.model.key? 'g'
    model.model['g'].each do |key, ast|
      rm = ast.rm
      functions[key] = Util::BuiltinOperators.generate_g_function(rm)
    end
  end

  functions
end
init() click to toggle source
# File lib/casbin-ruby/core_enforcer.rb, line 304
def init
  self.rm_map = {}
  self.effector = Effect::DefaultEffector.get_effector(model.model['e']['e'].value)

  self.enabled = true
  self.auto_save = true
  self.auto_build_role_links = true

  init_rm_map
end
init_rm_map() click to toggle source
# File lib/casbin-ruby/core_enforcer.rb, line 350
def init_rm_map
  return unless model.model.keys.include?('g')

  model.model['g'].each_key do |ptype|
    rm_map[ptype] = Rbac::DefaultRoleManager::RoleManager.new(10)
  end
end
load_params(tokens, values) click to toggle source
# File lib/casbin-ruby/core_enforcer.rb, line 319
def load_params(tokens, values)
  params = {}
  tokens.each_with_index { |token, i| params[token] = values[i] }

  params
end
log_request(rvals, result) click to toggle source
# File lib/casbin-ruby/core_enforcer.rb, line 339
def log_request(rvals, result)
  req_str = "Request: #{rvals.map(&:to_s).join ', '} ---> #{result}"

  if result
    Logger.info(req_str)
  else
    # leaving this in error for now, if it's very noise this can be changed to info or debug
    Logger.error(req_str)
  end
end