| Class | Authorization::DevelopmentSupport::ChangeAnalyzer |
| In: |
lib/declarative_authorization/development_support/change_analyzer.rb
|
| Parent: | AbstractAnalyzer |
Ideas for improvement
NOTE:
# File lib/declarative_authorization/development_support/change_analyzer.rb, line 30
30: def find_approaches_for (change_action, type, options, &tests)
31: raise ArgumentError, "Missing options" if !options[:on] or !options[:to]
32:
33: # * strategy for removing: [remove privilege, add privilege to different role]
34: @seen_states = Set.new
35: # * heuristic: change of failed tests; small number of policy items
36: strategy = case [change_action, type]
37: when [:remove, :permission]
38: [:remove_role_from_user, :remove_privilege, :add_privilege,
39: :add_role, :assign_role_to_user]
40: when [:add, :permission]
41: [:add_role, :add_privilege, :assign_role_to_user]
42: else
43: raise ArgumentError, "Unknown change action/type: #{[change_action, type].inspect}"
44: end
45:
46: candidates = []
47: viable_approaches = []
48: approach_checker = ApproachChecker.new(self, tests)
49:
50: starting_candidate = Approach.new(@engine, options[:users], [])
51: if starting_candidate.check(approach_checker)
52: viable_approaches << starting_candidate
53: else
54: candidates << starting_candidate
55: end
56:
57: step_count = 0
58: while !candidates.empty? and step_count < 100
59: next_step(viable_approaches, candidates, approach_checker, options[:to],
60: options[:on], strategy)
61: step_count += 1
62: end
63:
64: # remove subsets
65:
66: viable_approaches.sort!
67: end
# File lib/declarative_authorization/development_support/change_analyzer.rb, line 164
164: def next_step (viable_approaches, candidates, approach_checker,
165: privilege, context, strategy)
166: candidate = candidates.shift
167: next_in_strategy = strategy[candidate.steps.length % strategy.length]
168:
169: #if @seen_states.include?([candidate.state_hash, next_in_strategy])
170: # puts "SKIPPING #{next_in_strategy}; #{candidate.inspect}"
171: #end
172: return if @seen_states.include?([candidate.state_hash, next_in_strategy])
173: @seen_states << [candidate.state_hash, next_in_strategy]
174: candidate.steps << [next_in_strategy]
175: candidates << candidate
176:
177: new_approaches = []
178:
179: #puts "#{next_in_strategy} on #{candidate.inspect}"
180: case next_in_strategy
181: when :add_role
182: # ensure non-existent name
183: approach = candidate.clone_for_step(:add_role, :new_role_for_change_analyzer)
184: if AnalyzerEngine.apply_change(approach.engine, approach.changes.last)
185: #AnalyzerEngine.apply_change(approach.engine, [:add_privilege, privilege, context, :new_role_for_change_analyzer])
186: new_approaches << approach
187: end
188: when :assign_role_to_user
189: candidate.users.each do |user|
190: relevant_roles(candidate).each do |role|
191: next if user.role_symbols.include?(role.to_sym)
192: approach = candidate.clone_for_step(:assign_role_to_user, role, user)
193: # beware of shallow copies!
194: cloned_user = user.clone
195: approach.users[approach.users.index(user)] = cloned_user
196: # possible on real user objects?
197: cloned_user.role_symbols << role.to_sym
198: new_approaches << approach
199: end
200: end
201: when :remove_role_from_user
202: candidate.users.each do |user|
203: user.role_symbols.each do |role_sym|
204: approach = candidate.clone_for_step(:remove_role_from_user, role_sym, user)
205: # beware of shallow copies!
206: cloned_user = user.clone
207: approach.users[approach.users.index(user)] = cloned_user
208: # possible on real user objects?
209: cloned_user.role_symbols.delete(role_sym)
210: new_approaches << approach
211: end
212: end
213: when :add_privilege
214: relevant_roles(candidate).each do |role|
215: approach = candidate.clone_for_step(:add_privilege, privilege, context, role)
216: AnalyzerEngine.apply_change(approach.engine, approach.changes.last)
217: new_approaches << approach
218: end
219: when :remove_privilege
220: relevant_roles(candidate).each do |role|
221: approach = candidate.clone_for_step(:remove_privilege, privilege, context, role)
222: if AnalyzerEngine.apply_change(approach.engine, approach.changes.last)
223: new_approaches << approach
224: end
225: end
226: else
227: raise "Unknown next strategy step #{next_in_strategy}"
228: end
229:
230: new_approaches.each do |new_approach|
231: if new_approach.check(approach_checker)
232: unless viable_approaches.any? {|viable_approach| viable_approach.subset?(new_approach) }
233: #puts "New: #{new_approach.changes.inspect}\n #{viable_approaches.map(&:changes).inspect}"
234: viable_approaches.delete_if {|viable_approach| new_approach.subset?(viable_approach)}
235: viable_approaches << new_approach unless viable_approaches.find {|v_a| v_a.state_hash == new_approach.state_hash}
236: end
237: else
238: candidates << new_approach
239: end
240: end
241:
242: candidates.sort!
243: end
# File lib/declarative_authorization/development_support/change_analyzer.rb, line 245
245: def relevant_roles (approach)
246: #return AnalyzerEngine.roles(approach.engine)
247: (AnalyzerEngine.relevant_roles(approach.engine, approach.users) +
248: (approach.engine.roles.include?(:new_role_for_change_analyzer) ?
249: [AnalyzerEngine::Role.for_sym(:new_role_for_change_analyzer, approach.engine)] : [])).uniq
250: end