Ideas for improvement
Algorithm
Objective function:
affected user count,
as specific as possible (roles, privileges)
as little changes as necessary
Modify role, privilege hierarchy
Merge, split roles
Add privilege to existing rules
Features
Improve review facts: impact, affected users count
group similar candidates: only show abstract methods?
restructure GUI layout: more room for analyzing suggestions
changelog, previous tests, etc.
multiple permissions in tests
Evaluation of approaches with Analyzer algorithms
Authorization constraints
Algorithm
for each candidate
abstract actions: solving first failing test (remove privilege from role)
for each abstract action
specific actions: concrete steps (remove privilege from specific role)
for each specific action
next if reversal action of previous step
apply specific action on candidate
save as solution if no failing tests on changed_candidate
else: queue as candidate
equivalent states
NOTE:
user.clone needs to clone role_symbols
user.role_symbols needs to respond to <<
user.login is needed
# File lib/declarative_authorization/development_support/change_supporter.rb, line 613 def self.relevant_roles (approach) (AnalyzerEngine.relevant_roles(approach.engine, approach.users) + (approach.engine.roles.include?(:new_role_for_change_analyzer) ? [AnalyzerEngine::Role.for_sym(:new_role_for_change_analyzer, approach.engine)] : [])).uniq end
Returns a list of possible approaches for changes to the current
authorization rules that achieve a given goal. The goal is given as
permission tests in the block. The instance method users
is
available when the block is executed to refer to the then-current users,
whose roles might have changed as one suggestion.
# File lib/declarative_authorization/development_support/change_supporter.rb, line 48 def find_approaches_for (options, &tests) @prohibited_actions = (options[:prohibited_actions] || []).to_set @approaches_by_actions = {} candidates = [] suggestions = [] approach_checker = ApproachChecker.new(self, tests) starting_candidate = Approach.new(@engine, options[:users], []) if starting_candidate.check(approach_checker) suggestions << starting_candidate else candidates << starting_candidate end checked_candidates = 0 while !candidates.empty? and checked_candidates < 200 checked_candidates += next_step(suggestions, candidates, approach_checker) end # remove subsets suggestions.sort! end
Returns an array of GroupedApproaches for the given array of approaches. Only groups directly adjacent approaches
# File lib/declarative_authorization/development_support/change_supporter.rb, line 75 def group_approaches (approaches) approaches.each_with_object([]) do |approach, grouped| if grouped.last and grouped.last.approach.similar_to(approach) grouped.last.similar_approaches << approach else grouped << GroupedApproach.new(approach) end end end
# File lib/declarative_authorization/development_support/change_supporter.rb, line 598 def add_to_approaches_by_action! (candidate) candidate.changes.each do |action| (@approaches_by_actions[action] ||= []) << candidate end end
# File lib/declarative_authorization/development_support/change_supporter.rb, line 566 def check_child_candidates! (approach_checker, viable_approaches, candidates, child_candidates) child_candidates.each do |child_candidate| if child_candidate.check(approach_checker) unless superset_of_existing?(child_candidate) remove_supersets!(viable_approaches, child_candidate) viable_approaches << child_candidate add_to_approaches_by_action!(child_candidate) end else candidates << child_candidate end child_candidate.freeze end end
# File lib/declarative_authorization/development_support/change_supporter.rb, line 550 def generate_child_candidates (candidate) child_candidates = [] abstract_actions = candidate.abstract_actions abstract_actions.each do |abstract_action| abstract_action.specific_actions(candidate).each do |specific_action| child_candidate = candidate.dup if !specific_action.resembles_any?(@prohibited_actions) and !child_candidate.reverse_of_previous?(specific_action) and child_candidate.apply(specific_action) child_candidates << child_candidate end end end child_candidates end
# File lib/declarative_authorization/development_support/change_supporter.rb, line 540 def next_step (viable_approaches, candidates, approach_checker) candidate = candidates.shift child_candidates = generate_child_candidates(candidate) check_child_candidates!(approach_checker, viable_approaches, candidates, child_candidates) candidates.sort! child_candidates.length end
# File lib/declarative_authorization/development_support/change_supporter.rb, line 610 def relevant_roles (approach) self.class.relevant_roles(approach) end
# File lib/declarative_authorization/development_support/change_supporter.rb, line 604 def remove_from_approaches_by_action! (candidate) candidate.changes.each do |action| (@approaches_by_actions[action] ||= []).delete(candidate) end end
# File lib/declarative_authorization/development_support/change_supporter.rb, line 587 def remove_supersets! (existing, candidate) candidate.changes.inject([]) do |memo, action| memo += (@approaches_by_actions[action] ||= []).select do |approach| candidate.subset?(approach) end end.uniq.each do |approach| existing.delete(approach) remove_from_approaches_by_action!(approach) end end
# File lib/declarative_authorization/development_support/change_supporter.rb, line 581 def superset_of_existing? (candidate) candidate.changes.any? do |action| (@approaches_by_actions[action] ||= []).any? {|approach| approach.subset?(candidate)} end end