flexible-authorization

 flexible-authorization

Flexible Authorization: Storing & Managing Rules in Database presentation for RDRC 2016

0fe18dfd87b3e48c0a45280e07cf96c6?s=128

Giovanni Sakti

June 23, 2016
Tweet

Transcript

  1. Storing & Managing Rules in Database Flexible Authorization

  2. @giosakti Giovanni Sakti

  3. None
  4. Storing & Managing Rules in Database Flexible Authorization

  5. Storing & Managing Rules in Database Flexible Authorization

  6. Why is flexibility necessary?

  7. Why is flexibility necessary? It’s for future improvement and
 because

    my blood type is also O
  8. U: Can you make role A able to read this

    document after its state changes to approved? Me: *(hack the source code a bit)* Done U: Can you make role B release this document after at least 5 people agree? Me: *(hack the source code a bit)* Done U: *(Insert some very specific requests here)* Me: *(hack the source code a bit)* Done
  9. U: Can you just give me a nice interfaces to

    work with, so that I don’t have to bug you anymore when new requirements appear?
  10. Steps

  11. Regulating Collecting Evaluating Enforcing / Scoping Subsystems

  12. Subsystems Store rules/regulations/policies Regulating 1 Can I read this document

    Enforcing / Scoping 2 3 Evaluating 4 Collecting
  13. Subsystems Store rules/regulations/policies Regulating 1 Can I read this document

    Enforcing / Scoping 2 3 Evaluating 4 Collecting
  14. Subject Who Action What Object / Resource What Environment When,

    Where, How, Why Elements
  15. Regulating

  16. users roles activities Defining Tables & Columns N N N

    N username password e-mail name name actions : JSONB object conditions : JSONB Regulating
  17. actions: ['READ'], object: 'Document', conditions: [ "object.state = 'APPROVED'" ]

    actions: ['RELEASE'], object: 'Document', conditions: [ "object.approver_count >= 5" ] Regulating
  18. actions: ['READ', 'UPDATE', 'DELETE'], object: 'Document', conditions: [ "AND", "object.organization.code

    = 'A000'", "object.state = 'RELEASED" ] Regulating
  19. actions: ['READ', 'UPDATE', 'DELETE'], object: 'Document', conditions: [ "AND", [

    "OR", "object.organization.code = 'A000'", "object.organization.code = ‘B000'" ], "object.state = 'RELEASED" ] Regulating
  20. WYSIWYGish editor document organization code = ‘A000’ Live preview Regulating

  21. Collecting

  22. # documents_controller.rb ... def destroy authorize @document, :delete? @document.destroy! render

    json: @document end ... Collecting
  23. # application_policy.rb ... activities = @user.active_role.activities. where("actions ?? :action", action:

    "DESTROY"). where(object: “Document") ... Collecting
  24. Evaluating

  25. actions: ['READ', 'UPDATE', 'DELETE'], object: 'Document', conditions: [ "AND", [

    "OR", "object.organization.code = 'A000'", "object.organization.code = ‘B000'" ], "object.state = 'RELEASED" ] Evaluate conditions tree Evaluating
  26. Enforcing / Scoping

  27. May I (read/update/approve) this document? Enforcing

  28. # documents_controller.rb ... def destroy authorize @document, :delete? @document.destroy! render

    json: @document end ... Enforcing
  29. What documents can I read? Scoping

  30. actions: ['READ', 'UPDATE', 'DELETE'], object: 'Document', conditions: [ "AND", [

    "OR", "object.organization.code = 'A000'", "object.organization.code = ‘B000'" ], "object.state = 'RELEASED" ] Scoping def parse_json(opts = {}) instruction = {} instruction[:joins] = [] instruction[:selects] = {} # If json_arr is blank if opts[:json_arr].blank? instruction[:query] = TRUE_QUERY return instruction end # If json_arr is not blank operator = nil operand_stack = [] opts[:json_arr].each_with_index do |token, idx| if (idx == 0) && (%w(AND OR).include? token) operator = token else if token.is_a? Array temp = parse_json(opts.merge({json_arr: token})) instruction[:joins] |= temp[:joins].flatten instruction[:selects].merge! temp[:selects] query = "(#{temp[:query]})" else query_tokens = token.scan(/(?:"(?:\\.|[^"])*"|[^" ])+/) if (query_tokens.size != 3) && (!%w(= IN).include? query_tokens[1]) raise "Syntax error #{token}" else lhs_join = nil lhs_select = nil lhs_query = "" lhs_arr = query_tokens[0].split(".") lhs_arr.to_enum.with_index.reverse_each do |atom, idx| if idx == lhs_arr.size - 1 lhs_query = atom lhs_select = {"#{atom}" => lhs_query} elsif idx < lhs_arr.size - 1 && idx > 0 if lhs_join.nil? lhs_join = atom.to_sym else lhs_join = {atom.to_sym => lhs_join} end lhs_query = "#{atom}.#{lhs_arr[lhs_arr.size - 1]}" lhs_select = {"#{lhs_arr[lhs_arr.size - 1]}" => lhs_query} else # If array size is 2, then we should rename object to avoid ambiguity sql statement if lhs_arr.size == 2 lhs_query = "#{opts[:object].table_name}.#{lhs_arr[lhs_arr.size - 1]}" lhs_select = {"#{lhs_arr[lhs_arr.size - 1]}" => lhs_query} end end end rhs_query = "" if query_tokens[2].start_with? "subject" subject_scope = opts[:subject] rhs_arr = query_tokens[2].split(".") rhs_arr.each_with_index do |atom, idx| # If subject is not exist then there is no need to construct query, move along unless subject_scope rhs_query = "" next end if idx == 0 # NOP elsif idx > 0 && idx < (rhs_arr.size - 1) subject_scope = subject_scope.send(atom.to_sym) end if idx == (rhs_arr.size - 1) if query_tokens[1] == "IN" values = subject_scope.map{|m| "'#{m.send(atom.to_sym)}'"} rhs_query = "(#{values.join(',')})" if values.present? else rhs_query = "'#{subject_scope.send(atom.to_sym)}'" end end end else rhs_query = query_tokens[2] end instruction[:joins] |= [lhs_join] if lhs_join.present? instruction[:selects].merge! lhs_select if lhs_select.present? if rhs_query.present? query = "#{lhs_query} #{query_tokens[1]} #{rhs_query}" else query = FALSE_QUERY end end end operand_stack.push query end end if operator instruction[:query] = operand_stack.join(" #{operator} ") else instruction[:query] = operand_stack.shift end return instruction end What to select? What to join? What to filter?
  31. Challenges & Improvements

  32. Performance

  33. Conflict Resolution What if there are two or more rules

    with different outcome
  34. e.g. XACML Use Open Standard ?

  35. With the help of oAuth Centralized Authorization

  36. Conclusion

  37. 4 subsystems to consider regulating, collecting, evaluating, enforcing / scoping

  38. Format for storing authorization rules is important That’s why there’s

    even a standard for this
  39. The current focus is on how to make our authorization

    system less dependent on developers and give power to user
  40. Thanks! @giosakti https://speakerdeck.com/giosakti/flexible-authorization