Class: ActionBlocks::AuthorizationAdapter

Inherits:
Object
  • Object
show all
Defined in:
lib/action_blocks/data_engine/authorization_adapter.rb

Overview

Data Engine

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(engine:, user:) ⇒ AuthorizationAdapter

Returns a new instance of AuthorizationAdapter.



6
7
8
9
10
# File 'lib/action_blocks/data_engine/authorization_adapter.rb', line 6

def initialize(engine:, user:)
  @engine = engine
  @user = user
  @model_id = @engine.root_klass.to_s.underscore
end

Instance Attribute Details

#engineObject

Returns the value of attribute engine.



4
5
6
# File 'lib/action_blocks/data_engine/authorization_adapter.rb', line 4

def engine
  @engine
end

#userObject

Returns the value of attribute user.



4
5
6
# File 'lib/action_blocks/data_engine/authorization_adapter.rb', line 4

def user
  @user
end

Instance Method Details

#evaluate(expression) ⇒ Object



58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
# File 'lib/action_blocks/data_engine/authorization_adapter.rb', line 58

def evaluate(expression)
  # Convert Symbol to Arel Attribute
  if expression.class == Symbol
    return @arel_attributes[expression]
  end

  # Convert Proc to it's result
  if expression.class == Proc
    proc_args = {}
    # debug expression.parameters
    if expression.parameters.include?([:keyreq, :user])
      proc_args[:user] = @user
    end
    return expression.call(**proc_args)
  end

  # Convert expression to Arel Predicate
  if expression.class == Array
    fn, *args = expression
    case fn
    when :user
      return @user.send(args[0])
    when :eq
      left, right = args
      return evaluate(left).eq(evaluate(right))
    when :not_eq
      left, right = args
      return evaluate(left).not_eq(evaluate(right))            
    when :and
      return args.map {|x| evaluate(x)}.reduce(&:and)
    when :or
      return args.map {|x| evaluate(x)}.reduce(&:or)
    else
      raise "RLS function #{fn.inspect} not recognized"
    end
  end
  return expression
end

#get_arel_attributesObject

Convert all fields to arel nodes while building up needed @engine.joins



42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
# File 'lib/action_blocks/data_engine/authorization_adapter.rb', line 42

def get_arel_attributes()
  @fields = get_fields(rls_scheme)
  @arel_attributes = {}
  [@fields].flatten.each do |f|
    f = ActionBlocks.find("field-#{@model_id}-#{f}")
    select_req = f.select_requirements
    if select_req[:type] == :summary
      raise "Summary fields not supported in authorizations"
    end
    field_name = select_req[:field_name]
    node, *rest = select_req[:path]
    @arel_attributes[field_name] = walk_path(@engine.root_klass, node, @engine.root_key, rest)
  end
  return @arel_attributes
end

#get_fields(expression) ⇒ Object

Extract fields from lisp/scheme



25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
# File 'lib/action_blocks/data_engine/authorization_adapter.rb', line 25

def get_fields(expression)
  results = []
  if expression.class == Array
    fn, *args = expression
    if fn == :user
      return []
    else
      return args.map { |a| get_fields(a) }.flatten.uniq
    end
  end
  if expression.class == Symbol
    return expression
  end
  return []
end

#processObject



97
98
99
100
# File 'lib/action_blocks/data_engine/authorization_adapter.rb', line 97

def process
  @arel_attributes = get_arel_attributes()
  @engine.wheres << evaluate(rls_scheme)
end

#rls_schemeObject

get the lisp/scheme like data structure specifying row level security



13
14
15
16
17
18
19
20
21
22
# File 'lib/action_blocks/data_engine/authorization_adapter.rb', line 13

def rls_scheme
  rls = ActionBlocks.find("rls-#{@model_id}-#{@user.role}")
  if !rls
      return Arel::Nodes::False.new # [:eq, Arel::Nodes::True.new, Arel::Nodes::False.new]
  end
  if rls.scheme == nil
      return Arel::Nodes::True.new # [:eq, Arel::Nodes::True.new, Arel::Nodes::True.new]
  end
  return ActionBlocks.find("rls-#{@model_id}-#{@user.role}").scheme
end

#walk_path(klass, node, parent_key, col_path) ⇒ Object



102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
# File 'lib/action_blocks/data_engine/authorization_adapter.rb', line 102

def walk_path(klass, node, parent_key, col_path)
  key = [parent_key, node].compact.join('_').to_sym
  if node.class != Symbol
    return node
  end
  if !col_path.empty?
    # Create Arel Table Alias
    relation = klass.reflections[node.to_s]
    klass = relation.klass
    @engine.tables[key] = klass.arel_table.alias(key) unless @engine.tables[key]
    # Create Join
    fk = relation.join_foreign_key
    pk = relation.join_primary_key
    join_on = @engine.tables[key].create_on(@engine.tables[parent_key][fk].eq(@engine.tables[key][pk]))
    @engine.joins[key] = @engine.tables[parent_key].create_join(@engine.tables[key], join_on, Arel::Nodes::OuterJoin)
    # Recurse
    next_node, *rest = col_path
    return walk_path(klass, next_node, key, rest)
  else
    return @engine.tables[parent_key][node.to_sym]
  end
end