From 80409686ac6a1809e90cea6d53e87ae0efc27aa6 Mon Sep 17 00:00:00 2001 From: Anna Date: Tue, 24 May 2016 20:57:48 -0400 Subject: [PATCH 01/55] Do not put a space between a method name and the opening parenthesis use parentheses around parameters in method definitions --- Rakefile | 2 +- .../authorization_rules_controller.rb | 10 +- app/helpers/authorization_rules_helper.rb | 42 +++---- .../authorization.rb | 91 +++++++------- .../development_support/analyzer.rb | 46 +++---- .../development_support/change_analyzer.rb | 26 ++-- .../development_support/change_supporter.rb | 118 +++++++++--------- .../development_support.rb | 48 +++---- lib/declarative_authorization/helper.rb | 6 +- .../in_controller.rb | 32 ++--- lib/declarative_authorization/in_model.rb | 8 +- lib/declarative_authorization/maintenance.rb | 20 +-- .../obligation_scope.rb | 10 +- lib/declarative_authorization/reader.rb | 72 +++++------ .../install/install_generator.rb | 4 +- .../controller_filter_resource_access_test.rb | 12 +- test/development_support/analyzer_test.rb | 2 +- test/model_test.rb | 2 +- test/test_helper.rb | 16 +-- 19 files changed, 286 insertions(+), 281 deletions(-) diff --git a/Rakefile b/Rakefile index 635ba70f..8dadc80d 100644 --- a/Rakefile +++ b/Rakefile @@ -5,7 +5,7 @@ require 'rdoc/task' desc 'Default: run unit tests against all versions.' task :default => 'bundles:test' -def run_for_bundles cmd +def run_for_bundles(cmd) Dir['gemfiles/*.gemfile'].each do |gemfile| puts "\n#{gemfile}: #{cmd}" ENV['BUNDLE_GEMFILE'] = gemfile diff --git a/app/controllers/authorization_rules_controller.rb b/app/controllers/authorization_rules_controller.rb index 9c454378..d1076fba 100644 --- a/app/controllers/authorization_rules_controller.rb +++ b/app/controllers/authorization_rules_controller.rb @@ -108,7 +108,7 @@ def suggest_change end private - def auth_to_dot (options = {}) + def auth_to_dot(options = {}) options = { :effective_role_privs => true, :privilege_hierarchy => false, @@ -198,7 +198,7 @@ def auth_to_dot (options = {}) render_to_string :template => 'authorization_rules/graph.dot.erb', :layout => false end - def replay_changes (engine, users, changes) + def replay_changes(engine, users, changes) changes.inject({}) do |memo, info| case info[0] when :add_privilege, :add_role @@ -212,7 +212,7 @@ def replay_changes (engine, users, changes) end end - def dot_to_svg (dot_data) + def dot_to_svg(dot_data) gv = IO.popen("#{Authorization.dot_path} -q -Tsvg", "w+") gv.puts dot_data gv.close_write @@ -235,7 +235,7 @@ def graph_options } end - def deserialize_changes (changes) + def deserialize_changes(changes) if changes changes.split(';').collect do |info| info.split(',').collect do |info_part| @@ -245,7 +245,7 @@ def deserialize_changes (changes) end end - def find_user_by_id (id) + def find_user_by_id(id) User.find(id) end def find_all_users diff --git a/app/helpers/authorization_rules_helper.rb b/app/helpers/authorization_rules_helper.rb index dba93924..1cb29e43 100644 --- a/app/helpers/authorization_rules_helper.rb +++ b/app/helpers/authorization_rules_helper.rb @@ -1,5 +1,5 @@ module AuthorizationRulesHelper - def syntax_highlight (rules) + def syntax_highlight(rules) regexps = { :constant => [/(:)(\w+)/], :proc => ['role', 'authorization', 'privileges'], @@ -22,7 +22,7 @@ def syntax_highlight (rules) rules end - def policy_analysis_hints (marked_up, policy_data) + def policy_analysis_hints(marked_up, policy_data) analyzer = Authorization::DevelopmentSupport::Analyzer.new(controller.authorization_engine) analyzer.analyze(policy_data) marked_up_by_line = marked_up.split("\n") @@ -39,7 +39,7 @@ def policy_analysis_hints (marked_up, policy_data) (marked_up_by_line * "\n").html_safe end - def link_to_graph (title, options = {}) + def link_to_graph(title, options = {}) type = options[:type] || '' link_to_function title, "$$('object')[0].data = '#{url_for :action => 'index', :format => 'svg', :type => type}'" end @@ -53,7 +53,7 @@ def navigation # link_to("XACML export", :action => 'index', :format => 'xacml') end - def role_color (role, fill = false) + def role_color(role, fill = false) if @has_changes if has_changed(:add_role, role) fill ? '#ddffdd' : '#000000' @@ -74,17 +74,17 @@ def role_color (role, fill = false) end end - def role_fill_color (role) + def role_fill_color(role) role_color(role, true) end - def privilege_color (privilege, context, role) + def privilege_color(privilege, context, role) has_changed(:add_privilege, privilege, context, role) ? '#00dd00' : (has_changed(:remove_privilege, privilege, context, role) ? '#dd0000' : role_color(role)) end - def human_privilege (privilege) + def human_privilege(privilege) begin I18n.t(privilege, :scope => [:declarative_authorization, :privilege], :raise => true) rescue @@ -92,7 +92,7 @@ def human_privilege (privilege) end end - def human_context (context) + def human_context(context) begin context.to_s.classify.constantize.human_name rescue @@ -100,7 +100,7 @@ def human_context (context) end end - def human_privilege_context (privilege, context) + def human_privilege_context(privilege, context) human = [human_privilege(privilege), human_context(context)] begin unless I18n.t(:verb_in_front_of_object, :scope => :declarative_authorization, :raise => true) @@ -111,11 +111,11 @@ def human_privilege_context (privilege, context) human * " " end - def human_role (role) + def human_role(role) Authorization::Engine.instance.title_for(role) or role.to_s end - def describe_step (step, options = {}) + def describe_step(step, options = {}) options = {:with_removal => false}.merge(options) case step[0] @@ -147,14 +147,14 @@ def describe_step (step, options = {}) "Don't suggest this action.", options) end - def prohibit_link (step, text, title, options) + def prohibit_link(step, text, title, options) options[:with_removal] ? link_to_function("[x]", "prohibit_action('#{serialize_action(step)}', '#{text}')", :class => 'prohibit', :title => title) : '' end - def readable_step_info (info) + def readable_step_info(info) case info when Symbol then info.inspect when User then info.login @@ -162,29 +162,29 @@ def readable_step_info (info) end end - def serialize_changes (approach) + def serialize_changes(approach) changes = approach.changes.collect {|step| step.to_a.first.is_a?(Enumerable) ? step.to_a : [step.to_a]} changes.collect {|multi_step| multi_step.collect {|step| serialize_action(step) }}.flatten * ';' end - def serialize_action (step) + def serialize_action(step) step.collect {|info| readable_step_info(info) } * ',' end - def serialize_relevant_roles (approach) - {:filter_roles => (Authorization::DevelopmentSupport::AnalyzerEngine.relevant_roles(approach.engine, approach.users). + def serialize_relevant_roles(approach) + {:filter_roles =>(Authorization::DevelopmentSupport::AnalyzerEngine.relevant_roles(approach.engine, approach.users). map(&:to_sym) + [:new_role_for_change_analyzer]).uniq}.to_param end - def has_changed (*args) + def has_changed(*args) @changes && @changes[args[0]] && @changes[args[0]].include?(args[1..-1]) end - def affected_users_count (approach) + def affected_users_count(approach) @affected_users[approach] end - def auth_usage_info_classes (auth_info) + def auth_usage_info_classes(auth_info) classes = [] if auth_info[:controller_permissions] if auth_info[:controller_permissions][0] @@ -199,7 +199,7 @@ def auth_usage_info_classes (auth_info) classes * " " end - def auth_usage_info_title (auth_info) + def auth_usage_info_title(auth_info) titles = [] if auth_usage_info_classes(auth_info) =~ /unprotected/ titles << "No filter_access_to call protects this action" diff --git a/lib/declarative_authorization/authorization.rb b/lib/declarative_authorization/authorization.rb index b8fc761a..82573edf 100644 --- a/lib/declarative_authorization/authorization.rb +++ b/lib/declarative_authorization/authorization.rb @@ -34,7 +34,7 @@ def self.current_user=(user) end # For use in test cases only - def self.ignore_access_control (state = nil) # :nodoc: + def self.ignore_access_control(state = nil) # :nodoc: Thread.current["ignore_access_control"] = state unless state.nil? Thread.current["ignore_access_control"] || false end @@ -48,7 +48,7 @@ def self.dot_path @@dot_path end - def self.dot_path= (path) + def self.dot_path=(path) @@dot_path = path end @@ -57,11 +57,11 @@ def self.default_role @@default_role end - def self.default_role= (role) + def self.default_role=(role) @@default_role = role.to_sym end - def self.is_a_association_proxy? (object) + def self.is_a_association_proxy?(object) if Rails.version < "3.2" object.respond_to?(:proxy_reflection) else @@ -84,12 +84,12 @@ class Engine # If +reader+ is not given, a new one is created with the default # authorization configuration of +AUTH_DSL_FILES+. If given, may be either # a Reader object or a path to a configuration file. - def initialize (reader = nil) + def initialize(reader = nil) #@auth_rules = AuthorizationRuleSet.new reader.auth_rules_reader.auth_rules @reader = Reader::DSLReader.factory(reader || AUTH_DSL_FILES) end - def initialize_copy (from) # :nodoc: + def initialize_copy(from) # :nodoc: @reader = from.reader.clone end @@ -142,7 +142,7 @@ def rev_role_hierarchy # Should NotAuthorized exceptions be raised # Defaults to true. # - def permit! (privilege, options = {}) + def permit!(privilege, options = {}) return true if Authorization.ignore_access_control options = { :object => nil, @@ -202,7 +202,7 @@ def permit! (privilege, options = {}) # Calls permit! but doesn't raise authorization errors. If no exception is # raised, permit? returns true and yields to the optional block. - def permit? (privilege, options = {}) # :yields: + def permit?(privilege, options = {}) # :yields: if permit!(privilege, options.merge(:bang=> false)) yield if block_given? true @@ -227,7 +227,7 @@ def permit? (privilege, options = {}) # :yields: # [:+context+] See permit! # [:+user+] See permit! # - def obligations (privilege, options = {}) + def obligations(privilege, options = {}) options = {:context => nil}.merge(options) user, roles, privileges = user_roles_privleges_from_options(privilege, options) @@ -244,19 +244,19 @@ def obligations (privilege, options = {}) # Returns the description for the given role. The description may be # specified with the authorization rules. Returns +nil+ if none was # given. - def description_for (role) + def description_for(role) role_descriptions[role] end # Returns the title for the given role. The title may be # specified with the authorization rules. Returns +nil+ if none was # given. - def title_for (role) + def title_for(role) role_titles[role] end # Returns the role symbols of the given user. - def roles_for (user) + def roles_for(user) user ||= Authorization.current_user raise AuthorizationUsageError, "User object doesn't respond to roles (#{user.inspect})" \ if !user.respond_to?(:role_symbols) and !user.respond_to?(:roles) @@ -292,7 +292,7 @@ def self.development_reload? # Returns an instance of Engine, which is created if there isn't one # yet. If +dsl_file+ is given, it is passed on to Engine.new and # a new instance is always created. - def self.instance (dsl_file = nil) + def self.instance(dsl_file = nil) if dsl_file or development_reload? @@instance = new(dsl_file) else @@ -302,7 +302,7 @@ def self.instance (dsl_file = nil) class AttributeValidator # :nodoc: attr_reader :user, :object, :engine, :context, :privilege - def initialize (engine, user, object = nil, privilege = nil, context = nil) + def initialize(engine, user, object = nil, privilege = nil, context = nil) @engine = engine @user = user @object = object @@ -310,7 +310,7 @@ def initialize (engine, user, object = nil, privilege = nil, context = nil) @context = context end - def evaluate (value_block) + def evaluate(value_block) # TODO cache? instance_eval(&value_block) end @@ -334,7 +334,7 @@ def user_roles_privleges_from_options(privilege, options) [user, roles, privileges] end - def flatten_roles (roles, flattened_roles = Set.new) + def flatten_roles(roles, flattened_roles = Set.new) # TODO caching? roles.reject {|role| flattened_roles.include?(role)}.each do |role| flattened_roles << role @@ -344,7 +344,7 @@ def flatten_roles (roles, flattened_roles = Set.new) end # Returns the privilege hierarchy flattened for given privileges in context. - def flatten_privileges (privileges, context = nil, flattened_privileges = Set.new) + def flatten_privileges(privileges, context = nil, flattened_privileges = Set.new) # TODO caching? raise AuthorizationUsageError, "No context given or inferable from object" unless context privileges.reject {|priv| flattened_privileges.include?(priv)}.each do |priv| @@ -355,7 +355,7 @@ def flatten_privileges (privileges, context = nil, flattened_privileges = Set.ne flattened_privileges.to_a end - def matching_auth_rules (roles, privileges, context) + def matching_auth_rules(roles, privileges, context) auth_rules.matching(roles, privileges, context) end end @@ -366,12 +366,12 @@ class AuthorizationRuleSet extend Forwardable def_delegators :@rules, :each, :length, :[] - def initialize (rules = []) + def initialize(rules = []) @rules = rules.clone reset! end - def initialize_copy (source) + def initialize_copy(source) @rules = @rules.collect {|rule| rule.clone} reset! end @@ -383,15 +383,18 @@ def matching(roles, privileges, context) rule.matches? roles, privileges, context end end - def delete rule + + def delete(rule) @rules.delete rule reset! end - def << rule + + def <<(rule) @rules << rule reset! end - def each &block + + def each(&block) @rules.each &block end @@ -399,6 +402,7 @@ def each &block def reset! @cached_auth_rules =nil end + def cached_auth_rules return @cached_auth_rules if @cached_auth_rules @cached_auth_rules = {} @@ -411,11 +415,12 @@ def cached_auth_rules @cached_auth_rules end end + class AuthorizationRule attr_reader :attributes, :contexts, :role, :privileges, :join_operator, :source_file, :source_line - def initialize (role, privileges = [], contexts = nil, join_operator = :or, + def initialize(role, privileges = [], contexts = nil, join_operator = :or, options = {}) @role = role @privileges = Set.new(privileges) @@ -426,27 +431,27 @@ def initialize (role, privileges = [], contexts = nil, join_operator = :or, @source_line = options[:source_line] end - def initialize_copy (from) + def initialize_copy(from) @privileges = @privileges.clone @contexts = @contexts.clone @attributes = @attributes.collect {|attribute| attribute.clone } end - def append_privileges (privs) + def append_privileges(privs) @privileges.merge(privs) end - def append_attribute (attribute) + def append_attribute(attribute) @attributes << attribute end - def matches? (roles, privs, context = nil) + def matches?(roles, privs, context = nil) roles = [roles] unless roles.is_a?(Array) @contexts.include?(context) and roles.include?(@role) and not (@privileges & privs).empty? end - def validate? (attr_validator, skip_attribute = false) + def validate?(attr_validator, skip_attribute = false) skip_attribute or @attributes.empty? or @attributes.send(@join_operator == :and ? :all? : :any?) do |attr| begin @@ -457,7 +462,7 @@ def validate? (attr_validator, skip_attribute = false) end end - def obligations (attr_validator) + def obligations(attr_validator) exceptions = [] obligations = @attributes.collect do |attr| begin @@ -500,15 +505,15 @@ class Attribute # attr_conditions_hash of form # { :object_attribute => [operator, value_block], ... } # { :object_attribute => { :attr => ... } } - def initialize (conditions_hash) + def initialize(conditions_hash) @conditions_hash = conditions_hash end - def initialize_copy (from) + def initialize_copy(from) @conditions_hash = deep_hash_clone(@conditions_hash) end - def validate? (attr_validator, object = nil, hash = nil) + def validate?(attr_validator, object = nil, hash = nil) object ||= attr_validator.object return false unless object @@ -602,7 +607,7 @@ def validate? (attr_validator, object = nil, hash = nil) end # resolves all the values in condition_hash - def obligation (attr_validator, hash = nil) + def obligation(attr_validator, hash = nil) hash = (hash || @conditions_hash).clone hash.each do |attr, value| if value.is_a?(Hash) @@ -616,7 +621,7 @@ def obligation (attr_validator, hash = nil) hash end - def to_long_s (hash = nil) + def to_long_s(hash = nil) if hash hash.inject({}) do |memo, key_val| key, val = key_val @@ -632,7 +637,7 @@ def to_long_s (hash = nil) end protected - def object_attribute_value (object, attr) + def object_attribute_value(object, attr) begin object.send(attr) rescue ArgumentError, NoMethodError => e @@ -642,7 +647,7 @@ def object_attribute_value (object, attr) end end - def deep_hash_clone (hash) + def deep_hash_clone(hash) hash.inject({}) do |memo, (key, val)| memo[key] = case val when Hash @@ -662,17 +667,17 @@ def deep_hash_clone (hash) class AttributeWithPermission < Attribute # E.g. privilege :read, attr_or_hash either :attribute or # { :attribute => :deeper_attribute } - def initialize (privilege, attr_or_hash, context = nil) + def initialize(privilege, attr_or_hash, context = nil) @privilege = privilege @context = context @attr_hash = attr_or_hash end - def initialize_copy (from) + def initialize_copy(from) @attr_hash = deep_hash_clone(@attr_hash) if @attr_hash.is_a?(Hash) end - def validate? (attr_validator, object = nil, hash_or_attr = nil) + def validate?(attr_validator, object = nil, hash_or_attr = nil) object ||= attr_validator.object hash_or_attr ||= @attr_hash return false unless object @@ -711,7 +716,7 @@ def validate? (attr_validator, object = nil, hash_or_attr = nil) end # may return an array of obligations to be OR'ed - def obligation (attr_validator, hash_or_attr = nil, path = []) + def obligation(attr_validator, hash_or_attr = nil, path = []) hash_or_attr ||= @attr_hash case hash_or_attr when Symbol @@ -771,7 +776,7 @@ def to_long_s end private - def self.reflection_for_path (parent_model, path) + def self.reflection_for_path(parent_model, path) reflection = path.empty? ? parent_model : begin parent = reflection_for_path(parent_model, path[0..-2]) if !parent.respond_to?(:proxy_reflection) and parent.respond_to?(:klass) @@ -790,7 +795,7 @@ def self.reflection_for_path (parent_model, path) # Represents a pseudo-user to facilitate anonymous users in applications class AnonymousUser attr_reader :role_symbols - def initialize (roles = [Authorization.default_role]) + def initialize(roles = [Authorization.default_role]) @role_symbols = roles end end diff --git a/lib/declarative_authorization/development_support/analyzer.rb b/lib/declarative_authorization/development_support/analyzer.rb index a49f2c7a..d817f52a 100644 --- a/lib/declarative_authorization/development_support/analyzer.rb +++ b/lib/declarative_authorization/development_support/analyzer.rb @@ -21,7 +21,7 @@ module DevelopmentSupport # Merge-able Rules: respect if_permitted_to hash # class Analyzer < AbstractAnalyzer - def analyze (rules) + def analyze(rules) sexp_array = RubyParser.new.parse(rules) #sexp_array = ParseTree.translate(rules) @reports = [] @@ -48,11 +48,11 @@ def initialize(analyzer) def analyze mark(:policy, nil) if analyze_policy roles.select {|role| analyze_role(role) }. - each { |role| mark(:role, role) } + each { |role| mark(:role, role) } rules.select {|rule| analyze_rule(rule) }. - each { |rule| mark(:rule, rule) } + each { |rule| mark(:rule, rule) } privileges.select {|privilege| !!analyze_privilege(privilege) }. - each { |privilege| mark(:privilege, privilege) } + each { |privilege| mark(:privilege, privilege) } end protected @@ -70,21 +70,21 @@ def privileges # to be implemented by specific processor def analyze_policy; end - def analyze_role (a_role); end - def analyze_rule (a_rule); end - def analyze_privilege (a_privilege); end - def message (object); end + def analyze_role(a_role); end + def analyze_rule(a_rule); end + def analyze_privilege(a_privilege); end + def message(object); end private - def source_line (object) + def source_line(object) object.source_line if object.respond_to?(:source_line) end - def source_file (object) + def source_file(object) object.source_file if object.respond_to?(:source_file) end - def mark (type, object) + def mark(type, object) @analyzer.reports << Report.new(report_type, source_file(object), source_line(object), message(object)) end @@ -103,7 +103,7 @@ def analyze_policy small_roles.length > 1 and small_roles.length.to_f / roles.length.to_f > SMALL_ROLES_RATIO end - def message (object) + def message(object) "The ratio of small roles is quite high (> %.0f%%). Consider refactoring." % (SMALL_ROLES_RATIO * 100) end @@ -114,25 +114,25 @@ def small_roles end class InheritingPrivilegesAnalyzer < GeneralRulesAnalyzer - def analyze_rule (rule) + def analyze_rule(rule) rule.privileges.any? {|privilege| rule.privileges.intersects?(privilege.ancestors) } end - def message (object) + def message(object) "At least one privilege inherits from another in this rule." end end class ProposedPrivilegeHierarchyAnalyzer < GeneralRulesAnalyzer # TODO respect, consider contexts - def analyze_privilege (privilege) + def analyze_privilege(privilege) privileges.find do |other_privilege| other_privilege != privilege and other_privilege.rules.all? {|rule| rule.privileges.include?(privilege)} end end - def message (privilege) + def message(privilege) other_privilege = analyze_privilege(privilege) "Privilege #{other_privilege.to_sym} is always used together with #{privilege.to_sym}. " + "Consider to include #{other_privilege.to_sym} in #{privilege.to_sym}." @@ -148,7 +148,7 @@ def initialize(analyzer) @analyzer = analyzer end - def analyze (sexp_array) + def analyze(sexp_array) process(sexp_array) analyze_rules end @@ -157,19 +157,19 @@ def analyze_rules # to be implemented by specific processor end - def process_iter (exp) + def process_iter(exp) s(:iter, process(exp.shift), process(exp.shift), process(exp.shift)) end - def process_arglist (exp) + def process_arglist(exp) s(exp.collect {|inner_exp| process(inner_exp).shift}) end - def process_hash (exp) + def process_hash(exp) s(Hash[*exp.collect {|inner_exp| process(inner_exp).shift}]) end - def process_lit (exp) + def process_lit(exp) s(exp.shift) end end @@ -198,7 +198,7 @@ def analyze_rules end end - def process_call (exp) + def process_call(exp) klass = exp.shift name = exp.shift case name @@ -249,7 +249,7 @@ def process_call (exp) class Report attr_reader :type, :filename, :line, :message - def initialize (type, filename, line, msg) + def initialize(type, filename, line, msg) @type = type @filename = filename @line = line diff --git a/lib/declarative_authorization/development_support/change_analyzer.rb b/lib/declarative_authorization/development_support/change_analyzer.rb index 7647fd6d..ac8ee698 100644 --- a/lib/declarative_authorization/development_support/change_analyzer.rb +++ b/lib/declarative_authorization/development_support/change_analyzer.rb @@ -27,7 +27,7 @@ module DevelopmentSupport # class ChangeAnalyzer < AbstractAnalyzer - def find_approaches_for (change_action, type, options, &tests) + def find_approaches_for(change_action, type, options, &tests) raise ArgumentError, "Missing options" if !options[:on] or !options[:to] # * strategy for removing: [remove privilege, add privilege to different role] @@ -69,11 +69,11 @@ def find_approaches_for (change_action, type, options, &tests) class ApproachChecker attr_reader :failed_test_count, :users - def initialize (analyzer, tests) + def initialize(analyzer, tests) @analyzer, @tests = analyzer, tests end - def check (engine, users) + def check(engine, users) @current_engine = engine @failed_test_count = 0 @users = users @@ -82,30 +82,30 @@ def check (engine, users) @ok end - def assert (ok) + def assert(ok) @failed_test_count += 1 unless ok @ok &&= ok end - def permit? (*args) + def permit?(*args) @current_engine.permit?(*args) end end class Approach attr_reader :steps, :engine, :users - def initialize (engine, users, steps) + def initialize(engine, users, steps) @engine, @users, @steps = engine, users, steps end - def check (approach_checker) + def check(approach_checker) res = approach_checker.check(@engine, @users) @failed_test_count = approach_checker.failed_test_count #puts "CHECKING #{inspect} (#{res}, #{sort_value})" res end - def clone_for_step (*step_params) + def clone_for_step(*step_params) self.class.new(@engine.clone, @users.clone, @steps + [Step.new(step_params)]) end @@ -113,7 +113,7 @@ def changes @steps.select {|step| step.length > 1} end - def subset? (other_approach) + def subset?(other_approach) other_approach.changes.length >= changes.length && changes.all? {|step| other_approach.changes.any? {|step_2| step_2.eql?(step)} } end @@ -138,13 +138,13 @@ def inspect # "\n Users: #{@users.map(&:role_symbols).inspect}" end - def <=> (other) + def <=>(other) sort_value <=> other.sort_value end end class Step < Array - def eql? (other) + def eql?(other) # TODO use approach.users.index(self[idx]) == # other.approach.users.index(other[idx]) # instead of user.login @@ -161,7 +161,7 @@ def inspect end protected - def next_step (viable_approaches, candidates, approach_checker, + def next_step(viable_approaches, candidates, approach_checker, privilege, context, strategy) candidate = candidates.shift next_in_strategy = strategy[candidate.steps.length % strategy.length] @@ -242,7 +242,7 @@ def next_step (viable_approaches, candidates, approach_checker, candidates.sort! end - def relevant_roles (approach) + def relevant_roles(approach) #return AnalyzerEngine.roles(approach.engine) (AnalyzerEngine.relevant_roles(approach.engine, approach.users) + (approach.engine.roles.include?(:new_role_for_change_analyzer) ? diff --git a/lib/declarative_authorization/development_support/change_supporter.rb b/lib/declarative_authorization/development_support/change_supporter.rb index 8e476057..b8d406bc 100644 --- a/lib/declarative_authorization/development_support/change_supporter.rb +++ b/lib/declarative_authorization/development_support/change_supporter.rb @@ -45,7 +45,7 @@ class ChangeSupporter < AbstractAnalyzer # 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. - def find_approaches_for (options, &tests) + def find_approaches_for(options, &tests) @prohibited_actions = (options[:prohibited_actions] || []).to_set @approaches_by_actions = {} @@ -72,7 +72,7 @@ def find_approaches_for (options, &tests) # Returns an array of GroupedApproaches for the given array of approaches. # Only groups directly adjacent approaches - def group_approaches (approaches) + 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 @@ -84,7 +84,7 @@ def group_approaches (approaches) class GroupedApproach attr_accessor :approach, :similar_approaches - def initialize (approach) + def initialize(approach) @approach = approach @similar_approaches = [] end @@ -93,11 +93,11 @@ def initialize (approach) class ApproachChecker attr_reader :users, :failed_tests - def initialize (analyzer, tests) + def initialize(analyzer, tests) @analyzer, @tests = analyzer, tests end - def check (engine, users) + def check(engine, users) @current_engine = engine @failed_tests = [] @current_test_args = nil @@ -108,12 +108,12 @@ def check (engine, users) @ok end - def assert (ok) + def assert(ok) @failed_tests << Test.new(*([!@current_permit_result] + @current_test_args)) unless ok @ok &&= ok end - def permit? (*args) + def permit?(*args) @current_test_args = args @current_permit_result = @current_engine.permit?( *(args[0...-1] + [args.last.merge(:skip_attribute_test => true)])) @@ -122,7 +122,7 @@ def permit? (*args) class Test attr_reader :positive, :privilege, :context, :user - def initialize (positive, privilege, options = {}) + def initialize(positive, privilege, options = {}) @positive, @privilege = positive, privilege @context = options[:context] @user = options[:user] @@ -131,18 +131,18 @@ def initialize (positive, privilege, options = {}) class Approach attr_reader :steps, :engine, :users, :failed_tests - def initialize (engine, users, steps) + def initialize(engine, users, steps) @engine, @users, @steps = engine, users, steps end - def check (approach_checker) + def check(approach_checker) res = approach_checker.check(@engine, @users) @failed_tests = approach_checker.failed_tests #puts "CHECKING #{inspect} (#{res}, #{sort_value})" res end - def affected_users (original_engine, original_users, privilege, context) + def affected_users(original_engine, original_users, privilege, context) (0...@users.length).select do |i| original_engine.permit?(privilege, :context => context, :skip_attribute_test => true, :user => original_users[i]) != @@ -151,7 +151,7 @@ def affected_users (original_engine, original_users, privilege, context) end.collect {|i| original_users[i]} end - def initialize_copy (other) + def initialize_copy(other) @engine = @engine.clone @users = @users.clone @steps = @steps.clone @@ -177,17 +177,17 @@ def abstract_actions end end - def reverse_of_previous? (specific_action) + def reverse_of_previous?(specific_action) changes.any? {|step| step.reverse?(specific_action)} end - def apply (action) + def apply(action) ok = action.apply(self) @steps << action if ok ok end - def subset? (other_approach) + def subset?(other_approach) other_approach.changes.length >= changes.length && changes.all? {|step| other_approach.changes.any? {|step_2| step_2.eql?(step)} } end @@ -210,7 +210,7 @@ def weight changes.sum(&:weight) end - def similar_to (other) + def similar_to(other) other.weight == weight and other.changes.map {|change| change.class.name}.sort == changes.map {|change| change.class.name}.sort @@ -222,7 +222,7 @@ def inspect # "\n Users: #{@users.map(&:role_symbols).inspect}" end - def <=> (other) + def <=>(other) sort_value <=> other.sort_value end end @@ -233,16 +233,16 @@ def weight end # returns a list of instances of the action that may be applied - def self.specific_actions (candidate) + def self.specific_actions(candidate) raise NotImplementedError, "Not yet?" end # applies the specific action on the given candidate - def apply (candidate) + def apply(candidate) raise NotImplementedError, "Not yet?" end - def eql? (other) + def eql?(other) other.class == self.class and hash == other.hash end @@ -250,7 +250,7 @@ def hash @hash ||= to_a.hash end - def reverse? (other) + def reverse?(other) false end @@ -262,16 +262,16 @@ def to_a [:abstract] end - def resembles? (spec) + def resembles?(spec) min_length = [spec.length, to_a.length].min to_a[0,min_length] == spec[0,min_length] end - def resembles_any? (specs) + def resembles_any?(specs) specs.any? {|spec| resembles?(spec) } end - def self.readable_info (info) + def self.readable_info(info) if info.respond_to?(:to_sym) info.to_sym.inspect else @@ -285,11 +285,11 @@ def weight @actions.sum(&:weight) + 1 end - def apply (candidate) + def apply(candidate) @actions.all? {|action| action.apply(candidate)} end - def reverse? (other) + def reverse?(other) @actions.any? {|action| action.reverse?(other)} end @@ -301,7 +301,7 @@ def hash @hash ||= @actions.inject(0) {|memo, action| memo += action.hash } end - def resembles? (spec) + def resembles?(spec) @actions.any? {|action| action.resembles?(spec) } or to_a.any? do |array| min_length = [spec.length, array.length].min @@ -311,7 +311,7 @@ def resembles? (spec) end class AssignPrivilegeToRoleAction < AbstractAction - def self.specific_actions (candidate) + def self.specific_actions(candidate) privilege = AnalyzerEngine::Privilege.for_sym( candidate.failed_tests.first.privilege, candidate.engine) context = candidate.failed_tests.first.context @@ -326,15 +326,15 @@ def self.specific_actions (candidate) end attr_reader :privilege, :context, :role - def initialize (privilege_sym, context, role_sym) + def initialize(privilege_sym, context, role_sym) @privilege, @context, @role = privilege_sym, context, role_sym end - def apply (candidate) + def apply(candidate) AnalyzerEngine.apply_change(candidate.engine, to_a) end - def reverse? (other) + def reverse?(other) other.is_a?(RemovePrivilegeFromRoleAction) and other.privilege == @privilege and other.context == @context and @@ -347,7 +347,7 @@ def to_a end class AssignRoleToUserAction < AbstractAction - def self.specific_actions (candidate) + def self.specific_actions(candidate) privilege = candidate.failed_tests.first.privilege context = candidate.failed_tests.first.context user = candidate.failed_tests.first.user @@ -357,11 +357,11 @@ def self.specific_actions (candidate) end attr_reader :user, :role - def initialize (user, role_sym) + def initialize(user, role_sym) @user, @role = user, role_sym end - def apply (candidate) + def apply(candidate) if candidate.engine.roles_with_hierarchy_for(@user).include?(@role) false else @@ -381,13 +381,13 @@ def hash to_a[0,2].hash + @user.login.hash end - def reverse? (other) + def reverse?(other) other.is_a?(RemoveRoleFromUserAction) and other.user.login == @user.login and other.role == @role end - def resembles? (spec) + def resembles?(spec) super(spec[0,2]) and (spec.length == 2 or spec[2] == @user.login) end @@ -397,7 +397,7 @@ def to_a end class CreateAndAssignRoleToUserAction < AbstractCompoundAction - def self.specific_actions (candidate) + def self.specific_actions(candidate) privilege = AnalyzerEngine::Privilege.for_sym( candidate.failed_tests.first.privilege, candidate.engine) context = candidate.failed_tests.first.context @@ -409,12 +409,12 @@ def self.specific_actions (candidate) end attr_reader :user, :privilege, :context, :role - def initialize (user, privilege_sym, context_sym, role_sym) + def initialize(user, privilege_sym, context_sym, role_sym) @user, @privilege, @context, @role = user, privilege_sym, context_sym, role_sym @actions = [AddPrivilegeAndAssignRoleToUserAction.new(@user, @privilege, @context, role_sym)] end - def apply (candidate) + def apply(candidate) if AnalyzerEngine.apply_change(candidate.engine, [:add_role, @role]) super(candidate) else @@ -432,7 +432,7 @@ def to_a end class AddPrivilegeAndAssignRoleToUserAction < AbstractCompoundAction - def self.specific_actions (candidate) + def self.specific_actions(candidate) privilege = AnalyzerEngine::Privilege.for_sym( candidate.failed_tests.first.privilege, candidate.engine) context = candidate.failed_tests.first.context @@ -445,7 +445,7 @@ def self.specific_actions (candidate) end attr_reader :user, :privilege, :context, :role - def initialize (user, privilege_sym, context, role_sym) + def initialize(user, privilege_sym, context, role_sym) @user, @privilege, @context, @role = user, privilege_sym, context, role_sym @actions = [ AssignRoleToUserAction.new(@user, @role), @@ -455,7 +455,7 @@ def initialize (user, privilege_sym, context, role_sym) end class RemovePrivilegeFromRoleAction < AbstractAction - def self.specific_actions (candidate) + def self.specific_actions(candidate) privilege = AnalyzerEngine::Privilege.for_sym( candidate.failed_tests.first.privilege, candidate.engine) context = candidate.failed_tests.first.context @@ -469,15 +469,15 @@ def self.specific_actions (candidate) end attr_reader :privilege, :context, :role - def initialize (privilege_sym, context, role_sym) + def initialize(privilege_sym, context, role_sym) @privilege, @context, @role = privilege_sym, context, role_sym end - def apply (candidate) + def apply(candidate) AnalyzerEngine.apply_change(candidate.engine, to_a) end - def reverse? (other) + def reverse?(other) (other.is_a?(AssignPrivilegeToRoleAction) or other.is_a?(AbstractCompoundAction)) and other.reverse?(self) @@ -489,7 +489,7 @@ def to_a end class RemoveRoleFromUserAction < AbstractAction - def self.specific_actions (candidate) + def self.specific_actions(candidate) privilege = candidate.failed_tests.first.privilege context = candidate.failed_tests.first.context user = candidate.failed_tests.first.user @@ -502,11 +502,11 @@ def self.specific_actions (candidate) end attr_reader :user, :role - def initialize (user, role_sym) + def initialize(user, role_sym) @user, @role = user, role_sym end - def apply (candidate) + def apply(candidate) # beware of shallow copies! cloned_user = @user.clone user_index = candidate.users.index(@user) @@ -521,13 +521,13 @@ def hash to_a[0,2].hash + @user.login.hash end - def reverse? (other) + def reverse?(other) (other.is_a?(AssignRoleToUserAction) or other.is_a?(AbstractCompoundAction)) and other.reverse?(self) end - def resembles? (spec) + def resembles?(spec) super(spec[0,2]) and (spec.length == 2 or spec[2] == @user.login) end @@ -537,7 +537,7 @@ def to_a end protected - def next_step (viable_approaches, candidates, approach_checker) + def next_step(viable_approaches, candidates, approach_checker) candidate = candidates.shift child_candidates = generate_child_candidates(candidate) @@ -547,7 +547,7 @@ def next_step (viable_approaches, candidates, approach_checker) child_candidates.length end - def generate_child_candidates (candidate) + def generate_child_candidates(candidate) child_candidates = [] abstract_actions = candidate.abstract_actions abstract_actions.each do |abstract_action| @@ -563,7 +563,7 @@ def generate_child_candidates (candidate) child_candidates end - def check_child_candidates! (approach_checker, viable_approaches, candidates, child_candidates) + 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) @@ -578,13 +578,13 @@ def check_child_candidates! (approach_checker, viable_approaches, candidates, ch end end - def superset_of_existing? (candidate) + def superset_of_existing?(candidate) candidate.changes.any? do |action| (@approaches_by_actions[action] ||= []).any? {|approach| approach.subset?(candidate)} end end - def remove_supersets! (existing, candidate) + def remove_supersets!(existing, candidate) candidate.changes.inject([]) do |memo, action| memo += (@approaches_by_actions[action] ||= []).select do |approach| candidate.subset?(approach) @@ -595,22 +595,22 @@ def remove_supersets! (existing, candidate) end end - def add_to_approaches_by_action! (candidate) + def add_to_approaches_by_action!(candidate) candidate.changes.each do |action| (@approaches_by_actions[action] ||= []) << candidate end end - def remove_from_approaches_by_action! (candidate) + def remove_from_approaches_by_action!(candidate) candidate.changes.each do |action| (@approaches_by_actions[action] ||= []).delete(candidate) end end - def relevant_roles (approach) + def relevant_roles(approach) self.class.relevant_roles(approach) end - def self.relevant_roles (approach) + 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 diff --git a/lib/declarative_authorization/development_support/development_support.rb b/lib/declarative_authorization/development_support/development_support.rb index 37ddd098..97dd7611 100644 --- a/lib/declarative_authorization/development_support/development_support.rb +++ b/lib/declarative_authorization/development_support/development_support.rb @@ -4,7 +4,7 @@ module DevelopmentSupport class AbstractAnalyzer attr_reader :engine - def initialize (engine) + def initialize(engine) @engine = engine end @@ -21,23 +21,23 @@ def rules # model. module AnalyzerEngine - def self.roles (engine) + def self.roles(engine) Role.all(engine) end - def self.relevant_roles (engine, users) + def self.relevant_roles(engine, users) users.collect {|user| user.role_symbols.map {|role_sym| Role.for_sym(role_sym, engine)}}. flatten.uniq.collect {|role| [role] + role.ancestors}.flatten.uniq end - def self.rule_for_permission (engine, privilege, context, role) + def self.rule_for_permission(engine, privilege, context, role) AnalyzerEngine.roles(engine). find {|cloned_role| cloned_role.to_sym == role.to_sym}.rules.find do |rule| rule.contexts.include?(context) and rule.privileges.include?(privilege) end end - def self.apply_change (engine, change) + def self.apply_change(engine, change) case change[0] when :add_role role_symbol = change[1] @@ -78,7 +78,7 @@ def self.apply_change (engine, change) class Role @@role_objects = {} attr_reader :role - def initialize (role, rules, engine) + def initialize(role, rules, engine) @role = role @rules = rules @engine = engine @@ -92,13 +92,13 @@ def source_file end # ancestors' privileges are included in in the current role - def ancestors (role_symbol = nil) + def ancestors(role_symbol = nil) role_symbol ||= @role (@engine.role_hierarchy[role_symbol] || []). collect {|lower_role| ancestors(lower_role) }.flatten + (role_symbol == @role ? [] : [Role.for_sym(role_symbol, @engine)]) end - def descendants (role_symbol = nil) + def descendants(role_symbol = nil) role_symbol ||= @role (@engine.rev_role_hierarchy[role_symbol] || []). collect {|higher_role| descendants(higher_role) }.flatten + @@ -109,7 +109,7 @@ def rules @rules ||= @engine.auth_rules.select {|rule| rule.role == @role}. collect {|rule| Rule.new(rule, @engine)} end - def rules_for_permission (privilege, context) + def rules_for_permission(privilege, context) rules.select do |rule| rule.matches?([@role], [privilege.to_sym], context) end @@ -118,11 +118,11 @@ def rules_for_permission (privilege, context) def to_sym @role end - def self.for_sym (role_sym, engine) + def self.for_sym(role_sym, engine) @@role_objects[[role_sym, engine]] ||= new(role_sym, nil, engine) end - def self.all (engine) + def self.all(engine) rules_by_role = engine.auth_rules.inject({}) do |memo, rule| memo[rule.role] ||= [] memo[rule.role] << rule @@ -133,7 +133,7 @@ def self.all (engine) collect {|rule| Rule.new(rule, engine)}, engine) end end - def self.all_for_privilege (privilege, context, engine) + def self.all_for_privilege(privilege, context, engine) privilege = privilege.is_a?(Symbol) ? Privilege.for_sym(privilege, engine) : privilege privilege_symbols = ([privilege] + privilege.ancestors).map(&:to_sym) all(engine).select {|role| role.rules.any? {|rule| rule.matches?([role.to_sym], privilege_symbols, context)}}. @@ -145,35 +145,35 @@ class Rule @@rule_objects = {} delegate :source_line, :source_file, :contexts, :matches?, :to => :@rule attr_reader :rule - def initialize (rule, engine) + def initialize(rule, engine) @rule = rule @engine = engine end def privileges PrivilegesSet.new(self, @engine, @rule.privileges.collect {|privilege| Privilege.for_sym(privilege, @engine) }) end - def self.for_rule (rule, engine) + def self.for_rule(rule, engine) @@rule_objects[[rule, engine]] ||= new(rule, engine) end end class Privilege @@privilege_objects = {} - def initialize (privilege, engine) + def initialize(privilege, engine) @privilege = privilege @engine = engine end # Ancestor privileges are higher in the hierarchy. # Doesn't take context into account. - def ancestors (priv_symbol = nil) + def ancestors(priv_symbol = nil) priv_symbol ||= @privilege # context-specific? (@engine.rev_priv_hierarchy[[priv_symbol, nil]] || []). collect {|higher_priv| ancestors(higher_priv) }.flatten + (priv_symbol == @privilege ? [] : [Privilege.for_sym(priv_symbol, @engine)]) end - def descendants (priv_symbol = nil) + def descendants(priv_symbol = nil) priv_symbol ||= @privilege # context-specific? (@engine.privilege_hierarchy[priv_symbol] || []). @@ -194,7 +194,7 @@ def source_file def to_sym @privilege end - def self.for_sym (privilege_sym, engine) + def self.for_sym(privilege_sym, engine) @@privilege_objects[[privilege_sym, engine]] ||= new(privilege_sym, engine) end @@ -206,21 +206,21 @@ def find_rules_for_privilege end class PrivilegesSet < Set - def initialize (*args) + def initialize(*args) if args.length > 2 @rule = args.shift @engine = args.shift end super(*args) end - def include? (privilege) + def include?(privilege) if privilege.is_a?(Symbol) super(privilege_from_symbol(privilege)) else super end end - def delete (privilege) + def delete(privilege) @rule.rule.privileges.delete(privilege.to_sym) if privilege.is_a?(Symbol) super(privilege_from_symbol(privilege)) @@ -229,15 +229,15 @@ def delete (privilege) end end - def intersects? (privileges) + def intersects?(privileges) intersection(privileges).length > 0 end private - def privilege_from_symbol (privilege_sym) + def privilege_from_symbol(privilege_sym) Privilege.for_sym(privilege_sym, @engine) end end end end -end \ No newline at end of file +end diff --git a/lib/declarative_authorization/helper.rb b/lib/declarative_authorization/helper.rb index 00bb9472..d60a15f8 100644 --- a/lib/declarative_authorization/helper.rb +++ b/lib/declarative_authorization/helper.rb @@ -28,7 +28,7 @@ module AuthorizationHelper # options: # permitted_to? :update, user, :context => :account # - def permitted_to? (privilege, object_or_sym = nil, options = {}, &block) + def permitted_to?(privilege, object_or_sym = nil, options = {}, &block) controller.permitted_to?(privilege, object_or_sym, options, &block) end @@ -48,7 +48,7 @@ def permitted_to? (privilege, object_or_sym = nil, options = {}, &block) # ... # <% end %> # - def has_role? (*roles, &block) + def has_role?(*roles, &block) controller.has_role?(*roles, &block) end @@ -65,4 +65,4 @@ def has_any_role_with_hierarchy?(*roles, &block) controller.has_any_role_with_hierarchy?(*roles, &block) end end -end \ No newline at end of file +end diff --git a/lib/declarative_authorization/in_controller.rb b/lib/declarative_authorization/in_controller.rb index fae894df..0e38bfda 100644 --- a/lib/declarative_authorization/in_controller.rb +++ b/lib/declarative_authorization/in_controller.rb @@ -23,7 +23,7 @@ def self.included(base) # :nodoc: def self.failed_auto_loading_is_not_found? @@failed_auto_loading_is_not_found end - def self.failed_auto_loading_is_not_found= (new_value) + def self.failed_auto_loading_is_not_found=(new_value) @@failed_auto_loading_is_not_found = new_value end @@ -42,7 +42,7 @@ def authorization_engine # If no object or context is specified, the controller_name is used as # context. # - def permitted_to? (privilege, object_or_sym = nil, options = {}) + def permitted_to?(privilege, object_or_sym = nil, options = {}) if authorization_engine.permit!(privilege, options_for_permit(object_or_sym, options, false)) yield if block_given? true @@ -53,7 +53,7 @@ def permitted_to? (privilege, object_or_sym = nil, options = {}) # Works similar to the permitted_to? method, but # throws the authorization exceptions, just like Engine#permit! - def permitted_to! (privilege, object_or_sym = nil, options = {}) + def permitted_to!(privilege, object_or_sym = nil, options = {}) authorization_engine.permit!(privilege, options_for_permit(object_or_sym, options, true)) end @@ -61,7 +61,7 @@ def permitted_to! (privilege, object_or_sym = nil, options = {}) # content should only be shown to some users without being concerned # with authorization. E.g. to only show the most relevant menu options # to a certain group of users. That is what has_role? should be used for. - def has_role? (*roles, &block) + def has_role?(*roles, &block) user_roles = authorization_engine.roles_for(current_user) result = roles.all? do |role| user_roles.include?(role) @@ -137,19 +137,19 @@ def filter_access_filter # :nodoc: end end - def load_controller_object (context_without_namespace = nil, model = nil) # :nodoc: + def load_controller_object(context_without_namespace = nil, model = nil) # :nodoc: instance_var = :"@#{context_without_namespace.to_s.singularize}" model = model ? model.classify.constantize : context_without_namespace.to_s.classify.constantize instance_variable_set(instance_var, model.find(params[:id])) end - def load_parent_controller_object (parent_context_without_namespace) # :nodoc: + def load_parent_controller_object(parent_context_without_namespace) # :nodoc: instance_var = :"@#{parent_context_without_namespace.to_s.singularize}" model = parent_context_without_namespace.to_s.classify.constantize instance_variable_set(instance_var, model.find(params[:"#{parent_context_without_namespace.to_s.singularize}_id"])) end - def new_controller_object_from_params (context_without_namespace, parent_context_without_namespace, strong_params) # :nodoc: + def new_controller_object_from_params(context_without_namespace, parent_context_without_namespace, strong_params) # :nodoc: model_or_proxy = parent_context_without_namespace ? instance_variable_get(:"@#{parent_context_without_namespace.to_s.singularize}").send(context_without_namespace.to_sym) : context_without_namespace.to_s.classify.constantize @@ -158,7 +158,7 @@ def new_controller_object_from_params (context_without_namespace, parent_context model_or_proxy.new(params[context_without_namespace.to_s.singularize])) end - def new_blank_controller_object (context_without_namespace, parent_context_without_namespace, strong_params, model) # :nodoc: + def new_blank_controller_object(context_without_namespace, parent_context_without_namespace, strong_params, model) # :nodoc: if model model_or_proxy = model.to_s.classify.constantize else @@ -171,7 +171,7 @@ def new_blank_controller_object (context_without_namespace, parent_context_witho model_or_proxy.new()) end - def new_controller_object_for_collection (context_without_namespace, parent_context_without_namespace, strong_params) # :nodoc: + def new_controller_object_for_collection(context_without_namespace, parent_context_without_namespace, strong_params) # :nodoc: model_or_proxy = parent_context_without_namespace ? instance_variable_get(:"@#{parent_context_without_namespace.to_s.singularize}").send(context_without_namespace.to_sym) : context_without_namespace.to_s.classify.constantize @@ -179,7 +179,7 @@ def new_controller_object_for_collection (context_without_namespace, parent_cont instance_variable_set(instance_var, model_or_proxy.new) end - def options_for_permit (object_or_sym = nil, options = {}, bang = true) + def options_for_permit(object_or_sym = nil, options = {}, bang = true) context = object = nil if object_or_sym.nil? context = self.class.decl_auth_context @@ -296,7 +296,7 @@ module ClassMethods # :load_method => lambda { User.find(params[:id]) } # - def filter_access_to (*args, &filter_block) + def filter_access_to(*args, &filter_block) options = args.last.is_a?(Hash) ? args.pop : {} options = { :require => nil, @@ -611,7 +611,7 @@ def filter_access_permissions? # :nodoc: class_variable_defined?(:@@declarative_authorization_permissions) end - def actions_from_option (option) # :nodoc: + def actions_from_option(option) # :nodoc: case option when nil {} @@ -635,7 +635,7 @@ def actions_from_option (option) # :nodoc: class ControllerPermission # :nodoc: attr_reader :actions, :privilege, :context, :attribute_check, :strong_params - def initialize (actions, privilege, context, strong_params, attribute_check = false, + def initialize(actions, privilege, context, strong_params, attribute_check = false, load_object_model = nil, load_object_method = nil, filter_block = nil) @actions = actions.to_set @@ -648,11 +648,11 @@ def initialize (actions, privilege, context, strong_params, attribute_check = fa @strong_params = strong_params end - def matches? (action_name) + def matches?(action_name) @actions.include?(action_name.to_sym) end - def permit! (contr) + def permit!(contr) if @filter_block return contr.instance_eval(&@filter_block) end @@ -666,7 +666,7 @@ def permit! (contr) :context => @context || contr.class.decl_auth_context) end - def remove_actions (actions) + def remove_actions(actions) @actions -= actions self end diff --git a/lib/declarative_authorization/in_model.rb b/lib/declarative_authorization/in_model.rb index 11edee60..54303f8b 100644 --- a/lib/declarative_authorization/in_model.rb +++ b/lib/declarative_authorization/in_model.rb @@ -8,7 +8,7 @@ module AuthorizationInModel # If the user meets the given privilege, permitted_to? returns true # and yields to the optional block. - def permitted_to? (privilege, options = {}, &block) + def permitted_to?(privilege, options = {}, &block) options = { :user => Authorization.current_user, :object => self @@ -21,7 +21,7 @@ def permitted_to? (privilege, options = {}, &block) # Works similar to the permitted_to? method, but doesn't accept a block # and throws the authorization exceptions, just like Engine#permit! - def permitted_to! (privilege, options = {} ) + def permitted_to!(privilege, options = {} ) options = { :user => Authorization.current_user, :object => self @@ -97,7 +97,7 @@ def self.obligation_scope_for( privileges, options = {} ) # User to be used for gathering obligations; defaults to the # current user. # - def self.with_permissions_to (*args) + def self.with_permissions_to(*args) if Rails.version < "3.1" scopes[:with_permissions_to].call(self, *args) else @@ -146,7 +146,7 @@ def self.with_permissions_to (*args) # [:+context+] Specify context different from the models table name. # [:+include_read+] Also check for :+read+ privilege after find. # - def self.using_access_control (options = {}) + def self.using_access_control(options = {}) options = { :context => nil, :include_read => false diff --git a/lib/declarative_authorization/maintenance.rb b/lib/declarative_authorization/maintenance.rb index cc63b9d8..9787a82c 100644 --- a/lib/declarative_authorization/maintenance.rb +++ b/lib/declarative_authorization/maintenance.rb @@ -15,7 +15,7 @@ module Maintenance # without_access_control do # SomeModel.find(:first).save # end - def without_access_control (&block) + def without_access_control(&block) Authorization::Maintenance.without_access_control(&block) end @@ -36,11 +36,11 @@ def self.without_access_control # Sets the current user for the declarative authorization plugin to the # given one for the execution of the supplied block. Suitable for tests # on certain users. - def with_user (user, &block) + def with_user(user, &block) Authorization::Maintenance.with_user(user, &block) end - def self.with_user (user) + def self.with_user(user) prev_user = Authorization.current_user Authorization.current_user = user yield @@ -140,7 +140,7 @@ module TestHelper # Analogue to the Ruby's assert_raise method, only executing the block # in the context of the given user. - def assert_raise_with_user (user, *args, &block) + def assert_raise_with_user(user, *args, &block) assert_raise(*args) do with_user(user, &block) end @@ -158,7 +158,7 @@ def assert_raise_with_user (user, *args, &block) # # If you use specify the object and context manually, you can also specify the user manually, skipping the with_user block: # should_be_allowed_to :create, :object => car, :context => :vehicles, :user => a_normal_user - def should_be_allowed_to (privilege, *args) + def should_be_allowed_to(privilege, *args) options = {} if(args.first.class == Hash) options = args.extract_options! @@ -171,7 +171,7 @@ def should_be_allowed_to (privilege, *args) end # See should_be_allowed_to - def should_not_be_allowed_to (privilege, *args) + def should_not_be_allowed_to(privilege, *args) options = {} if(args.first.class == Hash) options = args.extract_options! @@ -181,7 +181,7 @@ def should_not_be_allowed_to (privilege, *args) assert !Authorization::Engine.instance.permit?(privilege, options) end - def request_with (user, method, xhr, action, params = {}, + def request_with(user, method, xhr, action, params = {}, session = {}, flash = {}) session = session.merge({:user => user, :user_id => user && user.id}) with_user(user) do @@ -193,14 +193,14 @@ def request_with (user, method, xhr, action, params = {}, end end - def self.included (base) + def self.included(base) [:get, :post, :put, :delete].each do |method| base.class_eval <<-EOV, __FILE__, __LINE__ - def #{method}_with (user, *args) + def #{method}_with(user, *args) request_with(user, #{method.inspect}, false, *args) end - def #{method}_by_xhr_with (user, *args) + def #{method}_by_xhr_with(user, *args) request_with(user, #{method.inspect}, true, *args) end EOV diff --git a/lib/declarative_authorization/obligation_scope.rb b/lib/declarative_authorization/obligation_scope.rb index 379c58b0..a4db8a78 100644 --- a/lib/declarative_authorization/obligation_scope.rb +++ b/lib/declarative_authorization/obligation_scope.rb @@ -43,7 +43,7 @@ module Authorization # @proxy_options[:conditions] = [ 'foos_bazzes.attr = :foos_bazzes__id_0', { :foos_bazzes__id_0 => 1 } ]+ # class ObligationScope < (Rails.version < "3" ? ActiveRecord::NamedScope::Scope : ActiveRecord::Relation) - def initialize (model, options) + def initialize(model, options) @finder_options = {} if Rails.version < "3" super(model, options) @@ -141,7 +141,7 @@ def add_obligation_join_for( path ) end # Returns the model associated with the given path. - def model_for (path) + def model_for(path) reflection = reflection_for(path) if Authorization.is_a_association_proxy?(reflection) @@ -294,7 +294,7 @@ def rebuild_condition_options! finder_options[:conditions] = [ conds.join( " OR " ), binds ] end - def attribute_value (value) + def attribute_value(value) value.class.respond_to?(:descends_from_active_record?) && value.class.descends_from_active_record? && value.id || value.is_a?(Array) && value[0].class.respond_to?(:descends_from_active_record?) && value[0].class.descends_from_active_record? && value.map( &:id ) || value @@ -335,7 +335,7 @@ def rebuild_join_options! end end - def path_to_join (path) + def path_to_join(path) case path.length when 0 then nil when 1 then path[0] @@ -348,7 +348,7 @@ def path_to_join (path) end end - def join_to_path (join) + def join_to_path(join) case join when Symbol [join] diff --git a/lib/declarative_authorization/reader.rb b/lib/declarative_authorization/reader.rb index cc04a303..5ca55a1e 100644 --- a/lib/declarative_authorization/reader.rb +++ b/lib/declarative_authorization/reader.rb @@ -54,12 +54,12 @@ class DSLSyntaxError < DSLError; end class DSLReader attr_reader :privileges_reader, :auth_rules_reader # :nodoc: - def initialize () + def initialize() @privileges_reader = PrivilegesReader.new @auth_rules_reader = AuthorizationRulesReader.new end - def initialize_copy (from) # :nodoc: + def initialize_copy(from) # :nodoc: @privileges_reader = from.privileges_reader.clone @auth_rules_reader = from.auth_rules_reader.clone end @@ -79,7 +79,7 @@ def self.factory(obj) # Parses a authorization DSL specification from the string given # in +dsl_data+. Raises DSLSyntaxError if errors occur on parsing. - def parse (dsl_data, file_name = nil) + def parse(dsl_data, file_name = nil) if file_name DSLMethods.new(self).instance_eval(dsl_data, file_name) else @@ -90,19 +90,19 @@ def parse (dsl_data, file_name = nil) end # Load and parse a DSL from the given file name. - def load (dsl_file) + def load(dsl_file) parse(File.read(dsl_file), dsl_file) if File.exist?(dsl_file) end # Load and parse a DSL from the given file name. Raises Authorization::Reader::DSLFileNotFoundError # if the file cannot be found. - def load! (dsl_file) + def load!(dsl_file) raise ::Authorization::Reader::DSLFileNotFoundError, "Error reading authorization rules file with path '#{dsl_file}'! Please ensure it exists and that it is accessible." unless File.exist?(dsl_file) load(dsl_file) end # Loads and parses DSL files and returns a new reader - def self.load (dsl_files) + def self.load(dsl_files) # TODO cache reader in production mode? reader = new dsl_files = [dsl_files].flatten @@ -114,19 +114,19 @@ def self.load (dsl_files) # DSL methods class DSLMethods # :nodoc: - def initialize (parent) + def initialize(parent) @parent = parent end - def privileges (&block) + def privileges(&block) @parent.privileges_reader.instance_eval(&block) end - def contexts (&block) + def contexts(&block) # Not implemented end - def authorization (&block) + def authorization(&block) @parent.auth_rules_reader.instance_eval(&block) end end @@ -146,12 +146,12 @@ def initialize # :nodoc: @privilege_hierarchy = {} end - def initialize_copy (from) # :nodoc: + def initialize_copy(from) # :nodoc: @privileges = from.privileges.clone @privilege_hierarchy = from.privilege_hierarchy.clone end - def append_privilege (priv) # :nodoc: + def append_privilege(priv) # :nodoc: @privileges << priv unless @privileges.include?(priv) end @@ -160,7 +160,7 @@ def append_privilege (priv) # :nodoc: # or as option :+includes+. If the optional context is given, # the privilege hierarchy is limited to that context. # - def privilege (privilege, context = nil, options = {}, &block) + def privilege(privilege, context = nil, options = {}, &block) if context.is_a?(Hash) options = context context = nil @@ -177,7 +177,7 @@ def privilege (privilege, context = nil, options = {}, &block) # Specifies +privileges+ that are to be assigned as lower ones. Only to # be used inside a privilege block. - def includes (*privileges) + def includes(*privileges) raise DSLError, "includes only in privilege block" if @current_priv.nil? privileges.each do |priv| append_privilege priv @@ -203,14 +203,14 @@ def initialize # :nodoc: @auth_rules = AuthorizationRuleSet.new end - def initialize_copy (from) # :nodoc: + def initialize_copy(from) # :nodoc: [:roles, :role_hierarchy, :auth_rules, :role_descriptions, :role_titles, :omnipotent_roles].each do |attribute| instance_variable_set(:"@#{attribute}", from.send(attribute).clone) end end - def append_role (role, options = {}) # :nodoc: + def append_role(role, options = {}) # :nodoc: @roles << role unless @roles.include? role @role_titles[role] = options[:title] if options[:title] @role_descriptions[role] = options[:description] if options[:description] @@ -222,7 +222,7 @@ def append_role (role, options = {}) # :nodoc: # has_permissions_on ... # end # - def role (role, options = {}, &block) + def role(role, options = {}, &block) append_role role, options @current_role = role yield @@ -240,7 +240,7 @@ def role (role, options = {}, &block) # has_permission_on :employees, :to => :read # end # - def includes (*roles) + def includes(*roles) raise DSLError, "includes only in role blocks" if @current_role.nil? @role_hierarchy[@current_role] ||= [] @role_hierarchy[@current_role] += roles.flatten @@ -274,7 +274,7 @@ def includes (*roles) # Join operator to logically connect the constraint statements inside # of the has_permission_on block. May be :+and+ or :+or+. Defaults to :+or+. # - def has_permission_on (*args, &block) + def has_permission_on(*args, &block) options = args.extract_options! context = args.flatten @@ -312,7 +312,7 @@ def has_omnipotence # description "To be assigned to administrative personnel" # has_permission_on ... # end - def description (text) + def description(text) raise DSLError, "description only allowed in role blocks" if @current_role.nil? role_descriptions[@current_role] = text end @@ -322,7 +322,7 @@ def description (text) # title "Administrator" # has_permission_on ... # end - def title (text) + def title(text) raise DSLError, "title only allowed in role blocks" if @current_role.nil? role_titles[@current_role] = text end @@ -335,7 +335,7 @@ def title (text) # to :create, :read, :update, :delete # end # end - def to (*privs) + def to(*privs) raise DSLError, "to only allowed in has_permission_on blocks" if @current_rule.nil? @current_rule.append_privileges(privs.flatten) end @@ -394,7 +394,7 @@ def to (*privs) # if_attribute :type => "special" # if_attribute :id => [1,2] # - def if_attribute (attr_conditions_hash) + def if_attribute(attr_conditions_hash) raise DSLError, "if_attribute only in has_permission blocks" if @current_rule.nil? parse_attribute_conditions_hash!(attr_conditions_hash) @current_rule.append_attribute Attribute.new(attr_conditions_hash) @@ -446,7 +446,7 @@ def if_attribute (attr_conditions_hash) # if_permitted_to :read, :home_branch, :context => :branches # if_permitted_to :read, :branch => :main_company, :context => :companies # - def if_permitted_to (privilege, attr_or_hash = nil, options = {}) + def if_permitted_to(privilege, attr_or_hash = nil, options = {}) raise DSLError, "if_permitted_to only in has_permission blocks" if @current_rule.nil? options[:context] ||= attr_or_hash.delete(:context) if attr_or_hash.is_a?(Hash) # only :context option in attr_or_hash: @@ -458,25 +458,25 @@ def if_permitted_to (privilege, attr_or_hash = nil, options = {}) # In an if_attribute statement, is says that the value has to be # met exactly by the if_attribute attribute. For information on the block # argument, see if_attribute. - def is (&block) + def is(&block) [:is, block] end # The negation of is. - def is_not (&block) + def is_not(&block) [:is_not, block] end # In an if_attribute statement, contains says that the value has to be # part of the collection specified by the if_attribute attribute. # For information on the block argument, see if_attribute. - def contains (&block) + def contains(&block) [:contains, block] end # The negation of contains. Currently, query rewriting is disabled # for does_not_contain. - def does_not_contain (&block) + def does_not_contain(&block) [:does_not_contain, block] end @@ -484,44 +484,44 @@ def does_not_contain (&block) # one of the values has to be part of the collection specified by the # if_attribute attribute. The value block needs to evaluate to an # Enumerable. For information on the block argument, see if_attribute. - def intersects_with (&block) + def intersects_with(&block) [:intersects_with, block] end # In an if_attribute statement, is_in says that the value has to # contain the attribute value. # For information on the block argument, see if_attribute. - def is_in (&block) + def is_in(&block) [:is_in, block] end # The negation of is_in. - def is_not_in (&block) + def is_not_in(&block) [:is_not_in, block] end # Less than - def lt (&block) + def lt(&block) [:lt, block] end # Less than or equal to - def lte (&block) + def lte(&block) [:lte, block] end # Greater than - def gt (&block) + def gt(&block) [:gt, block] end # Greater than or equal to - def gte (&block) + def gte(&block) [:gte, block] end private - def parse_attribute_conditions_hash! (hash) + def parse_attribute_conditions_hash!(hash) merge_hash = {} hash.each do |key, value| if value.is_a?(Hash) diff --git a/lib/generators/authorization/install/install_generator.rb b/lib/generators/authorization/install/install_generator.rb index f96eea9b..e4deadf2 100644 --- a/lib/generators/authorization/install/install_generator.rb +++ b/lib/generators/authorization/install/install_generator.rb @@ -11,7 +11,7 @@ class InstallGenerator < Rails::Generators::Base class_option :commit, type: :boolean, default: false, desc: "Performs rake tasks such as migrate and seed." class_option :user_belongs_to_role, type: :boolean, default: false, desc: "Users have only one role, which can inherit others roles." - def self.next_migration_number dirname + def self.next_migration_number(dirname) if ActiveRecord::Base.timestamped_migrations Time.now.utc.strftime("%Y%m%d%H%M%S") else @@ -74,4 +74,4 @@ def role_symbols puts "Please run `rake db:migrate` and `rake db:seed` to finish installing." unless options[:commit] end end -end \ No newline at end of file +end diff --git a/test/controller_filter_resource_access_test.rb b/test/controller_filter_resource_access_test.rb index f7becfa4..76d1d592 100644 --- a/test/controller_filter_resource_access_test.rb +++ b/test/controller_filter_resource_access_test.rb @@ -71,7 +71,7 @@ def test_basic_filter_new_with_params class NestedResource < MockDataObject - def initialize (attributes = {}) + def initialize(attributes = {}) if attributes[:id] attributes[:parent_mock] ||= ParentMock.new(:id => attributes[:id]) end @@ -83,7 +83,7 @@ def self.name end class ShallowNestedResource < MockDataObject - def initialize (attributes = {}) + def initialize(attributes = {}) if attributes[:id] attributes[:parent_mock] ||= ParentMock.new(:id => attributes[:id]) end @@ -97,10 +97,10 @@ def self.name class ParentMock < MockDataObject def nested_resources Class.new do - def initialize (parent_mock) + def initialize(parent_mock) @parent_mock = parent_mock end - def new (attributes = {}) + def new(attributes = {}) NestedResource.new(attributes.merge(:parent_mock => @parent_mock)) end end.new(self) @@ -108,7 +108,7 @@ def new (attributes = {}) alias :shallow_nested_resources :nested_resources - def == (other) + def ==(other) id == other.id end def self.name @@ -572,4 +572,4 @@ def test_new_strong_resource # assert assigns :strong_resource end end -end \ No newline at end of file +end diff --git a/test/development_support/analyzer_test.rb b/test/development_support/analyzer_test.rb index f2535af6..7c1aa190 100644 --- a/test/development_support/analyzer_test.rb +++ b/test/development_support/analyzer_test.rb @@ -266,7 +266,7 @@ def test_analyze_for_proposed_privilege_hierarchy end protected - def engine_analyzer_for (rules) + def engine_analyzer_for(rules) reader = Authorization::Reader::DSLReader.new reader.parse rules engine = Authorization::Engine.new(reader) diff --git a/test/model_test.rb b/test/model_test.rb index 2fc2b763..ffdd941d 100644 --- a/test/model_test.rb +++ b/test/model_test.rb @@ -99,7 +99,7 @@ class TestAttr < ActiveRecord::Base :test_model_id, :test_another_model_id end - def initialize (*args) + def initialize(*args) @role_symbols = [] super(*args) end diff --git a/test/test_helper.rb b/test/test_helper.rb index 2d0ffc1b..1fe63fdc 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -46,7 +46,7 @@ class MockDataObject - def initialize (attrs = {}) + def initialize(attrs = {}) attrs.each do |key, value| instance_variable_set(:"@#{key}", value) self.class.class_eval do @@ -79,12 +79,12 @@ def self.find_or_initialize_by(args) end class MockUser < MockDataObject - def initialize (*roles) + def initialize(*roles) options = roles.last.is_a?(::Hash) ? roles.pop : {} super({:role_symbols => roles, :login => hash}.merge(options)) end - def initialize_copy (other) + def initialize_copy(other) @role_symbols = @role_symbols.clone end end @@ -97,7 +97,7 @@ def authorized? !!@authorized end - def self.define_action_methods (*methods) + def self.define_action_methods(*methods) methods.each do |method| define_method method do @authorized = true @@ -110,7 +110,7 @@ def self.define_resource_actions define_action_methods :index, :show, :edit, :update, :new, :create, :destroy end - def logger (*args) + def logger(*args) Class.new do def warn(*args) #p args @@ -176,7 +176,7 @@ class Application < ::Rails::Application class Test::Unit::TestCase include Authorization::TestHelper - def request! (user, action, reader, params = {}) + def request!(user, action, reader, params = {}) action = action.to_sym if action.is_a?(String) @controller.current_user = user @controller.authorization_engine = Authorization::Engine.new(reader) @@ -203,7 +203,7 @@ class Test::Unit::TestCase class ActiveSupport::TestCase include Authorization::TestHelper - def request! (user, action, reader, params = {}) + def request!(user, action, reader, params = {}) action = action.to_sym if action.is_a?(String) @controller.current_user = user @controller.authorization_engine = Authorization::Engine.new(reader) @@ -234,7 +234,7 @@ class Test::Unit::TestCase < Minitest::Test class ActiveSupport::TestCase include Authorization::TestHelper - def request! (user, action, reader, params = {}) + def request!(user, action, reader, params = {}) action = action.to_sym if action.is_a?(String) @controller.current_user = user @controller.authorization_engine = Authorization::Engine.new(reader) From b29c1e21615fbd845b7b2a5b3d0bb628e3b5a894 Mon Sep 17 00:00:00 2001 From: Anna Date: Tue, 24 May 2016 20:05:18 -0400 Subject: [PATCH 02/55] Don't explicity support rails < 4.0. or ruby <2.0 Also, make depentencies clear in .gemspec --- .travis.yml | 14 +++----------- declarative_authorization.gemspec | 6 +++--- gemfiles/2.3.gemfile | 8 -------- gemfiles/3.0.gemfile | 8 -------- gemfiles/3.1.gemfile | 8 -------- gemfiles/3.2.gemfile | 1 - gemfiles/4.0.gemfile | 1 - gemfiles/4.1.gemfile | 3 +-- 8 files changed, 7 insertions(+), 42 deletions(-) delete mode 100644 gemfiles/2.3.gemfile delete mode 100644 gemfiles/3.0.gemfile delete mode 100644 gemfiles/3.1.gemfile diff --git a/.travis.yml b/.travis.yml index 2cd0bb7b..38e11e21 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,20 +1,12 @@ language: ruby script: bundle exec rake test rvm: - - 1.8.7 - - 1.9.3 + - 2.0.0 + - 2.1.9 gemfile: - - gemfiles/2.3.gemfile - - gemfiles/3.0.gemfile - - gemfiles/3.1.gemfile - - gemfiles/3.2.gemfile - gemfiles/4.0.gemfile - gemfiles/4.1.gemfile matrix: exclude: - - rvm: 1.8.7 - gemfile: gemfiles/4.0.gemfile - - rvm: 1.8.7 + - rvm: 2.0.0 gemfile: gemfiles/4.1.gemfile - - rvm: 1.9.3 - gemfile: gemfiles/2.3.gemfile diff --git a/declarative_authorization.gemspec b/declarative_authorization.gemspec index c36e1cb7..1071c15a 100644 --- a/declarative_authorization.gemspec +++ b/declarative_authorization.gemspec @@ -4,7 +4,7 @@ Gem::Specification.new do |s| s.name = "declarative_authorization" s.version = "1.0.0.pre" - s.required_ruby_version = ">= 1.8.6" + s.required_ruby_version = ">= 2.0.0" s.authors = ["Steffen Bartsch"] s.summary = "declarative_authorization is a Rails plugin for maintainable authorization based on readable authorization rules." s.email = "sbartsch@tzi.org" @@ -12,6 +12,6 @@ Gem::Specification.new do |s| s.has_rdoc = true s.extra_rdoc_files = ['README.rdoc', 'CHANGELOG'] s.homepage = %q{http://github.com/stffn/declarative_authorization} - - #s.add_dependency('rails', '>= 2.1.0') + s.add_dependency('ruby_parser', '~> 3.6.6') + s.add_dependency('rails', '>= 4.0.0', '< 4.2.0') end diff --git a/gemfiles/2.3.gemfile b/gemfiles/2.3.gemfile deleted file mode 100644 index fa5f3b14..00000000 --- a/gemfiles/2.3.gemfile +++ /dev/null @@ -1,8 +0,0 @@ -source 'https://rubygems.org' - -gem 'rails', '~> 2.3.0' -gem 'sqlite3' -gem 'ruby_parser' -gem 'rdoc' -gemspec :path => '..' - diff --git a/gemfiles/3.0.gemfile b/gemfiles/3.0.gemfile deleted file mode 100644 index d4349642..00000000 --- a/gemfiles/3.0.gemfile +++ /dev/null @@ -1,8 +0,0 @@ -source 'https://rubygems.org' - -gem 'rails', '~> 3.0.0' -gem 'sqlite3' -gem 'ruby_parser' -gem 'rdoc' -gemspec :path => '..' - diff --git a/gemfiles/3.1.gemfile b/gemfiles/3.1.gemfile deleted file mode 100644 index c9cddba2..00000000 --- a/gemfiles/3.1.gemfile +++ /dev/null @@ -1,8 +0,0 @@ -source 'https://rubygems.org' - -gem 'rails', '~> 3.1.0' -gem 'sqlite3' -gem 'ruby_parser' -gem 'rdoc' -gemspec :path => '..' - diff --git a/gemfiles/3.2.gemfile b/gemfiles/3.2.gemfile index cdff0429..939a6b89 100644 --- a/gemfiles/3.2.gemfile +++ b/gemfiles/3.2.gemfile @@ -2,7 +2,6 @@ source 'https://rubygems.org' gem 'rails', '~> 3.2.0' gem 'sqlite3' -gem 'ruby_parser' gem 'rdoc' gemspec :path => '..' diff --git a/gemfiles/4.0.gemfile b/gemfiles/4.0.gemfile index 2096153a..5de2126d 100644 --- a/gemfiles/4.0.gemfile +++ b/gemfiles/4.0.gemfile @@ -2,7 +2,6 @@ source 'https://rubygems.org' gem 'rails', '~> 4.0.0' gem 'sqlite3' -gem 'ruby_parser' gem 'rdoc' gemspec :path => '..' diff --git a/gemfiles/4.1.gemfile b/gemfiles/4.1.gemfile index a54f675c..85f32ba5 100644 --- a/gemfiles/4.1.gemfile +++ b/gemfiles/4.1.gemfile @@ -2,6 +2,5 @@ source 'https://rubygems.org' gem 'rails', '~> 4.1.0' gem 'sqlite3' -gem 'ruby_parser' gem 'rdoc' -gemspec :path => '..' \ No newline at end of file +gemspec :path => '..' From 5a36ddca9e1a55e1b983c7804f37919697d92163 Mon Sep 17 00:00:00 2001 From: Anna Date: Tue, 15 Mar 2016 15:09:21 -0400 Subject: [PATCH 03/55] Don't inspect user; too much sensitve data in log --- .../authorization.rb | 96 +++++++++---------- 1 file changed, 48 insertions(+), 48 deletions(-) diff --git a/lib/declarative_authorization/authorization.rb b/lib/declarative_authorization/authorization.rb index 82573edf..b6566e85 100644 --- a/lib/declarative_authorization/authorization.rb +++ b/lib/declarative_authorization/authorization.rb @@ -19,20 +19,20 @@ class AuthorizationUsageError < AuthorizationError ; end # NilAttributeValueError is raised by Attribute#validate? when it hits a nil attribute value. # The exception is raised to ensure that the entire rule is invalidated. class NilAttributeValueError < AuthorizationError; end - + AUTH_DSL_FILES = [Pathname.new(Rails.root || '').join("config", "authorization_rules.rb").to_s] unless defined? AUTH_DSL_FILES - + # Controller-independent method for retrieving the current user. # Needed for model security where the current controller is not available. def self.current_user Thread.current["current_user"] || AnonymousUser.new end - + # Controller-independent method for setting the current user. def self.current_user=(user) Thread.current["current_user"] = user end - + # For use in test cases only def self.ignore_access_control(state = nil) # :nodoc: Thread.current["ignore_access_control"] = state unless state.nil? @@ -51,7 +51,7 @@ def self.dot_path def self.dot_path=(path) @@dot_path = path end - + @@default_role = :guest def self.default_role @@default_role @@ -68,7 +68,7 @@ def self.is_a_association_proxy?(object) object.respond_to?(:proxy_association) end end - + # Authorization::Engine implements the reference monitor. It may be used # for querying the permission and retrieving obligations under which # a certain privilege is granted for the current user. @@ -80,7 +80,7 @@ class Engine def_delegators :@reader, :auth_rules_reader, :privileges_reader, :load, :load! def_delegators :auth_rules_reader, :auth_rules, :roles, :omnipotent_roles, :role_hierarchy, :role_titles, :role_descriptions def_delegators :privileges_reader, :privileges, :privilege_hierarchy - + # If +reader+ is not given, a new one is created with the default # authorization configuration of +AUTH_DSL_FILES+. If given, may be either # a Reader object or a path to a configuration file. @@ -98,7 +98,7 @@ def rev_priv_hierarchy if @rev_priv_hierarchy.nil? @rev_priv_hierarchy = {} privilege_hierarchy.each do |key, value| - value.each do |val| + value.each do |val| @rev_priv_hierarchy[val] ||= [] @rev_priv_hierarchy[val] << key end @@ -106,9 +106,9 @@ def rev_priv_hierarchy end @rev_priv_hierarchy end - + # {[priv, ctx] => [priv, ...]} - def rev_role_hierarchy + def rev_role_hierarchy if @rev_role_hierarchy.nil? @rev_role_hierarchy = {} role_hierarchy.each do |higher_role, lower_roles| @@ -119,23 +119,23 @@ def rev_role_hierarchy end @rev_role_hierarchy end - + # Returns true if privilege is met by the current user. Raises # AuthorizationError otherwise. +privilege+ may be given with or # without context. In the latter case, the :+context+ option is # required. - # + # # Options: # [:+context+] # The context part of the privilege. # Defaults either to the tableized +class_name+ of the given :+object+, if given. - # That is, :+users+ for :+object+ of type User. + # That is, :+users+ for :+object+ of type User. # Raises AuthorizationUsageError if context is missing and not to be inferred. # [:+object+] An context object to test attribute checks against. # [:+skip_attribute_test+] - # Skips those attribute checks in the + # Skips those attribute checks in the # authorization rules. Defaults to false. - # [:+user+] + # [:+user+] # The user to check the authorization for. # Defaults to Authorization#current_user. # [:+bang+] @@ -150,12 +150,12 @@ def permit!(privilege, options = {}) :context => nil, :bang => true }.merge(options) - + # Make sure we're handling all privileges as symbols. privilege = privilege.is_a?( Array ) ? privilege.flatten.collect { |priv| priv.to_sym } : privilege.to_sym - + # # If the object responds to :proxy_reflection, we're probably working with # an association proxy. Use 'new' to leverage ActiveRecord's builder @@ -166,22 +166,22 @@ def permit!(privilege, options = {}) if Authorization.is_a_association_proxy?(options[:object]) && options[:object].respond_to?(:new) options[:object] = (Rails.version < "3.0" ? options[:object] : options[:object].where(nil)).new end - + options[:context] ||= options[:object] && ( options[:object].class.respond_to?(:decl_auth_context) ? options[:object].class.decl_auth_context : options[:object].class.name.tableize.to_sym ) rescue NoMethodError - + user, roles, privileges = user_roles_privleges_from_options(privilege, options) return true if roles.is_a?(Array) and not (roles & omnipotent_roles).empty? - # find a authorization rule that matches for at least one of the roles and + # find a authorization rule that matches for at least one of the roles and # at least one of the given privileges attr_validator = AttributeValidator.new(self, user, options[:object], privilege, options[:context]) rules = matching_auth_rules(roles, privileges, options[:context]) - + # Test each rule in turn to see whether any one of them is satisfied. rules.each do |rule| return true if rule.validate?(attr_validator, options[:skip_attribute_test]) @@ -189,17 +189,17 @@ def permit!(privilege, options = {}) if options[:bang] if rules.empty? - raise NotAuthorized, "No matching rules found for #{privilege} for #{user.inspect} " + + raise NotAuthorized, "No matching rules found for #{privilege} for User with id #{user.try(:id)} " + "(roles #{roles.inspect}, privileges #{privileges.inspect}, " + "context #{options[:context].inspect})." else - raise AttributeAuthorizationError, "#{privilege} not allowed for #{user.inspect} on #{(options[:object] || options[:context]).inspect}." + raise AttributeAuthorizationError, "#{privilege} not allowed for User with id #{user.try(:id)} on #{(options[:object] || options[:context]).inspect}." end else false end end - + # Calls permit! but doesn't raise authorization errors. If no exception is # raised, permit? returns true and yields to the optional block. def permit?(privilege, options = {}) # :yields: @@ -210,19 +210,19 @@ def permit?(privilege, options = {}) # :yields: false end end - - # Returns the obligations to be met by the current user for the given - # privilege as an array of obligation hashes in form of + + # Returns the obligations to be met by the current user for the given + # privilege as an array of obligation hashes in form of # [{:object_attribute => obligation_value, ...}, ...] # where +obligation_value+ is either (recursively) another obligation hash # or a value spec, such as # [operator, literal_value] # The obligation hashes in the array should be OR'ed, conditions inside # the hashes AND'ed. - # + # # Example # {:branch => {:company => [:is, 24]}, :active => [:is, true]} - # + # # Options # [:+context+] See permit! # [:+user+] See permit! @@ -232,22 +232,22 @@ def obligations(privilege, options = {}) user, roles, privileges = user_roles_privleges_from_options(privilege, options) permit!(privilege, :skip_attribute_test => true, :user => user, :context => options[:context]) - + return [] if roles.is_a?(Array) and not (roles & omnipotent_roles).empty? - + attr_validator = AttributeValidator.new(self, user, nil, privilege, options[:context]) matching_auth_rules(roles, privileges, options[:context]).collect do |rule| rule.obligations(attr_validator) end.flatten end - + # Returns the description for the given role. The description may be # specified with the authorization rules. Returns +nil+ if none was # given. def description_for(role) role_descriptions[role] end - + # Returns the title for the given role. The title may be # specified with the authorization rules. Returns +nil+ if none was # given. @@ -258,7 +258,7 @@ def title_for(role) # Returns the role symbols of the given user. def roles_for(user) user ||= Authorization.current_user - raise AuthorizationUsageError, "User object doesn't respond to roles (#{user.inspect})" \ + raise AuthorizationUsageError, "User object doesn't respond to roles (#{user.try(:id)})" \ if !user.respond_to?(:role_symbols) and !user.respond_to?(:roles) Rails.logger.info("The use of user.roles is deprecated. Please add a method " + @@ -272,7 +272,7 @@ def roles_for(user) (roles.empty? ? [Authorization.default_role] : roles) end - + # Returns the role symbols and inherritted role symbols for the given user def roles_with_hierarchy_for(user) flatten_roles(roles_for(user)) @@ -290,7 +290,7 @@ def self.development_reload? end # Returns an instance of Engine, which is created if there isn't one - # yet. If +dsl_file+ is given, it is passed on to Engine.new and + # yet. If +dsl_file+ is given, it is passed on to Engine.new and # a new instance is always created. def self.instance(dsl_file = nil) if dsl_file or development_reload? @@ -299,7 +299,7 @@ def self.instance(dsl_file = nil) @@instance ||= new end end - + class AttributeValidator # :nodoc: attr_reader :user, :object, :engine, :context, :privilege def initialize(engine, user, object = nil, privilege = nil, context = nil) @@ -315,7 +315,7 @@ def evaluate(value_block) instance_eval(&value_block) end end - + private def user_roles_privleges_from_options(privilege, options) options = { @@ -325,15 +325,15 @@ def user_roles_privleges_from_options(privilege, options) }.merge(options) user = options[:user] || Authorization.current_user privileges = privilege.is_a?(Array) ? privilege : [privilege] - - raise AuthorizationUsageError, "No user object given (#{user.inspect}) or " + + + raise AuthorizationUsageError, "No user object given for user id (#{user.try(:id)}) or " + "set through Authorization.current_user" unless user roles = options[:user_roles] || flatten_roles(roles_for(user)) privileges = flatten_privileges privileges, options[:context] [user, roles, privileges] end - + def flatten_roles(roles, flattened_roles = Set.new) # TODO caching? roles.reject {|role| flattened_roles.include?(role)}.each do |role| @@ -342,7 +342,7 @@ def flatten_roles(roles, flattened_roles = Set.new) end flattened_roles.to_a end - + # Returns the privilege hierarchy flattened for given privileges in context. def flatten_privileges(privileges, context = nil, flattened_privileges = Set.new) # TODO caching? @@ -359,7 +359,7 @@ def matching_auth_rules(roles, privileges, context) auth_rules.matching(roles, privileges, context) end end - + class AuthorizationRuleSet include Enumerable @@ -447,7 +447,7 @@ def append_attribute(attribute) def matches?(roles, privs, context = nil) roles = [roles] unless roles.is_a?(Array) - @contexts.include?(context) and roles.include?(@role) and + @contexts.include?(context) and roles.include?(@role) and not (@privileges & privs).empty? end @@ -500,7 +500,7 @@ def to_long_s attributes.collect {|attr| attr.to_long_s } * "; " end end - + class Attribute # attr_conditions_hash of form # { :object_attribute => [operator, value_block], ... } @@ -605,7 +605,7 @@ def validate?(attr_validator, object = nil, hash = nil) end end end - + # resolves all the values in condition_hash def obligation(attr_validator, hash = nil) hash = (hash || @conditions_hash).clone @@ -731,7 +731,7 @@ def obligation(attr_validator, hash_or_attr = nil, path = []) rescue # missing model, reflections hash_or_attr.to_s.pluralize.to_sym end - + obligations = attr_validator.engine.obligations(@privilege, :context => @context, :user => attr_validator.user) @@ -791,7 +791,7 @@ def self.reflection_for_path(parent_model, path) reflection end end - + # Represents a pseudo-user to facilitate anonymous users in applications class AnonymousUser attr_reader :role_symbols From fd2c478873ebea7e511c3bb5dfc97aca0a87ae6b Mon Sep 17 00:00:00 2001 From: Anna Date: Wed, 25 May 2016 14:08:55 -0500 Subject: [PATCH 04/55] trim trailing whitespace --- .../authorization_rules_controller.rb | 16 +-- .../authorization_usages_controller.rb | 2 +- app/helpers/authorization_rules_helper.rb | 12 +- authorization_rules.dist.rb | 2 +- .../authorization.rb | 20 ++-- .../development_support/change_analyzer.rb | 2 +- .../development_support/change_supporter.rb | 2 +- lib/declarative_authorization/helper.rb | 20 ++-- .../in_controller.rb | 94 ++++++++-------- lib/declarative_authorization/in_model.rb | 22 ++-- lib/declarative_authorization/maintenance.rb | 22 ++-- .../obligation_scope.rb | 30 ++--- lib/declarative_authorization/reader.rb | 34 +++--- .../install/install_generator.rb | 2 +- .../authorization/rules/rules_generator.rb | 2 +- .../rules/templates/authorization_rules.rb | 2 +- test/authorization_test.rb | 106 +++++++++--------- test/controller_test.rb | 64 +++++------ .../change_analyzer_test.rb | 4 +- .../change_supporter_test.rb | 4 +- test/dsl_reader_test.rb | 30 ++--- test/helper_test.rb | 52 ++++----- test/model_test.rb | 44 ++++---- test/test_helper.rb | 24 ++-- 24 files changed, 306 insertions(+), 306 deletions(-) diff --git a/app/controllers/authorization_rules_controller.rb b/app/controllers/authorization_rules_controller.rb index d1076fba..d32f7d31 100644 --- a/app/controllers/authorization_rules_controller.rb +++ b/app/controllers/authorization_rules_controller.rb @@ -12,7 +12,7 @@ rescue LoadError; end class AuthorizationRulesController < ApplicationController - + filter_access_to :all, :require => :read def index respond_to do |format| @@ -32,7 +32,7 @@ def graph def change @users = find_all_users @users.sort! {|a, b| a.login <=> b.login } - + @privileges = authorization_engine.auth_rules.collect {|rule| rule.privileges.to_a}.flatten.uniq @privileges = @privileges.collect do |priv| priv = Authorization::DevelopmentSupport::AnalyzerEngine::Privilege.for_sym(priv, authorization_engine) @@ -67,7 +67,7 @@ def suggest_change end analyzer = Authorization::DevelopmentSupport::ChangeSupporter.new(authorization_engine) - + privilege = params[:privilege].to_sym context = params[:context].to_sym all_users = User.all @@ -145,7 +145,7 @@ def auth_to_dot(options = {}) @roles = @roles.select {|r| filter_roles_flattened.include?(r) } if options[:filter_roles] @role_hierarchy = engine.role_hierarchy @privilege_hierarchy = engine.privilege_hierarchy - + @contexts = engine.auth_rules. collect {|ar| ar.contexts.to_a}.flatten.uniq @contexts = @contexts.select {|c| c == options[:filter_contexts] } if options[:filter_contexts] @@ -183,7 +183,7 @@ def auth_to_dot(options = {}) @roles.all? {|role| !@role_privs[role] || !@role_privs[role].any? {|info| info[0] == context}} end end - + if options[:privilege_hierarchy] @context_privs.each do |context, privs| privs.each do |priv| @@ -194,7 +194,7 @@ def auth_to_dot(options = {}) end end end - + render_to_string :template => 'authorization_rules/graph.dot.erb', :layout => false end @@ -211,7 +211,7 @@ def replay_changes(engine, users, changes) memo end end - + def dot_to_svg(dot_data) gv = IO.popen("#{Authorization.dot_path} -q -Tsvg", "w+") gv.puts dot_data @@ -220,7 +220,7 @@ def dot_to_svg(dot_data) rescue IOError, Errno::EPIPE => e raise Exception, "Error in call to graphviz: #{e}" end - + def graph_options { :effective_role_privs => !params[:effective_role_privs].blank?, diff --git a/app/controllers/authorization_usages_controller.rb b/app/controllers/authorization_usages_controller.rb index effa802d..8e8f0355 100644 --- a/app/controllers/authorization_usages_controller.rb +++ b/app/controllers/authorization_usages_controller.rb @@ -3,7 +3,7 @@ require File.join(File.dirname(__FILE__), %w{.. .. lib declarative_authorization maintenance}) class AuthorizationUsagesController < ApplicationController - + helper :authorization_rules filter_access_to :all, :require => :read # TODO set context? diff --git a/app/helpers/authorization_rules_helper.rb b/app/helpers/authorization_rules_helper.rb index 1cb29e43..b7d895b3 100644 --- a/app/helpers/authorization_rules_helper.rb +++ b/app/helpers/authorization_rules_helper.rb @@ -1,7 +1,7 @@ module AuthorizationRulesHelper def syntax_highlight(rules) regexps = { - :constant => [/(:)(\w+)/], + :constant => [/(:)(\w+)/], :proc => ['role', 'authorization', 'privileges'], :statement => ['has_permission_on', 'if_attribute', 'if_permitted_to', 'includes', 'privilege', 'to'], :operator => ['is', 'contains', 'is_in', 'is_not', 'is_not_in', 'intersects'], @@ -15,7 +15,7 @@ def syntax_highlight(rules) res.each do |re| rules = rules.gsub( re.is_a?(String) ? Regexp.new("(^|[^:])\\b(#{Regexp.escape(re)})\\b") : - (re.is_a?(Symbol) ? Regexp.new("()(:#{Regexp.escape(re.to_s)})\\b") : re), + (re.is_a?(Symbol) ? Regexp.new("()(:#{Regexp.escape(re.to_s)})\\b") : re), "\\1\\2") end end @@ -52,7 +52,7 @@ def navigation # 'Edit | ' << # link_to("XACML export", :action => 'index', :format => 'xacml') end - + def role_color(role, fill = false) if @has_changes if has_changed(:add_role, role) @@ -73,7 +73,7 @@ def role_color(role, fill = false) @@role_colors[role][fill ? 1 : 0] end end - + def role_fill_color(role) role_color(role, true) end @@ -125,7 +125,7 @@ def describe_step(step, options = {}) "Don't suggest adding #{h human_privilege_context(step[1], step[2])}.", options) "Add privilege #{h human_privilege_context(step[1], step[2])}#{dont_assign} to role #{h human_role(step[3].to_sym)}" when :remove_privilege - dont_remove = prohibit_link(step[0,3], + dont_remove = prohibit_link(step[0,3], "Remove privilege #{h human_privilege_context(step[1], step[2])} from any role", "Don't suggest removing #{h human_privilege_context(step[1], step[2])}.", options) "Remove privilege #{h human_privilege_context(step[1], step[2])}#{dont_remove} from role #{h human_role(step[3].to_sym)}" @@ -153,7 +153,7 @@ def prohibit_link(step, text, title, options) :class => 'prohibit', :title => title) : '' end - + def readable_step_info(info) case info when Symbol then info.inspect diff --git a/authorization_rules.dist.rb b/authorization_rules.dist.rb index 78326f7e..93644a9e 100644 --- a/authorization_rules.dist.rb +++ b/authorization_rules.dist.rb @@ -3,7 +3,7 @@ # add permissions for guests here, e.g. #has_permission_on :conferences, :to => :read end - + # permissions on other roles, such as #role :admin do # has_permission_on :conferences, :to => :manage diff --git a/lib/declarative_authorization/authorization.rb b/lib/declarative_authorization/authorization.rb index b6566e85..20cbec47 100644 --- a/lib/declarative_authorization/authorization.rb +++ b/lib/declarative_authorization/authorization.rb @@ -226,7 +226,7 @@ def permit?(privilege, options = {}) # :yields: # Options # [:+context+] See permit! # [:+user+] See permit! - # + # def obligations(privilege, options = {}) options = {:context => nil}.merge(options) user, roles, privileges = user_roles_privleges_from_options(privilege, options) @@ -309,7 +309,7 @@ def initialize(engine, user, object = nil, privilege = nil, context = nil) @privilege = privilege @context = context end - + def evaluate(value_block) # TODO cache? instance_eval(&value_block) @@ -354,7 +354,7 @@ def flatten_privileges(privileges, context = nil, flattened_privileges = Set.new end flattened_privileges.to_a end - + def matching_auth_rules(roles, privileges, context) auth_rules.matching(roles, privileges, context) end @@ -419,7 +419,7 @@ def cached_auth_rules class AuthorizationRule attr_reader :attributes, :contexts, :role, :privileges, :join_operator, :source_file, :source_line - + def initialize(role, privileges = [], contexts = nil, join_operator = :or, options = {}) @role = role @@ -436,15 +436,15 @@ def initialize_copy(from) @contexts = @contexts.clone @attributes = @attributes.collect {|attribute| attribute.clone } end - + def append_privileges(privs) @privileges.merge(privs) end - + def append_attribute(attribute) @attributes << attribute end - + def matches?(roles, privs, context = nil) roles = [roles] unless roles.is_a?(Array) @contexts.include?(context) and roles.include?(@role) and @@ -512,11 +512,11 @@ def initialize(conditions_hash) def initialize_copy(from) @conditions_hash = deep_hash_clone(@conditions_hash) end - + def validate?(attr_validator, object = nil, hash = nil) object ||= attr_validator.object return false unless object - + if ( Authorization.is_a_association_proxy?(object) && object.respond_to?(:empty?) ) return false if object.empty? @@ -525,7 +525,7 @@ def validate?(attr_validator, object = nil, hash = nil) end return false end - + (hash || @conditions_hash).all? do |attr, value| attr_value = object_attribute_value(object, attr) if value.is_a?(Hash) diff --git a/lib/declarative_authorization/development_support/change_analyzer.rb b/lib/declarative_authorization/development_support/change_analyzer.rb index ac8ee698..980dadce 100644 --- a/lib/declarative_authorization/development_support/change_analyzer.rb +++ b/lib/declarative_authorization/development_support/change_analyzer.rb @@ -56,7 +56,7 @@ def find_approaches_for(change_action, type, options, &tests) step_count = 0 while !candidates.empty? and step_count < 100 - next_step(viable_approaches, candidates, approach_checker, options[:to], + next_step(viable_approaches, candidates, approach_checker, options[:to], options[:on], strategy) step_count += 1 end diff --git a/lib/declarative_authorization/development_support/change_supporter.rb b/lib/declarative_authorization/development_support/change_supporter.rb index b8d406bc..b2cc32dc 100644 --- a/lib/declarative_authorization/development_support/change_supporter.rb +++ b/lib/declarative_authorization/development_support/change_supporter.rb @@ -476,7 +476,7 @@ def initialize(privilege_sym, context, role_sym) def apply(candidate) AnalyzerEngine.apply_change(candidate.engine, to_a) end - + def reverse?(other) (other.is_a?(AssignPrivilegeToRoleAction) or other.is_a?(AbstractCompoundAction)) and diff --git a/lib/declarative_authorization/helper.rb b/lib/declarative_authorization/helper.rb index d60a15f8..71c8273a 100644 --- a/lib/declarative_authorization/helper.rb +++ b/lib/declarative_authorization/helper.rb @@ -3,12 +3,12 @@ module Authorization module AuthorizationHelper - + # If the current user meets the given privilege, permitted_to? returns true # and yields to the optional block. The attribute checks that are defined # in the authorization rules are only evaluated if an object is given # for context. - # + # # Examples: # <% permitted_to? :create, :users do %> # <%= link_to 'New', new_user_path %> @@ -27,16 +27,16 @@ module AuthorizationHelper # To pass in an object and override the context, you can use the optional # options: # permitted_to? :update, user, :context => :account - # + # def permitted_to?(privilege, object_or_sym = nil, options = {}, &block) controller.permitted_to?(privilege, object_or_sym, options, &block) end - + # While permitted_to? is used for authorization in views, in some cases # content should only be shown to some users without being concerned - # with authorization. E.g. to only show the most relevant menu options + # with authorization. E.g. to only show the most relevant menu options # to a certain group of users. That is what has_role? should be used for. - # + # # Examples: # <% has_role?(:sales) do %> # <%= link_to 'All contacts', contacts_path %> @@ -47,20 +47,20 @@ def permitted_to?(privilege, object_or_sym = nil, options = {}, &block) # <% else %> # ... # <% end %> - # + # def has_role?(*roles, &block) controller.has_role?(*roles, &block) end - + # As has_role? except checks all roles included in the role hierarchy def has_role_with_hierarchy?(*roles, &block) controller.has_role_with_hierarchy?(*roles, &block) end - + def has_any_role?(*roles,&block) controller.has_any_role?(*roles,&block) end - + def has_any_role_with_hierarchy?(*roles, &block) controller.has_any_role_with_hierarchy?(*roles, &block) end diff --git a/lib/declarative_authorization/in_controller.rb b/lib/declarative_authorization/in_controller.rb index 0e38bfda..db624601 100644 --- a/lib/declarative_authorization/in_controller.rb +++ b/lib/declarative_authorization/in_controller.rb @@ -3,15 +3,15 @@ module Authorization module AuthorizationInController - + def self.included(base) # :nodoc: base.extend(ClassMethods) base.hide_action :authorization_engine, :permitted_to?, :permitted_to! end - + DEFAULT_DENY = false - + # If attribute_check is set for filter_access_to, decl_auth_context will try to # load the appropriate object from the current controller's model with # the id from params[:id]. If that fails, a 404 Not Found is often the @@ -31,12 +31,12 @@ def self.failed_auto_loading_is_not_found=(new_value) def authorization_engine @authorization_engine ||= Authorization::Engine.instance end - + # If the current user meets the given privilege, permitted_to? returns true # and yields to the optional block. The attribute checks that are defined # in the authorization rules are only evaluated if an object is given # for context. - # + # # See examples for Authorization::AuthorizationHelper #permitted_to? # # If no object or context is specified, the controller_name is used as @@ -50,7 +50,7 @@ def permitted_to?(privilege, object_or_sym = nil, options = {}) false end end - + # Works similar to the permitted_to? method, but # throws the authorization exceptions, just like Engine#permit! def permitted_to!(privilege, object_or_sym = nil, options = {}) @@ -59,7 +59,7 @@ def permitted_to!(privilege, object_or_sym = nil, options = {}) # While permitted_to? is used for authorization, in some cases # content should only be shown to some users without being concerned - # with authorization. E.g. to only show the most relevant menu options + # with authorization. E.g. to only show the most relevant menu options # to a certain group of users. That is what has_role? should be used for. def has_role?(*roles, &block) user_roles = authorization_engine.roles_for(current_user) @@ -69,8 +69,8 @@ def has_role?(*roles, &block) yield if result and block_given? result end - - # Intended to be used where you want to allow users with any single listed role to view + + # Intended to be used where you want to allow users with any single listed role to view # the content in question def has_any_role?(*roles,&block) user_roles = authorization_engine.roles_for(current_user) @@ -80,7 +80,7 @@ def has_any_role?(*roles,&block) yield if result and block_given? result end - + # As has_role? except checks all roles included in the role hierarchy def has_role_with_hierarchy?(*roles, &block) user_roles = authorization_engine.roles_with_hierarchy_for(current_user) @@ -90,7 +90,7 @@ def has_role_with_hierarchy?(*roles, &block) yield if result and block_given? result end - + # As has_any_role? except checks all roles included in the role hierarchy def has_any_role_with_hierarchy?(*roles, &block) user_roles = authorization_engine.roles_with_hierarchy_for(current_user) @@ -100,7 +100,7 @@ def has_any_role_with_hierarchy?(*roles, &block) yield if result and block_given? result end - + protected def filter_access_filter # :nodoc: permissions = self.class.all_filter_access_permissions @@ -210,16 +210,16 @@ module ClassMethods # filter_access_to :all # ... # end - # + # # The default is to allow access unconditionally if no rule matches. # Thus, including the +filter_access_to+ :+all+ statement is a good # idea, implementing a default-deny policy. - # + # # When the access is denied, the method +permission_denied+ is called # on the current controller, if defined. Else, a simple "you are not # allowed" string is output. Log.info is given more information on the # reasons of denial. - # + # # def permission_denied # flash[:error] = 'Sorry, you are not allowed to the requested page.' # respond_to do |format| @@ -228,7 +228,7 @@ module ClassMethods # format.js { head :unauthorized } # end # end - # + # # By default, required privileges are inferred from the action name and # the controller name. Thus, in UserController :+edit+ requires # :+edit+ +users+. To specify required privilege, use the option :+require+ @@ -252,10 +252,10 @@ module ClassMethods # end # NOTE: +before_filters+ need to be defined before the first # +filter_access_to+ call. - # + # # For further customization, a custom filter expression may be formulated # in a block, which is then evaluated in the context of the controller - # on a matching request. That is, for checking two objects, use the + # on a matching request. That is, for checking two objects, use the # following: # filter_access_to :merge do # permitted_to!(:update, User.find(params[:original_id])) and @@ -263,14 +263,14 @@ module ClassMethods # end # The block should raise a Authorization::AuthorizationError or return # false if the access is to be denied. - # + # # Later calls to filter_access_to with overlapping actions overwrite # previous ones for that action. - # + # # All options: - # [:+require+] + # [:+require+] # Privilege required; defaults to action_name - # [:+context+] + # [:+context+] # The privilege's context, defaults to decl_auth_context, which consists # of controller_name, prepended by any namespaces # [:+attribute_check+] @@ -283,19 +283,19 @@ module ClassMethods # * a find on the context model, using +params+[:id] as id value. # Any of these methods will only be employed if :+attribute_check+ # is enabled. - # [:+model+] + # [:+model+] # The data model to load a context object from. Defaults to the # context, singularized. # [:+load_method+] - # Specify a method by symbol or a Proc object which should be used + # Specify a method by symbol or a Proc object which should be used # to load the object. Both should return the loaded object. # If a Proc object is given, e.g. by way of - # +lambda+, it is called in the instance of the controller. + # +lambda+, it is called in the instance of the controller. # Example demonstrating the default behavior: # filter_access_to :show, :attribute_check => true, # :load_method => lambda { User.find(params[:id]) } - # - + # + def filter_access_to(*args, &filter_block) options = args.last.is_a?(Hash) ? args.pop : {} options = { @@ -313,11 +313,11 @@ def filter_access_to(*args, &filter_block) # prevent setting filter_access_filter multiple times skip_before_filter :filter_access_filter before_filter :filter_access_filter - + filter_access_permissions.each do |perm| perm.remove_actions(actions) end - filter_access_permissions << + filter_access_permissions << ControllerPermission.new(actions, privilege, context, options[:strong_parameters], options[:attribute_check], @@ -325,15 +325,15 @@ def filter_access_to(*args, &filter_block) options[:load_method], filter_block) end - + # Collecting all the ControllerPermission objects from the controller - # hierarchy. Permissions for actions are overwritten by calls to + # hierarchy. Permissions for actions are overwritten by calls to # filter_access_to in child controllers with the same action. def all_filter_access_permissions # :nodoc: ancestors.inject([]) do |perms, mod| if mod.respond_to?(:filter_access_permissions, true) - perms + - mod.filter_access_permissions.collect do |p1| + perms + + mod.filter_access_permissions.collect do |p1| p1.clone.remove_actions(perms.inject(Set.new) {|actions, p2| actions + p2.actions}) end else @@ -393,12 +393,12 @@ def all_filter_access_permissions # :nodoc: # filter_resource_access :additional_member => { :toggle_open => :update } # Would add a member action :+toggle_open+ to the default members, such as :+show+. # - # If :+collection+ is an array of method names filter_resource_access will - # associate a permission with the method that is the same as the method - # name and no attribute checks will be performed unless + # If :+collection+ is an array of method names filter_resource_access will + # associate a permission with the method that is the same as the method + # name and no attribute checks will be performed unless # :attribute_check => true # is added in the options. - # + # # You can override the default object loading by implementing any of the # following instance methods on the controller. Examples are given for the # BranchController (with +nested_in+ set to :+companies+): @@ -409,7 +409,7 @@ def all_filter_access_permissions # :nodoc: # [+load_branch+] # Used for +member+ actions. # [+load_company+] - # Used for all +new+, +member+, and +collection+ actions if the + # Used for all +new+, +member+, and +collection+ actions if the # +nested_in+ option is set. # # All options: @@ -555,7 +555,7 @@ def filter_resource_access(options = {}) controller.send(:new_blank_controller_object, options[:context] || controller_name, options[:nested_in], options[:strong_parameters], options[:model]) end - end + end end load_method = :"load_#{controller_name.singularize}" @@ -595,7 +595,7 @@ def decl_auth_context prefixes = name.split('::')[0..-2].map(&:underscore) ((prefixes + [controller_name]) * '_').to_sym end - + protected def filter_access_permissions # :nodoc: unless filter_access_permissions? @@ -606,7 +606,7 @@ def filter_access_permissions # :nodoc: class_variable_set(:@@declarative_authorization_permissions, {}) unless filter_access_permissions? class_variable_get(:@@declarative_authorization_permissions)[self.name] ||= [] end - + def filter_access_permissions? # :nodoc: class_variable_defined?(:@@declarative_authorization_permissions) end @@ -632,7 +632,7 @@ def actions_from_option(option) # :nodoc: end end end - + class ControllerPermission # :nodoc: attr_reader :actions, :privilege, :context, :attribute_check, :strong_params def initialize(actions, privilege, context, strong_params, attribute_check = false, @@ -647,11 +647,11 @@ def initialize(actions, privilege, context, strong_params, attribute_check = fal @attribute_check = attribute_check @strong_params = strong_params end - + def matches?(action_name) @actions.include?(action_name.to_sym) end - + def permit!(contr) if @filter_block return contr.instance_eval(&@filter_block) @@ -659,18 +659,18 @@ def permit!(contr) object = @attribute_check ? load_object(contr) : nil privilege = @privilege || :"#{contr.action_name}" - contr.authorization_engine.permit!(privilege, + contr.authorization_engine.permit!(privilege, :user => contr.send(:current_user), :object => object, :skip_attribute_test => !@attribute_check, :context => @context || contr.class.decl_auth_context) end - + def remove_actions(actions) @actions -= actions self end - + private def load_object(contr) diff --git a/lib/declarative_authorization/in_model.rb b/lib/declarative_authorization/in_model.rb index 54303f8b..fdfeb105 100644 --- a/lib/declarative_authorization/in_model.rb +++ b/lib/declarative_authorization/in_model.rb @@ -3,7 +3,7 @@ require File.dirname(__FILE__) + '/obligation_scope.rb' module Authorization - + module AuthorizationInModel # If the user meets the given privilege, permitted_to? returns true @@ -30,7 +30,7 @@ def permitted_to!(privilege, options = {} ) {:user => options[:user], :object => options[:object]}) end - + def self.included(base) # :nodoc: #base.extend(ClassMethods) base.module_eval do @@ -60,7 +60,7 @@ def self.included(base) # :nodoc: :context => context, :engine => engine, :model => parent_scope) end end - + # Builds and returns a scope with joins and conditions satisfying all obligations. def self.obligation_scope_for( privileges, options = {} ) options = { @@ -81,14 +81,14 @@ def self.obligation_scope_for( privileges, options = {} ) # Named scope for limiting query results according to the authorization # of the current user. If no privilege is given, :+read+ is assumed. - # + # # User.with_permissions_to # User.with_permissions_to(:update) # User.with_permissions_to(:update, :context => :users) - # + # # As in the case of other named scopes, this one may be chained: # User.with_permission_to.find(:all, :conditions...) - # + # # Options # [:+context+] # Context for the privilege to be evaluated in; defaults to the @@ -124,24 +124,24 @@ def self.with_permissions_to(*args) :context => context, :engine => engine, :model => parent_scope.klass) end end - + # Activates model security for the current model. Then, CRUD operations # are checked against the authorization of the current user. The # privileges are :+create+, :+read+, :+update+ and :+delete+ in the # context of the model. By default, :+read+ is not checked because of # performance impacts, especially with large result sets. - # + # # class User < ActiveRecord::Base # using_access_control # end - # + # # If an operation is not permitted, a Authorization::AuthorizationError # is raised. # # To activate model security on all models, call using_access_control # on ActiveRecord::Base # ActiveRecord::Base.using_access_control - # + # # Available options # [:+context+] Specify context different from the models table name. # [:+include_read+] Also check for :+read+ privilege after find. @@ -159,7 +159,7 @@ def self.using_access_control(options = {}) :object => object, :context => options[:context]) end end - + if options[:include_read] # after_find is only called if after_find is implemented after_find do |object| diff --git a/lib/declarative_authorization/maintenance.rb b/lib/declarative_authorization/maintenance.rb index 9787a82c..6cbed5e5 100644 --- a/lib/declarative_authorization/maintenance.rb +++ b/lib/declarative_authorization/maintenance.rb @@ -7,7 +7,7 @@ module Authorization module Maintenance # Disables access control for the given block. Appropriate for # maintenance operation at the Rails console or in test case setup. - # + # # For use in the Rails console: # require "vendor/plugins/declarative_authorization/lib/maintenance" # include Authorization::Maintenance @@ -102,27 +102,27 @@ def self.usages_by_controller end end end - + # TestHelper provides assert methods and controller request methods which # take authorization into account and set the current user to a specific # one. # - # Defines get_with, post_with, get_by_xhr_with etc. for methods + # Defines get_with, post_with, get_by_xhr_with etc. for methods # get, post, put, delete each with the signature # get_with(user, action, params = {}, session = {}, flash = {}) # # Use it by including it in your TestHelper: - # require File.expand_path(File.dirname(__FILE__) + + # require File.expand_path(File.dirname(__FILE__) + # "/../vendor/plugins/declarative_authorization/lib/maintenance") - # class Test::Unit::TestCase + # class Test::Unit::TestCase # include Authorization::TestHelper # ... - # + # # def admin # # create admin user # end # end - # + # # class SomeControllerTest < ActionController::TestCase # def test_should_get_index # ... @@ -137,7 +137,7 @@ def self.usages_by_controller # way, these methods might not work for you. module TestHelper include Authorization::Maintenance - + # Analogue to the Ruby's assert_raise method, only executing the block # in the context of the given user. def assert_raise_with_user(user, *args, &block) @@ -180,8 +180,8 @@ def should_not_be_allowed_to(privilege, *args) end assert !Authorization::Engine.instance.permit?(privilege, options) end - - def request_with(user, method, xhr, action, params = {}, + + def request_with(user, method, xhr, action, params = {}, session = {}, flash = {}) session = session.merge({:user => user, :user_id => user && user.id}) with_user(user) do @@ -192,7 +192,7 @@ def request_with(user, method, xhr, action, params = {}, end end end - + def self.included(base) [:get, :post, :put, :delete].each do |method| base.class_eval <<-EOV, __FILE__, __LINE__ diff --git a/lib/declarative_authorization/obligation_scope.rb b/lib/declarative_authorization/obligation_scope.rb index a4db8a78..cac38f27 100644 --- a/lib/declarative_authorization/obligation_scope.rb +++ b/lib/declarative_authorization/obligation_scope.rb @@ -74,9 +74,9 @@ def parse!( obligation ) rebuild_condition_options! rebuild_join_options! end - + protected - + # Parses the next step in the association path. If it's an association, we advance down the # path. Otherwise, it's an attribute, and we need to evaluate it as a comparison operation. def follow_path( steps, past_steps = [] ) @@ -112,7 +112,7 @@ def top_level_model def finder_options Rails.version < "3" ? @proxy_options : @finder_options end - + # At the end of every association path, we expect to see a comparison of some kind; for # example, +:attr => [ :is, :value ]+. # @@ -124,7 +124,7 @@ def follow_comparison( steps, past_steps, attribute ) add_obligation_condition_for( past_steps, [attribute, operator, value] ) end - + # Adds the given expression to the current obligation's indicated path's conditions. # # Condition expressions must follow the format +[ , , ]+. @@ -134,12 +134,12 @@ def add_obligation_condition_for( path, expression ) obligation_conditions[@current_obligation] ||= {} ( obligation_conditions[@current_obligation][path] ||= Set.new ) << expression end - + # Adds the given path to the list of obligation joins, if we haven't seen it before. def add_obligation_join_for( path ) map_reflection_for( path ) if reflections[path].nil? end - + # Returns the model associated with the given path. def model_for(path) reflection = reflection_for(path) @@ -156,13 +156,13 @@ def model_for(path) reflection end end - + # Returns the reflection corresponding to the given path. def reflection_for(path, for_join_table_only = false) @join_table_joins << path if for_join_table_only and !reflections[path] reflections[path] ||= map_reflection_for( path ) end - + # Returns a proper table alias for the given path. This alias may be used in SQL statements. def table_alias_for( path ) table_aliases[path] ||= map_table_alias_for( path ) @@ -193,27 +193,27 @@ def map_reflection_for( path ) join_table_path = path[0..-2] + [reflection.options[:through]] reflection_for(join_table_path, true) end - + reflection end # Attempts to map a table alias for the given path. Raises if already defined. def map_table_alias_for( path ) return "table alias for #{path.inspect} already exists" unless table_aliases[path].nil? - + reflection = reflection_for( path ) table_alias = reflection.table_name if table_aliases.values.include?( table_alias ) max_length = reflection.active_record.connection.table_alias_length # Rails seems to pluralize reflection names table_alias = "#{reflection.name.to_s.pluralize}_#{reflection.active_record.table_name}".to(max_length-1) - end + end while table_aliases.values.include?( table_alias ) if table_alias =~ /\w(_\d+?)$/ table_index = $1.succ table_alias = "#{table_alias[0..-(table_index.length+1)]}_#{table_index}" else - table_alias = "#{table_alias[0..(max_length-3)]}_2" + table_alias = "#{table_alias[0..(max_length-3)]}_2" end end table_aliases[path] = table_alias @@ -229,12 +229,12 @@ def reflections # lets try to get the order of joins right @reflections ||= ActiveSupport::OrderedHash.new end - + # Returns a hash mapping paths to proper table aliases to use in SQL statements. def table_aliases @table_aliases ||= {} end - + # Parses all of the defined obligation conditions and defines the scope's :conditions option. def rebuild_condition_options! conds = [] @@ -299,7 +299,7 @@ def attribute_value(value) value.is_a?(Array) && value[0].class.respond_to?(:descends_from_active_record?) && value[0].class.descends_from_active_record? && value.map( &:id ) || value end - + # Parses all of the defined obligation joins and defines the scope's :joins or :includes option. # TODO: Support non-linear association paths. Right now, we just break down the longest path parsed. def rebuild_join_options! diff --git a/lib/declarative_authorization/reader.rb b/lib/declarative_authorization/reader.rb index 5ca55a1e..98f5ed1c 100644 --- a/lib/declarative_authorization/reader.rb +++ b/lib/declarative_authorization/reader.rb @@ -5,8 +5,8 @@ module Authorization # Parses an authorization configuration file in the authorization DSL and # constructs a data model of its contents. - # - # For examples and the modeled data model, see the + # + # For examples and the modeled data model, see the # README[link:files/README_rdoc.html]. # # Also, see role definition methods @@ -45,7 +45,7 @@ class DSLFileNotFoundError < Exception; end class DSLError < Exception; end # Signals errors in the syntax of an authorization DSL. class DSLSyntaxError < DSLError; end - + # Top-level reader, parses the methods +privileges+ and +authorization+. # +authorization+ takes a block with authorization rules as described in # AuthorizationRulesReader. The block to +privileges+ defines privilege @@ -245,7 +245,7 @@ def includes(*roles) @role_hierarchy[@current_role] ||= [] @role_hierarchy[@current_role] += roles.flatten end - + # Allows the definition of privileges to be allowed for the current role, # either in a has_permission_on block or directly in one call. # role :admin @@ -265,7 +265,7 @@ def includes(*roles) # statements in one block are OR'ed if no :+join_by+ option is given # (see below). To AND conditions, either set :+join_by+ to :and or place # them in one if_attribute statement. - # + # # Available options # [:+to+] # A symbol or an array of symbols representing the privileges that @@ -277,11 +277,11 @@ def includes(*roles) def has_permission_on(*args, &block) options = args.extract_options! context = args.flatten - + raise DSLError, "has_permission_on only allowed in role blocks" if @current_role.nil? options = {:to => [], :join_by => :or}.merge(options) - - privs = options[:to] + + privs = options[:to] privs = [privs] unless privs.is_a?(Array) raise DSLError, "has_permission_on either needs a block or :to option" if !block_given? and privs.empty? @@ -316,7 +316,7 @@ def description(text) raise DSLError, "description only allowed in role blocks" if @current_role.nil? role_descriptions[@current_role] = text end - + # Sets a human-readable title for the current role. E.g. # role :admin # title "Administrator" @@ -326,7 +326,7 @@ def title(text) raise DSLError, "title only allowed in role blocks" if @current_role.nil? role_titles[@current_role] = text end - + # Used in a has_permission_on block, to may be used to specify privileges # to be assigned to the current role under the conditions specified in # the current block. @@ -343,7 +343,7 @@ def to(*privs) # In a has_permission_on block, if_attribute specifies conditions # of dynamic parameters that have to be met for the user to meet the # privileges in this block. Conditions are evaluated on the context - # object. Thus, the following allows CRUD for branch admins only on + # object. Thus, the following allows CRUD for branch admins only on # employees that belong to the same branch as the current user. # role :branch_admin # has_permission_on :employees do @@ -355,7 +355,7 @@ def to(*privs) # operator is contains for collections. In the block supplied to the # operator, +user+ specifies the current user for whom the condition # is evaluated. - # + # # Conditions may be nested: # role :company_admin # has_permission_on :employees do @@ -375,7 +375,7 @@ def to(*privs) # object.company.branches.any? { |branch| branch.manager ... } # will be executed. with_permission_to scopes construct efficient SQL # joins, though. - # + # # Multiple attributes in one :if_attribute statement are AND'ed. # Multiple if_attribute statements are OR'ed if the join operator for the # has_permission_on block isn't explicitly set. Thus, the following would @@ -454,7 +454,7 @@ def if_permitted_to(privilege, attr_or_hash = nil, options = {}) @current_rule.append_attribute AttributeWithPermission.new(privilege, attr_or_hash, options[:context]) end - + # In an if_attribute statement, is says that the value has to be # met exactly by the if_attribute attribute. For information on the block # argument, see if_attribute. @@ -487,7 +487,7 @@ def does_not_contain(&block) def intersects_with(&block) [:intersects_with, block] end - + # In an if_attribute statement, is_in says that the value has to # contain the attribute value. # For information on the block argument, see if_attribute. @@ -499,7 +499,7 @@ def is_in(&block) def is_not_in(&block) [:is_not_in, block] end - + # Less than def lt(&block) [:lt, block] @@ -534,7 +534,7 @@ def parse_attribute_conditions_hash!(hash) end hash.merge!(merge_hash) end - + def file_and_line_number_from_call_stack caller_parts = caller(2).first.split(':') [caller_parts[0] == "(eval)" ? nil : caller_parts[0], diff --git a/lib/generators/authorization/install/install_generator.rb b/lib/generators/authorization/install/install_generator.rb index e4deadf2..669da185 100644 --- a/lib/generators/authorization/install/install_generator.rb +++ b/lib/generators/authorization/install/install_generator.rb @@ -1,7 +1,7 @@ require 'rails/generators' module Authorization class InstallGenerator < Rails::Generators::Base - + include Rails::Generators::Migration source_root File.expand_path('../templates', __FILE__) diff --git a/lib/generators/authorization/rules/rules_generator.rb b/lib/generators/authorization/rules/rules_generator.rb index db090955..dd675c5d 100644 --- a/lib/generators/authorization/rules/rules_generator.rb +++ b/lib/generators/authorization/rules/rules_generator.rb @@ -5,7 +5,7 @@ class RulesGenerator < Rails::Generators::Base source_root File.expand_path('../templates', __FILE__) def copy_auth_rules - + puts "WARNING - Copying authorization_rules template. Make sure to back up any existing rules before overwriting." copy_file "authorization_rules.rb", "config/authorization_rules.rb" diff --git a/lib/generators/authorization/rules/templates/authorization_rules.rb b/lib/generators/authorization/rules/templates/authorization_rules.rb index bdaa9c71..81b63cd8 100644 --- a/lib/generators/authorization/rules/templates/authorization_rules.rb +++ b/lib/generators/authorization/rules/templates/authorization_rules.rb @@ -3,7 +3,7 @@ # add permissions for guests here, e.g. # has_permission_on :conferences, :to => :read end - + # permissions on other roles, such as # role :admin do # has_permission_on :conferences, :to => :manage diff --git a/test/authorization_test.rb b/test/authorization_test.rb index ea466fda..601f4b70 100644 --- a/test/authorization_test.rb +++ b/test/authorization_test.rb @@ -1,7 +1,7 @@ require 'test_helper' class AuthorizationTest < Test::Unit::TestCase - + def test_permit reader = Authorization::Reader::DSLReader.new reader.parse %{ @@ -12,14 +12,14 @@ def test_permit end } engine = Authorization::Engine.new(reader) - assert engine.permit?(:test, :context => :permissions, + assert engine.permit?(:test, :context => :permissions, :user => MockUser.new(:test_role, :test_role_2)) - assert !engine.permit?(:test_2, :context => :permissions_2, + assert !engine.permit?(:test_2, :context => :permissions_2, :user => MockUser.new(:test_role)) - assert !engine.permit?(:test, :context => :permissions, + assert !engine.permit?(:test, :context => :permissions, :user => MockUser.new(:test_role_2)) end - + def test_permit_context_people reader = Authorization::Reader::DSLReader.new reader.parse %{ @@ -30,7 +30,7 @@ def test_permit_context_people end } engine = Authorization::Engine.new(reader) - assert engine.permit?(:test, :context => :people, + assert engine.permit?(:test, :context => :people, :user => MockUser.new(:test_role)) end @@ -59,13 +59,13 @@ def test_permit_multiple_contexts end } engine = Authorization::Engine.new(reader) - assert engine.permit?(:test, :context => :permissions, + assert engine.permit?(:test, :context => :permissions, :user => MockUser.new(:test_role)) - assert engine.permit?(:test, :context => :permissions_2, + assert engine.permit?(:test, :context => :permissions_2, :user => MockUser.new(:test_role)) - assert !engine.permit?(:test, :context => :permissions_3, + assert !engine.permit?(:test, :context => :permissions_3, :user => MockUser.new(:test_role)) - + assert engine.permit?(:test, :context => :permissions_4, :user => MockUser.new(:test_role)) assert engine.permit?(:test, :context => :permissions_5, :user => MockUser.new(:test_role)) end @@ -89,7 +89,7 @@ def test_permit_with_frozen_roles :user => MockUser.new(:role_symbols => roles)) end end - + def test_obligations_without_conditions reader = Authorization::Reader::DSLReader.new reader.parse %{ @@ -100,10 +100,10 @@ def test_obligations_without_conditions end } engine = Authorization::Engine.new(reader) - assert_equal [{}], engine.obligations(:test, :context => :permissions, + assert_equal [{}], engine.obligations(:test, :context => :permissions, :user => MockUser.new(:test_role)) end - + def test_obligations_with_conditions reader = Authorization::Reader::DSLReader.new reader.parse %{ @@ -116,8 +116,8 @@ def test_obligations_with_conditions end } engine = Authorization::Engine.new(reader) - assert_equal [{:attr => [:is, 1]}], - engine.obligations(:test, :context => :permissions, + assert_equal [{:attr => [:is, 1]}], + engine.obligations(:test, :context => :permissions, :user => MockUser.new(:test_role, :attr => 1)) end @@ -193,7 +193,7 @@ def test_obligations_with_has_many engine.obligations(:test, :context => :permissions, :user => MockUser.new(:test_role, :deeper_attr => 1)) end - + def test_obligations_with_conditions_and_empty reader = Authorization::Reader::DSLReader.new reader.parse %{ @@ -207,8 +207,8 @@ def test_obligations_with_conditions_and_empty end } engine = Authorization::Engine.new(reader) - assert_equal [{}, {:attr => [:is, 1]}], - engine.obligations(:test, :context => :permissions, + assert_equal [{}, {:attr => [:is, 1]}], + engine.obligations(:test, :context => :permissions, :user => MockUser.new(:test_role, :attr => 1)) end @@ -321,7 +321,7 @@ def test_obligations_with_permissions_and_anded_conditions engine.obligations(:test, :context => :permission_children, :user => MockUser.new(:test_role)) end - + def test_guest_user reader = Authorization::Reader::DSLReader.new reader.parse %{ @@ -335,7 +335,7 @@ def test_guest_user assert engine.permit?(:test, :context => :permissions) assert !engine.permit?(:test, :context => :permissions_2) end - + def test_default_role previous_default_role = Authorization.default_role Authorization.default_role = :anonymous @@ -349,12 +349,12 @@ def test_default_role } engine = Authorization::Engine.new(reader) assert engine.permit?(:test, :context => :permissions) - assert !engine.permit?(:test, :context => :permissions, + assert !engine.permit?(:test, :context => :permissions, :user => MockUser.new(:guest)) # reset the default role, so that it does not mess up other tests Authorization.default_role = previous_default_role end - + def test_invalid_user_model reader = Authorization::Reader::DSLReader.new reader.parse %{ @@ -372,7 +372,7 @@ def test_invalid_user_model engine.permit?(:test, :context => :permissions, :user => MockDataObject.new) end end - + def test_role_hierarchy reader = Authorization::Reader::DSLReader.new reader.parse %{ @@ -387,10 +387,10 @@ def test_role_hierarchy end } engine = Authorization::Engine.new(reader) - assert engine.permit?(:lower, :context => :permissions, + assert engine.permit?(:lower, :context => :permissions, :user => MockUser.new(:test_role)) end - + def test_role_hierarchy_infinity reader = Authorization::Reader::DSLReader.new reader.parse %{ @@ -406,10 +406,10 @@ def test_role_hierarchy_infinity end } engine = Authorization::Engine.new(reader) - assert engine.permit?(:lower, :context => :permissions, + assert engine.permit?(:lower, :context => :permissions, :user => MockUser.new(:test_role)) end - + def test_privilege_hierarchy reader = Authorization::Reader::DSLReader.new reader.parse %{ @@ -425,10 +425,10 @@ def test_privilege_hierarchy end } engine = Authorization::Engine.new(reader) - assert engine.permit?(:lower, :context => :permissions, + assert engine.permit?(:lower, :context => :permissions, :user => MockUser.new(:test_role)) end - + def test_privilege_hierarchy_without_context reader = Authorization::Reader::DSLReader.new reader.parse %{ @@ -444,10 +444,10 @@ def test_privilege_hierarchy_without_context end } engine = Authorization::Engine.new(reader) - assert engine.permit?(:list, :context => :permissions, + assert engine.permit?(:list, :context => :permissions, :user => MockUser.new(:test_role)) end - + def test_attribute_is reader = Authorization::Reader::DSLReader.new reader.parse %| @@ -461,13 +461,13 @@ def test_attribute_is end | engine = Authorization::Engine.new(reader) - assert engine.permit?(:test, :context => :permissions, + assert engine.permit?(:test, :context => :permissions, :user => MockUser.new(:test_role, :test_attr => 1), :object => MockDataObject.new(:test_attr => 1)) - assert engine.permit?(:test, :context => :permissions, + assert engine.permit?(:test, :context => :permissions, :user => MockUser.new(:test_role, :test_attr => 2), :object => MockDataObject.new(:test_attr => 3)) - assert((not(engine.permit?(:test, :context => :permissions, + assert((not(engine.permit?(:test, :context => :permissions, :user => MockUser.new(:test_role, :test_attr => 2), :object => MockDataObject.new(:test_attr => 1))))) end @@ -491,7 +491,7 @@ def test_attribute_is_not :user => MockUser.new(:test_role, :test_attr => 2), :object => MockDataObject.new(:test_attr => 1)) end - + def test_attribute_contains reader = Authorization::Reader::DSLReader.new reader.parse %| @@ -504,10 +504,10 @@ def test_attribute_contains end | engine = Authorization::Engine.new(reader) - assert engine.permit?(:test, :context => :permissions, + assert engine.permit?(:test, :context => :permissions, :user => MockUser.new(:test_role, :test_attr => 1), :object => MockDataObject.new(:test_attr => [1,2])) - assert !engine.permit?(:test, :context => :permissions, + assert !engine.permit?(:test, :context => :permissions, :user => MockUser.new(:test_role, :test_attr => 3), :object => MockDataObject.new(:test_attr => [1,2])) end @@ -531,7 +531,7 @@ def test_attribute_does_not_contain :user => MockUser.new(:test_role, :test_attr => 3), :object => MockDataObject.new(:test_attr => [1,2])) end - + def test_attribute_in_array reader = Authorization::Reader::DSLReader.new reader.parse %| @@ -545,13 +545,13 @@ def test_attribute_in_array end | engine = Authorization::Engine.new(reader) - assert engine.permit?(:test, :context => :permissions, + assert engine.permit?(:test, :context => :permissions, :user => MockUser.new(:test_role), :object => MockDataObject.new(:test_attr => 1)) - assert engine.permit?(:test, :context => :permissions, + assert engine.permit?(:test, :context => :permissions, :user => MockUser.new(:test_role), :object => MockDataObject.new(:test_attr => 3)) - assert !engine.permit?(:test, :context => :permissions, + assert !engine.permit?(:test, :context => :permissions, :user => MockUser.new(:test_role), :object => MockDataObject.new(:test_attr => 4)) end @@ -611,7 +611,7 @@ def test_attribute_intersects_with :user => MockUser.new(:test_role), :object => MockDataObject.new(:test_attrs => [3,4] )) end - + def test_attribute_lte reader = Authorization::Reader::DSLReader.new reader.parse %| @@ -725,8 +725,8 @@ def test_attribute_deep :user => MockUser.new(:test_role), :object => MockDataObject.new(:test_attr_1 => MockDataObject.new(:test_attr_2 => [3,4]))) - assert_equal [{:test_attr_1 => {:test_attr_2 => [:contains, 1]}}], - engine.obligations(:test, :context => :permissions, + assert_equal [{:test_attr_1 => {:test_attr_2 => [:contains, 1]}}], + engine.obligations(:test, :context => :permissions, :user => MockUser.new(:test_role)) end @@ -754,7 +754,7 @@ def test_attribute_has_many :user => MockUser.new(:test_role, :city => 'London'), :object => company) end - + def test_attribute_non_block reader = Authorization::Reader::DSLReader.new reader.parse %| @@ -770,11 +770,11 @@ def test_attribute_non_block assert engine.permit?(:test, :context => :permissions, :user => MockUser.new(:test_role), :object => MockDataObject.new(:test_attr => 1)) - assert !engine.permit?(:test, :context => :permissions, + assert !engine.permit?(:test, :context => :permissions, :user => MockUser.new(:test_role), :object => MockDataObject.new(:test_attr => 2)) end - + def test_attribute_multiple reader = Authorization::Reader::DSLReader.new reader.parse %{ @@ -791,7 +791,7 @@ def test_attribute_multiple assert engine.permit?(:test, :context => :permissions, :user => MockUser.new(:test_role), :object => MockDataObject.new(:test_attr => 1)) - assert engine.permit?(:test, :context => :permissions, + assert engine.permit?(:test, :context => :permissions, :user => MockUser.new(:test_role), :object => MockDataObject.new(:test_attr => 2)) end @@ -930,7 +930,7 @@ def test_attribute_with_permissions_nil :user => MockUser.new(:test_role), :object => MockDataObject.new(:permission => nil)) end - + assert !engine.permit?(:test, :context => :permission_children, :user => MockUser.new(:test_role), :object => MockDataObject.new(:permission => nil)) @@ -1039,7 +1039,7 @@ def test_attribute_with_anded_rules :user => MockUser.new(:test_role), :object => MockDataObject.new(:test_attr => 1, :test_attr_2 => 3)) end - + def test_raise_on_if_attribute_hash_on_collection reader = Authorization::Reader::DSLReader.new reader.parse %{ @@ -1058,7 +1058,7 @@ def test_raise_on_if_attribute_hash_on_collection :object => MockDataObject.new(:test_attrs => [1, 2, 3])) end end - + def test_role_title_description reader = Authorization::Reader::DSLReader.new reader.parse %{ @@ -1077,7 +1077,7 @@ def test_role_title_description assert_equal "Test Role Description", engine.description_for(:test_role) assert_nil engine.description_for(:test_role_2) end - + def test_multithread reader = Authorization::Reader::DSLReader.new reader.parse %{ @@ -1087,7 +1087,7 @@ def test_multithread end end } - + engine = Authorization::Engine.new(reader) Authorization.current_user = MockUser.new(:test_role) assert engine.permit?(:test, :context => :permissions) diff --git a/test/controller_test.rb b/test/controller_test.rb index 3cbe678c..0f7185fa 100644 --- a/test/controller_test.rb +++ b/test/controller_test.rb @@ -16,7 +16,7 @@ class SpecificMocksController < MocksController filter_access_to :edit_2, :require => :test, :context => :permissions, :attribute_check => true, :model => LoadMockObject filter_access_to :new, :require => :test, :context => :permissions - + filter_access_to [:action_group_action_1, :action_group_action_2] define_action_methods :test_action, :test_action_2, :show, :edit, :create, :edit_2, :new, :unprotected_action, :action_group_action_1, :action_group_action_2 @@ -24,7 +24,7 @@ class SpecificMocksController < MocksController class BasicControllerTest < ActionController::TestCase tests SpecificMocksController - + def test_filter_access_to_receiving_an_explicit_array reader = Authorization::Reader::DSLReader.new @@ -43,10 +43,10 @@ def test_filter_access_to_receiving_an_explicit_array request!(nil, "action_group_action_2", reader) assert !@controller.authorized? end - + def test_filter_access assert !@controller.class.before_filters.empty? - + reader = Authorization::Reader::DSLReader.new reader.parse %{ authorization do @@ -56,21 +56,21 @@ def test_filter_access end end } - + request!(MockUser.new(:test_role), "test_action", reader) assert @controller.authorized? - + request!(MockUser.new(:test_role), "test_action_2", reader) assert !@controller.authorized? - + request!(MockUser.new(:test_role_2), "test_action", reader) assert_response :forbidden assert !@controller.authorized? - + request!(MockUser.new(:test_role), "show", reader) assert @controller.authorized? end - + def test_filter_access_multi_actions reader = Authorization::Reader::DSLReader.new reader.parse %{ @@ -79,11 +79,11 @@ def test_filter_access_multi_actions has_permission_on :permissions, :to => :test end end - } + } request!(MockUser.new(:test_role), "create", reader) assert @controller.authorized? end - + def test_filter_access_unprotected_actions reader = Authorization::Reader::DSLReader.new reader.parse %{ @@ -113,7 +113,7 @@ def test_filter_access_priv_hierarchy request!(MockUser.new(:test_role), "show", reader) assert @controller.authorized? end - + def test_filter_access_skip_attribute_test reader = Authorization::Reader::DSLReader.new reader.parse %{ @@ -128,7 +128,7 @@ def test_filter_access_skip_attribute_test request!(MockUser.new(:test_role), "new", reader) assert @controller.authorized? end - + def test_existing_instance_var_remains_unchanged reader = Authorization::Reader::DSLReader.new reader.parse %{ @@ -144,7 +144,7 @@ def test_existing_instance_var_remains_unchanged @controller.send(:instance_variable_set, :"@load_mock_object", mock_object) request!(MockUser.new(:test_role), "edit_2", reader) - assert_equal mock_object, + assert_equal mock_object, @controller.send(:instance_variable_get, :"@load_mock_object") assert @controller.authorized? end @@ -183,13 +183,13 @@ def test_filter_access_all end end } - + request!(MockUser.new(:test_role), "show", reader) assert @controller.authorized? - + request!(MockUser.new(:test_role), "view", reader) assert @controller.authorized? - + request!(MockUser.new(:test_role_2), "show", reader) assert !@controller.authorized? end @@ -223,7 +223,7 @@ def self.load_method_call_count end class LoadObjectControllerTest < ActionController::TestCase tests LoadMockObjectsController - + def test_filter_access_with_object_load reader = Authorization::Reader::DSLReader.new reader.parse %{ @@ -236,14 +236,14 @@ def test_filter_access_with_object_load end end } - + request!(MockUser.new(:test_role), "show", reader, :id => 2) assert !@controller.authorized? - + request!(MockUser.new(:test_role), "show", reader, :id => 1, :clear => [:@load_mock_object]) assert @controller.authorized? - + request!(MockUser.new(:test_role), "edit", reader, :id => 1, :clear => [:@load_mock_object]) assert @controller.authorized? @@ -265,7 +265,7 @@ def test_filter_access_object_load_without_param assert_raise StandardError, "No id param supplied" do request!(MockUser.new(:test_role), "show", reader) end - + Authorization::AuthorizationInController.failed_auto_loading_is_not_found = false assert_nothing_raised "Load error is only logged" do request!(MockUser.new(:test_role), "show", reader) @@ -273,7 +273,7 @@ def test_filter_access_object_load_without_param assert !@controller.authorized? Authorization::AuthorizationInController.failed_auto_loading_is_not_found = true end - + def test_filter_access_with_object_load_custom reader = Authorization::Reader::DSLReader.new reader.parse %{ @@ -291,14 +291,14 @@ def test_filter_access_with_object_load_custom end end } - + request!(MockUser.new(:test_role), "delete", reader) assert !@controller.authorized? - + request!(MockUser.new(:test_role), "view", reader) assert @controller.authorized? assert_equal 1, @controller.class.load_method_call_count - + request!(MockUser.new(:test_role_2), "view", reader) assert !@controller.authorized? assert_equal 1, @controller.class.load_method_call_count @@ -306,7 +306,7 @@ def test_filter_access_with_object_load_custom request!(MockUser.new(:test_role), "update", reader) assert @controller.authorized? end - + def test_filter_access_custom reader = Authorization::Reader::DSLReader.new reader.parse %{ @@ -319,10 +319,10 @@ def test_filter_access_custom end end } - + request!(MockUser.new(:test_role), "create", reader) assert @controller.authorized? - + request!(MockUser.new(:test_role_2), "create", reader) assert !@controller.authorized? end @@ -331,7 +331,7 @@ def test_filter_access_custom ################## class AccessOverwritesController < MocksController - filter_access_to :test_action, :test_action_2, + filter_access_to :test_action, :test_action_2, :require => :test, :context => :permissions_2 filter_access_to :test_action, :require => :test, :context => :permissions define_action_methods :test_action, :test_action_2 @@ -348,7 +348,7 @@ def test_filter_access_overwrite } request!(MockUser.new(:test_role), "test_action_2", reader) assert !@controller.authorized? - + request!(MockUser.new(:test_role), "test_action", reader) assert @controller.authorized? end @@ -362,7 +362,7 @@ class PeopleController < MocksController end class PluralizationControllerTest < ActionController::TestCase tests PeopleController - + def test_filter_access_people_controller reader = Authorization::Reader::DSLReader.new reader.parse %{ diff --git a/test/development_support/change_analyzer_test.rb b/test/development_support/change_analyzer_test.rb index 46471af5..66a6a740 100644 --- a/test/development_support/change_analyzer_test.rb +++ b/test/development_support/change_analyzer_test.rb @@ -62,7 +62,7 @@ def test_adding_permission_by_assigning_role #assert_equal :role, approaches.first.target_type #assert_equal :test_role_2, approaches.first.target.to_sym end - + def test_adding_permission_with_new_role reader = Authorization::Reader::DSLReader.new reader.parse %{ @@ -163,7 +163,7 @@ def test_moving_permission assert !permit?(:read, :context => :permissions, :user => users.first) assert permit?(:read, :context => :permissions, :user => users[1]) end - + assert approaches.find {|approach| approach.steps.find {|step| step.first == :remove_privilege}} assert approaches.find {|approach| approach.steps.find {|step| step.first == :add_privilege}} end diff --git a/test/development_support/change_supporter_test.rb b/test/development_support/change_supporter_test.rb index 1b694b9a..50736318 100644 --- a/test/development_support/change_supporter_test.rb +++ b/test/development_support/change_supporter_test.rb @@ -148,7 +148,7 @@ def test_adding_permission_by_assigning_role_many assert approaches.any? {|approach| approach.changes.first.class == Authorization::DevelopmentSupport::ChangeSupporter::AssignRoleToUserAction} end - + def test_adding_permission_with_new_role reader = Authorization::Reader::DSLReader.new reader.parse %{ @@ -343,7 +343,7 @@ def test_moving_permission assert !permit?(:read, :context => :permissions, :user => users.first) assert permit?(:read, :context => :permissions, :user => users[1]) end - + assert approaches.any? {|approach| approach.steps.find {|step| step.class == Authorization::DevelopmentSupport::ChangeSupporter::RemovePrivilegeFromRoleAction}} assert approaches.any? {|approach| approach.steps.find {|step| step.class == Authorization::DevelopmentSupport::ChangeSupporter::AssignPrivilegeToRoleAction}} end diff --git a/test/dsl_reader_test.rb b/test/dsl_reader_test.rb index 2c11ba5d..9a33aee9 100644 --- a/test/dsl_reader_test.rb +++ b/test/dsl_reader_test.rb @@ -11,10 +11,10 @@ def test_privileges end } assert_equal 2, reader.privileges_reader.privileges.length - assert_equal [[:lower_priv, nil]], + assert_equal [[:lower_priv, nil]], reader.privileges_reader.privilege_hierarchy[:test_priv] end - + def test_privileges_with_context reader = Authorization::Reader::DSLReader.new reader.parse %{ @@ -24,10 +24,10 @@ def test_privileges_with_context end end } - assert_equal [[:lower_priv, :test_context]], + assert_equal [[:lower_priv, :test_context]], reader.privileges_reader.privilege_hierarchy[:test_priv] end - + def test_privileges_one_line reader = Authorization::Reader::DSLReader.new reader.parse %{ @@ -37,14 +37,14 @@ def test_privileges_one_line privilege :test_priv_3, :includes => [:lower_priv] end } - assert_equal [[:lower_priv, :test_context]], + assert_equal [[:lower_priv, :test_context]], reader.privileges_reader.privilege_hierarchy[:test_priv] - assert_equal [[:lower_priv, :test_context]], + assert_equal [[:lower_priv, :test_context]], reader.privileges_reader.privilege_hierarchy[:test_priv_2] - assert_equal [[:lower_priv, nil]], + assert_equal [[:lower_priv, nil]], reader.privileges_reader.privilege_hierarchy[:test_priv_3] end - + def test_auth_role reader = Authorization::Reader::DSLReader.new reader.parse %{ @@ -59,7 +59,7 @@ def test_auth_role assert_equal [:lesser_role], reader.auth_rules_reader.role_hierarchy[:test_role] assert_equal 1, reader.auth_rules_reader.auth_rules.length end - + def test_auth_role_permit_on reader = Authorization::Reader::DSLReader.new reader.parse %| @@ -77,7 +77,7 @@ def test_auth_role_permit_on assert reader.auth_rules_reader.auth_rules[0].matches?(:test_role, [:test_perm], :test_context) assert reader.auth_rules_reader.auth_rules[0].matches?(:test_role, [:manage], :test_context) end - + def test_permit_block reader = Authorization::Reader::DSLReader.new reader.parse %| @@ -102,7 +102,7 @@ def test_permit_block assert_equal 1, reader.auth_rules_reader.auth_rules.length assert reader.auth_rules_reader.auth_rules[0].matches?(:test_role, [:test], :perms) end - + def test_has_permission_to_with_context reader = Authorization::Reader::DSLReader.new reader.parse %| @@ -116,7 +116,7 @@ def test_has_permission_to_with_context assert_equal 1, reader.auth_rules_reader.auth_rules.length assert reader.auth_rules_reader.auth_rules[0].matches?(:test_role, [:test], :perms) end - + def test_context reader = Authorization::Reader::DSLReader.new reader.parse %{ @@ -127,7 +127,7 @@ def test_context end } end - + def test_dsl_error reader = Authorization::Reader::DSLReader.new assert_raise(Authorization::Reader::DSLError) do @@ -138,7 +138,7 @@ def test_dsl_error } end end - + def test_syntax_error reader = Authorization::Reader::DSLReader.new assert_raise(Authorization::Reader::DSLSyntaxError) do @@ -148,7 +148,7 @@ def test_syntax_error } end end - + def test_syntax_error_2 reader = Authorization::Reader::DSLReader.new assert_raise(Authorization::Reader::DSLSyntaxError) do diff --git a/test/helper_test.rb b/test/helper_test.rb index d0f1c674..8df2716b 100644 --- a/test/helper_test.rb +++ b/test/helper_test.rb @@ -10,7 +10,7 @@ class HelperTest < ActionController::TestCase tests HelperMocksController include Authorization::AuthorizationHelper attr_reader :controller - + def test_permit reader = Authorization::Reader::DSLReader.new reader.parse %{ @@ -25,16 +25,16 @@ def test_permit } user = MockUser.new(:test_role) request!(user, :action, reader) - + assert permitted_to?(:show, :mocks) assert !permitted_to?(:update, :mocks) - + block_evaled = false permitted_to?(:show, :mocks) do block_evaled = true end assert block_evaled - + block_evaled = false permitted_to?(:update, :mocks) do block_evaled = true @@ -58,7 +58,7 @@ def test_permit_with_object mock = MockDataObject.new(:test_attr => 1) mock_2 = MockDataObject.new(:test_attr => 2) request!(user, :action, reader) - + assert permitted_to?(:show, mock) assert permitted_to?(:show, :mocks) assert !permitted_to?(:show, mock_2) @@ -84,7 +84,7 @@ def test_permit_with_object_and_context assert permitted_to?(:show, mock, :context => :other_mocks) assert !permitted_to?(:show, mock_2, :context => :other_mocks) end - + def test_has_role reader = Authorization::Reader::DSLReader.new reader.parse %{ @@ -96,24 +96,24 @@ def test_has_role } user = MockUser.new(:test_role) request!(user, :action, reader) - + assert has_role?(:test_role) assert !has_role?(:test_role2) assert !has_role?(:test_role, :test_role2) - + block_evaled = false has_role?(:test_role) do block_evaled = true end assert block_evaled - + block_evaled = false has_role?(:test_role2) do block_evaled = true end assert !block_evaled end - + def test_has_any_role reader = Authorization::Reader::DSLReader.new reader.parse %{ @@ -125,30 +125,30 @@ def test_has_any_role } user = MockUser.new(:test_role) request!(user, :action, reader) - + assert has_any_role?(:test_role) assert !has_any_role?(:test_role2) assert has_any_role?(:test_role, :test_role2) - + block_evaled = false has_any_role?(:test_role) do block_evaled = true end assert block_evaled - + block_evaled = false has_any_role?(:test_role2) do block_evaled = true end assert !block_evaled - + block_evaled = false has_any_role?(:test_role,:test_role2) do block_evaled = true end assert block_evaled end - + def test_has_role_with_guest_user reader = Authorization::Reader::DSLReader.new reader.parse %{ @@ -165,7 +165,7 @@ def test_has_role_with_guest_user end assert !block_evaled end - + def test_has_role_with_hierarchy reader = Authorization::Reader::DSLReader.new reader.parse %{ @@ -181,11 +181,11 @@ def test_has_role_with_hierarchy includes :test_role end end - } - + } + user = MockUser.new(:root) request!(user, :action, reader) - + assert has_role_with_hierarchy?(:test_role) assert !has_role_with_hierarchy?(:other_role) @@ -194,14 +194,14 @@ def test_has_role_with_hierarchy block_evaled = true end assert block_evaled - + block_evaled = false has_role_with_hierarchy?(:test_role2) do block_evaled = true end assert !block_evaled end - + def test_has_any_role_with_hierarchy reader = Authorization::Reader::DSLReader.new reader.parse %{ @@ -217,11 +217,11 @@ def test_has_any_role_with_hierarchy includes :test_role end end - } - + } + user = MockUser.new(:root) request!(user, :action, reader) - + assert has_any_role_with_hierarchy?(:test_role) assert !has_any_role_with_hierarchy?(:other_role) assert has_any_role_with_hierarchy?(:test_role,:other_role) @@ -231,13 +231,13 @@ def test_has_any_role_with_hierarchy block_evaled = true end assert block_evaled - + block_evaled = false has_any_role_with_hierarchy?(:test_role2) do block_evaled = true end assert !block_evaled - + block_evaled = false has_any_role_with_hierarchy?(:test_role,:test_role2) do block_evaled = true diff --git a/test/model_test.rb b/test/model_test.rb index ffdd941d..ecbddb3f 100644 --- a/test/model_test.rb +++ b/test/model_test.rb @@ -23,14 +23,14 @@ class TestModel < ActiveRecord::Base # :conditions is deprecated in Rails 4.1 if Rails.version >= '4' has_many :test_attrs_with_attr, lambda { where(:attr => 1) }, :class_name => "TestAttr" - has_many :test_attr_throughs_with_attr, lambda { where("test_attrs.attr = 1") }, :through => :test_attrs, + has_many :test_attr_throughs_with_attr, lambda { where("test_attrs.attr = 1") }, :through => :test_attrs, :class_name => "TestAttrThrough", :source => :test_attr_throughs has_one :test_attr_throughs_with_attr_and_has_one, lambda { where("test_attrs.attr = 1") }, :through => :test_attrs, :class_name => "TestAttrThrough", :source => :test_attr_throughs - else + else has_many :test_attrs_with_attr, :class_name => "TestAttr", :conditions => {:attr => 1} - has_many :test_attr_throughs_with_attr, :through => :test_attrs, + has_many :test_attr_throughs_with_attr, :through => :test_attrs, :class_name => "TestAttrThrough", :source => :test_attr_throughs, :conditions => "test_attrs.attr = 1" @@ -62,7 +62,7 @@ class TestModel < ActiveRecord::Base unless Rails.version < "2.2" has_many :test_attrs_with_primary_id, :class_name => "TestAttr", :primary_key => :test_attr_through_id, :foreign_key => :test_attr_through_id - has_many :test_attr_throughs_with_primary_id, + has_many :test_attr_throughs_with_primary_id, :through => :test_attrs_with_primary_id, :class_name => "TestAttrThrough", :source => :n_way_join_item end @@ -95,7 +95,7 @@ class TestAttr < ActiveRecord::Base if Rails.version < '4' attr_accessible :test_model, :test_another_model, :attr, :branch, :company, :test_attr, - :test_a_third_model, :n_way_join_item, :n_way_join_item_id, :test_attr_through_id, + :test_a_third_model, :n_way_join_item, :n_way_join_item_id, :test_attr_through_id, :test_model_id, :test_another_model_id end @@ -125,9 +125,9 @@ class TestModelSecurityModelWithFind < ActiveRecord::Base end has_many :test_attrs belongs_to :test_attr - using_access_control :include_read => true, + using_access_control :include_read => true, :context => :test_model_security_models - + if Rails.version < '4' attr_accessible :test_attr, :attr end @@ -137,7 +137,7 @@ class Branch < ActiveRecord::Base has_many :test_attrs belongs_to :company belongs_to :test_model - + if Rails.version < '4' attr_accessible :name, :company, :test_model end @@ -146,7 +146,7 @@ class Company < ActiveRecord::Base has_many :test_attrs has_many :branches belongs_to :country - + if Rails.version < '4' attr_accessible :name, :country, :country_id end @@ -159,7 +159,7 @@ def self.decl_auth_context class Country < ActiveRecord::Base has_many :test_models has_many :companies - + if Rails.version < '4' attr_accessible :name end @@ -1539,17 +1539,17 @@ def test_permit_with_has_one_raises_no_name_error end } instance = Authorization::Engine.instance(reader) - + test_model = TestModel.create! test_attr = test_model.create_test_attr_has_one assert !test_attr.new_record? - + user = MockUser.new(:test_role, :test_attr => test_attr) - + assert_nothing_raised do - assert instance.permit?(:update, :user => user, :object => test_model.test_attr_has_one) + assert instance.permit?(:update, :user => user, :object => test_model.test_attr_has_one) end - + TestModel.delete_all TestAttr.delete_all end @@ -1604,7 +1604,7 @@ def test_model_security_write_not_allowed_no_privilege object.update_attributes(:attr_2 => 2) end end - + def test_model_security_write_not_allowed_wrong_attribute_value reader = Authorization::Reader::DSLReader.new reader.parse %{ @@ -1623,7 +1623,7 @@ def test_model_security_write_not_allowed_wrong_attribute_value end } Authorization::Engine.instance(reader) - + Authorization.current_user = MockUser.new(:test_role) assert(object = TestModelSecurityModel.create) assert_raise Authorization::AttributeAuthorizationError do @@ -1695,7 +1695,7 @@ def test_model_security_with_read_restrictions_and_exists object_with_find.class.find(object_with_find.id) end assert_equal 1, test_attr.test_model_security_model_with_finds.length - + # Raises error since AR does not populate the object #assert test_attr.test_model_security_model_with_finds.exists?(object_with_find) end @@ -1784,7 +1784,7 @@ def test_model_security_with_assoc end } Authorization::Engine.instance(reader) - + test_attr = TestAttr.create test_attr.role_symbols << :test_role Authorization.current_user = test_attr @@ -1795,7 +1795,7 @@ def test_model_security_with_assoc without_access_control do object.reload end - assert_equal 2, object.attr_2 + assert_equal 2, object.attr_2 object.destroy assert_raise ActiveRecord::RecordNotFound do TestModelSecurityModel.find(object.id) @@ -1886,10 +1886,10 @@ def test_authorization_permit_nested_association_proxy test_model_2 = TestModel.create! test_attr_2 = test_model_2.test_attrs.create!(:attr => 2) test_branch_2 = Branch.create!(:test_model => test_model_2) - + test_model_3 = TestModel.create! test_branch_3 = Branch.create!(:test_model => test_model_3) - + assert engine.permit?(:read, :object => test_branch, :user => MockUser.new(:test_role)) assert !engine.permit?(:read, :object => test_branch_2, diff --git a/test/test_helper.rb b/test/test_helper.rb index 1fe63fdc..dd3fc59f 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -54,7 +54,7 @@ def initialize(attrs = {}) end end end - + def self.descends_from_active_record? true end @@ -66,7 +66,7 @@ def self.table_name def self.name "Mock" end - + def self.find(*args) raise StandardError, "Couldn't find #{self.name} with id #{args[0].inspect}" unless args[0] new :id => args[0] @@ -92,11 +92,11 @@ def initialize_copy(other) class MocksController < ActionController::Base attr_accessor :current_user attr_writer :authorization_engine - + def authorized? !!@authorized end - + def self.define_action_methods(*methods) methods.each do |method| define_method method do @@ -109,9 +109,9 @@ def self.define_action_methods(*methods) def self.define_resource_actions define_action_methods :index, :show, :edit, :update, :new, :create, :destroy end - + def logger(*args) - Class.new do + Class.new do def warn(*args) #p args end @@ -175,12 +175,12 @@ class Application < ::Rails::Application if Rails.version < "4" class Test::Unit::TestCase include Authorization::TestHelper - + def request!(user, action, reader, params = {}) action = action.to_sym if action.is_a?(String) @controller.current_user = user @controller.authorization_engine = Authorization::Engine.new(reader) - + ((params.delete(:clear) || []) + [:@authorized]).each do |var| @controller.instance_variable_set(var, nil) end @@ -202,12 +202,12 @@ class Test::Unit::TestCase class ActiveSupport::TestCase include Authorization::TestHelper - + def request!(user, action, reader, params = {}) action = action.to_sym if action.is_a?(String) @controller.current_user = user @controller.authorization_engine = Authorization::Engine.new(reader) - + ((params.delete(:clear) || []) + [:@authorized]).each do |var| @controller.instance_variable_set(var, nil) end @@ -233,12 +233,12 @@ class Test::Unit::TestCase < Minitest::Test class ActiveSupport::TestCase include Authorization::TestHelper - + def request!(user, action, reader, params = {}) action = action.to_sym if action.is_a?(String) @controller.current_user = user @controller.authorization_engine = Authorization::Engine.new(reader) - + ((params.delete(:clear) || []) + [:@authorized]).each do |var| @controller.instance_variable_set(var, nil) end From 0b193253cfbb7433586248223fd4359ceaa1aab1 Mon Sep 17 00:00:00 2001 From: Anna Date: Wed, 25 May 2016 15:25:04 -0500 Subject: [PATCH 05/55] tests pass with ruby 2.2 --- .travis.yml | 5 +++-- declarative_authorization.gemspec | 1 + lib/declarative_authorization/authorization.rb | 8 +++++++- lib/declarative_authorization/reader.rb | 3 --- 4 files changed, 11 insertions(+), 6 deletions(-) diff --git a/.travis.yml b/.travis.yml index 38e11e21..3344cc47 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,8 +1,9 @@ language: ruby script: bundle exec rake test rvm: - - 2.0.0 - - 2.1.9 + - 2.0 + - 2.1 + - 2.2 gemfile: - gemfiles/4.0.gemfile - gemfiles/4.1.gemfile diff --git a/declarative_authorization.gemspec b/declarative_authorization.gemspec index 1071c15a..055e19ca 100644 --- a/declarative_authorization.gemspec +++ b/declarative_authorization.gemspec @@ -14,4 +14,5 @@ Gem::Specification.new do |s| s.homepage = %q{http://github.com/stffn/declarative_authorization} s.add_dependency('ruby_parser', '~> 3.6.6') s.add_dependency('rails', '>= 4.0.0', '< 4.2.0') + s.add_development_dependency('test-unit') end diff --git a/lib/declarative_authorization/authorization.rb b/lib/declarative_authorization/authorization.rb index b6566e85..d439ad58 100644 --- a/lib/declarative_authorization/authorization.rb +++ b/lib/declarative_authorization/authorization.rb @@ -280,7 +280,13 @@ def roles_with_hierarchy_for(user) def self.development_reload? if Rails.env.development? - mod_time = AUTH_DSL_FILES.map { |m| File.mtime(m) rescue Time.at(0) }.flatten.max + mod_time = AUTH_DSL_FILES.map do |m| + begin + File.mtime(m) + rescue + Time.at(0) + end + end.flatten.max @@auth_dsl_last_modified ||= mod_time if mod_time > @@auth_dsl_last_modified @@auth_dsl_last_modified = mod_time diff --git a/lib/declarative_authorization/reader.rb b/lib/declarative_authorization/reader.rb index 5ca55a1e..7d450327 100644 --- a/lib/declarative_authorization/reader.rb +++ b/lib/declarative_authorization/reader.rb @@ -1,7 +1,4 @@ # Authorization::Reader - -require File.dirname(__FILE__) + '/authorization.rb' - module Authorization # Parses an authorization configuration file in the authorization DSL and # constructs a data model of its contents. From a6114f2047458280e9b69ce60c49e0037c4b66d4 Mon Sep 17 00:00:00 2001 From: Jonathan Arnett Date: Thu, 21 Jul 2016 16:23:47 -0400 Subject: [PATCH 06/55] Corrected rdoc inline code formatting --- README.rdoc | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/README.rdoc b/README.rdoc index e6118710..5c6ce747 100644 --- a/README.rdoc +++ b/README.rdoc @@ -55,14 +55,14 @@ Next, bundle and install. This installer will create a Role model, an admin and a user role, and set a has_and_belongs_to_many relationship between the User model and the Role model. -It will also add a `role_symbols` method to the user model to meet +It will also add a +role_symbols+ method to the user model to meet declarative_authorization's requirements. The default User model is User. You can override this by simply typing the name of a model as above. -You can create the model with the fields provided by using the `--create-user` option. +You can create the model with the fields provided by using the +--create-user+ option. -The `--commit` option will run `rake db:migrate` and `rake db:seed`. +The +--commit+ option will run +rake db:migrate+ and +rake db:seed+. -The `--user-belongs-to-role` option will set up a one-to-many relationship between Users and Roles. +The +--user-belongs-to-role+ option will set up a one-to-many relationship between Users and Roles. That is, each user has a role_id column and can only have one role. Role inheritance can be used in authorization rules. @@ -74,7 +74,7 @@ To copy a default set of authorization rules which includes CRUD priveleges, run $ rails g authorization:rules -This command will copy the following to `config/authorization_rules.rb`. Remember +This command will copy the following to +config/authorization_rules.rb+. Remember to implement the requirements of this gem as described in the Installation section at the end of this README if you do not use the above installer. @@ -108,14 +108,14 @@ at the end of this README if you do not use the above installer. === Controller Authorization -For RESTful controllers, add `filter_resource_access`: +For RESTful controllers, add +filter_resource_access+: class MyRestfulController < ApplicationController filter_resource_access ... end -For a non-RESTful controller, you can use `filter_access_to`: +For a non-RESTful controller, you can use +filter_access_to+: class MyOtherController < ApplicationController filter_access_to :all @@ -125,7 +125,7 @@ For a non-RESTful controller, you can use `filter_access_to`: === View Authorization -Declarative Authorization will use `current_user` to check authorization. +Declarative Authorization will use +current_user+ to check authorization. <%= link_to 'Edit Post', edit_post_path(@post) if permitted_to? :update, @post %> @@ -186,14 +186,14 @@ filter_access_to with the appropriate parameters to protect the CRUD methods. See Authorization::AuthorizationInController::ClassMethods for options on nested resources and custom member and collection actions. -By default, declarative_authorization will enable filter_resource_access compatibility with strong_parameters in Rails 4. If you want to disable this behavior, you can use the `:strong_parameters` option. +By default, declarative_authorization will enable filter_resource_access compatibility with strong_parameters in Rails 4. If you want to disable this behavior, you can use the +:strong_parameters+ option. class EmployeesController < ApplicationController filter_resource_access :strong_parameters => false ... end -Simalarly, you can use `:strong_parameters => true` if you are using strong_parameters in Rails 3. +Simalarly, you can use +:strong_parameters => true+ if you are using strong_parameters in Rails 3. If you prefer less magic or your controller has no resemblance with the resource controllers, directly calling filter_access_to may be the better option. Examples From 414112fc5cd17e84ca51f1d3c67a60dd1f34c892 Mon Sep 17 00:00:00 2001 From: Chris Baynes Date: Tue, 6 Dec 2016 19:09:49 +0100 Subject: [PATCH 07/55] Implement support for polymorphic associations in read scopes. --- .../obligation_scope.rb | 283 ++++++++++++------ 1 file changed, 188 insertions(+), 95 deletions(-) diff --git a/lib/declarative_authorization/obligation_scope.rb b/lib/declarative_authorization/obligation_scope.rb index 379c58b0..241f10ae 100644 --- a/lib/declarative_authorization/obligation_scope.rb +++ b/lib/declarative_authorization/obligation_scope.rb @@ -74,17 +74,18 @@ def parse!( obligation ) rebuild_condition_options! rebuild_join_options! end - + protected - + # Parses the next step in the association path. If it's an association, we advance down the # path. Otherwise, it's an attribute, and we need to evaluate it as a comparison operation. def follow_path( steps, past_steps = [] ) if steps.is_a?( Hash ) steps.each do |step, next_steps| path_to_this_point = [past_steps, step].flatten - reflection = reflection_for( path_to_this_point ) rescue nil - if reflection + reflection = reflection_for( path_to_this_point ) # fixme: rescue nil + + unless reflection.empty? follow_path( next_steps, path_to_this_point ) else follow_comparison( next_steps, past_steps, step ) @@ -112,7 +113,7 @@ def top_level_model def finder_options Rails.version < "3" ? @proxy_options : @finder_options end - + # At the end of every association path, we expect to see a comparison of some kind; for # example, +:attr => [ :is, :value ]+. # @@ -124,7 +125,7 @@ def follow_comparison( steps, past_steps, attribute ) add_obligation_condition_for( past_steps, [attribute, operator, value] ) end - + # Adds the given expression to the current obligation's indicated path's conditions. # # Condition expressions must follow the format +[ , , ]+. @@ -134,35 +135,39 @@ def add_obligation_condition_for( path, expression ) obligation_conditions[@current_obligation] ||= {} ( obligation_conditions[@current_obligation][path] ||= Set.new ) << expression end - + # Adds the given path to the list of obligation joins, if we haven't seen it before. def add_obligation_join_for( path ) - map_reflection_for( path ) if reflections[path].nil? + reflection_for(path) if !reflections[path].empty? end - - # Returns the model associated with the given path. - def model_for (path) - reflection = reflection_for(path) - if Authorization.is_a_association_proxy?(reflection) - if Rails.version < "3.2" - reflection.proxy_reflection.klass + # Returns the model associated with the given path. + def models_for(path) + reflection_for(path).map do |reflection| + if Authorization.is_a_association_proxy?(reflection) + if Rails.version < "3.2" + reflection.proxy_reflection.klass + else + reflection.proxy_association.reflection.klass + end + elsif reflection.respond_to?(:klass) + if polymorphic?(reflection) + reflection.active_record.poly_resources + else + reflection.klass + end else - reflection.proxy_association.reflection.klass + reflection end - elsif reflection.respond_to?(:klass) - reflection.klass - else - reflection - end + end.flatten.uniq end - + # Returns the reflection corresponding to the given path. def reflection_for(path, for_join_table_only = false) @join_table_joins << path if for_join_table_only and !reflections[path] - reflections[path] ||= map_reflection_for( path ) + reflections[path] || map_reflection_for(path) end - + # Returns a proper table alias for the given path. This alias may be used in SQL statements. def table_alias_for( path ) table_aliases[path] ||= map_table_alias_for( path ) @@ -170,53 +175,80 @@ def table_alias_for( path ) # Attempts to map a reflection for the given path. Raises if already defined. def map_reflection_for( path ) - raise "reflection for #{path.inspect} already exists" unless reflections[path].nil? + refls_for_path = reflections_for_path path + return [] if refls_for_path.empty? - reflection = path.empty? ? top_level_model : begin - parent = reflection_for( path[0..-2] ) - if !Authorization.is_a_association_proxy?(parent) and parent.respond_to?(:klass) - parent.klass.reflect_on_association( path.last ) - else - parent.reflect_on_association( path.last ) - end - rescue - parent.reflect_on_association( path.last ) - end - raise "invalid path #{path.inspect}" if reflection.nil? + reflections[path] = refls_for_path - reflections[path] = reflection - map_table_alias_for( path ) # Claim a table alias for the path. + map_table_alias_for path # Claim a table alias for the path. # Claim alias for join table # TODO change how this is checked - if !Authorization.is_a_association_proxy?(reflection) and !reflection.respond_to?(:proxy_scope) and reflection.is_a?(ActiveRecord::Reflection::ThroughReflection) - join_table_path = path[0..-2] + [reflection.options[:through]] - reflection_for(join_table_path, true) + refls_for_path.each do |reflection| + if !Authorization.is_a_association_proxy?(reflection) and !reflection.respond_to?(:proxy_scope) and reflection.is_a?(ActiveRecord::Reflection::ThroughReflection) + join_table_path = path[0..-2] + [reflection.options[:through]] + reflection_for(join_table_path, true) + end end - - reflection + + refls_for_path + end + + def reflections_for_path(path) + return [top_level_model] if path.empty? + + refls_for = reflections_for_path path[0..-2] + + refls_for_path = refls_for.map.with_index do |refl_for, idx| + if polymorphic?(refl_for) + refl_for.active_record.poly_resources + elsif !Authorization.is_a_association_proxy?(refl_for) and refl_for.respond_to?(:klass) + refl_for.klass + else + refl_for + end + end.flatten.uniq + + refls_for_path.map do |refl| + refl.reflect_on_association path.last + end.compact end # Attempts to map a table alias for the given path. Raises if already defined. def map_table_alias_for( path ) return "table alias for #{path.inspect} already exists" unless table_aliases[path].nil? - - reflection = reflection_for( path ) + + table_aliases[path] = reflection_for(path).map do |ref_for| + if polymorphic?(ref_for) + rel_name = ref_for.active_record + rel_name.poly_resources.map { |res| construct_table_alias res } + else + construct_table_alias ref_for + end + end.flatten.uniq + end + + def construct_table_alias(reflection) table_alias = reflection.table_name - if table_aliases.values.include?( table_alias ) + if table_aliases.values.flatten.include?( table_alias ) max_length = reflection.active_record.connection.table_alias_length # Rails seems to pluralize reflection names table_alias = "#{reflection.name.to_s.pluralize}_#{reflection.active_record.table_name}".to(max_length-1) - end - while table_aliases.values.include?( table_alias ) + end + while table_aliases.values.flatten.include?( table_alias ) if table_alias =~ /\w(_\d+?)$/ table_index = $1.succ table_alias = "#{table_alias[0..-(table_index.length+1)]}_#{table_index}" else - table_alias = "#{table_alias[0..(max_length-3)]}_2" + table_alias = "#{table_alias[0..(max_length-3)]}_2" end end - table_aliases[path] = table_alias + + table_alias + end + + def polymorphic?(relation) + relation.respond_to?(:options) && relation.options[:polymorphic] end # Returns a hash mapping obligations to zero or more condition path sets. @@ -229,12 +261,12 @@ def reflections # lets try to get the order of joins right @reflections ||= ActiveSupport::OrderedHash.new end - + # Returns a hash mapping paths to proper table aliases to use in SQL statements. def table_aliases @table_aliases ||= {} end - + # Parses all of the defined obligation conditions and defines the scope's :conditions option. def rebuild_condition_options! conds = [] @@ -244,51 +276,66 @@ def rebuild_condition_options! obligation_conditions.each_with_index do |array, obligation_index| obligation, conditions = array obligation_conds = [] + conditions.each do |path, expressions| - model = model_for( path ) - table_alias = table_alias_for(path) - parent_model = (path.length > 1 ? model_for(path[0..-2]) : top_level_model) - expressions.each do |expression| - attribute, operator, value = expression - # prevent unnecessary joins: - if attribute == :id and operator == :is and parent_model.columns_hash["#{path.last}_id"] - attribute_name = :"#{path.last}_id" - attribute_table_alias = table_alias_for(path[0..-2]) - used_paths << path[0..-2] - delete_paths << path - else - attribute_name = model.columns_hash["#{attribute}_id"] && :"#{attribute}_id" || - model.columns_hash[attribute.to_s] && attribute || - model.primary_key - attribute_table_alias = table_alias - used_paths << path - end - bindvar = "#{attribute_table_alias}__#{attribute_name}_#{obligation_index}".to_sym - - sql_attribute = "#{parent_model.connection.quote_table_name(attribute_table_alias)}." + - "#{parent_model.connection.quote_table_name(attribute_name)}" - if value.nil? and [:is, :is_not].include?(operator) - obligation_conds << "#{sql_attribute} IS #{[:contains, :is].include?(operator) ? '' : 'NOT '}NULL" - else - attribute_operator = case operator - when :contains, :is then "= :#{bindvar}" - when :does_not_contain, :is_not then "<> :#{bindvar}" - when :is_in, :intersects_with then "IN (:#{bindvar})" - when :is_not_in then "NOT IN (:#{bindvar})" - when :lt then "< :#{bindvar}" - when :lte then "<= :#{bindvar}" - when :gt then "> :#{bindvar}" - when :gte then ">= :#{bindvar}" - else raise AuthorizationUsageError, "Unknown operator: #{operator}" - end - obligation_conds << "#{sql_attribute} #{attribute_operator}" - binds[bindvar] = attribute_value(value) + models = models_for path + raise "too many models" if models.length > 1 + model = models.first + + table_alias_list = table_alias_for(path) + parent_models = (path.length > 1 ? models_for(path[0..-2]) : [top_level_model]) + parent_models.each do |parent_model| + + expressions.each do |expression| + attribute, operator, value = expression + # prevent unnecessary joins: + if attribute == :id and operator == :is and parent_model.columns_hash["#{path.last}_id"] + attribute_name = :"#{path.last}_id" + attribute_table_alias_list = table_alias_for(path[0..-2]) + used_paths << path[0..-2] + delete_paths << path + else + attribute_name = model.columns_hash["#{attribute}_id"] && :"#{attribute}_id" || + model.columns_hash[attribute.to_s] && attribute || + model.primary_key + attribute_table_alias_list = table_alias_list + used_paths << path + end + + attribute_table_alias_list.each do |attribute_table_alias| + bindvar = "#{attribute_table_alias}__#{attribute_name}_#{obligation_index}".to_sym + + sql_attribute = "#{parent_model.connection.quote_table_name(attribute_table_alias)}." + + "#{parent_model.connection.quote_table_name(attribute_name)}" + if value.nil? and [:is, :is_not].include?(operator) + obligation_conds << "#{sql_attribute} IS #{[:contains, :is].include?(operator) ? '' : 'NOT '}NULL" + else + attribute_operator = case operator + when :contains, :is then "= :#{bindvar}" + when :does_not_contain, :is_not then "<> :#{bindvar}" + when :is_in, :intersects_with then "IN (:#{bindvar})" + when :is_not_in then "NOT IN (:#{bindvar})" + when :lt then "< :#{bindvar}" + when :lte then "<= :#{bindvar}" + when :gt then "> :#{bindvar}" + when :gte then ">= :#{bindvar}" + else raise AuthorizationUsageError, "Unknown operator: #{operator}" + end + obligation_conds << "#{sql_attribute} #{attribute_operator}" + binds[bindvar] = attribute_value(value) + end + end end end end + + # remove any duplicate conditions (due to polymorphic relations) + obligation_conds.uniq! + obligation_conds << "1=1" if obligation_conds.empty? conds << "(#{obligation_conds.join(' AND ')})" end + # remove reflection paths that use a condition (delete_paths - used_paths).each {|path| reflections.delete(path)} finder_options[:conditions] = [ conds.join( " OR " ), binds ] @@ -299,15 +346,24 @@ def attribute_value (value) value.is_a?(Array) && value[0].class.respond_to?(:descends_from_active_record?) && value[0].class.descends_from_active_record? && value.map( &:id ) || value end - + # Parses all of the defined obligation joins and defines the scope's :joins or :includes option. # TODO: Support non-linear association paths. Right now, we just break down the longest path parsed. def rebuild_join_options! joins = (finder_options[:joins] || []) + (finder_options[:includes] || []) - reflections.keys.each do |path| + polymorphic_paths = {} + reflections.each do |path, refs| next if path.empty? or @join_table_joins.include?(path) + first_ref = refs.first + if polymorphic?(first_ref) + # sanity check + raise "Only one polymorphic relation is allowed at each step" if refs.length > 1 + + polymorphic_paths[path] = first_ref.active_record.poly_resource_names + end + existing_join = joins.find do |join| existing_path = join_to_path(join) min_length = [existing_path.length, path.length].min @@ -323,13 +379,41 @@ def rebuild_join_options! end end - case obligation_conditions.length - when 0 then + # construct normal joins replacing polymorphic references to the actual resources (of which there can be many) + polymorphic_paths.to_a.sort_by { |p| p.first.length }.reverse.each do |ppath, resource_names| + pjoin = path_to_join ppath + + normalised_joins = [] + joins.each do |join| + path = join_to_path join + + # check if ppath is a subset of path + if ppath == path[0, ppath.length] + resource_names.each do |resource_name| + resource_idx = ppath.length - 1 + path[resource_idx] = resource_name + normal_join = path_to_join path + + normalised_joins << normal_join + end + else + normalised_joins << join + end + end + + joins = normalised_joins + end + + conds_len = obligation_conditions.length + if conds_len == 0 # No obligation conditions means we don't have to mess with joins or includes at all. - when 1 then + elsif conds_len == 1 && polymorphic_paths.empty? + # joins in a scope are converted to inner joins finder_options[:joins] = joins finder_options.delete( :include ) else + # polymorphic paths must use left joins (include) + # include in a scope is converted to left joins finder_options.delete( :joins ) finder_options[:include] = joins end @@ -356,6 +440,15 @@ def join_to_path (join) [join.keys.first] + join_to_path(join[join.keys.first]) end end + + # Override AR Relation dynamic method finder. + # + # Afaik ObligationScope does not need to inherit the Relation + # dynamic methods. This makes debugging typos in this class + # much easier. + def method_missing(name, *args) + raise "Method #{name} does not exist" + end end end From 1ed351f7049127d217d23914f6b1df2898944b51 Mon Sep 17 00:00:00 2001 From: Chris Baynes Date: Thu, 8 Dec 2016 18:38:13 +0100 Subject: [PATCH 08/55] Do not try to generate table aliases for empty paths. --- lib/declarative_authorization/obligation_scope.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/declarative_authorization/obligation_scope.rb b/lib/declarative_authorization/obligation_scope.rb index 241f10ae..eb766e3a 100644 --- a/lib/declarative_authorization/obligation_scope.rb +++ b/lib/declarative_authorization/obligation_scope.rb @@ -216,7 +216,8 @@ def reflections_for_path(path) # Attempts to map a table alias for the given path. Raises if already defined. def map_table_alias_for( path ) - return "table alias for #{path.inspect} already exists" unless table_aliases[path].nil? + return [] if path.empty? + raise "table alias for #{path.inspect} already exists" unless table_aliases[path].nil? table_aliases[path] = reflection_for(path).map do |ref_for| if polymorphic?(ref_for) From 85f32d778ba480c18543e14d0a9fd1e9a64835f5 Mon Sep 17 00:00:00 2001 From: Chris Baynes Date: Fri, 9 Dec 2016 17:34:18 +0100 Subject: [PATCH 09/55] Join conditions on concrete polymorphisms with an OR. --- .../obligation_scope.rb | 50 ++++++++++++------- 1 file changed, 33 insertions(+), 17 deletions(-) diff --git a/lib/declarative_authorization/obligation_scope.rb b/lib/declarative_authorization/obligation_scope.rb index eb766e3a..7ae56c48 100644 --- a/lib/declarative_authorization/obligation_scope.rb +++ b/lib/declarative_authorization/obligation_scope.rb @@ -138,7 +138,7 @@ def add_obligation_condition_for( path, expression ) # Adds the given path to the list of obligation joins, if we haven't seen it before. def add_obligation_join_for( path ) - reflection_for(path) if !reflections[path].empty? + reflection_for(path) if reflections.key?(path) && !reflections[path].empty? end # Returns the model associated with the given path. @@ -277,6 +277,7 @@ def rebuild_condition_options! obligation_conditions.each_with_index do |array, obligation_index| obligation, conditions = array obligation_conds = [] + obligation_conds_poly = [] conditions.each do |path, expressions| models = models_for path @@ -285,6 +286,8 @@ def rebuild_condition_options! table_alias_list = table_alias_for(path) parent_models = (path.length > 1 ? models_for(path[0..-2]) : [top_level_model]) + parent_is_polymorphic = parent_models.length > 1 + parent_models.each do |parent_model| expressions.each do |expression| @@ -308,31 +311,44 @@ def rebuild_condition_options! sql_attribute = "#{parent_model.connection.quote_table_name(attribute_table_alias)}." + "#{parent_model.connection.quote_table_name(attribute_name)}" - if value.nil? and [:is, :is_not].include?(operator) - obligation_conds << "#{sql_attribute} IS #{[:contains, :is].include?(operator) ? '' : 'NOT '}NULL" + + obligation_cond = + if value.nil? and [:is, :is_not].include?(operator) + "#{sql_attribute} IS #{[:contains, :is].include?(operator) ? '' : 'NOT '}NULL" + else + attribute_operator = case operator + when :contains, :is then "= :#{bindvar}" + when :does_not_contain, :is_not then "<> :#{bindvar}" + when :is_in, :intersects_with then "IN (:#{bindvar})" + when :is_not_in then "NOT IN (:#{bindvar})" + when :lt then "< :#{bindvar}" + when :lte then "<= :#{bindvar}" + when :gt then "> :#{bindvar}" + when :gte then ">= :#{bindvar}" + else raise AuthorizationUsageError, "Unknown operator: #{operator}" + end + + binds[bindvar] = attribute_value(value) + "#{sql_attribute} #{attribute_operator}" + end + + if parent_is_polymorphic && attribute == :id + obligation_conds_poly << obligation_cond else - attribute_operator = case operator - when :contains, :is then "= :#{bindvar}" - when :does_not_contain, :is_not then "<> :#{bindvar}" - when :is_in, :intersects_with then "IN (:#{bindvar})" - when :is_not_in then "NOT IN (:#{bindvar})" - when :lt then "< :#{bindvar}" - when :lte then "<= :#{bindvar}" - when :gt then "> :#{bindvar}" - when :gte then ">= :#{bindvar}" - else raise AuthorizationUsageError, "Unknown operator: #{operator}" - end - obligation_conds << "#{sql_attribute} #{attribute_operator}" - binds[bindvar] = attribute_value(value) + obligation_conds << obligation_cond end end end end end - # remove any duplicate conditions (due to polymorphic relations) + # join conditions directly connecting a parent to its polymorphic children by OR + poly_conds_sql = obligation_conds_poly.empty? ? nil : "(#{obligation_conds_poly.uniq.join(' OR ')})" + + # remove any duplicate ordinary conditions (defined multiple times because of polymorphism) obligation_conds.uniq! + obligation_conds << poly_conds_sql if poly_conds_sql obligation_conds << "1=1" if obligation_conds.empty? conds << "(#{obligation_conds.join(' AND ')})" end From e98d9db15d9ebb9700b23386076f22495037dcab Mon Sep 17 00:00:00 2001 From: Chris Baynes Date: Tue, 13 Dec 2016 23:38:53 +0100 Subject: [PATCH 10/55] Simplify recursive methods, remove rails 2 support, make tests pass. --- .../obligation_scope.rb | 137 ++++++++---------- 1 file changed, 57 insertions(+), 80 deletions(-) diff --git a/lib/declarative_authorization/obligation_scope.rb b/lib/declarative_authorization/obligation_scope.rb index 7ae56c48..f2e47e79 100644 --- a/lib/declarative_authorization/obligation_scope.rb +++ b/lib/declarative_authorization/obligation_scope.rb @@ -43,6 +43,8 @@ module Authorization # @proxy_options[:conditions] = [ 'foos_bazzes.attr = :foos_bazzes__id_0', { :foos_bazzes__id_0 => 1 } ]+ # class ObligationScope < (Rails.version < "3" ? ActiveRecord::NamedScope::Scope : ActiveRecord::Relation) + attr_reader :finder_options + def initialize (model, options) @finder_options = {} if Rails.version < "3" @@ -79,23 +81,21 @@ def parse!( obligation ) # Parses the next step in the association path. If it's an association, we advance down the # path. Otherwise, it's an attribute, and we need to evaluate it as a comparison operation. - def follow_path( steps, past_steps = [] ) + def follow_path(steps, past_steps=[]) if steps.is_a?( Hash ) steps.each do |step, next_steps| path_to_this_point = [past_steps, step].flatten - reflection = reflection_for( path_to_this_point ) # fixme: rescue nil - - unless reflection.empty? - follow_path( next_steps, path_to_this_point ) - else - follow_comparison( next_steps, past_steps, step ) - end + init_reflections_for past_steps + follow_path(next_steps, path_to_this_point) + # follow_comparison( next_steps, past_steps, step ) end - elsif steps.is_a?( Array ) && steps.length == 2 - if reflection_for( past_steps ) - follow_comparison( steps, past_steps, :id ) + elsif steps.is_a?(Array) && steps.length == 2 + init_reflections_for past_steps + + if reflections_for(past_steps) + follow_comparison(steps, past_steps, :id) else - follow_comparison( steps, past_steps[0..-2], past_steps[-1] ) + follow_comparison(steps, past_steps[0..-2], past_steps[-1]) end else raise "invalid obligation path #{[past_steps, steps].inspect}" @@ -103,91 +103,53 @@ def follow_path( steps, past_steps = [] ) end def top_level_model - if Rails.version < "3" - @proxy_scope - else - self.klass - end - end - - def finder_options - Rails.version < "3" ? @proxy_options : @finder_options + klass end # At the end of every association path, we expect to see a comparison of some kind; for # example, +:attr => [ :is, :value ]+. # # This method parses the comparison and creates an obligation condition from it. - def follow_comparison( steps, past_steps, attribute ) + def follow_comparison(steps, past_steps, attribute) operator = steps[0] value = steps[1..-1] value = value[0] if value.length == 1 - add_obligation_condition_for( past_steps, [attribute, operator, value] ) + add_obligation_condition_for(past_steps, [attribute, operator, value]) end # Adds the given expression to the current obligation's indicated path's conditions. # # Condition expressions must follow the format +[ , , ]+. - def add_obligation_condition_for( path, expression ) - raise "invalid expression #{expression.inspect}" unless expression.is_a?( Array ) && expression.length == 3 - add_obligation_join_for( path ) - obligation_conditions[@current_obligation] ||= {} - ( obligation_conditions[@current_obligation][path] ||= Set.new ) << expression + def add_obligation_condition_for(path, expression) + (obligation_conditions[@current_obligation][path] ||= Set.new) << expression end - # Adds the given path to the list of obligation joins, if we haven't seen it before. - def add_obligation_join_for( path ) - reflection_for(path) if reflections.key?(path) && !reflections[path].empty? - end - - # Returns the model associated with the given path. - def models_for(path) - reflection_for(path).map do |reflection| - if Authorization.is_a_association_proxy?(reflection) - if Rails.version < "3.2" - reflection.proxy_reflection.klass - else - reflection.proxy_association.reflection.klass - end - elsif reflection.respond_to?(:klass) - if polymorphic?(reflection) - reflection.active_record.poly_resources - else - reflection.klass - end - else - reflection - end - end.flatten.uniq + def reflections_for(path) + reflections[path] end # Returns the reflection corresponding to the given path. - def reflection_for(path, for_join_table_only = false) - @join_table_joins << path if for_join_table_only and !reflections[path] - reflections[path] || map_reflection_for(path) - end - - # Returns a proper table alias for the given path. This alias may be used in SQL statements. - def table_alias_for( path ) - table_aliases[path] ||= map_table_alias_for( path ) + def init_reflections_for(path, for_join_table_only = false) + @join_table_joins << path if for_join_table_only && !reflections_for(path) + reflections_for(path) || map_reflection_for(path) end # Attempts to map a reflection for the given path. Raises if already defined. - def map_reflection_for( path ) + def map_reflection_for(path) refls_for_path = reflections_for_path path - return [] if refls_for_path.empty? + return nil if refls_for_path.empty? reflections[path] = refls_for_path - map_table_alias_for path # Claim a table alias for the path. + init_table_alias_for path # Claim a table alias for the path. # Claim alias for join table # TODO change how this is checked refls_for_path.each do |reflection| - if !Authorization.is_a_association_proxy?(reflection) and !reflection.respond_to?(:proxy_scope) and reflection.is_a?(ActiveRecord::Reflection::ThroughReflection) + if !Authorization.is_a_association_proxy?(reflection) && reflection.is_a?(ActiveRecord::Reflection::ThroughReflection) join_table_path = path[0..-2] + [reflection.options[:through]] - reflection_for(join_table_path, true) + init_reflections_for(join_table_path, true) end end @@ -199,7 +161,7 @@ def reflections_for_path(path) refls_for = reflections_for_path path[0..-2] - refls_for_path = refls_for.map.with_index do |refl_for, idx| + refls_for_path = refls_for.map do |refl_for| if polymorphic?(refl_for) refl_for.active_record.poly_resources elsif !Authorization.is_a_association_proxy?(refl_for) and refl_for.respond_to?(:klass) @@ -214,12 +176,37 @@ def reflections_for_path(path) end.compact end + # Returns the model associated with the given path. + def models_for(path) + reflections_for(path).map do |reflection| + if Authorization.is_a_association_proxy?(reflection) + if Rails.version < "3.2" + reflection.proxy_reflection.klass + else + reflection.proxy_association.reflection.klass + end + elsif reflection.respond_to?(:klass) + if polymorphic?(reflection) + reflection.active_record.poly_resources + else + reflection.klass + end + else + reflection + end + end.flatten.uniq + end + + # Returns a proper table alias for the given path. This alias may be used in SQL statements. + def table_alias_for(path) + table_aliases[path] || init_table_alias_for( path ) + end + # Attempts to map a table alias for the given path. Raises if already defined. - def map_table_alias_for( path ) - return [] if path.empty? + def init_table_alias_for( path ) raise "table alias for #{path.inspect} already exists" unless table_aliases[path].nil? - table_aliases[path] = reflection_for(path).map do |ref_for| + table_aliases[path] = reflections_for(path).map do |ref_for| if polymorphic?(ref_for) rel_name = ref_for.active_record rel_name.poly_resources.map { |res| construct_table_alias res } @@ -272,10 +259,7 @@ def table_aliases def rebuild_condition_options! conds = [] binds = {} - used_paths = Set.new - delete_paths = Set.new - obligation_conditions.each_with_index do |array, obligation_index| - obligation, conditions = array + obligation_conditions.each_with_index do |(_, conditions), obligation_index| obligation_conds = [] obligation_conds_poly = [] @@ -296,14 +280,11 @@ def rebuild_condition_options! if attribute == :id and operator == :is and parent_model.columns_hash["#{path.last}_id"] attribute_name = :"#{path.last}_id" attribute_table_alias_list = table_alias_for(path[0..-2]) - used_paths << path[0..-2] - delete_paths << path else attribute_name = model.columns_hash["#{attribute}_id"] && :"#{attribute}_id" || model.columns_hash[attribute.to_s] && attribute || model.primary_key attribute_table_alias_list = table_alias_list - used_paths << path end attribute_table_alias_list.each do |attribute_table_alias| @@ -352,8 +333,6 @@ def rebuild_condition_options! obligation_conds << "1=1" if obligation_conds.empty? conds << "(#{obligation_conds.join(' AND ')})" end - # remove reflection paths that use a condition - (delete_paths - used_paths).each {|path| reflections.delete(path)} finder_options[:conditions] = [ conds.join( " OR " ), binds ] end @@ -398,8 +377,6 @@ def rebuild_join_options! # construct normal joins replacing polymorphic references to the actual resources (of which there can be many) polymorphic_paths.to_a.sort_by { |p| p.first.length }.reverse.each do |ppath, resource_names| - pjoin = path_to_join ppath - normalised_joins = [] joins.each do |join| path = join_to_path join From 1035df3a6284a2fe0813c151b06478cc0ea839f8 Mon Sep 17 00:00:00 2001 From: Chris Baynes Date: Wed, 14 Dec 2016 10:23:16 +0100 Subject: [PATCH 11/55] Add readme specific for this branch. --- README.rdoc | 632 ---------------------------------------------------- Readme.md | 19 ++ 2 files changed, 19 insertions(+), 632 deletions(-) delete mode 100644 README.rdoc create mode 100644 Readme.md diff --git a/README.rdoc b/README.rdoc deleted file mode 100644 index e6118710..00000000 --- a/README.rdoc +++ /dev/null @@ -1,632 +0,0 @@ -= Declarative Authorization - -The declarative authorization plugin offers an authorization mechanism inspired -by _RBAC_. The most notable distinction to other authorization plugins is the -declarative approach. That is, authorization rules are not defined -programmatically in between business logic but in an authorization configuration. - -With programmatic authorization rules, the developer needs to specify which roles are -allowed to access a specific controller action or a part of a view, which is -not DRY. With a growing application code base roles' permissions often -change and new roles are introduced. Then, at several places of the source code -the changes have to be implemented, possibly leading to omissions and thus hard -to find errors. In these cases, a declarative approach as offered by decl_auth -increases the development and maintenance efficiency. - - -Plugin features -* Authorization at controller action level -* Authorization helpers for Views -* Authorization at model level - * Authorize CRUD (Create, Read, Update, Delete) activities - * Query rewriting to automatically only fetch authorized records -* DSL for specifying Authorization rules in an authorization configuration -* Support for Rails 4, with backwards compatibility through Rails 2 - - -Requirements -* An authentication mechanism - * User object in Controller#current_user - * (For model security) Setting Authorization.current_user -* User objects need to respond to a method :role_symbols that returns an - array of role symbols -See below for installation instructions. - - -There is a decl_auth screencast by Ryan Bates, nicely introducing the main concepts: -http://railscasts.com/episodes/188-declarative-authorization - - -= Quick Start - -=== Installer - -Declarative Authorization comes with an installer to make setup easy. - -First, include declarative_authorization in your gemfile. - - #! Gemfile - gem 'declarative_authorization' - -Next, bundle and install. - - $ bundle - $ rails g authorization:install [UserModel=User] [field:type field:type ...] [--create-user --commit --user-belongs-to-role] - -This installer will create a Role model, an admin and a user role, and set a -has_and_belongs_to_many relationship between the User model and the Role model. -It will also add a `role_symbols` method to the user model to meet -declarative_authorization's requirements. The default User model is User. You can override this by simply typing the name of a model as above. - -You can create the model with the fields provided by using the `--create-user` option. - -The `--commit` option will run `rake db:migrate` and `rake db:seed`. - -The `--user-belongs-to-role` option will set up a one-to-many relationship between Users and Roles. -That is, each user has a role_id column and can only have one role. Role inheritance can be used -in authorization rules. - -Finally, the installer also copies default authorization rules, as below. - -=== Generate Authorization Rules - -To copy a default set of authorization rules which includes CRUD priveleges, run: - - $ rails g authorization:rules - -This command will copy the following to `config/authorization_rules.rb`. Remember -to implement the requirements of this gem as described in the Installation section -at the end of this README if you do not use the above installer. - - authorization do - role :guest do - # add permissions for guests here, e.g. - # has_permission_on :conferences, :to => :read - end - - # permissions on other roles, such as - # role :admin do - # has_permission_on :conferences, :to => :manage - # end - # role :user do - # has_permission_on :conferences, :to => [:read, :create] - # has_permission_on :conferences, :to => [:update, :delete] do - # if_attribute :user_id => is {user.id} - # end - # end - # See the readme or GitHub for more examples - end - - privileges do - # default privilege hierarchies to facilitate RESTful Rails apps - privilege :manage, :includes => [:create, :read, :update, :delete] - privilege :create, :includes => :new - privilege :read, :includes => [:index, :show] - privilege :update, :includes => :edit - privilege :delete, :includes => :destroy - end - -=== Controller Authorization - -For RESTful controllers, add `filter_resource_access`: - - class MyRestfulController < ApplicationController - filter_resource_access - ... - end - -For a non-RESTful controller, you can use `filter_access_to`: - - class MyOtherController < ApplicationController - filter_access_to :all - # or a group: filter_access_to [:action1, :action2] - ... - end - -=== View Authorization - -Declarative Authorization will use `current_user` to check authorization. - - <%= link_to 'Edit Post', edit_post_path(@post) if permitted_to? :update, @post %> - - -= Authorization Data Model - - ----- App domain ----|-------- Authorization conf ---------|------- App domain ------ - - includes includes - .--. .---. - | v | v - .------. can_play .------. has_permission .------------. requires .----------. - | User |----------->| Role |----------------->| Permission |<-----------| Activity | - '------' * * '------' * * '------------' 1 * '----------' - | - .-------+------. - 1 / | 1 \ * - .-----------. .---------. .-----------. - | Privilege | | Context | | Attribute | - '-----------' '---------' '-----------' - -In the application domain, each *User* may be assigned to *Roles* that should -define the users' job in the application, such as _Administrator_. On the -right-hand side of this diagram, application developers specify which *Permissions* -are necessary for users to perform activities, such as calling a controller action, -viewing parts of a View or acting on records in the database. Note that -Permissions consist of an *Privilege* that is to be performed, such as _read_, -and a *Context* in that the Operation takes place, such as _companies_. - -In the authorization configuration, Permissions are assigned to Roles and Role -and Permission hierarchies are defined. *Attributes* may be employed to allow -authorization according to dynamic information about the context and the -current user, e.g. "only allow access on employees that belong to the -current user's branch." - - -= Examples - -A fully functional example application can be found at -http://github.com/stffn/decl_auth_demo_app - -Details on the demonstrated methods can be found in the API docs, either -generated by yourself or at http://www.tzi.org/~sbartsch/declarative_authorization - -== Controller - -If authentication is in place, there are two ways to enable user-specific -access control on controller actions. For resource controllers, which more -or less follow the CRUD pattern, +filter_resource_access+ is the simplest -approach. It sets up instance variables in before filters and calls -filter_access_to with the appropriate parameters to protect the CRUD methods. - - class EmployeesController < ApplicationController - filter_resource_access - ... - end - -See Authorization::AuthorizationInController::ClassMethods for options on -nested resources and custom member and collection actions. - -By default, declarative_authorization will enable filter_resource_access compatibility with strong_parameters in Rails 4. If you want to disable this behavior, you can use the `:strong_parameters` option. - - class EmployeesController < ApplicationController - filter_resource_access :strong_parameters => false - ... - end - -Simalarly, you can use `:strong_parameters => true` if you are using strong_parameters in Rails 3. - -If you prefer less magic or your controller has no resemblance with the resource -controllers, directly calling filter_access_to may be the better option. Examples -are given in the following. E.g. the privilege index users is required for -action index. This works as a first default configuration for RESTful -controllers, with these privileges easily handled in the authorization -configuration, which will be described below. - - class EmployeesController < ApplicationController - filter_access_to :all - def index - ... - end - ... - end - -When custom actions are added to such a controller, it helps to define more -clearly which privileges are the respective requirements. That is when the -filter_access_to call may become more verbose: - - class EmployeesController < ApplicationController - filter_access_to :all - # this one would be included in :all, but :read seems to be - # a more suitable privilege than :auto_complete_for_user_name - filter_access_to :auto_complete_for_employee_name, :require => :read - def auto_complete_for_employee_name - ... - end - ... - end - -For some actions it might be necessary to check certain attributes of the -object the action is to be acting on. Then, the object needs to be loaded -before the action's access control is evaluated. On the other hand, some actions -might prefer the authorization to ignore specific attribute checks as the object is -unknown at checking time, so attribute checks and thus automatic loading of -objects needs to be enabled explicitly. - - class EmployeesController < ApplicationController - filter_access_to :update, :attribute_check => true - def update - # @employee is already loaded from param[:id] because of :attribute_check - end - end - -You can provide the needed object through before_filters. This way, you have -full control over the object that the conditions are checked against. Just make -sure, your before_filters occur before any of the filter_access_to calls. - - class EmployeesController < ApplicationController - before_filter :new_employee_from_params, :only => :create - before_filter :new_employee, :only => [:index, :new] - filter_access_to :all, :attribute_check => true - - def create - @employee.save! - end - - protected - def new_employee_from_params - @employee = Employee.new(params[:employee]) - end - end - -If the access is denied, a +permission_denied+ method is called on the -current_controller, if defined, and the issue is logged. -For further customization of the filters and object loading, have a look at -the complete API documentation of filter_access_to in -Authorization::AuthorizationInController::ClassMethods. - - -== Views - -In views, a simple permitted_to? helper makes showing blocks according to the -current user's privileges easy: - - <% permitted_to? :create, :employees do %> - <%= link_to 'New', new_employee_path %> - <% end %> - -Only giving a symbol :employees as context prevents any checks of attributes -as there is no object to check against. For example, in case of nested resources -a new object may come in handy: - - <% permitted_to? :create, Branch.new(:company => @company) do - # or @company.branches.new - # or even @company.branches %> - <%= link_to 'New', new_company_branch_path(@company) %> - <% end %> - -Lists are straight-forward: - - <% for employee in @employees %> - <%= link_to 'Edit', edit_employee_path(employee) if permitted_to? :update, employee %> - <% end %> - -See also Authorization::AuthorizationHelper. - - -== Models - -There are two distinct features for model security built into this plugin: -authorizing CRUD operations on objects as well as query rewriting to limit -results according to certain privileges. - -See also Authorization::AuthorizationInModel. - -=== Model security for CRUD operations -To activate model security, all it takes is an explicit enabling for each -model that model security should be enforced on, i.e. - - class Employee < ActiveRecord::Base - using_access_control - ... - end - -Thus, - Employee.create(...) -fails, if the current user is not allowed to :create :employees according -to the authorization rules. For the application to find out about what -happened if an operation is denied, the filters throw -Authorization::NotAuthorized exceptions. - -As access control on read are costly, with possibly lots of objects being -loaded at a time in one query, checks on read need to be activated explicitly by -adding the :include_read option. - -=== Query rewriting through named scopes -When retrieving large sets of records from databases, any authorization needs -to be integrated into the query in order to prevent inefficient filtering -afterwards and to use LIMIT and OFFSET in SQL statements. To keep authorization -rules out of the source code, this plugin offers query rewriting mechanisms -through named scopes. Thus, - - Employee.with_permissions_to(:read) - -returns all employee records that the current user is authorized to read. In -addition, just like normal named scopes, query rewriting may be chained with -the usual find method: - - Employee.with_permissions_to(:read).find(:all, :conditions => ...) - -If the current user is completely missing the permissions, an -Authorization::NotAuthorized exception is raised. Through -Model.obligation_conditions, application developers may retrieve -the conditions for manual rewrites. - - -== Authorization Rules - -Authorization rules are defined in config/authorization_rules.rb -(Or redefine rules files path via +Authorization::AUTH_DSL_FILES+). E.g. - - authorization do - role :admin do - has_permission_on :employees, :to => [:create, :read, :update, :delete] - end - end - -There is a default role :+guest+ that is used if a request is not associated -with any user or with a user without any roles. So, if your application has -public pages, :+guest+ can be used to allow access for users that are not -logged in. All other roles are application defined and need to be associated -with users by the application. - -If you need to change the default role, you can do so by adding an initializer -that contains the following statement: - - Authorization.default_role = :anonymous - -Privileges, such as :create, may be put into hierarchies to simplify -maintenance. So the example above has the same meaning as - - authorization do - role :admin do - has_permission_on :employees, :to => :manage - end - end - - privileges do - privilege :manage do - includes :create, :read, :update, :delete - end - end - -Privilege hierarchies may be context-specific, e.g. applicable to :employees. - - privileges do - privilege :manage, :employees, :includes => :increase_salary - end - -For more complex use cases, authorizations need to be based on attributes. Note -that you then also need to set :attribute_check => true in controllers for filter_access_to. -E.g. if a branch admin should manage only employees of his branch (see -Authorization::Reader in the API docs for a full list of available operators): - - authorization do - role :branch_admin do - has_permission_on :employees do - to :manage - # user refers to the current_user when evaluating - if_attribute :branch => is {user.branch} - end - end - end - -To reduce redundancy in has_permission_on blocks, a rule may depend on -permissions on associated objects: - - authorization do - role :branch_admin do - has_permission_on :branches, :to => :manage do - if_attribute :managers => contains {user} - end - - has_permission_on :employees, :to => :manage do - if_permitted_to :manage, :branch - # instead of - #if_attribute :branch => {:managers => contains {user}} - end - end - end - -Lastly, not only privileges may be organized in a hierarchy but roles as well. -Here, project manager inherit the permissions of employees. - - role :project_manager do - includes :employee - end - -See also Authorization::Reader. - -== Testing - -declarative_authorization provides a few helpers to ease the testing with -authorization in mind. - -In your test_helper.rb, to enable the helpers add - - require 'declarative_authorization/maintenance' - - class Test::Unit::TestCase - include Authorization::TestHelper - ... - end - -For using the test helpers with RSpec, just add the following lines to your -spec_helper.rb (somewhere after require 'spec/rails'): - - require 'declarative_authorization/maintenance' - include Authorization::TestHelper - -Now, in unit tests, you may deactivate authorization if needed e.g. for test -setup and assume certain identities for tests: - - class EmployeeTest < ActiveSupport::TestCase - def test_should_read - without_access_control do - Employee.create(...) - end - assert_nothing_raised do - with_user(admin) do - Employee.find(:first) - end - end - end - end - -Or, with RSpec, it would work like this: - - describe Employee do - it "should read" do - without_access_control do - Employee.create(...) - end - with_user(admin) do - Employee.find(:first) - end - end - end - -In functional tests, get, posts, etc. may be tested in the name of certain users: - - get_with admin, :index - post_with admin, :update, :employee => {...} - -See Authorization::TestHelper for more information. - - -= Installation of declarative_authorization - -One of three options to install the plugin: -* Install by Gem: Add to your environment.rb in the initializer block: - config.gem "declarative_authorization" - Note: you need gemcutter support in place, i.e. call - gem install gemcutter - gem tumble - And call from your application's root directory - rake gems:install -* Alternativelyi, in Rails 2, to install from github, execute in your application's root directory - cd vendor/plugins && git clone git://github.com/stffn/declarative_authorization.git - -Then, -* provide the requirements as noted below, -* create a basic config/authorization_rules.rb--you might want to take the - provided example authorization_rules.dist.rb in the plugin root as a starting - point, -* add +filter_access_to+, +permitted_to+? and model security as needed. - -== Providing the Plugin's Requirements -The requirements are -* Rails >= 2.2, including 3 and Ruby >= 1.8.6, including 1.9 -* An authentication mechanism -* A user object returned by Controller#current_user -* An array of role symbols returned by User#role_symbols -* (For model security) Setting Authorization.current_user to the request's user - -Of the various ways to provide these requirements, here is one way employing -restful_authentication. - -* Install restful_authentication - cd vendor/plugins && git clone git://github.com/technoweenie/restful-authentication.git restful_authentication - cd ../.. && ruby script/generate authenticated user sessions -* Move "include AuthenticatedSystem" to ApplicationController -* Add +filter_access_to+ calls as described above. -* If you'd like to use model security, add a before_filter that sets the user - globally to your ApplicationController. This is thread-safe. - before_filter :set_current_user - protected - def set_current_user - Authorization.current_user = current_user - end - -* Add roles field to the User model through a :+has_many+ association - (this is just one possible approach; you could just as easily use - :+has_many+ :+through+ or a serialized roles array): - * create a migration for table roles - class CreateRoles < ActiveRecord::Migration - def self.up - create_table "roles" do |t| - t.column :title, :string - t.references :user - end - end - - def self.down - drop_table "roles" - end - end - - * create a model Role, - class Role < ActiveRecord::Base - belongs_to :user - end - - * add +has_many+ :+roles+ to the User model and a roles method that returns the roles - as an Array of Symbols, e.g. - class User < ActiveRecord::Base - has_many :roles - def role_symbols - (roles || []).map {|r| r.title.to_sym} - end - end - - * add roles to your User objects using e.g. - user.roles.create(:title => "admin") - -Note: If you choose to generate an Account model for restful_authentication -instead of a User model as described above, you have to customize the -examples and create a ApplicationController#current_user method. - - -== Debugging Authorization - -Currently, the main means of debugging authorization decisions is logging and -exceptions. Denied access to actions is logged to +warn+ or +info+, including -some hints about what went wrong. - -All bang methods throw exceptions which may be used to retrieve more -information about a denied access than a Boolean value. - - -== Authorization Development Support - -If your authorization rules become more complex, you might be glad to use -the authorization rules browser that comes with declarative_authorization. -It has a syntax-highlighted and a graphical view with filtering of the current -authorization rules. - -By default, it will only be available in development mode. To use it, add -the following lines to your authorization_rules.rb for the appropriate role: - - has_permission_on :authorization_rules, :to => :read - -Then, point your browser to - http://localhost/authorization_rules - -The browser needs Rails 2.3 (for Engine support). The graphical view requires -Graphviz (which e.g. can be installed through the graphviz package under Debian -and Ubuntu) and has only been tested under Linux. Note: for Change Support -you'll need to have a User#login method that returns a non-ambiguous user -name for identification. - - -= Help and Contact - -We have an issue tracker[http://github.com/stffn/declarative_authorization/issues] -for bugs and feature requests as well as a -Google Group[http://groups.google.com/group/declarative_authorization] for -discussions on the usage of the plugin. You are very welcome to contribute. -Just fork the git repository and create a new issue, send a pull request or -contact me personally. - -Maintained by - -Steffen Bartsch -TZI, Universität Bremen, Germany -sbartsch at tzi.org - - -= Contributors - -Thanks to John Joseph Bachir, Dennis Blöte, Eike Carls, Damian Caruso, Kai Chen, Erik Dahlstrand, -Jeroen van Dijk, Alexander Dobriakov, Sebastian Dyck, Ari Epstein, Jeremy Friesen, -Tim Harper, John Hawthorn, hollownest, Daniel Kristensen, Jeremy Kleindl, Joel Kociolek, -Benjamin ter Kuile, Brad Langhorst, Brian Langenfeld, -Georg Ledermann, Geoff Longman, Olly Lylo, Mark Mansour, Thomas Maurer, Kevin Moore, -Tyler Pickett, Edward Rudd, Sharagoz, -TJ Singleton, Mike Vincent, Joel Westerberg - - -= License - -Copyright (c) 2008 Steffen Bartsch, TZI, Universität Bremen, Germany -released under the MIT license - diff --git a/Readme.md b/Readme.md new file mode 100644 index 00000000..8ad3dcc2 --- /dev/null +++ b/Readme.md @@ -0,0 +1,19 @@ +Original docs: [https://github.com/stffn/declarative_authorization/blob/master/README.rdoc](https://github.com/stffn/declarative_authorization/blob/master/README.rdoc) + +### Polymorphic associations + +This branch contains polymorphic belongs_to association support. +It relies on a monkey patch to active record which provides the method `poly_resources` +that returns a list of classes that the polymorphic association can point to. + + +### Running tests for DA + +``` +cp gemfiles/3.2.gemfile Gemfile +bundle + +bundle exec rake test +``` + + From 843ffd043f904e5a741eb9c995f0612b1c4b6f14 Mon Sep 17 00:00:00 2001 From: Aaron Huntsman Date: Thu, 26 Jan 2017 11:16:46 -0500 Subject: [PATCH 12/55] pickle test --- test/model_test.rb | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/test/model_test.rb b/test/model_test.rb index ffdd941d..e927ee70 100644 --- a/test/model_test.rb +++ b/test/model_test.rb @@ -774,6 +774,31 @@ def test_with_deep_attribute TestAttr.delete_all end + def test_with_pickle + reader = Authorization::Reader::DSLReader.new + reader.parse %{ + authorization do + role :test_role do + has_permission_on :test_attrs, :to => :read do + if_attribute :test_model => {:content => is { "pickle" } } + end + end + end + } + Authorization::Engine.instance(reader) + + test_model_1 = TestModel.create!(content: "pickle") + test_model_1.test_attrs.create! + TestModel.create!.test_attrs.create! + + user = MockUser.new(:test_role, :test_model_id => test_model_1.id) + assert_equal 1, TestAttr.with_permissions_to(:read, + :context => :test_attrs, :user => user).length + + TestModel.delete_all + TestAttr.delete_all + end + def test_with_anded_rules reader = Authorization::Reader::DSLReader.new reader.parse %{ From beaafa9a6dec6d6f387d8e2fbd6d276b000744f1 Mon Sep 17 00:00:00 2001 From: Aaron Huntsman Date: Thu, 26 Jan 2017 11:43:24 -0500 Subject: [PATCH 13/55] BUGFIX: Account for no implicit join references in Rails 4.1 --- lib/declarative_authorization/obligation_scope.rb | 2 +- test/model_test.rb | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/declarative_authorization/obligation_scope.rb b/lib/declarative_authorization/obligation_scope.rb index a4db8a78..d1d3008f 100644 --- a/lib/declarative_authorization/obligation_scope.rb +++ b/lib/declarative_authorization/obligation_scope.rb @@ -60,7 +60,7 @@ def scope self.klass.scoped(@finder_options) else # TODO Refactor this. There is certainly a better way. - self.klass.joins(@finder_options[:joins]).includes(@finder_options[:include]).where(@finder_options[:conditions]) + self.klass.joins(@finder_options[:joins]).includes(@finder_options[:include]).where(@finder_options[:conditions]).references(@finder_options[:include]) end end diff --git a/test/model_test.rb b/test/model_test.rb index e927ee70..f30ada5f 100644 --- a/test/model_test.rb +++ b/test/model_test.rb @@ -774,13 +774,14 @@ def test_with_deep_attribute TestAttr.delete_all end - def test_with_pickle + def test_with_multiple_conditions reader = Authorization::Reader::DSLReader.new reader.parse %{ authorization do role :test_role do has_permission_on :test_attrs, :to => :read do if_attribute :test_model => {:content => is { "pickle" } } + if_attribute :test_model => {:content => is { "hotdog" } } end end end From 6f49f5e04646243f574a804cfe3d51cfd66924ba Mon Sep 17 00:00:00 2001 From: Daniel Becker Date: Fri, 3 Feb 2017 16:38:00 +0100 Subject: [PATCH 14/55] Ensure no read-only records are returned when involving DA scopes. --- lib/declarative_authorization/obligation_scope.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/declarative_authorization/obligation_scope.rb b/lib/declarative_authorization/obligation_scope.rb index f2e47e79..909543d8 100644 --- a/lib/declarative_authorization/obligation_scope.rb +++ b/lib/declarative_authorization/obligation_scope.rb @@ -59,7 +59,7 @@ def scope self elsif Rails.version < "4" # for Rails < 4: use scoped method - self.klass.scoped(@finder_options) + self.klass.scoped(@finder_options.merge(readonly: false)) else # TODO Refactor this. There is certainly a better way. self.klass.joins(@finder_options[:joins]).includes(@finder_options[:include]).where(@finder_options[:conditions]) From 90202de7b6a8e51b3e2790fea53361fb9fc6dfeb Mon Sep 17 00:00:00 2001 From: Daniel Becker Date: Thu, 11 May 2017 11:01:09 +0200 Subject: [PATCH 15/55] Fix return of readonly records for rails 4. --- lib/declarative_authorization/obligation_scope.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/declarative_authorization/obligation_scope.rb b/lib/declarative_authorization/obligation_scope.rb index 909543d8..a77c8178 100644 --- a/lib/declarative_authorization/obligation_scope.rb +++ b/lib/declarative_authorization/obligation_scope.rb @@ -62,7 +62,7 @@ def scope self.klass.scoped(@finder_options.merge(readonly: false)) else # TODO Refactor this. There is certainly a better way. - self.klass.joins(@finder_options[:joins]).includes(@finder_options[:include]).where(@finder_options[:conditions]) + self.klass.joins(@finder_options[:joins]).includes(@finder_options[:include]).where(@finder_options[:conditions]).readonly(false) end end From 761b1dd0b24695be0b897c26ca544371cbeebd8a Mon Sep 17 00:00:00 2001 From: Daniel Becker Date: Thu, 11 May 2017 11:05:33 +0200 Subject: [PATCH 16/55] Fix handling of activerecord relations. --- .../obligation_scope.rb | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/lib/declarative_authorization/obligation_scope.rb b/lib/declarative_authorization/obligation_scope.rb index a77c8178..5e423ccf 100644 --- a/lib/declarative_authorization/obligation_scope.rb +++ b/lib/declarative_authorization/obligation_scope.rb @@ -338,9 +338,21 @@ def rebuild_condition_options! end def attribute_value (value) - value.class.respond_to?(:descends_from_active_record?) && value.class.descends_from_active_record? && value.id || - value.is_a?(Array) && value[0].class.respond_to?(:descends_from_active_record?) && value[0].class.descends_from_active_record? && value.map( &:id ) || - value + value_record?(value) && value.id || + (value_array?(value) || value_relation?(value)) && value.to_a.map( &:id ) || + value + end + + def value_record?(value) + value.class.respond_to?(:descends_from_active_record?) && value.class.descends_from_active_record? + end + + def value_array?(value) + value.is_a?(Array) && value[0].class.respond_to?(:descends_from_active_record?) && value[0].class.descends_from_active_record? + end + + def value_relation?(value) + value.is_a?(ActiveRecord::Relation) end # Parses all of the defined obligation joins and defines the scope's :joins or :includes option. From 97fc010fefb074060a862fb9cbe566747f655c51 Mon Sep 17 00:00:00 2001 From: Daniel Becker Date: Mon, 15 May 2017 14:10:06 +0200 Subject: [PATCH 17/55] Fix scoped query for rails 4.1. --- lib/declarative_authorization/obligation_scope.rb | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/declarative_authorization/obligation_scope.rb b/lib/declarative_authorization/obligation_scope.rb index 5e423ccf..eb935854 100644 --- a/lib/declarative_authorization/obligation_scope.rb +++ b/lib/declarative_authorization/obligation_scope.rb @@ -62,7 +62,11 @@ def scope self.klass.scoped(@finder_options.merge(readonly: false)) else # TODO Refactor this. There is certainly a better way. - self.klass.joins(@finder_options[:joins]).includes(@finder_options[:include]).where(@finder_options[:conditions]).readonly(false) + self.klass.joins(@finder_options[:joins]). + includes(@finder_options[:include]). + where(@finder_options[:conditions]). + references(@finder_options[:include]). + readonly(false) end end From 13f0ee2569845cb7c3e8e161161218514b04a1ee Mon Sep 17 00:00:00 2001 From: Anna Date: Wed, 13 Jul 2016 13:28:20 -0400 Subject: [PATCH 18/55] allow for testsing rails 4.2 --- declarative_authorization.gemspec | 2 +- gemfiles/4.2.gemfile | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) create mode 100644 gemfiles/4.2.gemfile diff --git a/declarative_authorization.gemspec b/declarative_authorization.gemspec index 055e19ca..b284b968 100644 --- a/declarative_authorization.gemspec +++ b/declarative_authorization.gemspec @@ -13,6 +13,6 @@ Gem::Specification.new do |s| s.extra_rdoc_files = ['README.rdoc', 'CHANGELOG'] s.homepage = %q{http://github.com/stffn/declarative_authorization} s.add_dependency('ruby_parser', '~> 3.6.6') - s.add_dependency('rails', '>= 4.0.0', '< 4.2.0') + s.add_dependency('rails', '>= 4.0.0', '< 4.3.0') s.add_development_dependency('test-unit') end diff --git a/gemfiles/4.2.gemfile b/gemfiles/4.2.gemfile new file mode 100644 index 00000000..a9d60ab6 --- /dev/null +++ b/gemfiles/4.2.gemfile @@ -0,0 +1,6 @@ +source 'https://rubygems.org' + +gem 'rails', '~> 4.2.0' +gem 'sqlite3' +gem 'rdoc' +gemspec :path => '..' From 747e960b23853fb7615c744d8da2a29f067cb96a Mon Sep 17 00:00:00 2001 From: Anna Date: Fri, 7 Jul 2017 17:09:02 -0400 Subject: [PATCH 19/55] Added Testing for Rails 4.2 removed testing for Rails <4.1, ruby <2.2 --- .travis.yml | 8 +--- declarative_authorization.gemspec | 4 +- gemfiles/3.2.gemfile | 7 --- gemfiles/4.0.gemfile | 7 --- test/controller_test.rb | 75 ++++++++++++++++++------------- 5 files changed, 46 insertions(+), 55 deletions(-) delete mode 100644 gemfiles/3.2.gemfile delete mode 100644 gemfiles/4.0.gemfile diff --git a/.travis.yml b/.travis.yml index 3344cc47..56b2d550 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,13 +1,7 @@ language: ruby script: bundle exec rake test rvm: - - 2.0 - - 2.1 - 2.2 gemfile: - - gemfiles/4.0.gemfile - gemfiles/4.1.gemfile -matrix: - exclude: - - rvm: 2.0.0 - gemfile: gemfiles/4.1.gemfile + - gemfiles/4.2.gemfile diff --git a/declarative_authorization.gemspec b/declarative_authorization.gemspec index b284b968..d43508ba 100644 --- a/declarative_authorization.gemspec +++ b/declarative_authorization.gemspec @@ -4,7 +4,7 @@ Gem::Specification.new do |s| s.name = "declarative_authorization" s.version = "1.0.0.pre" - s.required_ruby_version = ">= 2.0.0" + s.required_ruby_version = ">= 2.2.0" s.authors = ["Steffen Bartsch"] s.summary = "declarative_authorization is a Rails plugin for maintainable authorization based on readable authorization rules." s.email = "sbartsch@tzi.org" @@ -13,6 +13,6 @@ Gem::Specification.new do |s| s.extra_rdoc_files = ['README.rdoc', 'CHANGELOG'] s.homepage = %q{http://github.com/stffn/declarative_authorization} s.add_dependency('ruby_parser', '~> 3.6.6') - s.add_dependency('rails', '>= 4.0.0', '< 4.3.0') + s.add_dependency('rails', '>= 4.1.0', '< 4.3.0') s.add_development_dependency('test-unit') end diff --git a/gemfiles/3.2.gemfile b/gemfiles/3.2.gemfile deleted file mode 100644 index 939a6b89..00000000 --- a/gemfiles/3.2.gemfile +++ /dev/null @@ -1,7 +0,0 @@ -source 'https://rubygems.org' - -gem 'rails', '~> 3.2.0' -gem 'sqlite3' -gem 'rdoc' -gemspec :path => '..' - diff --git a/gemfiles/4.0.gemfile b/gemfiles/4.0.gemfile deleted file mode 100644 index 5de2126d..00000000 --- a/gemfiles/4.0.gemfile +++ /dev/null @@ -1,7 +0,0 @@ -source 'https://rubygems.org' - -gem 'rails', '~> 4.0.0' -gem 'sqlite3' -gem 'rdoc' -gemspec :path => '..' - diff --git a/test/controller_test.rb b/test/controller_test.rb index 3cbe678c..ddf7a2da 100644 --- a/test/controller_test.rb +++ b/test/controller_test.rb @@ -8,6 +8,17 @@ def self.name end ################## + +class ActionController::Base + class << self + def before_actions + filters = _process_action_callbacks.select { |c| c.kind == :before } + filters.map! { |c| c.raw_filter } + end + alias_method :before_filters, :before_actions + end +end + class SpecificMocksController < MocksController filter_access_to :test_action, :require => :test, :context => :permissions filter_access_to :test_action_2, :require => :test, :context => :permissions_2 @@ -16,7 +27,7 @@ class SpecificMocksController < MocksController filter_access_to :edit_2, :require => :test, :context => :permissions, :attribute_check => true, :model => LoadMockObject filter_access_to :new, :require => :test, :context => :permissions - + filter_access_to [:action_group_action_1, :action_group_action_2] define_action_methods :test_action, :test_action_2, :show, :edit, :create, :edit_2, :new, :unprotected_action, :action_group_action_1, :action_group_action_2 @@ -24,7 +35,7 @@ class SpecificMocksController < MocksController class BasicControllerTest < ActionController::TestCase tests SpecificMocksController - + def test_filter_access_to_receiving_an_explicit_array reader = Authorization::Reader::DSLReader.new @@ -43,10 +54,10 @@ def test_filter_access_to_receiving_an_explicit_array request!(nil, "action_group_action_2", reader) assert !@controller.authorized? end - + def test_filter_access assert !@controller.class.before_filters.empty? - + reader = Authorization::Reader::DSLReader.new reader.parse %{ authorization do @@ -56,21 +67,21 @@ def test_filter_access end end } - + request!(MockUser.new(:test_role), "test_action", reader) assert @controller.authorized? - + request!(MockUser.new(:test_role), "test_action_2", reader) assert !@controller.authorized? - + request!(MockUser.new(:test_role_2), "test_action", reader) assert_response :forbidden assert !@controller.authorized? - + request!(MockUser.new(:test_role), "show", reader) assert @controller.authorized? end - + def test_filter_access_multi_actions reader = Authorization::Reader::DSLReader.new reader.parse %{ @@ -79,11 +90,11 @@ def test_filter_access_multi_actions has_permission_on :permissions, :to => :test end end - } + } request!(MockUser.new(:test_role), "create", reader) assert @controller.authorized? end - + def test_filter_access_unprotected_actions reader = Authorization::Reader::DSLReader.new reader.parse %{ @@ -113,7 +124,7 @@ def test_filter_access_priv_hierarchy request!(MockUser.new(:test_role), "show", reader) assert @controller.authorized? end - + def test_filter_access_skip_attribute_test reader = Authorization::Reader::DSLReader.new reader.parse %{ @@ -128,7 +139,7 @@ def test_filter_access_skip_attribute_test request!(MockUser.new(:test_role), "new", reader) assert @controller.authorized? end - + def test_existing_instance_var_remains_unchanged reader = Authorization::Reader::DSLReader.new reader.parse %{ @@ -144,7 +155,7 @@ def test_existing_instance_var_remains_unchanged @controller.send(:instance_variable_set, :"@load_mock_object", mock_object) request!(MockUser.new(:test_role), "edit_2", reader) - assert_equal mock_object, + assert_equal mock_object, @controller.send(:instance_variable_get, :"@load_mock_object") assert @controller.authorized? end @@ -183,13 +194,13 @@ def test_filter_access_all end end } - + request!(MockUser.new(:test_role), "show", reader) assert @controller.authorized? - + request!(MockUser.new(:test_role), "view", reader) assert @controller.authorized? - + request!(MockUser.new(:test_role_2), "show", reader) assert !@controller.authorized? end @@ -223,7 +234,7 @@ def self.load_method_call_count end class LoadObjectControllerTest < ActionController::TestCase tests LoadMockObjectsController - + def test_filter_access_with_object_load reader = Authorization::Reader::DSLReader.new reader.parse %{ @@ -236,14 +247,14 @@ def test_filter_access_with_object_load end end } - + request!(MockUser.new(:test_role), "show", reader, :id => 2) assert !@controller.authorized? - + request!(MockUser.new(:test_role), "show", reader, :id => 1, :clear => [:@load_mock_object]) assert @controller.authorized? - + request!(MockUser.new(:test_role), "edit", reader, :id => 1, :clear => [:@load_mock_object]) assert @controller.authorized? @@ -265,7 +276,7 @@ def test_filter_access_object_load_without_param assert_raise StandardError, "No id param supplied" do request!(MockUser.new(:test_role), "show", reader) end - + Authorization::AuthorizationInController.failed_auto_loading_is_not_found = false assert_nothing_raised "Load error is only logged" do request!(MockUser.new(:test_role), "show", reader) @@ -273,7 +284,7 @@ def test_filter_access_object_load_without_param assert !@controller.authorized? Authorization::AuthorizationInController.failed_auto_loading_is_not_found = true end - + def test_filter_access_with_object_load_custom reader = Authorization::Reader::DSLReader.new reader.parse %{ @@ -291,14 +302,14 @@ def test_filter_access_with_object_load_custom end end } - + request!(MockUser.new(:test_role), "delete", reader) assert !@controller.authorized? - + request!(MockUser.new(:test_role), "view", reader) assert @controller.authorized? assert_equal 1, @controller.class.load_method_call_count - + request!(MockUser.new(:test_role_2), "view", reader) assert !@controller.authorized? assert_equal 1, @controller.class.load_method_call_count @@ -306,7 +317,7 @@ def test_filter_access_with_object_load_custom request!(MockUser.new(:test_role), "update", reader) assert @controller.authorized? end - + def test_filter_access_custom reader = Authorization::Reader::DSLReader.new reader.parse %{ @@ -319,10 +330,10 @@ def test_filter_access_custom end end } - + request!(MockUser.new(:test_role), "create", reader) assert @controller.authorized? - + request!(MockUser.new(:test_role_2), "create", reader) assert !@controller.authorized? end @@ -331,7 +342,7 @@ def test_filter_access_custom ################## class AccessOverwritesController < MocksController - filter_access_to :test_action, :test_action_2, + filter_access_to :test_action, :test_action_2, :require => :test, :context => :permissions_2 filter_access_to :test_action, :require => :test, :context => :permissions define_action_methods :test_action, :test_action_2 @@ -348,7 +359,7 @@ def test_filter_access_overwrite } request!(MockUser.new(:test_role), "test_action_2", reader) assert !@controller.authorized? - + request!(MockUser.new(:test_role), "test_action", reader) assert @controller.authorized? end @@ -362,7 +373,7 @@ class PeopleController < MocksController end class PluralizationControllerTest < ActionController::TestCase tests PeopleController - + def test_filter_access_people_controller reader = Authorization::Reader::DSLReader.new reader.parse %{ From 47a726aaf9d6d0c871681ab26137c2b9eaadafa2 Mon Sep 17 00:00:00 2001 From: Anna Date: Thu, 20 Jul 2017 11:54:13 -0400 Subject: [PATCH 20/55] Remove code related to rails <=4.0 --- README.rdoc | 74 +++--- config/routes.rb | 8 - lib/declarative_authorization.rb | 6 - .../adapters/active_record.rb | 4 - .../authorization.rb | 8 +- .../in_controller.rb | 3 +- lib/declarative_authorization/in_model.rb | 77 ++---- .../obligation_scope.rb | 33 +-- lib/declarative_authorization/rails_legacy.rb | 22 -- test/authorization_test.rb | 2 + .../controller_filter_resource_access_test.rb | 96 ++++---- test/helper_test.rb | 2 +- test/model_test.rb | 222 ++++-------------- test/test_helper.rb | 175 ++++---------- 14 files changed, 206 insertions(+), 526 deletions(-) delete mode 100644 lib/declarative_authorization/rails_legacy.rb diff --git a/README.rdoc b/README.rdoc index 5c6ce747..97f45795 100644 --- a/README.rdoc +++ b/README.rdoc @@ -1,6 +1,6 @@ = Declarative Authorization -The declarative authorization plugin offers an authorization mechanism inspired +The declarative authorization plugin offers an authorization mechanism inspired by _RBAC_. The most notable distinction to other authorization plugins is the declarative approach. That is, authorization rules are not defined programmatically in between business logic but in an authorization configuration. @@ -21,11 +21,11 @@ Plugin features * Authorize CRUD (Create, Read, Update, Delete) activities * Query rewriting to automatically only fetch authorized records * DSL for specifying Authorization rules in an authorization configuration -* Support for Rails 4, with backwards compatibility through Rails 2 +* Support for Rails 4.1-2 Requirements -* An authentication mechanism +* An authentication mechanism * User object in Controller#current_user * (For model security) Setting Authorization.current_user * User objects need to respond to a method :role_symbols that returns an @@ -83,7 +83,7 @@ at the end of this README if you do not use the above installer. # add permissions for guests here, e.g. # has_permission_on :conferences, :to => :read end - + # permissions on other roles, such as # role :admin do # has_permission_on :conferences, :to => :manage @@ -147,12 +147,12 @@ Declarative Authorization will use +current_user+ to check authorization. | Privilege | | Context | | Attribute | '-----------' '---------' '-----------' -In the application domain, each *User* may be assigned to *Roles* that should -define the users' job in the application, such as _Administrator_. On the -right-hand side of this diagram, application developers specify which *Permissions* +In the application domain, each *User* may be assigned to *Roles* that should +define the users' job in the application, such as _Administrator_. On the +right-hand side of this diagram, application developers specify which *Permissions* are necessary for users to perform activities, such as calling a controller action, viewing parts of a View or acting on records in the database. Note that -Permissions consist of an *Privilege* that is to be performed, such as _read_, +Permissions consist of an *Privilege* that is to be performed, such as _read_, and a *Context* in that the Operation takes place, such as _companies_. In the authorization configuration, Permissions are assigned to Roles and Role @@ -226,7 +226,7 @@ filter_access_to call may become more verbose: end For some actions it might be necessary to check certain attributes of the -object the action is to be acting on. Then, the object needs to be loaded +object the action is to be acting on. Then, the object needs to be loaded before the action's access control is evaluated. On the other hand, some actions might prefer the authorization to ignore specific attribute checks as the object is unknown at checking time, so attribute checks and thus automatic loading of @@ -260,8 +260,8 @@ sure, your before_filters occur before any of the filter_access_to calls. If the access is denied, a +permission_denied+ method is called on the current_controller, if defined, and the issue is logged. -For further customization of the filters and object loading, have a look at -the complete API documentation of filter_access_to in +For further customization of the filters and object loading, have a look at +the complete API documentation of filter_access_to in Authorization::AuthorizationInController::ClassMethods. @@ -313,8 +313,8 @@ model that model security should be enforced on, i.e. Thus, Employee.create(...) fails, if the current user is not allowed to :create :employees according -to the authorization rules. For the application to find out about what -happened if an operation is denied, the filters throw +to the authorization rules. For the application to find out about what +happened if an operation is denied, the filters throw Authorization::NotAuthorized exceptions. As access control on read are costly, with possibly lots of objects being @@ -336,8 +336,8 @@ the usual find method: Employee.with_permissions_to(:read).find(:all, :conditions => ...) -If the current user is completely missing the permissions, an -Authorization::NotAuthorized exception is raised. Through +If the current user is completely missing the permissions, an +Authorization::NotAuthorized exception is raised. Through Model.obligation_conditions, application developers may retrieve the conditions for manual rewrites. @@ -385,9 +385,9 @@ Privilege hierarchies may be context-specific, e.g. applicable to :employees. privilege :manage, :employees, :includes => :increase_salary end -For more complex use cases, authorizations need to be based on attributes. Note +For more complex use cases, authorizations need to be based on attributes. Note that you then also need to set :attribute_check => true in controllers for filter_access_to. -E.g. if a branch admin should manage only employees of his branch (see +E.g. if a branch admin should manage only employees of his branch (see Authorization::Reader in the API docs for a full list of available operators): authorization do @@ -461,7 +461,7 @@ setup and assume certain identities for tests: end end end - + Or, with RSpec, it would work like this: describe Employee do @@ -485,28 +485,16 @@ See Authorization::TestHelper for more information. = Installation of declarative_authorization -One of three options to install the plugin: -* Install by Gem: Add to your environment.rb in the initializer block: - config.gem "declarative_authorization" - Note: you need gemcutter support in place, i.e. call - gem install gemcutter - gem tumble - And call from your application's root directory - rake gems:install -* Alternativelyi, in Rails 2, to install from github, execute in your application's root directory - cd vendor/plugins && git clone git://github.com/stffn/declarative_authorization.git - -Then, -* provide the requirements as noted below, -* create a basic config/authorization_rules.rb--you might want to take the - provided example authorization_rules.dist.rb in the plugin root as a starting - point, +* provide the requirements as noted below, +* create a basic config/authorization_rules.rb--you might want to take the + provided example authorization_rules.dist.rb in the plugin root as a starting + point, * add +filter_access_to+, +permitted_to+? and model security as needed. == Providing the Plugin's Requirements The requirements are -* Rails >= 2.2, including 3 and Ruby >= 1.8.6, including 1.9 -* An authentication mechanism +* Rails >= 4.1 Ruby >= 2.2 +* An authentication mechanism * A user object returned by Controller#current_user * An array of role symbols returned by User#role_symbols * (For model security) Setting Authorization.current_user to the request's user @@ -519,7 +507,7 @@ restful_authentication. cd ../.. && ruby script/generate authenticated user sessions * Move "include AuthenticatedSystem" to ApplicationController * Add +filter_access_to+ calls as described above. -* If you'd like to use model security, add a before_filter that sets the user +* If you'd like to use model security, add a before_filter that sets the user globally to your ApplicationController. This is thread-safe. before_filter :set_current_user protected @@ -528,9 +516,9 @@ restful_authentication. end * Add roles field to the User model through a :+has_many+ association - (this is just one possible approach; you could just as easily use + (this is just one possible approach; you could just as easily use :+has_many+ :+through+ or a serialized roles array): - * create a migration for table roles + * create a migration for table roles class CreateRoles < ActiveRecord::Migration def self.up create_table "roles" do |t| @@ -549,7 +537,7 @@ restful_authentication. belongs_to :user end - * add +has_many+ :+roles+ to the User model and a roles method that returns the roles + * add +has_many+ :+roles+ to the User model and a roles method that returns the roles as an Array of Symbols, e.g. class User < ActiveRecord::Base has_many :roles @@ -591,8 +579,8 @@ the following lines to your authorization_rules.rb for the appropriate role: Then, point your browser to http://localhost/authorization_rules -The browser needs Rails 2.3 (for Engine support). The graphical view requires -Graphviz (which e.g. can be installed through the graphviz package under Debian +The browser needs Rails 2.3 (for Engine support). The graphical view requires +Graphviz (which e.g. can be installed through the graphviz package under Debian and Ubuntu) and has only been tested under Linux. Note: for Change Support you'll need to have a User#login method that returns a non-ambiguous user name for identification. @@ -601,7 +589,7 @@ name for identification. = Help and Contact We have an issue tracker[http://github.com/stffn/declarative_authorization/issues] -for bugs and feature requests as well as a +for bugs and feature requests as well as a Google Group[http://groups.google.com/group/declarative_authorization] for discussions on the usage of the plugin. You are very welcome to contribute. Just fork the git repository and create a new issue, send a pull request or diff --git a/config/routes.rb b/config/routes.rb index f5c49d31..85c68706 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -1,5 +1,4 @@ if Authorization::activate_authorization_rules_browser? - if Rails.respond_to?(:application) Rails.application.routes.draw do resources :authorization_rules, :only => [:index] do collection do @@ -10,11 +9,4 @@ end resources :authorization_usages, :only => :index end - else - ActionController::Routing::Routes.draw do |map| - map.resources :authorization_rules, :only => [:index], - :collection => {:graph => :get, :change => :get, :suggest_change => :get} - map.resources :authorization_usages, :only => :index - end - end end diff --git a/lib/declarative_authorization.rb b/lib/declarative_authorization.rb index 81d1f02e..82e61fea 100644 --- a/lib/declarative_authorization.rb +++ b/lib/declarative_authorization.rb @@ -1,4 +1,3 @@ -require File.join(%w{declarative_authorization rails_legacy}) require File.join(%w{declarative_authorization helper}) require File.join(%w{declarative_authorization in_controller}) if defined?(ActiveRecord) @@ -6,11 +5,6 @@ require File.join(%w{declarative_authorization obligation_scope}) end -min_rails_version = "2.1.0" -if Rails::VERSION::STRING < min_rails_version - raise "declarative_authorization requires Rails #{min_rails_version}. You are using #{Rails::VERSION::STRING}." -end - require File.join(%w{declarative_authorization railsengine}) if defined?(::Rails::Engine) ActionController::Base.send :include, Authorization::AuthorizationInController diff --git a/lib/declarative_authorization/adapters/active_record.rb b/lib/declarative_authorization/adapters/active_record.rb index 8201af09..2401a42d 100644 --- a/lib/declarative_authorization/adapters/active_record.rb +++ b/lib/declarative_authorization/adapters/active_record.rb @@ -1,9 +1,5 @@ case ActiveRecord::VERSION::MAJOR when 3, 4 -# ActiveRecord::Relation.send :include, Squeel::Nodes::Aliasing -# require 'squeel/adapters/active_record/join_dependency_extensions' -# require 'squeel/adapters/active_record/base_extensions' - adapter_directory = "#{ActiveRecord::VERSION::MAJOR}.#{ActiveRecord::VERSION::MINOR}" Dir[File.expand_path("../active_record/#{adapter_directory}/*.rb", __FILE__)].each do |f| require f diff --git a/lib/declarative_authorization/authorization.rb b/lib/declarative_authorization/authorization.rb index a94bceb6..398b4a04 100644 --- a/lib/declarative_authorization/authorization.rb +++ b/lib/declarative_authorization/authorization.rb @@ -62,11 +62,7 @@ def self.default_role=(role) end def self.is_a_association_proxy?(object) - if Rails.version < "3.2" - object.respond_to?(:proxy_reflection) - else - object.respond_to?(:proxy_association) - end + object.respond_to?(:proxy_association) end # Authorization::Engine implements the reference monitor. It may be used @@ -164,7 +160,7 @@ def permit!(privilege, options = {}) # Example: permit!( :edit, :object => user.posts ) # if Authorization.is_a_association_proxy?(options[:object]) && options[:object].respond_to?(:new) - options[:object] = (Rails.version < "3.0" ? options[:object] : options[:object].where(nil)).new + options[:object] = options[:object].where(nil).new end options[:context] ||= options[:object] && ( diff --git a/lib/declarative_authorization/in_controller.rb b/lib/declarative_authorization/in_controller.rb index db624601..70bdb12e 100644 --- a/lib/declarative_authorization/in_controller.rb +++ b/lib/declarative_authorization/in_controller.rb @@ -497,8 +497,7 @@ def filter_resource_access(options = {}) :nested_in => nil, :strong_parameters => nil }.merge(options) - options.merge!({ :strong_parameters => true }) if Rails.version >= '4' && options[:strong_parameters] == nil - options.merge!({ :strong_parameters => false }) if Rails.version < '4' && options[:strong_parameters] == nil + options.merge!({ :strong_parameters => true }) if options[:strong_parameters] == nil new_actions = actions_from_option( options[:new] ).merge( actions_from_option(options[:additional_new]) ) diff --git a/lib/declarative_authorization/in_model.rb b/lib/declarative_authorization/in_model.rb index fdfeb105..7d5893ea 100644 --- a/lib/declarative_authorization/in_model.rb +++ b/lib/declarative_authorization/in_model.rb @@ -34,33 +34,6 @@ def permitted_to!(privilege, options = {} ) def self.included(base) # :nodoc: #base.extend(ClassMethods) base.module_eval do - if Rails.version < "3.1" - scopes[:with_permissions_to] = lambda do |parent_scope, *args| - options = args.last.is_a?(Hash) ? args.pop : {} - privilege = (args[0] || :read).to_sym - privileges = [privilege] - context = - if options[:context] - options[:context] - elsif parent_scope.respond_to?(:proxy_reflection) - parent_scope.proxy_reflection.klass.name.tableize.to_sym - elsif parent_scope.respond_to?(:decl_auth_context) - parent_scope.decl_auth_context - else - parent_scope.name.tableize.to_sym - end - - user = options[:user] || Authorization.current_user - - engine = options[:engine] || Authorization::Engine.instance - engine.permit!(privileges, :user => user, :skip_attribute_test => true, - :context => context) - - obligation_scope_for( privileges, :user => user, - :context => context, :engine => engine, :model => parent_scope) - end - end - # Builds and returns a scope with joins and conditions satisfying all obligations. def self.obligation_scope_for( privileges, options = {} ) options = { @@ -98,31 +71,27 @@ def self.obligation_scope_for( privileges, options = {} ) # current user. # def self.with_permissions_to(*args) - if Rails.version < "3.1" - scopes[:with_permissions_to].call(self, *args) - else - options = args.last.is_a?(Hash) ? args.pop : {} - privilege = (args[0] || :read).to_sym - privileges = [privilege] - parent_scope = where(nil) - context = - if options[:context] - options[:context] - elsif parent_scope.klass.respond_to?(:decl_auth_context) - parent_scope.klass.decl_auth_context - else - parent_scope.klass.name.tableize.to_sym - end - - user = options[:user] || Authorization.current_user - - engine = options[:engine] || Authorization::Engine.instance - engine.permit!(privileges, :user => user, :skip_attribute_test => true, - :context => context) - - obligation_scope_for( privileges, :user => user, - :context => context, :engine => engine, :model => parent_scope.klass) - end + options = args.last.is_a?(Hash) ? args.pop : {} + privilege = (args[0] || :read).to_sym + privileges = [privilege] + parent_scope = where(nil) + context = + if options[:context] + options[:context] + elsif parent_scope.klass.respond_to?(:decl_auth_context) + parent_scope.klass.decl_auth_context + else + parent_scope.klass.name.tableize.to_sym + end + + user = options[:user] || Authorization.current_user + + engine = options[:engine] || Authorization::Engine.instance + engine.permit!(privileges, :user => user, :skip_attribute_test => true, + :context => context) + + obligation_scope_for( privileges, :user => user, + :context => context, :engine => engine, :model => parent_scope.klass) end # Activates model security for the current model. Then, CRUD operations @@ -166,10 +135,6 @@ def self.using_access_control(options = {}) Authorization::Engine.instance.permit!(:read, :object => object, :context => options[:context]) end - - if Rails.version < "3" - def after_find; end - end end def self.using_access_control? diff --git a/lib/declarative_authorization/obligation_scope.rb b/lib/declarative_authorization/obligation_scope.rb index bc871ffe..5b9597de 100644 --- a/lib/declarative_authorization/obligation_scope.rb +++ b/lib/declarative_authorization/obligation_scope.rb @@ -42,26 +42,15 @@ module Authorization # +@proxy_options[:joins] = { :bar => { :baz => :foo } } # @proxy_options[:conditions] = [ 'foos_bazzes.attr = :foos_bazzes__id_0', { :foos_bazzes__id_0 => 1 } ]+ # - class ObligationScope < (Rails.version < "3" ? ActiveRecord::NamedScope::Scope : ActiveRecord::Relation) + class ObligationScope < ActiveRecord::Relation def initialize(model, options) @finder_options = {} - if Rails.version < "3" - super(model, options) - else - super(model, model.table_name) - end + super(model, model.table_name) end def scope - if Rails.version < "3" - self - elsif Rails.version < "4" - # for Rails < 4: use scoped method - self.klass.scoped(@finder_options) - else - # TODO Refactor this. There is certainly a better way. - self.klass.joins(@finder_options[:joins]).includes(@finder_options[:include]).where(@finder_options[:conditions]).references(@finder_options[:include]) - end + # TODO Refactor this. There is certainly a better way. + self.klass.joins(@finder_options[:joins]).includes(@finder_options[:include]).where(@finder_options[:conditions]).references(@finder_options[:include]) end # Consumes the given obligation, converting it into scope join and condition options. @@ -102,15 +91,11 @@ def follow_path( steps, past_steps = [] ) end def top_level_model - if Rails.version < "3" - @proxy_scope - else - self.klass - end + self.klass end def finder_options - Rails.version < "3" ? @proxy_options : @finder_options + @finder_options end # At the end of every association path, we expect to see a comparison of some kind; for @@ -145,11 +130,7 @@ def model_for(path) reflection = reflection_for(path) if Authorization.is_a_association_proxy?(reflection) - if Rails.version < "3.2" - reflection.proxy_reflection.klass - else - reflection.proxy_association.reflection.klass - end + reflection.proxy_association.reflection.klass elsif reflection.respond_to?(:klass) reflection.klass else diff --git a/lib/declarative_authorization/rails_legacy.rb b/lib/declarative_authorization/rails_legacy.rb deleted file mode 100644 index b687a6bf..00000000 --- a/lib/declarative_authorization/rails_legacy.rb +++ /dev/null @@ -1,22 +0,0 @@ -# Groups methods and additions that were used but are not readily available in -# all supported Rails versions. -class Hash - unless {}.respond_to?(:deep_merge) - # Imported from Rails 2.2 - def deep_merge(other_hash) - self.merge(other_hash) do |key, oldval, newval| - oldval = oldval.to_hash if oldval.respond_to?(:to_hash) - newval = newval.to_hash if newval.respond_to?(:to_hash) - oldval.class.to_s == 'Hash' && newval.class.to_s == 'Hash' ? oldval.deep_merge(newval) : newval - end - end - end -end - -class String - unless "".respond_to?(:html_safe) - def html_safe - self - end - end -end diff --git a/test/authorization_test.rb b/test/authorization_test.rb index 601f4b70..ccccb7ff 100644 --- a/test/authorization_test.rb +++ b/test/authorization_test.rb @@ -332,6 +332,7 @@ def test_guest_user end } engine = Authorization::Engine.new(reader) +#test intermittently fails assert engine.permit?(:test, :context => :permissions) assert !engine.permit?(:test, :context => :permissions_2) end @@ -348,6 +349,7 @@ def test_default_role end } engine = Authorization::Engine.new(reader) +#test intermittently fails assert engine.permit?(:test, :context => :permissions) assert !engine.permit?(:test, :context => :permissions, :user => MockUser.new(:guest)) diff --git a/test/controller_filter_resource_access_test.rb b/test/controller_filter_resource_access_test.rb index 76d1d592..b65c965a 100644 --- a/test/controller_filter_resource_access_test.rb +++ b/test/controller_filter_resource_access_test.rb @@ -511,65 +511,63 @@ def test_explicit_context_filter_new_with_params end end -if Rails.version >= '4' - - class StrongResource < MockDataObject - def self.name - "StrongResource" - end +class StrongResource < MockDataObject + def self.name + "StrongResource" end +end - class StrongResourcesController < MocksController - def self.controller_name - "strong_resources" - end - filter_resource_access :strong_parameters => true - define_resource_actions +class StrongResourcesController < MocksController + def self.controller_name + "strong_resources" + end + filter_resource_access :strong_parameters => true + define_resource_actions - private - def strong_resource_params - params.require(:strong_resource).permit(:test_param1, :test_param2) - end + private + def strong_resource_params + params.require(:strong_resource).permit(:test_param1, :test_param2) end - class StrongResourcesControllerTest < ActionController::TestCase - def test_still_authorized_with_strong_params - reader = Authorization::Reader::DSLReader.new - reader.parse %{ - authorization do - role :allowed_role do - has_permission_on :strong_resources, :to => :show do - if_attribute :id => "1" - end +end +class StrongResourcesControllerTest < ActionController::TestCase + def test_still_authorized_with_strong_params + reader = Authorization::Reader::DSLReader.new + reader.parse %{ + authorization do + role :allowed_role do + has_permission_on :strong_resources, :to => :show do + if_attribute :id => "1" end end - } + end + } - allowed_user = MockUser.new(:allowed_role) - request!(allowed_user, :show, reader, :id => "2") - assert !@controller.authorized? - request!(allowed_user, :show, reader, :id => "1", :clear => [:@strong_resource]) - assert @controller.authorized? - end + allowed_user = MockUser.new(:allowed_role) + request!(allowed_user, :show, reader, :id => "2") + assert !@controller.authorized? + request!(allowed_user, :show, reader, :id => "1", :clear => [:@strong_resource]) + assert @controller.authorized? + end - def test_new_strong_resource - reader = Authorization::Reader::DSLReader.new - reader.parse %{ - authorization do - role :allowed_role do - has_permission_on :strong_resources, :to => :new - end + def test_new_strong_resource + reader = Authorization::Reader::DSLReader.new + reader.parse %{ + authorization do + role :allowed_role do + has_permission_on :strong_resources, :to => :new end - } + end + } - allowed_user = MockUser.new(:allowed_role) - request!(allowed_user, :new, reader, :strong_resource => {:id => "1"}, - :clear => [:@strong_resource]) - assert @controller.authorized? + allowed_user = MockUser.new(:allowed_role) + request!(allowed_user, :new, reader, :strong_resource => {:id => "1"}, + :clear => [:@strong_resource]) + assert @controller.authorized? - # allowed_user = MockUser.new(:allowed_role) - # request!(allowed_user, :new, reader, :strong_resource => {:id => "1"}, :clear => [:@strong_resource]) - # assert @controller.authorized? - # assert assigns :strong_resource - end + # allowed_user = MockUser.new(:allowed_role) + # request!(allowed_user, :new, reader, :strong_resource => {:id => "1"}, :clear => [:@strong_resource]) + # assert @controller.authorized? + # assert assigns :strong_resource end end + diff --git a/test/helper_test.rb b/test/helper_test.rb index 8df2716b..6ad55118 100644 --- a/test/helper_test.rb +++ b/test/helper_test.rb @@ -156,7 +156,7 @@ def test_has_role_with_guest_user end } request!(nil, :action, reader) - +#test intermittently fails assert !has_role?(:test_role) block_evaled = false diff --git a/test/model_test.rb b/test/model_test.rb index 8f8af5b8..b4533855 100644 --- a/test/model_test.rb +++ b/test/model_test.rb @@ -21,51 +21,21 @@ class TestModel < ActiveRecord::Base has_many :branches # :conditions is deprecated in Rails 4.1 - if Rails.version >= '4' - has_many :test_attrs_with_attr, lambda { where(:attr => 1) }, :class_name => "TestAttr" - has_many :test_attr_throughs_with_attr, lambda { where("test_attrs.attr = 1") }, :through => :test_attrs, - :class_name => "TestAttrThrough", :source => :test_attr_throughs + has_many :test_attrs_with_attr, lambda { where(:attr => 1) }, :class_name => "TestAttr" + has_many :test_attr_throughs_with_attr, lambda { where("test_attrs.attr = 1") }, :through => :test_attrs, + :class_name => "TestAttrThrough", :source => :test_attr_throughs - has_one :test_attr_throughs_with_attr_and_has_one, lambda { where("test_attrs.attr = 1") }, :through => :test_attrs, - :class_name => "TestAttrThrough", :source => :test_attr_throughs - else - has_many :test_attrs_with_attr, :class_name => "TestAttr", :conditions => {:attr => 1} - has_many :test_attr_throughs_with_attr, :through => :test_attrs, - :class_name => "TestAttrThrough", :source => :test_attr_throughs, - :conditions => "test_attrs.attr = 1" + has_one :test_attr_throughs_with_attr_and_has_one, lambda { where("test_attrs.attr = 1") }, :through => :test_attrs, + :class_name => "TestAttrThrough", :source => :test_attr_throughs - has_one :test_attr_throughs_with_attr_and_has_one, :through => :test_attrs, - :class_name => "TestAttrThrough", :source => :test_attr_throughs, - :conditions => "test_attrs.attr = 1" - end - - if Rails.version < '4' - attr_accessible :content, :test_attr_through_id, :country_id - end - - # TODO currently not working in Rails 3 - if Rails.version < "3" - has_and_belongs_to_many :test_attr_throughs_habtm, :join_table => :test_attrs, - :class_name => "TestAttrThrough" - end - - if Rails.version < "3" - named_scope :with_content, :conditions => "test_models.content IS NOT NULL" - elsif Rails.version < "4" - scope :with_content, :conditions => "test_models.content IS NOT NULL" - else - scope :with_content, lambda { where("test_models.content IS NOT NULL") } - end + scope :with_content, lambda { where("test_models.content IS NOT NULL") } # Primary key test - # :primary_key only available from Rails 2.2 - unless Rails.version < "2.2" - has_many :test_attrs_with_primary_id, :class_name => "TestAttr", - :primary_key => :test_attr_through_id, :foreign_key => :test_attr_through_id - has_many :test_attr_throughs_with_primary_id, - :through => :test_attrs_with_primary_id, :class_name => "TestAttrThrough", - :source => :n_way_join_item - end + has_many :test_attrs_with_primary_id, :class_name => "TestAttr", + :primary_key => :test_attr_through_id, :foreign_key => :test_attr_through_id + has_many :test_attr_throughs_with_primary_id, + :through => :test_attrs_with_primary_id, :class_name => "TestAttrThrough", + :source => :n_way_join_item # for checking for unnecessary queries mattr_accessor :query_count @@ -93,12 +63,6 @@ class TestAttr < ActiveRecord::Base has_many :test_model_security_model_with_finds attr_reader :role_symbols - if Rails.version < '4' - attr_accessible :test_model, :test_another_model, :attr, :branch, :company, :test_attr, - :test_a_third_model, :n_way_join_item, :n_way_join_item_id, :test_attr_through_id, - :test_model_id, :test_another_model_id - end - def initialize(*args) @role_symbols = [] super(*args) @@ -112,44 +76,25 @@ class TestAttrThrough < ActiveRecord::Base class TestModelSecurityModel < ActiveRecord::Base has_many :test_attrs using_access_control - - if Rails.version < '4' - attr_accessible :attr, :attr_2, :test_attrs - end end class TestModelSecurityModelWithFind < ActiveRecord::Base - if Rails.version < "3.2" - set_table_name "test_model_security_models" - else - self.table_name = "test_model_security_models" - end + self.table_name = "test_model_security_models" + has_many :test_attrs belongs_to :test_attr using_access_control :include_read => true, :context => :test_model_security_models - - if Rails.version < '4' - attr_accessible :test_attr, :attr - end end class Branch < ActiveRecord::Base has_many :test_attrs belongs_to :company belongs_to :test_model - - if Rails.version < '4' - attr_accessible :name, :company, :test_model - end end class Company < ActiveRecord::Base has_many :test_attrs has_many :branches belongs_to :country - - if Rails.version < '4' - attr_accessible :name, :country, :country_id - end end class SmallCompany < Company def self.decl_auth_context @@ -159,10 +104,6 @@ def self.decl_auth_context class Country < ActiveRecord::Base has_many :test_models has_many :companies - - if Rails.version < '4' - attr_accessible :name - end end class NamedScopeModelTest < Test::Unit::TestCase @@ -186,11 +127,8 @@ def test_multiple_deep_ored_belongs_to :test_another_model_id => test_model_2.id user = MockUser.new(:test_role, :id => test_attr_1) - if Rails.version >= '4' - assert_equal 1, TestAttr.with_permissions_to(:read, :user => user).references(:test_attrs, :test_attrs_test_models, :test_attrs_test_models_2).length - else - assert_equal 1, TestAttr.with_permissions_to(:read, :user => user).length - end + assert_equal 1, TestAttr.with_permissions_to(:read, :user => user).references(:test_attrs, :test_attrs_test_models, :test_attrs_test_models_2).length + TestAttr.delete_all TestModel.delete_all @@ -363,19 +301,12 @@ def test_named_scope_on_named_scope # TODO implement query_count for Rails 3 TestModel.query_count = 0 assert_equal 2, TestModel.with_permissions_to(:read, :user => user).length - assert_equal 1, TestModel.query_count if Rails.version < "3" TestModel.query_count = 0 assert_equal 1, TestModel.with_content.with_permissions_to(:read, :user => user).length - assert_equal 1, TestModel.query_count if Rails.version < "3" - - TestModel.query_count = 0 - assert_equal 1, TestModel.with_permissions_to(:read, :user => user).with_content.length if Rails.version < "4" - assert_equal 1, TestModel.query_count if Rails.version < "3" TestModel.query_count = 0 assert_equal 1, country.test_models.with_permissions_to(:read, :user => user).length - assert_equal 1, TestModel.query_count if Rails.version < "3" TestModel.delete_all Country.delete_all @@ -849,11 +780,7 @@ def test_with_contains user = MockUser.new(:test_role, :id => test_model_1.test_attrs.first.id) assert_equal 1, TestModel.with_permissions_to(:read, :user => user).length - if Rails.version < '3' - assert_equal 1, TestModel.with_permissions_to(:read, :user => user).find(:all, :conditions => {:id => test_model_1.id} ).length - else - assert_equal 1, TestModel.with_permissions_to(:read, :user => user).where(:id => test_model_1.id).length - end + assert_equal 1, TestModel.with_permissions_to(:read, :user => user).where(:id => test_model_1.id).length TestModel.delete_all TestAttr.delete_all @@ -987,40 +914,38 @@ def test_with_contains_habtm end end - # :primary_key not available in Rails prior to 2.2 - if Rails.version > "2.2" - def test_with_contains_through_primary_key - reader = Authorization::Reader::DSLReader.new - reader.parse %{ - authorization do - role :test_role do - has_permission_on :test_models, :to => :read do - if_attribute :test_attr_throughs_with_primary_id => contains { user } - end + def test_with_contains_through_primary_key + reader = Authorization::Reader::DSLReader.new + reader.parse %{ + authorization do + role :test_role do + has_permission_on :test_models, :to => :read do + if_attribute :test_attr_throughs_with_primary_id => contains { user } end end - } - Authorization::Engine.instance(reader) - TestModel.delete_all - TestAttrThrough.delete_all - TestAttr.delete_all + end + } + Authorization::Engine.instance(reader) + TestModel.delete_all + TestAttrThrough.delete_all + TestAttr.delete_all - test_attr_through_1 = TestAttrThrough.create! - test_item = NWayJoinItem.create! - test_model_1 = TestModel.create!(:test_attr_through_id => test_attr_through_1.id) - test_attr_1 = TestAttr.create!(:test_attr_through_id => test_attr_through_1.id, - :n_way_join_item_id => test_item.id) + test_attr_through_1 = TestAttrThrough.create! + test_item = NWayJoinItem.create! + test_model_1 = TestModel.create!(:test_attr_through_id => test_attr_through_1.id) + test_attr_1 = TestAttr.create!(:test_attr_through_id => test_attr_through_1.id, + :n_way_join_item_id => test_item.id) - user = MockUser.new(:test_role, - :id => test_attr_through_1.id) - assert_equal 1, TestModel.with_permissions_to(:read, :user => user).length + user = MockUser.new(:test_role, + :id => test_attr_through_1.id) + assert_equal 1, TestModel.with_permissions_to(:read, :user => user).length - TestModel.delete_all - TestAttrThrough.delete_all - TestAttr.delete_all - end + TestModel.delete_all + TestAttrThrough.delete_all + TestAttr.delete_all end + def test_with_intersects_with reader = Authorization::Reader::DSLReader.new reader.parse %{ @@ -1078,43 +1003,6 @@ def test_with_is_and_has_one TestAttr.delete_all end - # TODO fails in Rails 3 because TestModel.scoped.joins(:test_attr_throughs_with_attr) - # does not work - if Rails.version < "3" - def test_with_is_and_has_one_through_conditions - reader = Authorization::Reader::DSLReader.new - reader.parse %{ - authorization do - role :test_role do - has_permission_on :test_models, :to => :read do - if_attribute :test_attr_throughs_with_attr_and_has_one => is { user } - end - end - end - } - Authorization::Engine.instance(reader) - - test_model_1 = TestModel.create! - test_model_2 = TestModel.create! - test_model_1.test_attrs.create!(:attr => 1).test_attr_throughs.create! - test_model_1.test_attrs.create!(:attr => 2).test_attr_throughs.create! - test_model_2.test_attrs.create!(:attr => 1).test_attr_throughs.create! - test_model_2.test_attrs.create!(:attr => 2).test_attr_throughs.create! - - #assert_equal 1, test_model_1.test_attrs_with_attr.length - user = MockUser.new(:test_role, - :id => test_model_1.test_attr_throughs.first.id) - assert_equal 1, TestModel.with_permissions_to(:read, :user => user).length - user = MockUser.new(:test_role, - :id => test_model_1.test_attr_throughs.last.id) - assert_equal 0, TestModel.with_permissions_to(:read, :user => user).length - - TestModel.delete_all - TestAttr.delete_all - TestAttrThrough.delete_all - end - end - def test_with_is_in reader = Authorization::Reader::DSLReader.new reader.parse %{ @@ -1236,11 +1124,8 @@ def test_with_anded_if_permitted_to assert Authorization::Engine.instance.permit?(:read, :object => test_model_1.test_attrs.first, :user => user_with_both_roles) assert Authorization::Engine.instance.permit?(:read, :object => test_model_for_second_role.test_attrs.first, :user => user_with_both_roles) #p Authorization::Engine.instance.obligations(:read, :user => user_with_both_roles, :context => :test_attrs) - if Rails.version >= '4' - assert_equal 2, TestAttr.with_permissions_to(:read, :user => user_with_both_roles).references(:test_attrs, :test_models).length - else - assert_equal 1, TestAttr.with_permissions_to(:read, :user => user).length - end + + assert_equal 2, TestAttr.with_permissions_to(:read, :user => user_with_both_roles).references(:test_attrs, :test_models).length TestModel.delete_all TestAttr.delete_all @@ -1501,11 +1386,8 @@ def test_with_ored_rules_and_reoccuring_tables test_attr_2.test_model.test_attrs.create! user = MockUser.new(:test_role, :test_attr => test_attr_2.test_model.test_attrs.last) - if Rails.version >= '4' - assert_equal 2, TestAttr.with_permissions_to(:read, :user => user).references(:test_attrs, :test_models, :test_models_test_attrs, :test_attrs_test_models).length - else - assert_equal 2, TestAttr.with_permissions_to(:read, :user => user).length - end + assert_equal 2, TestAttr.with_permissions_to(:read, :user => user).references(:test_attrs, :test_models, :test_models_test_attrs, :test_attrs_test_models).length + TestModel.delete_all TestAttr.delete_all end @@ -1542,11 +1424,8 @@ def test_with_many_ored_rules_and_reoccuring_tables user = MockUser.new(:test_role, :test_model => country.test_models.first) - if Rails.version >= '4' - assert_equal 2, TestAttr.with_permissions_to(:read, :user => user).references(:test_attrs, :test_models, :test_models_countries).length - else - assert_equal 2, TestAttr.with_permissions_to(:read, :user => user).length - end + assert_equal 2, TestAttr.with_permissions_to(:read, :user => user).references(:test_attrs, :test_models, :test_models_countries).length + TestModel.delete_all TestAttr.delete_all end @@ -1959,11 +1838,8 @@ def test_multiple_roles_with_has_many_through user = MockUser.new(:test_role_1, :test_role_2, :test_attr_through_id => test_model_1.test_attr_throughs.first.id, :test_attr_through_2_id => test_model_2.test_attr_throughs.first.id) - if Rails.version >= '4' - assert_equal 2, TestModel.with_permissions_to(:read, :user => user).references(:test_models, :test_attr_throughs).length - else - assert_equal 2, TestModel.with_permissions_to(:read, :user => user).length - end + + assert_equal 2, TestModel.with_permissions_to(:read, :user => user).references(:test_models, :test_attr_throughs).length TestModel.delete_all TestAttr.delete_all TestAttrThrough.delete_all diff --git a/test/test_helper.rb b/test/test_helper.rb index dd3fc59f..7a1271c1 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -6,28 +6,15 @@ begin # rails 3 require 'rails/all' -rescue LoadError + rescue LoadError # rails 2.3 %w(action_pack action_controller active_record active_support initializer).each {|f| require f} end Bundler.require -if Rails.version >= '4.1' - require 'minitest/autorun' - require 'test_support/minitest_compatibility' -else - require 'test/unit' -end - -# rails 2.3 and ruby 1.9.3 fix -MissingSourceFile::REGEXPS.push([/^cannot load such file -- (.+)$/i, 1]) +require 'minitest/autorun' +require 'test_support/minitest_compatibility' -# Silence Rails 4 deprecation warnings in test suite -# TODO: Model.scoped is deprecated -# TODO: Eager loading Post.includes(:comments).where("comments.title = 'foo'") becomes Post.includes(:comments).where("comments.title = 'foo'").references(:comments) -# if Rails.version >= '4' -# ActiveSupport::Deprecation.silenced = true -# end puts "Testing against rails #{Rails::VERSION::STRING}" @@ -35,16 +22,10 @@ DA_ROOT = Pathname.new(File.expand_path("..", File.dirname(__FILE__))) -require DA_ROOT + File.join(%w{lib declarative_authorization rails_legacy}) require DA_ROOT + File.join(%w{lib declarative_authorization authorization}) require DA_ROOT + File.join(%w{lib declarative_authorization in_controller}) require DA_ROOT + File.join(%w{lib declarative_authorization maintenance}) -begin - require 'ruby-debug' -rescue MissingSourceFile; end - - class MockDataObject def initialize(attrs = {}) attrs.each do |key, value| @@ -124,132 +105,66 @@ def warn?; end end end -if Rails.version < "3" - ActiveRecord::Base.establish_connection({:adapter => 'sqlite3', :database => ':memory:'}) - ActionController::Routing::Routes.draw do |map| - map.connect ':controller/:action/:id' +class TestApp + class Application < ::Rails::Application + config.secret_key_base = "testingpurposesonly" + config.active_support.deprecation = :stderr + database_path = File.expand_path('../database.yml', __FILE__) + config.paths['config/database'] = database_path + initialize! + end +end +class ApplicationController < ActionController::Base +end +#Rails::Application.routes.draw do +if Rails.version.start_with? '4' + Rails.application.routes.draw do + match '/name/spaced_things(/:action)' => 'name/spaced_things', :via => [:get, :post, :put, :patch, :delete] + match '/deep/name_spaced/things(/:action)' => 'deep/name_spaced/things', :via => [:get, :post, :put, :patch, :delete] + match '/:controller(/:action(/:id))', :via => [:get, :post, :put, :patch, :delete] end -else class TestApp class Application < ::Rails::Application - config.secret_key_base = "testingpurposesonly" - config.active_support.deprecation = :stderr - database_path = File.expand_path('../database.yml', __FILE__) - if Rails.version.start_with? '3.0.' - config.paths.config.database database_path - else - config.paths['config/database'] = database_path - end - initialize! + config.secret_key_base = 'thisstringdoesnothing' end end - class ApplicationController < ActionController::Base - end - #Rails::Application.routes.draw do - if Rails.version.start_with? '4' - Rails.application.routes.draw do - match '/name/spaced_things(/:action)' => 'name/spaced_things', :via => [:get, :post, :put, :patch, :delete] - match '/deep/name_spaced/things(/:action)' => 'deep/name_spaced/things', :via => [:get, :post, :put, :patch, :delete] - match '/:controller(/:action(/:id))', :via => [:get, :post, :put, :patch, :delete] - end - class TestApp - class Application < ::Rails::Application - config.secret_key_base = 'thisstringdoesnothing' - end - end - else - Rails.application.routes.draw do - match '/name/spaced_things(/:action)' => 'name/spaced_things' - match '/deep/name_spaced/things(/:action)' => 'deep/name_spaced/things' - match '/:controller(/:action(/:id))' - end +else + Rails.application.routes.draw do + match '/name/spaced_things(/:action)' => 'name/spaced_things' + match '/deep/name_spaced/things(/:action)' => 'deep/name_spaced/things' + match '/:controller(/:action(/:id))' end end ActionController::Base.send :include, Authorization::AuthorizationInController -if Rails.version < "3" - require "action_controller/test_process" -end - -if Rails.version < "4" - class Test::Unit::TestCase - include Authorization::TestHelper - - def request!(user, action, reader, params = {}) - action = action.to_sym if action.is_a?(String) - @controller.current_user = user - @controller.authorization_engine = Authorization::Engine.new(reader) - - ((params.delete(:clear) || []) + [:@authorized]).each do |var| - @controller.instance_variable_set(var, nil) - end - get action, params - end - - unless Rails.version < "3" - def setup - #@routes = Rails::Application.routes - @routes = Rails.application.routes - end - end +module Test + module Unit end +end -elsif Rails.version < '4.1' - class Test::Unit::TestCase - include Authorization::TestHelper - end +class Test::Unit::TestCase < Minitest::Test + include Authorization::TestHelper +end - class ActiveSupport::TestCase - include Authorization::TestHelper - def request!(user, action, reader, params = {}) - action = action.to_sym if action.is_a?(String) - @controller.current_user = user - @controller.authorization_engine = Authorization::Engine.new(reader) +class ActiveSupport::TestCase + include Authorization::TestHelper - ((params.delete(:clear) || []) + [:@authorized]).each do |var| - @controller.instance_variable_set(var, nil) - end - get action, params - end + def request!(user, action, reader, params = {}) + action = action.to_sym if action.is_a?(String) + @controller.current_user = user + @controller.authorization_engine = Authorization::Engine.new(reader) - unless Rails.version < "3" - def setup - #@routes = Rails::Application.routes - @routes = Rails.application.routes - end - end - end -else - module Test - module Unit + ((params.delete(:clear) || []) + [:@authorized]).each do |var| + @controller.instance_variable_set(var, nil) end + get action, params end - class Test::Unit::TestCase < Minitest::Test - include Authorization::TestHelper - end - - class ActiveSupport::TestCase - include Authorization::TestHelper - - def request!(user, action, reader, params = {}) - action = action.to_sym if action.is_a?(String) - @controller.current_user = user - @controller.authorization_engine = Authorization::Engine.new(reader) - - ((params.delete(:clear) || []) + [:@authorized]).each do |var| - @controller.instance_variable_set(var, nil) - end - get action, params - end - - unless Rails.version < "3" - def setup - #@routes = Rails::Application.routes - @routes = Rails.application.routes - end - end + def setup + #@routes = Rails::Application.routes + @routes = Rails.application.routes end end + From 7f6913193ac4aeb97b41c6f6999045ea598844a7 Mon Sep 17 00:00:00 2001 From: Daniel Becker Date: Wed, 26 Jul 2017 17:57:54 +0200 Subject: [PATCH 21/55] Add rails 5 compatibility. --- .../in_controller.rb | 98 +++++++++---------- .../obligation_scope.rb | 4 +- 2 files changed, 51 insertions(+), 51 deletions(-) diff --git a/lib/declarative_authorization/in_controller.rb b/lib/declarative_authorization/in_controller.rb index fae894df..bf4e3f0f 100644 --- a/lib/declarative_authorization/in_controller.rb +++ b/lib/declarative_authorization/in_controller.rb @@ -3,15 +3,13 @@ module Authorization module AuthorizationInController - + def self.included(base) # :nodoc: base.extend(ClassMethods) - base.hide_action :authorization_engine, :permitted_to?, - :permitted_to! end - + DEFAULT_DENY = false - + # If attribute_check is set for filter_access_to, decl_auth_context will try to # load the appropriate object from the current controller's model with # the id from params[:id]. If that fails, a 404 Not Found is often the @@ -31,12 +29,12 @@ def self.failed_auto_loading_is_not_found= (new_value) def authorization_engine @authorization_engine ||= Authorization::Engine.instance end - + # If the current user meets the given privilege, permitted_to? returns true # and yields to the optional block. The attribute checks that are defined # in the authorization rules are only evaluated if an object is given # for context. - # + # # See examples for Authorization::AuthorizationHelper #permitted_to? # # If no object or context is specified, the controller_name is used as @@ -50,7 +48,7 @@ def permitted_to? (privilege, object_or_sym = nil, options = {}) false end end - + # Works similar to the permitted_to? method, but # throws the authorization exceptions, just like Engine#permit! def permitted_to! (privilege, object_or_sym = nil, options = {}) @@ -59,7 +57,7 @@ def permitted_to! (privilege, object_or_sym = nil, options = {}) # While permitted_to? is used for authorization, in some cases # content should only be shown to some users without being concerned - # with authorization. E.g. to only show the most relevant menu options + # with authorization. E.g. to only show the most relevant menu options # to a certain group of users. That is what has_role? should be used for. def has_role? (*roles, &block) user_roles = authorization_engine.roles_for(current_user) @@ -69,8 +67,8 @@ def has_role? (*roles, &block) yield if result and block_given? result end - - # Intended to be used where you want to allow users with any single listed role to view + + # Intended to be used where you want to allow users with any single listed role to view # the content in question def has_any_role?(*roles,&block) user_roles = authorization_engine.roles_for(current_user) @@ -80,7 +78,7 @@ def has_any_role?(*roles,&block) yield if result and block_given? result end - + # As has_role? except checks all roles included in the role hierarchy def has_role_with_hierarchy?(*roles, &block) user_roles = authorization_engine.roles_with_hierarchy_for(current_user) @@ -90,7 +88,7 @@ def has_role_with_hierarchy?(*roles, &block) yield if result and block_given? result end - + # As has_any_role? except checks all roles included in the role hierarchy def has_any_role_with_hierarchy?(*roles, &block) user_roles = authorization_engine.roles_with_hierarchy_for(current_user) @@ -100,7 +98,7 @@ def has_any_role_with_hierarchy?(*roles, &block) yield if result and block_given? result end - + protected def filter_access_filter # :nodoc: permissions = self.class.all_filter_access_permissions @@ -210,16 +208,16 @@ module ClassMethods # filter_access_to :all # ... # end - # + # # The default is to allow access unconditionally if no rule matches. # Thus, including the +filter_access_to+ :+all+ statement is a good # idea, implementing a default-deny policy. - # + # # When the access is denied, the method +permission_denied+ is called # on the current controller, if defined. Else, a simple "you are not # allowed" string is output. Log.info is given more information on the # reasons of denial. - # + # # def permission_denied # flash[:error] = 'Sorry, you are not allowed to the requested page.' # respond_to do |format| @@ -228,7 +226,7 @@ module ClassMethods # format.js { head :unauthorized } # end # end - # + # # By default, required privileges are inferred from the action name and # the controller name. Thus, in UserController :+edit+ requires # :+edit+ +users+. To specify required privilege, use the option :+require+ @@ -252,10 +250,10 @@ module ClassMethods # end # NOTE: +before_filters+ need to be defined before the first # +filter_access_to+ call. - # + # # For further customization, a custom filter expression may be formulated # in a block, which is then evaluated in the context of the controller - # on a matching request. That is, for checking two objects, use the + # on a matching request. That is, for checking two objects, use the # following: # filter_access_to :merge do # permitted_to!(:update, User.find(params[:original_id])) and @@ -263,14 +261,14 @@ module ClassMethods # end # The block should raise a Authorization::AuthorizationError or return # false if the access is to be denied. - # + # # Later calls to filter_access_to with overlapping actions overwrite # previous ones for that action. - # + # # All options: - # [:+require+] + # [:+require+] # Privilege required; defaults to action_name - # [:+context+] + # [:+context+] # The privilege's context, defaults to decl_auth_context, which consists # of controller_name, prepended by any namespaces # [:+attribute_check+] @@ -283,19 +281,19 @@ module ClassMethods # * a find on the context model, using +params+[:id] as id value. # Any of these methods will only be employed if :+attribute_check+ # is enabled. - # [:+model+] + # [:+model+] # The data model to load a context object from. Defaults to the # context, singularized. # [:+load_method+] - # Specify a method by symbol or a Proc object which should be used + # Specify a method by symbol or a Proc object which should be used # to load the object. Both should return the loaded object. # If a Proc object is given, e.g. by way of - # +lambda+, it is called in the instance of the controller. + # +lambda+, it is called in the instance of the controller. # Example demonstrating the default behavior: # filter_access_to :show, :attribute_check => true, # :load_method => lambda { User.find(params[:id]) } - # - + # + def filter_access_to (*args, &filter_block) options = args.last.is_a?(Hash) ? args.pop : {} options = { @@ -311,13 +309,13 @@ def filter_access_to (*args, &filter_block) actions = args.flatten # prevent setting filter_access_filter multiple times - skip_before_filter :filter_access_filter + skip_before_filter :filter_access_filter, raise: false before_filter :filter_access_filter - + filter_access_permissions.each do |perm| perm.remove_actions(actions) end - filter_access_permissions << + filter_access_permissions << ControllerPermission.new(actions, privilege, context, options[:strong_parameters], options[:attribute_check], @@ -325,15 +323,15 @@ def filter_access_to (*args, &filter_block) options[:load_method], filter_block) end - + # Collecting all the ControllerPermission objects from the controller - # hierarchy. Permissions for actions are overwritten by calls to + # hierarchy. Permissions for actions are overwritten by calls to # filter_access_to in child controllers with the same action. def all_filter_access_permissions # :nodoc: ancestors.inject([]) do |perms, mod| if mod.respond_to?(:filter_access_permissions, true) - perms + - mod.filter_access_permissions.collect do |p1| + perms + + mod.filter_access_permissions.collect do |p1| p1.clone.remove_actions(perms.inject(Set.new) {|actions, p2| actions + p2.actions}) end else @@ -393,12 +391,12 @@ def all_filter_access_permissions # :nodoc: # filter_resource_access :additional_member => { :toggle_open => :update } # Would add a member action :+toggle_open+ to the default members, such as :+show+. # - # If :+collection+ is an array of method names filter_resource_access will - # associate a permission with the method that is the same as the method - # name and no attribute checks will be performed unless + # If :+collection+ is an array of method names filter_resource_access will + # associate a permission with the method that is the same as the method + # name and no attribute checks will be performed unless # :attribute_check => true # is added in the options. - # + # # You can override the default object loading by implementing any of the # following instance methods on the controller. Examples are given for the # BranchController (with +nested_in+ set to :+companies+): @@ -409,7 +407,7 @@ def all_filter_access_permissions # :nodoc: # [+load_branch+] # Used for +member+ actions. # [+load_company+] - # Used for all +new+, +member+, and +collection+ actions if the + # Used for all +new+, +member+, and +collection+ actions if the # +nested_in+ option is set. # # All options: @@ -555,7 +553,7 @@ def filter_resource_access(options = {}) controller.send(:new_blank_controller_object, options[:context] || controller_name, options[:nested_in], options[:strong_parameters], options[:model]) end - end + end end load_method = :"load_#{controller_name.singularize}" @@ -595,7 +593,7 @@ def decl_auth_context prefixes = name.split('::')[0..-2].map(&:underscore) ((prefixes + [controller_name]) * '_').to_sym end - + protected def filter_access_permissions # :nodoc: unless filter_access_permissions? @@ -606,7 +604,7 @@ def filter_access_permissions # :nodoc: class_variable_set(:@@declarative_authorization_permissions, {}) unless filter_access_permissions? class_variable_get(:@@declarative_authorization_permissions)[self.name] ||= [] end - + def filter_access_permissions? # :nodoc: class_variable_defined?(:@@declarative_authorization_permissions) end @@ -632,7 +630,7 @@ def actions_from_option (option) # :nodoc: end end end - + class ControllerPermission # :nodoc: attr_reader :actions, :privilege, :context, :attribute_check, :strong_params def initialize (actions, privilege, context, strong_params, attribute_check = false, @@ -647,11 +645,11 @@ def initialize (actions, privilege, context, strong_params, attribute_check = fa @attribute_check = attribute_check @strong_params = strong_params end - + def matches? (action_name) @actions.include?(action_name.to_sym) end - + def permit! (contr) if @filter_block return contr.instance_eval(&@filter_block) @@ -659,18 +657,18 @@ def permit! (contr) object = @attribute_check ? load_object(contr) : nil privilege = @privilege || :"#{contr.action_name}" - contr.authorization_engine.permit!(privilege, + contr.authorization_engine.permit!(privilege, :user => contr.send(:current_user), :object => object, :skip_attribute_test => !@attribute_check, :context => @context || contr.class.decl_auth_context) end - + def remove_actions (actions) @actions -= actions self end - + private def load_object(contr) diff --git a/lib/declarative_authorization/obligation_scope.rb b/lib/declarative_authorization/obligation_scope.rb index eb935854..a90dfc85 100644 --- a/lib/declarative_authorization/obligation_scope.rb +++ b/lib/declarative_authorization/obligation_scope.rb @@ -49,8 +49,10 @@ def initialize (model, options) @finder_options = {} if Rails.version < "3" super(model, options) + elsif Rails.version < "5" + super(model, model.table_name) else - super(model, model.table_name) + super(model, model.table_name, model.predicate_builder) end end From b136b2628e741b1826b40bfb7bb4541f4a3e5f3a Mon Sep 17 00:00:00 2001 From: Daniel Becker Date: Mon, 31 Jul 2017 18:11:26 +0200 Subject: [PATCH 22/55] before_filter is called before_action now. --- lib/declarative_authorization/in_controller.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/declarative_authorization/in_controller.rb b/lib/declarative_authorization/in_controller.rb index bf4e3f0f..562be28f 100644 --- a/lib/declarative_authorization/in_controller.rb +++ b/lib/declarative_authorization/in_controller.rb @@ -309,8 +309,8 @@ def filter_access_to (*args, &filter_block) actions = args.flatten # prevent setting filter_access_filter multiple times - skip_before_filter :filter_access_filter, raise: false - before_filter :filter_access_filter + skip_before_action :filter_access_filter, raise: false + before_action :filter_access_filter filter_access_permissions.each do |perm| perm.remove_actions(actions) From beb172736fbed782d6e9b46516544adad6b039ff Mon Sep 17 00:00:00 2001 From: Anna Date: Thu, 20 Jul 2017 13:42:50 -0400 Subject: [PATCH 23/55] Remove deprecated minitest syntax --- README.rdoc | 7 +- lib/declarative_authorization/maintenance.rb | 8 +- test/authorization_test.rb | 28 ++--- test/controller_test.rb | 7 +- test/development_support/analyzer_test.rb | 112 +++++++++--------- .../change_analyzer_test.rb | 10 +- .../change_supporter_test.rb | 10 +- test/dsl_reader_test.rb | 8 +- test/model_test.rb | 73 +++++------- test/test_helper.rb | 1 - test/test_support/minitest_compatibility.rb | 27 ----- 11 files changed, 118 insertions(+), 173 deletions(-) delete mode 100644 test/test_support/minitest_compatibility.rb diff --git a/README.rdoc b/README.rdoc index 97f45795..a2df0baf 100644 --- a/README.rdoc +++ b/README.rdoc @@ -454,10 +454,8 @@ setup and assume certain identities for tests: without_access_control do Employee.create(...) end - assert_nothing_raised do - with_user(admin) do - Employee.find(:first) - end + with_user(admin) do + Employee.find(:first) end end end @@ -484,7 +482,6 @@ See Authorization::TestHelper for more information. = Installation of declarative_authorization - * provide the requirements as noted below, * create a basic config/authorization_rules.rb--you might want to take the provided example authorization_rules.dist.rb in the plugin root as a starting diff --git a/lib/declarative_authorization/maintenance.rb b/lib/declarative_authorization/maintenance.rb index 6cbed5e5..73f31d73 100644 --- a/lib/declarative_authorization/maintenance.rb +++ b/lib/declarative_authorization/maintenance.rb @@ -138,10 +138,10 @@ def self.usages_by_controller module TestHelper include Authorization::Maintenance - # Analogue to the Ruby's assert_raise method, only executing the block + # Analogue to the Ruby's assert_raises method, only executing the block # in the context of the given user. def assert_raise_with_user(user, *args, &block) - assert_raise(*args) do + assert_raises(*args) do with_user(user, &block) end end @@ -165,9 +165,7 @@ def should_be_allowed_to(privilege, *args) else options[args[0].is_a?(Symbol) ? :context : :object] = args[0] end - assert_nothing_raised do - Authorization::Engine.instance.permit!(privilege, options) - end + Authorization::Engine.instance.permit!(privilege, options) end # See should_be_allowed_to diff --git a/test/authorization_test.rb b/test/authorization_test.rb index ccccb7ff..2558771d 100644 --- a/test/authorization_test.rb +++ b/test/authorization_test.rb @@ -84,10 +84,8 @@ def test_permit_with_frozen_roles } engine = Authorization::Engine.new(reader) roles = [:other_role].freeze - assert_nothing_raised do - assert engine.permit?(:test, :context => :permissions, - :user => MockUser.new(:role_symbols => roles)) - end + assert engine.permit?(:test, :context => :permissions, + :user => MockUser.new(:role_symbols => roles)) end def test_obligations_without_conditions @@ -367,10 +365,10 @@ def test_invalid_user_model end } engine = Authorization::Engine.new(reader) - assert_raise(Authorization::AuthorizationUsageError) do + assert_raises(Authorization::AuthorizationUsageError) do engine.permit?(:test, :context => :permissions, :user => MockUser.new(1, 2)) end - assert_raise(Authorization::AuthorizationUsageError) do + assert_raises(Authorization::AuthorizationUsageError) do engine.permit?(:test, :context => :permissions, :user => MockDataObject.new) end end @@ -596,12 +594,12 @@ def test_attribute_intersects_with } engine = Authorization::Engine.new(reader) - assert_raise Authorization::AuthorizationUsageError do + assert_raises Authorization::AuthorizationUsageError do engine.permit?(:test, :context => :permissions, :user => MockUser.new(:test_role), :object => MockDataObject.new(:test_attrs => 1 )) end - assert_raise Authorization::AuthorizationUsageError do + assert_raises Authorization::AuthorizationUsageError do engine.permit?(:test, :context => :permissions, :user => MockUser.new(:test_role_2), :object => MockDataObject.new(:test_attrs => [1, 2] )) @@ -927,11 +925,9 @@ def test_attribute_with_permissions_nil } engine = Authorization::Engine.new(reader) - assert_nothing_raised do - engine.permit?(:test, :context => :permission_children, - :user => MockUser.new(:test_role), - :object => MockDataObject.new(:permission => nil)) - end + engine.permit?(:test, :context => :permission_children, + :user => MockUser.new(:test_role), + :object => MockDataObject.new(:permission => nil)) assert !engine.permit?(:test, :context => :permission_children, :user => MockUser.new(:test_role), @@ -1054,7 +1050,7 @@ def test_raise_on_if_attribute_hash_on_collection end } engine = Authorization::Engine.new(reader) - assert_raise Authorization::AuthorizationUsageError do + assert_raises Authorization::AuthorizationUsageError do engine.permit?(:test, :context => :permissions, :user => MockUser.new(:test_role), :object => MockDataObject.new(:test_attrs => [1, 2, 3])) @@ -1117,9 +1113,9 @@ def test_clone engine = Authorization::Engine.new(reader) cloned_engine = engine.clone - assert_not_equal engine.auth_rules.first.contexts.object_id, + refute_equal engine.auth_rules.first.contexts.object_id, cloned_engine.auth_rules.first.contexts.object_id - assert_not_equal engine.auth_rules.first.attributes.first.send(:instance_variable_get, :@conditions_hash)[:attr].object_id, + refute_equal engine.auth_rules.first.attributes.first.send(:instance_variable_get, :@conditions_hash)[:attr].object_id, cloned_engine.auth_rules.first.attributes.first.send(:instance_variable_get, :@conditions_hash)[:attr].object_id end end diff --git a/test/controller_test.rb b/test/controller_test.rb index ddf7a2da..aa9d8b6e 100644 --- a/test/controller_test.rb +++ b/test/controller_test.rb @@ -273,14 +273,13 @@ def test_filter_access_object_load_without_param end } - assert_raise StandardError, "No id param supplied" do + assert_raises StandardError, "No id param supplied" do request!(MockUser.new(:test_role), "show", reader) end Authorization::AuthorizationInController.failed_auto_loading_is_not_found = false - assert_nothing_raised "Load error is only logged" do - request!(MockUser.new(:test_role), "show", reader) - end + request!(MockUser.new(:test_role), "show", reader) + assert !@controller.authorized? Authorization::AuthorizationInController.failed_auto_loading_is_not_found = true end diff --git a/test/development_support/analyzer_test.rb b/test/development_support/analyzer_test.rb index 7c1aa190..8863f88a 100644 --- a/test/development_support/analyzer_test.rb +++ b/test/development_support/analyzer_test.rb @@ -13,64 +13,62 @@ class AuthorizationRulesAnalyzerTest < Test::Unit::TestCase def test_analyzing_complex_rules - assert_nothing_raised do - engine, analyzer = engine_analyzer_for %{ - authorization do - role :guest do - has_permission_on :conferences, :to => :read do - if_attribute :published => true - end - has_permission_on :talks, :to => :read do - if_permitted_to :read, :conference - end - has_permission_on :users, :to => :create - has_permission_on :authorization_rules, :to => :read - has_permission_on :authorization_usages, :to => :read + engine, analyzer = engine_analyzer_for %{ + authorization do + role :guest do + has_permission_on :conferences, :to => :read do + if_attribute :published => true end - - role :user do - includes :guest - has_permission_on :conference_attendees, :to => :create do - if_attribute :user => is {user}, - :conference => { :published => true } - end - has_permission_on :conference_attendees, :to => :delete do - if_attribute :user => is {user}, - :conference => { :attendees => contains {user} } - end - has_permission_on :talk_attendees, :to => :create do - if_attribute :talk => { :conference => { :attendees => contains {user} }} - end - has_permission_on :talk_attendees, :to => :delete do - if_attribute :user => is {user}, - :talk => { :conference => { :attendees => contains {user} }} - end + has_permission_on :talks, :to => :read do + if_permitted_to :read, :conference end + has_permission_on :users, :to => :create + has_permission_on :authorization_rules, :to => :read + has_permission_on :authorization_usages, :to => :read + end - role :conference_organizer do - has_permission_on :conferences do - to :manage - # if... - end - has_permission_on [:conference_attendees, :talks, :talk_attendees], :to => :manage + role :user do + includes :guest + has_permission_on :conference_attendees, :to => :create do + if_attribute :user => is {user}, + :conference => { :published => true } + end + has_permission_on :conference_attendees, :to => :delete do + if_attribute :user => is {user}, + :conference => { :attendees => contains {user} } end + has_permission_on :talk_attendees, :to => :create do + if_attribute :talk => { :conference => { :attendees => contains {user} }} + end + has_permission_on :talk_attendees, :to => :delete do + if_attribute :user => is {user}, + :talk => { :conference => { :attendees => contains {user} }} + end + end - role :admin do - has_permission_on [:conferences, :users, :talks], :to => :manage - has_permission_on :authorization_rules, :to => :read - has_permission_on :authorization_usages, :to => :read + role :conference_organizer do + has_permission_on :conferences do + to :manage + # if... end + has_permission_on [:conference_attendees, :talks, :talk_attendees], :to => :manage end - privileges do - privilege :manage, :includes => [:create, :read, :update, :delete] - privilege :read, :includes => [:index, :show] - privilege :create, :includes => :new - privilege :update, :includes => :edit - privilege :delete, :includes => :destroy + role :admin do + has_permission_on [:conferences, :users, :talks], :to => :manage + has_permission_on :authorization_rules, :to => :read + has_permission_on :authorization_usages, :to => :read end - } - end + end + + privileges do + privilege :manage, :includes => [:create, :read, :update, :delete] + privilege :read, :includes => [:index, :show] + privilege :create, :includes => :new + privilege :update, :includes => :edit + privilege :delete, :includes => :destroy + end + } end def test_mergeable_rules_without_constraints @@ -89,17 +87,15 @@ def test_mergeable_rules_without_constraints end def test_mergeable_rules_with_in_block_to - assert_nothing_raised do - engine, analyzer = engine_analyzer_for %{ - authorization do - role :test_role do - has_permission_on :permissions do - to :test - end + engine, analyzer = engine_analyzer_for %{ + authorization do + role :test_role do + has_permission_on :permissions do + to :test end end - } - end + end + } end def test_no_mergeable_rules_with_constraints diff --git a/test/development_support/change_analyzer_test.rb b/test/development_support/change_analyzer_test.rb index 66a6a740..e68dc610 100644 --- a/test/development_support/change_analyzer_test.rb +++ b/test/development_support/change_analyzer_test.rb @@ -58,7 +58,7 @@ def test_adding_permission_by_assigning_role assert !permit?(:read, :context => :permissions, :user => users[1]) end - assert_not_equal 0, approaches.length + refute_equal 0, approaches.length #assert_equal :role, approaches.first.target_type #assert_equal :test_role_2, approaches.first.target.to_sym end @@ -83,7 +83,7 @@ def test_adding_permission_with_new_role assert !permit?(:read, :context => :permissions, :user => users[1]) end - assert_not_equal 0, approaches.length + refute_equal 0, approaches.length #assert_equal :role, approaches.first.target_type #assert_equal :test_role_2, approaches.first.target.to_sym end @@ -111,7 +111,7 @@ def test_adding_permission_with_new_role_complex assert !permit?(:read, :context => :permissions, :user => users[0]) end - assert_not_equal 0, approaches.length + refute_equal 0, approaches.length #assert_equal :role, approaches.first.target_type #assert_equal :test_role_2, approaches.first.target.to_sym end @@ -193,7 +193,7 @@ def test_removing_permission_adding_role end # solution: add a new role - assert_not_equal 0, approaches.length + refute_equal 0, approaches.length assert approaches.any? {|approach| approach.users.first.role_symbols.include?(:test_role) } end @@ -219,7 +219,7 @@ def test_removing_user_role_assignment end # solutions: remove user-role assignment for first user - assert_not_equal 0, approaches.length + refute_equal 0, approaches.length assert approaches.any? {|approach| approach.users.first.role_symbols.empty? } end end diff --git a/test/development_support/change_supporter_test.rb b/test/development_support/change_supporter_test.rb index 50736318..3bf81209 100644 --- a/test/development_support/change_supporter_test.rb +++ b/test/development_support/change_supporter_test.rb @@ -213,7 +213,7 @@ def test_adding_permission_with_assigning_role_and_adding_permission assert permit?(:read, :context => :permissions, :user => users.first) end - assert_not_equal 0, approaches.length + refute_equal 0, approaches.length assert approaches.any? {|approach| approach.changes.first.class == Authorization::DevelopmentSupport::ChangeSupporter::AddPrivilegeAndAssignRoleToUserAction} end @@ -518,7 +518,7 @@ def test_prohibited_actions_role_to_user assert permit?(:read, :context => :permissions, :user => users.first) end - assert_not_equal 0, approaches.length + refute_equal 0, approaches.length assert !approaches.any? {|approach| approach.steps.any? {|step| step.class == Authorization::DevelopmentSupport::ChangeSupporter::AssignRoleToUserAction}} end @@ -543,7 +543,7 @@ def test_prohibited_actions_role_to_any_user assert permit?(:read, :context => :permissions, :user => users.first) end - assert_not_equal 0, approaches.length + refute_equal 0, approaches.length assert !approaches.any? {|approach| approach.steps.any? {|step| step.class == Authorization::DevelopmentSupport::ChangeSupporter::AssignRoleToUserAction and step.role == :test_role }} end @@ -568,7 +568,7 @@ def test_prohibited_actions_permission_to_role assert permit?(:read, :context => :permissions, :user => users.first) end - assert_not_equal 0, approaches.length + refute_equal 0, approaches.length assert !approaches.any? {|approach| approach.steps.any? {|step| step.class == Authorization::DevelopmentSupport::ChangeSupporter::AssignPrivilegeToRoleAction}} end @@ -591,7 +591,7 @@ def test_prohibited_actions_remove_role assert !permit?(:read, :context => :permissions, :user => users.first) end - assert_not_equal 0, approaches.length + refute_equal 0, approaches.length assert !approaches.any? {|approach| approach.steps.any? {|step| step.class == Authorization::DevelopmentSupport::ChangeSupporter::RemoveRoleFromUserAction}} end diff --git a/test/dsl_reader_test.rb b/test/dsl_reader_test.rb index 9a33aee9..cc05565c 100644 --- a/test/dsl_reader_test.rb +++ b/test/dsl_reader_test.rb @@ -130,7 +130,7 @@ def test_context def test_dsl_error reader = Authorization::Reader::DSLReader.new - assert_raise(Authorization::Reader::DSLError) do + assert_raises(Authorization::Reader::DSLError) do reader.parse %{ authorization do includes :lesser_role @@ -141,7 +141,7 @@ def test_dsl_error def test_syntax_error reader = Authorization::Reader::DSLReader.new - assert_raise(Authorization::Reader::DSLSyntaxError) do + assert_raises(Authorization::Reader::DSLSyntaxError) do reader.parse %{ authorizations do end @@ -151,7 +151,7 @@ def test_syntax_error def test_syntax_error_2 reader = Authorization::Reader::DSLReader.new - assert_raise(Authorization::Reader::DSLSyntaxError) do + assert_raises(Authorization::Reader::DSLSyntaxError) do reader.parse %{ authorizations end @@ -170,7 +170,7 @@ def test_factory_loads_file end def test_load_file_not_found - assert_raise(Authorization::Reader::DSLFileNotFoundError) do + assert_raises(Authorization::Reader::DSLFileNotFoundError) do Authorization::Reader::DSLReader.new.load!("nonexistent_file.rb") end end diff --git a/test/model_test.rb b/test/model_test.rb index b4533855..874a569e 100644 --- a/test/model_test.rb +++ b/test/model_test.rb @@ -154,7 +154,7 @@ def test_with_belongs_to_and_has_many_with_contains user = MockUser.new(:test_role, :test_attr_value => test_model_1.test_attrs.first.id ) assert_equal 1, TestAttr.with_permissions_to( :read, :context => :test_attrs, :user => user ).length assert_equal 1, TestAttr.with_permissions_to( :read, :user => user ).length - assert_raise Authorization::NotAuthorized do + assert_raises Authorization::NotAuthorized do TestAttr.with_permissions_to( :update_test_attrs, :user => user ) end TestAttr.delete_all @@ -244,7 +244,7 @@ def test_with_is assert_equal 1, TestModel.with_permissions_to(:read, :context => :test_models, :user => user).length assert_equal 1, TestModel.with_permissions_to(:read, :user => user).length - assert_raise Authorization::NotAuthorized do + assert_raises Authorization::NotAuthorized do TestModel.with_permissions_to(:update_test_models, :user => user) end TestModel.delete_all @@ -403,7 +403,7 @@ def test_with_lt assert_equal 1, TestModel.with_permissions_to(:read, :context => :test_models, :user => user).length assert_equal 1, TestModel.with_permissions_to(:read, :user => user).length - assert_raise Authorization::NotAuthorized do + assert_raises Authorization::NotAuthorized do TestModel.with_permissions_to(:update_test_models, :user => user) end TestModel.delete_all @@ -429,7 +429,7 @@ def test_with_lte assert_equal 2, TestModel.with_permissions_to(:read, :context => :test_models, :user => user).length assert_equal 2, TestModel.with_permissions_to(:read, :user => user).length - assert_raise Authorization::NotAuthorized do + assert_raises Authorization::NotAuthorized do TestModel.with_permissions_to(:update_test_models, :user => user) end TestModel.delete_all @@ -455,7 +455,7 @@ def test_with_gt assert_equal 1, TestModel.with_permissions_to(:read, :context => :test_models, :user => user).length assert_equal 1, TestModel.with_permissions_to(:read, :user => user).length - assert_raise Authorization::NotAuthorized do + assert_raises Authorization::NotAuthorized do TestModel.with_permissions_to(:update_test_models, :user => user) end TestModel.delete_all @@ -481,7 +481,7 @@ def test_with_gte assert_equal 2, TestModel.with_permissions_to(:read, :context => :test_models, :user => user).length assert_equal 2, TestModel.with_permissions_to(:read, :user => user).length - assert_raise Authorization::NotAuthorized do + assert_raises Authorization::NotAuthorized do TestModel.with_permissions_to(:update_test_models, :user => user) end TestModel.delete_all @@ -502,7 +502,7 @@ def test_with_empty_obligations user = MockUser.new(:test_role) assert_equal 1, TestModel.with_permissions_to(:read, :user => user).length - assert_raise Authorization::NotAuthorized do + assert_raises Authorization::NotAuthorized do TestModel.with_permissions_to(:update, :user => user) end TestModel.delete_all @@ -1164,7 +1164,7 @@ def test_with_if_permitted_to_with_no_child_permissions assert_equal 1, TestAttr.with_permissions_to(:read, :user => user).length assert_equal 1, TestAttr.with_permissions_to(:read, :user => also_allowed_user).length - assert_raise Authorization::NotAuthorized do + assert_raises Authorization::NotAuthorized do TestAttr.with_permissions_to(:read, :user => non_allowed_user).find(:all) end @@ -1451,9 +1451,7 @@ def test_permit_with_has_one_raises_no_name_error user = MockUser.new(:test_role, :test_attr => test_attr) - assert_nothing_raised do - assert instance.permit?(:update, :user => user, :object => test_model.test_attr_has_one) - end + assert instance.permit?(:update, :user => user, :object => test_model.test_attr_has_one) TestModel.delete_all TestAttr.delete_all @@ -1475,12 +1473,11 @@ def test_model_security_write_allowed Authorization.current_user = MockUser.new(:test_role) assert(object = TestModelSecurityModel.create) - - assert_nothing_raised { object.update_attributes(:attr_2 => 2) } + object.update_attributes(:attr_2 => 2) object.reload assert_equal 2, object.attr_2 object.destroy - assert_raise ActiveRecord::RecordNotFound do + assert_raises ActiveRecord::RecordNotFound do TestModelSecurityModel.find(object.id) end end @@ -1505,7 +1502,7 @@ def test_model_security_write_not_allowed_no_privilege assert(object = TestModelSecurityModel.create) Authorization.current_user = MockUser.new(:test_role_restricted) - assert_raise Authorization::NotAuthorized do + assert_raises Authorization::NotAuthorized do object.update_attributes(:attr_2 => 2) end end @@ -1531,19 +1528,17 @@ def test_model_security_write_not_allowed_wrong_attribute_value Authorization.current_user = MockUser.new(:test_role) assert(object = TestModelSecurityModel.create) - assert_raise Authorization::AttributeAuthorizationError do + assert_raises Authorization::AttributeAuthorizationError do TestModelSecurityModel.create :attr => 2 end object = TestModelSecurityModel.create - assert_raise Authorization::AttributeAuthorizationError do + assert_raises Authorization::AttributeAuthorizationError do object.update_attributes(:attr => 2) end object.reload + object.update_attributes(:attr_2 => 1) - assert_nothing_raised do - object.update_attributes(:attr_2 => 1) - end - assert_raise Authorization::AttributeAuthorizationError do + assert_raises Authorization::AttributeAuthorizationError do object.update_attributes(:attr => 2) end end @@ -1571,10 +1566,8 @@ def test_model_security_with_and_without_find_restrictions object = TestModelSecurityModel.create :attr => 2 object_with_find = TestModelSecurityModelWithFind.create :attr => 2 Authorization.current_user = MockUser.new(:test_role) - assert_nothing_raised do - object.class.find(object.id) - end - assert_raise Authorization::AttributeAuthorizationError do + object.class.find(object.id) + assert_raises Authorization::AttributeAuthorizationError do object_with_find.class.find(object_with_find.id) end end @@ -1596,9 +1589,7 @@ def test_model_security_with_read_restrictions_and_exists test_attr = TestAttr.create Authorization.current_user = MockUser.new(:test_role, :test_attr => test_attr) object_with_find = TestModelSecurityModelWithFind.create :test_attr => test_attr - assert_nothing_raised do - object_with_find.class.find(object_with_find.id) - end + object_with_find.class.find(object_with_find.id) assert_equal 1, test_attr.test_model_security_model_with_finds.length # Raises error since AR does not populate the object @@ -1628,7 +1619,7 @@ def test_model_security_delete_unallowed object = TestModelSecurityModel.create :attr => 2 Authorization.current_user = MockUser.new(:test_role) - assert_raise Authorization::AttributeAuthorizationError do + assert_raises Authorization::AttributeAuthorizationError do object.destroy end end @@ -1657,7 +1648,7 @@ def test_model_security_changing_critical_attribute_unallowed Authorization.current_user = MockUser.new(:test_role) # TODO before not checked yet - #assert_raise Authorization::AuthorizationError do + #assert_raises Authorization::AuthorizationError do # object.update_attributes(:attr => 1) #end end @@ -1671,7 +1662,7 @@ def test_model_security_no_role_unallowed Authorization::Engine.instance(reader) Authorization.current_user = MockUser.new(:test_role_2) - assert_raise Authorization::NotAuthorized do + assert_raises Authorization::NotAuthorized do TestModelSecurityModel.create end end @@ -1694,15 +1685,14 @@ def test_model_security_with_assoc test_attr.role_symbols << :test_role Authorization.current_user = test_attr assert(object = TestModelSecurityModel.create(:test_attrs => [test_attr])) - assert_nothing_raised do - object.update_attributes(:attr_2 => 2) - end + object.update_attributes(:attr_2 => 2) + without_access_control do object.reload end assert_equal 2, object.attr_2 object.destroy - assert_raise ActiveRecord::RecordNotFound do + assert_raises ActiveRecord::RecordNotFound do TestModelSecurityModel.find(object.id) end end @@ -1730,9 +1720,7 @@ def test_model_security_with_update_attrbributes end with_user MockUser.new(:test_role, :branch => test_attr.branch) do - assert_nothing_raised do - test_model.update_attributes(params[:model_data]) - end + test_model.update_attributes(params[:model_data]) end without_access_control do assert_equal params[:model_data][:attr], test_model.reload.attr @@ -1878,13 +1866,12 @@ def test_model_permitted_to end assert !executed_block - assert_nothing_raised do - allowed_read_company.permitted_to!(:read, :user => user) - end - assert_raise Authorization::NotAuthorized do + allowed_read_company.permitted_to!(:read, :user => user) + + assert_raises Authorization::NotAuthorized do prohibited_company.permitted_to!(:update, :user => user) end - assert_raise Authorization::AttributeAuthorizationError do + assert_raises Authorization::AttributeAuthorizationError do prohibited_company.permitted_to!(:read, :user => user) end end diff --git a/test/test_helper.rb b/test/test_helper.rb index 7a1271c1..5abe5a55 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -13,7 +13,6 @@ Bundler.require require 'minitest/autorun' -require 'test_support/minitest_compatibility' puts "Testing against rails #{Rails::VERSION::STRING}" diff --git a/test/test_support/minitest_compatibility.rb b/test/test_support/minitest_compatibility.rb deleted file mode 100644 index ef894800..00000000 --- a/test/test_support/minitest_compatibility.rb +++ /dev/null @@ -1,27 +0,0 @@ -require 'minitest/assertions' - -module Minitest - module Assertions - - # test/unit backwards compatibility methods - alias :assert_raise :assert_raises - alias :assert_not_empty :refute_empty - alias :assert_not_equal :refute_equal - alias :assert_not_in_delta :refute_in_delta - alias :assert_not_in_epsilon :refute_in_epsilon - alias :assert_not_includes :refute_includes - alias :assert_not_instance_of :refute_instance_of - alias :assert_not_kind_of :refute_kind_of - alias :assert_no_match :refute_match - alias :assert_not_nil :refute_nil - alias :assert_not_operator :refute_operator - alias :assert_not_predicate :refute_predicate - alias :assert_not_respond_to :refute_respond_to - alias :assert_not_same :refute_same - - def assert_nothing_raised(*) - yield - end - - end -end \ No newline at end of file From 7f7929c627f68194ba415549ed042f278afbb6b2 Mon Sep 17 00:00:00 2001 From: Anna Carey <19188+annaswims@users.noreply.github.com> Date: Tue, 1 May 2018 17:01:50 -0400 Subject: [PATCH 24/55] test for rails 5.0 --- declarative_authorization.gemspec | 2 +- gemfiles/5.0.gemfile | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) create mode 100644 gemfiles/5.0.gemfile diff --git a/declarative_authorization.gemspec b/declarative_authorization.gemspec index d43508ba..8d782be9 100644 --- a/declarative_authorization.gemspec +++ b/declarative_authorization.gemspec @@ -13,6 +13,6 @@ Gem::Specification.new do |s| s.extra_rdoc_files = ['README.rdoc', 'CHANGELOG'] s.homepage = %q{http://github.com/stffn/declarative_authorization} s.add_dependency('ruby_parser', '~> 3.6.6') - s.add_dependency('rails', '>= 4.1.0', '< 4.3.0') + s.add_dependency('rails', '>= 4.1.0', '< 5.1.0') s.add_development_dependency('test-unit') end diff --git a/gemfiles/5.0.gemfile b/gemfiles/5.0.gemfile new file mode 100644 index 00000000..8df04b29 --- /dev/null +++ b/gemfiles/5.0.gemfile @@ -0,0 +1,6 @@ +source 'https://rubygems.org' + +gem 'rails', '~> 5.0.0' +gem 'sqlite3' +gem 'rdoc' +gemspec :path => '..' From 8c87b6015f2294f123d8a3bc4410a6466c20ec26 Mon Sep 17 00:00:00 2001 From: Anna Carey <19188+annaswims@users.noreply.github.com> Date: Tue, 1 May 2018 19:10:34 -0400 Subject: [PATCH 25/55] Rails 5 fixes --- lib/declarative_authorization/in_controller.rb | 5 ++--- test/test_helper.rb | 7 ++++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/lib/declarative_authorization/in_controller.rb b/lib/declarative_authorization/in_controller.rb index 70bdb12e..77029b2e 100644 --- a/lib/declarative_authorization/in_controller.rb +++ b/lib/declarative_authorization/in_controller.rb @@ -6,8 +6,6 @@ module AuthorizationInController def self.included(base) # :nodoc: base.extend(ClassMethods) - base.hide_action :authorization_engine, :permitted_to?, - :permitted_to! end DEFAULT_DENY = false @@ -311,7 +309,8 @@ def filter_access_to(*args, &filter_block) actions = args.flatten # prevent setting filter_access_filter multiple times - skip_before_filter :filter_access_filter + #todo, something better + skip_before_filter :filter_access_filter rescue nil before_filter :filter_access_filter filter_access_permissions.each do |perm| diff --git a/test/test_helper.rb b/test/test_helper.rb index 5abe5a55..574046f7 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -106,6 +106,7 @@ def warn?; end class TestApp class Application < ::Rails::Application + config.eager_load = false config.secret_key_base = "testingpurposesonly" config.active_support.deprecation = :stderr database_path = File.expand_path('../database.yml', __FILE__) @@ -129,9 +130,9 @@ class Application < ::Rails::Application end else Rails.application.routes.draw do - match '/name/spaced_things(/:action)' => 'name/spaced_things' - match '/deep/name_spaced/things(/:action)' => 'deep/name_spaced/things' - match '/:controller(/:action(/:id))' + get '/name/spaced_things(/:action)' => 'name/spaced_things' + get '/deep/name_spaced/things(/:action)' => 'deep/name_spaced/things' + get '/:controller(/:action(/:id))' end end From 9fb63d328cabdc4c1af711a9b59359f6f03133e7 Mon Sep 17 00:00:00 2001 From: Aaron Huntsman Date: Wed, 16 May 2018 05:48:05 -0400 Subject: [PATCH 26/55] check Rails 5, Ruby 2.4 on travis --- .travis.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 56b2d550..f1f63395 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,7 +1,8 @@ language: ruby script: bundle exec rake test rvm: - - 2.2 + - 2.4 gemfile: - - gemfiles/4.1.gemfile - gemfiles/4.2.gemfile + - gemfiles/5.0.gemfile + From f8fed7febc91f49a17fd29cef8663f780e463f6b Mon Sep 17 00:00:00 2001 From: Aaron Huntsman Date: Wed, 16 May 2018 06:27:20 -0400 Subject: [PATCH 27/55] clear current_user in test teardown --- test/controller_test.rb | 4 ++++ test/model_test.rb | 5 ++++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/test/controller_test.rb b/test/controller_test.rb index aa9d8b6e..0027820e 100644 --- a/test/controller_test.rb +++ b/test/controller_test.rb @@ -173,6 +173,10 @@ def test_permitted_to_without_context @controller.authorization_engine = Authorization::Engine.new(reader) assert @controller.permitted_to?(:test) end + + def teardown + @controller.current_user = nil + end end diff --git a/test/model_test.rb b/test/model_test.rb index 874a569e..49c3902d 100644 --- a/test/model_test.rb +++ b/test/model_test.rb @@ -1893,5 +1893,8 @@ def test_model_permitted_to_with_modified_context assert allowed_read_company.permitted_to?(:read, :user => user) assert !allowed_read_company.permitted_to?(:update, :user => user) end -end + def teardown + Authorization.current_user = nil + end +end From c6c80c17270f52b2d06b4c76854cd0aae0898a1e Mon Sep 17 00:00:00 2001 From: Xymist Date: Fri, 18 May 2018 14:44:33 +0100 Subject: [PATCH 28/55] Rubocop --- README.rdoc | 12 +- Rakefile | 6 +- .../authorization_rules_controller.rb | 419 ++++----- .../authorization_usages_controller.rb | 25 +- app/helpers/authorization_rules_helper.rb | 132 ++- authorization_rules.dist.rb | 16 +- config/routes.rb | 18 +- declarative_authorization.gemspec | 20 +- garlic_example.rb | 14 +- lib/declarative_authorization.rb | 10 +- .../authorization.rb | 272 +++--- .../development_support/analyzer.rb | 103 ++- .../development_support/change_analyzer.rb | 78 +- .../development_support/change_supporter.rb | 193 ++-- .../development_support.rb | 81 +- lib/declarative_authorization/helper.rb | 5 +- .../in_controller.rb | 215 ++--- lib/declarative_authorization/in_model.rb | 74 +- lib/declarative_authorization/maintenance.rb | 30 +- .../obligation_scope.rb | 82 +- lib/declarative_authorization/railsengine.rb | 2 +- lib/declarative_authorization/reader.rb | 60 +- .../install/install_generator.rb | 37 +- .../authorization/rules/rules_generator.rb | 8 +- .../rules/templates/authorization_rules.rb | 10 +- lib/tasks/authorization_tasks.rake | 56 +- test/authorization_test.rb | 782 ++++++++-------- .../controller_filter_resource_access_test.rb | 233 +++-- test/controller_test.rb | 221 +++-- test/development_support/analyzer_test.rb | 440 +++++---- .../change_analyzer_test.rb | 132 ++- .../change_supporter_test.rb | 322 ++++--- test/dsl_reader_test.rb | 65 +- test/helper_test.rb | 63 +- test/maintenance_test.rb | 37 +- test/model_test.rb | 856 +++++++++--------- test/test_helper.rb | 65 +- 37 files changed, 2592 insertions(+), 2602 deletions(-) diff --git a/README.rdoc b/README.rdoc index a2df0baf..12edfcab 100644 --- a/README.rdoc +++ b/README.rdoc @@ -239,13 +239,13 @@ objects needs to be enabled explicitly. end end -You can provide the needed object through before_filters. This way, you have +You can provide the needed object through before_actions. This way, you have full control over the object that the conditions are checked against. Just make -sure, your before_filters occur before any of the filter_access_to calls. +sure, your before_actions occur before any of the filter_access_to calls. class EmployeesController < ApplicationController - before_filter :new_employee_from_params, :only => :create - before_filter :new_employee, :only => [:index, :new] + before_action :new_employee_from_params, :only => :create + before_action :new_employee, :only => [:index, :new] filter_access_to :all, :attribute_check => true def create @@ -504,9 +504,9 @@ restful_authentication. cd ../.. && ruby script/generate authenticated user sessions * Move "include AuthenticatedSystem" to ApplicationController * Add +filter_access_to+ calls as described above. -* If you'd like to use model security, add a before_filter that sets the user +* If you'd like to use model security, add a before_action that sets the user globally to your ApplicationController. This is thread-safe. - before_filter :set_current_user + before_action :set_current_user protected def set_current_user Authorization.current_user = current_user diff --git a/Rakefile b/Rakefile index 8dadc80d..223a7d11 100644 --- a/Rakefile +++ b/Rakefile @@ -3,7 +3,7 @@ require 'rake/testtask' require 'rdoc/task' desc 'Default: run unit tests against all versions.' -task :default => 'bundles:test' +task default: 'bundles:test' def run_for_bundles(cmd) Dir['gemfiles/*.gemfile'].each do |gemfile| @@ -47,7 +47,7 @@ if File.directory?(File.join(File.dirname(__FILE__), 'garlic')) require File.join(File.dirname(__FILE__), 'garlic') end -desc "clone the garlic repo (for running ci tasks)" +desc 'clone the garlic repo (for running ci tasks)' task :get_garlic do - sh "git clone git://github.com/ianwhite/garlic.git garlic" + sh 'git clone git://github.com/ianwhite/garlic.git garlic' end diff --git a/app/controllers/authorization_rules_controller.rb b/app/controllers/authorization_rules_controller.rb index d32f7d31..8e92d7e0 100644 --- a/app/controllers/authorization_rules_controller.rb +++ b/app/controllers/authorization_rules_controller.rb @@ -1,258 +1,263 @@ -if Authorization::activate_authorization_rules_browser? - -require File.join(File.dirname(__FILE__), %w{.. .. lib declarative_authorization development_support analyzer}) -require File.join(File.dirname(__FILE__), %w{.. .. lib declarative_authorization development_support change_supporter}) -require File.join(File.dirname(__FILE__), %w{.. .. lib declarative_authorization development_support development_support}) - -begin - # for nice auth_rules output: - require "parse_tree" - require "parse_tree_extensions" - require "ruby2ruby" -rescue LoadError; end - -class AuthorizationRulesController < ApplicationController - - filter_access_to :all, :require => :read - def index - respond_to do |format| - format.html do - @auth_rules_script = File.read("#{::Rails.root}/config/authorization_rules.rb") +if Authorization.activate_authorization_rules_browser? + + require File.join(File.dirname(__FILE__), %w[.. .. lib declarative_authorization development_support analyzer]) + require File.join(File.dirname(__FILE__), %w[.. .. lib declarative_authorization development_support change_supporter]) + require File.join(File.dirname(__FILE__), %w[.. .. lib declarative_authorization development_support development_support]) + + begin + # for nice auth_rules output: + require 'parse_tree' + require 'parse_tree_extensions' + require 'ruby2ruby' + rescue LoadError; end + class AuthorizationRulesController < ApplicationController + filter_access_to :all, require: :read + def index + respond_to do |format| + format.html do + @auth_rules_script = File.read("#{::Rails.root}/config/authorization_rules.rb") + end end end - end - def graph - if params[:format] == "svg" - render :text => dot_to_svg(auth_to_dot(graph_options)), - :content_type => "image/svg+xml" + def graph + if params[:format] == 'svg' + render text: dot_to_svg(auth_to_dot(graph_options)), + content_type: 'image/svg+xml' + end end - end - def change - @users = find_all_users - @users.sort! {|a, b| a.login <=> b.login } - - @privileges = authorization_engine.auth_rules.collect {|rule| rule.privileges.to_a}.flatten.uniq - @privileges = @privileges.collect do |priv| - priv = Authorization::DevelopmentSupport::AnalyzerEngine::Privilege.for_sym(priv, authorization_engine) - ([priv] + priv.descendants + priv.ancestors).map(&:to_sym) - end.flatten.uniq - @privileges.sort_by {|priv| priv.to_s} - @privilege = params[:privilege].to_sym rescue @privileges.first - @contexts = authorization_engine.auth_rules.collect {|rule| rule.contexts.to_a}.flatten.uniq - @context = params[:context].to_sym rescue @contexts.first - - respond_to do |format| - format.html - format.js do - render :partial => 'change' + def change + @users = find_all_users + @users.sort! { |a, b| a.login <=> b.login } + + @privileges = authorization_engine.auth_rules.collect { |rule| rule.privileges.to_a }.flatten.uniq + @privileges = @privileges.collect do |priv| + priv = Authorization::DevelopmentSupport::AnalyzerEngine::Privilege.for_sym(priv, authorization_engine) + ([priv] + priv.descendants + priv.ancestors).map(&:to_sym) + end.flatten.uniq + @privileges.sort_by(&:to_s) + @privilege = begin + params[:privilege].to_sym + rescue StandardError + @privileges.first + end + @contexts = authorization_engine.auth_rules.collect { |rule| rule.contexts.to_a }.flatten.uniq + @context = begin + params[:context].to_sym + rescue StandardError + @contexts.first + end + + respond_to do |format| + format.html + format.js do + render partial: 'change' + end end end - end - def suggest_change - users_permission = params[:user].inject({}) do |memo, (user_id, data)| - if data[:permission] != "undetermined" + def suggest_change + users_permission = params[:user].each_with_object({}) do |(user_id, data), memo| + next unless data[:permission] != 'undetermined' begin memo[find_user_by_id(user_id)] = (data[:permission] == 'yes') rescue ActiveRecord::NotFound end end - memo - end - prohibited_actions = (params[:prohibited_action] || []).collect do |spec| - deserialize_changes(spec).flatten - end + prohibited_actions = (params[:prohibited_action] || []).collect do |spec| + deserialize_changes(spec).flatten + end - analyzer = Authorization::DevelopmentSupport::ChangeSupporter.new(authorization_engine) - - privilege = params[:privilege].to_sym - context = params[:context].to_sym - all_users = User.all - @context = context - @approaches = analyzer.find_approaches_for(:users => all_users, :prohibited_actions => prohibited_actions) do - users.each_with_index do |user, idx| - unless users_permission[all_users[idx]].nil? - args = [privilege, {:context => context, :user => user}] - assert(users_permission[all_users[idx]] ? permit?(*args) : !permit?(*args)) + analyzer = Authorization::DevelopmentSupport::ChangeSupporter.new(authorization_engine) + + privilege = params[:privilege].to_sym + context = params[:context].to_sym + all_users = User.all + @context = context + @approaches = analyzer.find_approaches_for(users: all_users, prohibited_actions: prohibited_actions) do + users.each_with_index do |user, idx| + unless users_permission[all_users[idx]].nil? + args = [privilege, { context: context, user: user }] + assert(users_permission[all_users[idx]] ? permit?(*args) : !permit?(*args)) + end end end - end - @affected_users = @approaches.each_with_object({}) do |approach, memo| - memo[approach] = approach.affected_users(authorization_engine, all_users, privilege, context).length - end - max_affected_users = @affected_users.values.max - if params[:affected_users] - @approaches = @approaches.sort_by do |approach| - affected_users_count = @affected_users[approach] - if params[:affected_users] == "many" - #approach.weight.to_f / [affected_users_count, 0.1].min - approach.weight + (max_affected_users - affected_users_count) * 10 - else - #approach.weight * affected_users_count - approach.weight + affected_users_count * 10 + @affected_users = @approaches.each_with_object({}) do |approach, memo| + memo[approach] = approach.affected_users(authorization_engine, all_users, privilege, context).length + end + max_affected_users = @affected_users.values.max + if params[:affected_users] + @approaches = @approaches.sort_by do |approach| + affected_users_count = @affected_users[approach] + if params[:affected_users] == 'many' + # approach.weight.to_f / [affected_users_count, 0.1].min + approach.weight + (max_affected_users - affected_users_count) * 10 + else + # approach.weight * affected_users_count + approach.weight + affected_users_count * 10 + end end end - end - @grouped_approaches = analyzer.group_approaches(@approaches) + @grouped_approaches = analyzer.group_approaches(@approaches) - respond_to do |format| - format.js do - render :partial => 'suggestions' + respond_to do |format| + format.js do + render partial: 'suggestions' + end end end - end - private - def auth_to_dot(options = {}) - options = { - :effective_role_privs => true, - :privilege_hierarchy => false, - :stacked_roles => false, - :only_relevant_contexts => true, - :only_relevant_roles => false, - :filter_roles => nil, - :filter_contexts => nil, - :highlight_privilege => nil, - :changes => nil, - :users => nil - }.merge(options) - - @has_changes = options[:changes] && !options[:changes].empty? - @highlight_privilege = options[:highlight_privilege] - @stacked_roles = options[:stacked_roles] - - @users = options[:users] - - engine = authorization_engine.clone - @changes = replay_changes(engine, @users, options[:changes]) if options[:changes] - - options[:filter_roles] ||= @users.collect {|user| user.role_symbols}.flatten.uniq if options[:only_relevant_roles] and @users - - filter_roles_flattened = nil - if options[:filter_roles] - filter_roles_flattened = options[:filter_roles].collect do |role_sym| - Authorization::DevelopmentSupport::AnalyzerEngine::Role.for_sym(role_sym, engine). - ancestors.map(&:to_sym) + [role_sym] - end.flatten.uniq - end + private + + def auth_to_dot(options = {}) + options = { + effective_role_privs: true, + privilege_hierarchy: false, + stacked_roles: false, + only_relevant_contexts: true, + only_relevant_roles: false, + filter_roles: nil, + filter_contexts: nil, + highlight_privilege: nil, + changes: nil, + users: nil + }.merge(options) + + @has_changes = options[:changes] && !options[:changes].empty? + @highlight_privilege = options[:highlight_privilege] + @stacked_roles = options[:stacked_roles] + + @users = options[:users] + + engine = authorization_engine.clone + @changes = replay_changes(engine, @users, options[:changes]) if options[:changes] + + options[:filter_roles] ||= @users.collect(&:role_symbols).flatten.uniq if options[:only_relevant_roles] && @users + + filter_roles_flattened = nil + if options[:filter_roles] + filter_roles_flattened = options[:filter_roles].collect do |role_sym| + Authorization::DevelopmentSupport::AnalyzerEngine::Role.for_sym(role_sym, engine) + .ancestors.map(&:to_sym) + [role_sym] + end.flatten.uniq + end - @roles = engine.roles - @roles = @roles.select {|r| filter_roles_flattened.include?(r) } if options[:filter_roles] - @role_hierarchy = engine.role_hierarchy - @privilege_hierarchy = engine.privilege_hierarchy - - @contexts = engine.auth_rules. - collect {|ar| ar.contexts.to_a}.flatten.uniq - @contexts = @contexts.select {|c| c == options[:filter_contexts] } if options[:filter_contexts] - @context_privs = {} - @role_privs = {} - engine.auth_rules.each do |auth_rule| - @role_privs[auth_rule.role] ||= [] - auth_rule.contexts. - select {|c| options[:filter_contexts].nil? or c == options[:filter_contexts]}. - each do |context| - @context_privs[context] ||= [] - @context_privs[context] += auth_rule.privileges.to_a - @context_privs[context].uniq! - @role_privs[auth_rule.role] += auth_rule.privileges.collect {|p| [context, p, auth_rule.attributes.empty?, auth_rule.to_long_s]} + @roles = engine.roles + @roles = @roles.select { |r| filter_roles_flattened.include?(r) } if options[:filter_roles] + @role_hierarchy = engine.role_hierarchy + @privilege_hierarchy = engine.privilege_hierarchy + + @contexts = engine.auth_rules + .collect { |ar| ar.contexts.to_a }.flatten.uniq + @contexts = @contexts.select { |c| c == options[:filter_contexts] } if options[:filter_contexts] + @context_privs = {} + @role_privs = {} + engine.auth_rules.each do |auth_rule| + @role_privs[auth_rule.role] ||= [] + auth_rule.contexts + .select { |c| options[:filter_contexts].nil? || (c == options[:filter_contexts]) } + .each do |context| + @context_privs[context] ||= [] + @context_privs[context] += auth_rule.privileges.to_a + @context_privs[context].uniq! + @role_privs[auth_rule.role] += auth_rule.privileges.collect { |p| [context, p, auth_rule.attributes.empty?, auth_rule.to_long_s] } + end end - end - if options[:effective_role_privs] - @roles.each do |role| - role = Authorization::DevelopmentSupport::AnalyzerEngine::Role.for_sym(role, engine) - @role_privs[role.to_sym] ||= [] - role.ancestors.each do |lower_role| - @role_privs[role.to_sym].concat(@role_privs[lower_role.to_sym]).uniq! + if options[:effective_role_privs] + @roles.each do |role| + role = Authorization::DevelopmentSupport::AnalyzerEngine::Role.for_sym(role, engine) + @role_privs[role.to_sym] ||= [] + role.ancestors.each do |lower_role| + @role_privs[role.to_sym].concat(@role_privs[lower_role.to_sym]).uniq! + end end end - end - @roles.delete_if do |role| - role = Authorization::DevelopmentSupport::AnalyzerEngine::Role.for_sym(role, engine) - ([role] + role.ancestors).all? {|inner_role| @role_privs[inner_role.to_sym].blank? } - end + @roles.delete_if do |role| + role = Authorization::DevelopmentSupport::AnalyzerEngine::Role.for_sym(role, engine) + ([role] + role.ancestors).all? { |inner_role| @role_privs[inner_role.to_sym].blank? } + end - if options[:only_relevant_contexts] - @contexts.delete_if do |context| - @roles.all? {|role| !@role_privs[role] || !@role_privs[role].any? {|info| info[0] == context}} + if options[:only_relevant_contexts] + @contexts.delete_if do |context| + @roles.all? { |role| !@role_privs[role] || @role_privs[role].none? { |info| info[0] == context } } + end end - end - if options[:privilege_hierarchy] - @context_privs.each do |context, privs| - privs.each do |priv| - context_lower_privs = (@privilege_hierarchy[priv] || []). - select {|p,c| c.nil? or c == context}. - collect {|p,c| p} - privs.concat(context_lower_privs).uniq! + if options[:privilege_hierarchy] + @context_privs.each do |context, privs| + privs.each do |priv| + context_lower_privs = (@privilege_hierarchy[priv] || []) + .select { |_p, c| c.nil? || (c == context) } + .collect { |p, _c| p } + privs.concat(context_lower_privs).uniq! + end end end - end - render_to_string :template => 'authorization_rules/graph.dot.erb', :layout => false - end + render_to_string template: 'authorization_rules/graph.dot.erb', layout: false + end - def replay_changes(engine, users, changes) - changes.inject({}) do |memo, info| - case info[0] - when :add_privilege, :add_role - Authorization::DevelopmentSupport::AnalyzerEngine.apply_change(engine, info) - when :assign_role_to_user - user = users.find {|u| u.login == info[2]} - user.role_symbols << info[1] if user + def replay_changes(engine, users, changes) + changes.each_with_object({}) do |info, memo| + case info[0] + when :add_privilege, :add_role + Authorization::DevelopmentSupport::AnalyzerEngine.apply_change(engine, info) + when :assign_role_to_user + user = users.find { |u| u.login == info[2] } + user.role_symbols << info[1] if user + end + (memo[info[0]] ||= Set.new) << info[1..-1] end - (memo[info[0]] ||= Set.new) << info[1..-1] - memo end - end - def dot_to_svg(dot_data) - gv = IO.popen("#{Authorization.dot_path} -q -Tsvg", "w+") - gv.puts dot_data - gv.close_write - gv.read - rescue IOError, Errno::EPIPE => e - raise Exception, "Error in call to graphviz: #{e}" - end + def dot_to_svg(dot_data) + gv = IO.popen("#{Authorization.dot_path} -q -Tsvg", 'w+') + gv.puts dot_data + gv.close_write + gv.read + rescue IOError, Errno::EPIPE => e + raise Exception, "Error in call to graphviz: #{e}" + end - def graph_options - { - :effective_role_privs => !params[:effective_role_privs].blank?, - :privilege_hierarchy => !params[:privilege_hierarchy].blank?, - :stacked_roles => !params[:stacked_roles].blank?, - :only_relevant_roles => !params[:only_relevant_roles].blank?, - :filter_roles => params[:filter_roles].blank? ? nil : (params[:filter_roles].is_a?(Array) ? params[:filter_roles].map(&:to_sym) : [params[:filter_roles].to_sym]), - :filter_contexts => params[:filter_contexts].blank? ? nil : params[:filter_contexts].to_sym, - :highlight_privilege => params[:highlight_privilege].blank? ? nil : params[:highlight_privilege].to_sym, - :changes => deserialize_changes(params[:changes]), - :users => params[:user_ids] && params[:user_ids].collect {|user_id| find_user_by_id(user_id)} - } - end + def graph_options + { + effective_role_privs: !params[:effective_role_privs].blank?, + privilege_hierarchy: !params[:privilege_hierarchy].blank?, + stacked_roles: !params[:stacked_roles].blank?, + only_relevant_roles: !params[:only_relevant_roles].blank?, + filter_roles: params[:filter_roles].blank? ? nil : (params[:filter_roles].is_a?(Array) ? params[:filter_roles].map(&:to_sym) : [params[:filter_roles].to_sym]), + filter_contexts: params[:filter_contexts].blank? ? nil : params[:filter_contexts].to_sym, + highlight_privilege: params[:highlight_privilege].blank? ? nil : params[:highlight_privilege].to_sym, + changes: deserialize_changes(params[:changes]), + users: params[:user_ids] && params[:user_ids].collect { |user_id| find_user_by_id(user_id) } + } + end - def deserialize_changes(changes) - if changes - changes.split(';').collect do |info| - info.split(',').collect do |info_part| - info_part[0,1] == ':' ? info_part[1..-1].to_sym : info_part + def deserialize_changes(changes) + if changes + changes.split(';').collect do |info| + info.split(',').collect do |info_part| + info_part[0, 1] == ':' ? info_part[1..-1].to_sym : info_part + end end end end - end - def find_user_by_id(id) - User.find(id) - end - def find_all_users - User.all.select {|user| !user.login.blank?} + def find_user_by_id(id) + User.find(id) + end + + def find_all_users + User.all.reject { |user| user.login.blank? } + end end -end else -class AuthorizationRulesController < ApplicationController; end + class AuthorizationRulesController < ApplicationController; end end # activate_authorization_rules_browser? diff --git a/app/controllers/authorization_usages_controller.rb b/app/controllers/authorization_usages_controller.rb index 8e8f0355..7aa9ba9c 100644 --- a/app/controllers/authorization_usages_controller.rb +++ b/app/controllers/authorization_usages_controller.rb @@ -1,22 +1,21 @@ -if Authorization::activate_authorization_rules_browser? +if Authorization.activate_authorization_rules_browser? -require File.join(File.dirname(__FILE__), %w{.. .. lib declarative_authorization maintenance}) + require File.join(File.dirname(__FILE__), %w[.. .. lib declarative_authorization maintenance]) -class AuthorizationUsagesController < ApplicationController + class AuthorizationUsagesController < ApplicationController + helper :authorization_rules + filter_access_to :all, require: :read + # TODO: set context? - helper :authorization_rules - filter_access_to :all, :require => :read - # TODO set context? - - def index - respond_to do |format| - format.html do - @auth_usages_by_controller = Authorization::Maintenance::Usage.usages_by_controller + def index + respond_to do |format| + format.html do + @auth_usages_by_controller = Authorization::Maintenance::Usage.usages_by_controller + end end end end -end else -class AuthorizationUsagesController < ApplicationController; end + class AuthorizationUsagesController < ApplicationController; end end # activate_authorization_rules_browser? diff --git a/app/helpers/authorization_rules_helper.rb b/app/helpers/authorization_rules_helper.rb index b7d895b3..bde1140d 100644 --- a/app/helpers/authorization_rules_helper.rb +++ b/app/helpers/authorization_rules_helper.rb @@ -1,13 +1,13 @@ module AuthorizationRulesHelper def syntax_highlight(rules) regexps = { - :constant => [/(:)(\w+)/], - :proc => ['role', 'authorization', 'privileges'], - :statement => ['has_permission_on', 'if_attribute', 'if_permitted_to', 'includes', 'privilege', 'to'], - :operator => ['is', 'contains', 'is_in', 'is_not', 'is_not_in', 'intersects'], - :special => ['user', 'true', 'false'], - :preproc => ['do', 'end', /()(=>)/, /()(\{)/, /()(\})/, /()(\[)/, /()(\])/], - :comment => [/()(#.*$)/]#, + constant: [/(:)(\w+)/], + proc: %w[role authorization privileges], + statement: %w[has_permission_on if_attribute if_permitted_to includes privilege to], + operator: %w[is contains is_in is_not is_not_in intersects], + special: %w[user true false], + preproc: ['do', 'end', /()(=>)/, /()(\{)/, /()(\})/, /()(\[)/, /()(\])/], + comment: [/()(#.*$)/] # , #:privilege => [:read], #:context => [:conferences] } @@ -16,7 +16,8 @@ def syntax_highlight(rules) rules = rules.gsub( re.is_a?(String) ? Regexp.new("(^|[^:])\\b(#{Regexp.escape(re)})\\b") : (re.is_a?(Symbol) ? Regexp.new("()(:#{Regexp.escape(re.to_s)})\\b") : re), - "\\1\\2") + "\\1\\2" + ) end end rules @@ -26,14 +27,13 @@ def policy_analysis_hints(marked_up, policy_data) analyzer = Authorization::DevelopmentSupport::Analyzer.new(controller.authorization_engine) analyzer.analyze(policy_data) marked_up_by_line = marked_up.split("\n") - reports_by_line = analyzer.reports.inject({}) do |memo, report| + reports_by_line = analyzer.reports.each_with_object({}) do |report, memo| memo[report.line || 1] ||= [] memo[report.line || 1] << report - memo end reports_by_line.each do |line, reports| - text = reports.collect {|report| "#{report.type}: #{report.message}"} * " " - note = %Q{[i]} + text = reports.collect { |report| "#{report.type}: #{report.message}" } * ' ' + note = %([i]) marked_up_by_line[line - 1] = note + marked_up_by_line[line - 1] end (marked_up_by_line * "\n").html_safe @@ -41,16 +41,16 @@ def policy_analysis_hints(marked_up, policy_data) def link_to_graph(title, options = {}) type = options[:type] || '' - link_to_function title, "$$('object')[0].data = '#{url_for :action => 'index', :format => 'svg', :type => type}'" + link_to_function title, "$$('object')[0].data = '#{url_for action: 'index', format: 'svg', type: type}'" end def navigation - link_to("Rules", authorization_rules_path) << ' | ' << - link_to("Change Support", change_authorization_rules_path) << ' | ' << - link_to("Graphical view", graph_authorization_rules_path) << ' | ' << - link_to("Usages", authorization_usages_path) #<< ' | ' << - # 'Edit | ' << - # link_to("XACML export", :action => 'index', :format => 'xacml') + link_to('Rules', authorization_rules_path) << ' | ' << + link_to('Change Support', change_authorization_rules_path) << ' | ' << + link_to('Graphical view', graph_authorization_rules_path) << ' | ' << + link_to('Usages', authorization_usages_path) # << ' | ' << + # 'Edit | ' << + # link_to("XACML export", :action => 'index', :format => 'xacml') end def role_color(role, fill = false) @@ -63,8 +63,8 @@ def role_color(role, fill = false) fill ? '#ddddff' : '#000000' end else - fill_colors = %w{#ffdddd #ddffdd #ddddff #ffffdd #ffddff #ddffff} - colors = %w{#dd0000 #00dd00 #0000dd #dddd00 #dd00dd #00dddd} + fill_colors = %w[#ffdddd #ddffdd #ddddff #ffffdd #ffddff #ddffff] + colors = %w[#dd0000 #00dd00 #0000dd #dddd00 #dd00dd #00dddd] @@role_colors ||= {} @@role_colors[role] ||= begin idx = @@role_colors.length % colors.length @@ -85,72 +85,68 @@ def privilege_color(privilege, context, role) end def human_privilege(privilege) - begin - I18n.t(privilege, :scope => [:declarative_authorization, :privilege], :raise => true) - rescue - privilege.to_s - end + I18n.t(privilege, scope: %i[declarative_authorization privilege], raise: true) + rescue StandardError + privilege.to_s end def human_context(context) - begin - context.to_s.classify.constantize.human_name - rescue - context.to_s - end + context.to_s.classify.constantize.human_name + rescue StandardError + context.to_s end def human_privilege_context(privilege, context) human = [human_privilege(privilege), human_context(context)] begin - unless I18n.t(:verb_in_front_of_object, :scope => :declarative_authorization, :raise => true) + unless I18n.t(:verb_in_front_of_object, scope: :declarative_authorization, raise: true) human.reverse! end - rescue + rescue StandardError end - human * " " + human * ' ' end def human_role(role) - Authorization::Engine.instance.title_for(role) or role.to_s + Authorization::Engine.instance.title_for(role) || role.to_s end def describe_step(step, options = {}) - options = {:with_removal => false}.merge(options) + options = { with_removal: false }.merge(options) case step[0] when :add_privilege - dont_assign = prohibit_link(step[0,3], - "Add privilege #{h human_privilege_context(step[1], step[2])} to any role", - "Don't suggest adding #{h human_privilege_context(step[1], step[2])}.", options) + dont_assign = prohibit_link(step[0, 3], + "Add privilege #{h human_privilege_context(step[1], step[2])} to any role", + "Don't suggest adding #{h human_privilege_context(step[1], step[2])}.", options) "Add privilege #{h human_privilege_context(step[1], step[2])}#{dont_assign} to role #{h human_role(step[3].to_sym)}" when :remove_privilege - dont_remove = prohibit_link(step[0,3], - "Remove privilege #{h human_privilege_context(step[1], step[2])} from any role", - "Don't suggest removing #{h human_privilege_context(step[1], step[2])}.", options) + dont_remove = prohibit_link(step[0, 3], + "Remove privilege #{h human_privilege_context(step[1], step[2])} from any role", + "Don't suggest removing #{h human_privilege_context(step[1], step[2])}.", options) "Remove privilege #{h human_privilege_context(step[1], step[2])}#{dont_remove} from role #{h human_role(step[3].to_sym)}" when :add_role "New role #{h human_role(step[1].to_sym)}" when :assign_role_to_user - dont_assign = prohibit_link(step[0,2], - "Assign role #{h human_role(step[1].to_sym)} to any user", - "Don't suggest assigning #{h human_role(step[1].to_sym)}.", options) + dont_assign = prohibit_link(step[0, 2], + "Assign role #{h human_role(step[1].to_sym)} to any user", + "Don't suggest assigning #{h human_role(step[1].to_sym)}.", options) "Assign role #{h human_role(step[1].to_sym)}#{dont_assign} to #{h readable_step_info(step[2])}" when :remove_role_from_user - dont_remove = prohibit_link(step[0,2], - "Remove role #{h human_role(step[1].to_sym)} from any user", - "Don't suggest removing #{h human_role(step[1].to_sym)}.", options) + dont_remove = prohibit_link(step[0, 2], + "Remove role #{h human_role(step[1].to_sym)} from any user", + "Don't suggest removing #{h human_role(step[1].to_sym)}.", options) "Remove role #{h human_role(step[1].to_sym)}#{dont_remove} from #{h readable_step_info(step[2])}" else - step.collect {|info| readable_step_info(info) }.map {|str| h str } * ', ' - end + prohibit_link(step, options[:with_removal] ? "#{escape_javascript(describe_step(step))}" : '', + step.collect { |info| readable_step_info(info) }.map { |str| h str } * ', ' + end + prohibit_link(step, options[:with_removal] ? escape_javascript(describe_step(step)).to_s : '', "Don't suggest this action.", options) end def prohibit_link(step, text, title, options) options[:with_removal] ? - link_to_function("[x]", "prohibit_action('#{serialize_action(step)}', '#{text}')", - :class => 'prohibit', :title => title) : + link_to_function('[x]', "prohibit_action('#{serialize_action(step)}', '#{text}')", + class: 'prohibit', title: title) : '' end @@ -163,17 +159,17 @@ def readable_step_info(info) end def serialize_changes(approach) - changes = approach.changes.collect {|step| step.to_a.first.is_a?(Enumerable) ? step.to_a : [step.to_a]} - changes.collect {|multi_step| multi_step.collect {|step| serialize_action(step) }}.flatten * ';' + changes = approach.changes.collect { |step| step.to_a.first.is_a?(Enumerable) ? step.to_a : [step.to_a] } + changes.collect { |multi_step| multi_step.collect { |step| serialize_action(step) } }.flatten * ';' end def serialize_action(step) - step.collect {|info| readable_step_info(info) } * ',' + step.collect { |info| readable_step_info(info) } * ',' end def serialize_relevant_roles(approach) - {:filter_roles =>(Authorization::DevelopmentSupport::AnalyzerEngine.relevant_roles(approach.engine, approach.users). - map(&:to_sym) + [:new_role_for_change_analyzer]).uniq}.to_param + { filter_roles: (Authorization::DevelopmentSupport::AnalyzerEngine.relevant_roles(approach.engine, approach.users) + .map(&:to_sym) + [:new_role_for_change_analyzer]).uniq }.to_param end def has_changed(*args) @@ -188,31 +184,31 @@ def auth_usage_info_classes(auth_info) classes = [] if auth_info[:controller_permissions] if auth_info[:controller_permissions][0] - classes << "catch-all" if auth_info[:controller_permissions][0].actions.include?(:all) - classes << "default-privilege" unless auth_info[:controller_permissions][0].privilege - classes << "default-context" unless auth_info[:controller_permissions][0].context - classes << "no-attribute-check" unless auth_info[:controller_permissions][0].attribute_check + classes << 'catch-all' if auth_info[:controller_permissions][0].actions.include?(:all) + classes << 'default-privilege' unless auth_info[:controller_permissions][0].privilege + classes << 'default-context' unless auth_info[:controller_permissions][0].context + classes << 'no-attribute-check' unless auth_info[:controller_permissions][0].attribute_check end else - classes << "unprotected" + classes << 'unprotected' end - classes * " " + classes * ' ' end def auth_usage_info_title(auth_info) titles = [] if auth_usage_info_classes(auth_info) =~ /unprotected/ - titles << "No filter_access_to call protects this action" + titles << 'No filter_access_to call protects this action' end if auth_usage_info_classes(auth_info) =~ /no-attribute-check/ - titles << "Action is not protected with attribute check" + titles << 'Action is not protected with attribute check' end if auth_usage_info_classes(auth_info) =~ /default-privilege/ - titles << "Privilege set automatically from action name by :all rule" + titles << 'Privilege set automatically from action name by :all rule' end if auth_usage_info_classes(auth_info) =~ /default-context/ - titles << "Context set automatically from controller name by filter_access_to call without :context option" + titles << 'Context set automatically from controller name by filter_access_to call without :context option' end - titles * ". " + titles * '. ' end end diff --git a/authorization_rules.dist.rb b/authorization_rules.dist.rb index 93644a9e..e32030a9 100644 --- a/authorization_rules.dist.rb +++ b/authorization_rules.dist.rb @@ -1,20 +1,20 @@ authorization do role :guest do # add permissions for guests here, e.g. - #has_permission_on :conferences, :to => :read + # has_permission_on :conferences, :to => :read end # permissions on other roles, such as - #role :admin do + # role :admin do # has_permission_on :conferences, :to => :manage - #end + # end end privileges do # default privilege hierarchies to facilitate RESTful Rails apps - privilege :manage, :includes => [:create, :read, :update, :delete] - privilege :read, :includes => [:index, :show] - privilege :create, :includes => :new - privilege :update, :includes => :edit - privilege :delete, :includes => :destroy + privilege :manage, includes: %i[create read update delete] + privilege :read, includes: %i[index show] + privilege :create, includes: :new + privilege :update, includes: :edit + privilege :delete, includes: :destroy end diff --git a/config/routes.rb b/config/routes.rb index 85c68706..25a92117 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -1,12 +1,12 @@ -if Authorization::activate_authorization_rules_browser? - Rails.application.routes.draw do - resources :authorization_rules, :only => [:index] do - collection do - get :graph - get :change - get :suggest_change - end +if Authorization.activate_authorization_rules_browser? + Rails.application.routes.draw do + resources :authorization_rules, only: [:index] do + collection do + get :graph + get :change + get :suggest_change end - resources :authorization_usages, :only => :index end + resources :authorization_usages, only: :index + end end diff --git a/declarative_authorization.gemspec b/declarative_authorization.gemspec index 8d782be9..53af6360 100644 --- a/declarative_authorization.gemspec +++ b/declarative_authorization.gemspec @@ -1,18 +1,16 @@ -# -*- encoding: utf-8 -*- - Gem::Specification.new do |s| - s.name = "declarative_authorization" - s.version = "1.0.0.pre" + s.name = 'declarative_authorization' + s.version = '1.0.0.pre' - s.required_ruby_version = ">= 2.2.0" - s.authors = ["Steffen Bartsch"] - s.summary = "declarative_authorization is a Rails plugin for maintainable authorization based on readable authorization rules." - s.email = "sbartsch@tzi.org" - s.files = %w{CHANGELOG MIT-LICENSE README.rdoc Rakefile authorization_rules.dist.rb garlic_example.rb init.rb} + Dir["app/**/*.rb"] + Dir["app/**/*.erb"] + Dir["config/*"] + Dir["lib/*.rb"] + Dir["lib/**/*.rb"] + Dir["lib/tasks/*"] + Dir["test/*"] + s.required_ruby_version = '>= 2.2.0' + s.authors = ['Steffen Bartsch'] + s.summary = 'declarative_authorization is a Rails plugin for maintainable authorization based on readable authorization rules.' + s.email = 'sbartsch@tzi.org' + s.files = %w[CHANGELOG MIT-LICENSE README.rdoc Rakefile authorization_rules.dist.rb garlic_example.rb init.rb] + Dir['app/**/*.rb'] + Dir['app/**/*.erb'] + Dir['config/*'] + Dir['lib/*.rb'] + Dir['lib/**/*.rb'] + Dir['lib/tasks/*'] + Dir['test/*'] s.has_rdoc = true s.extra_rdoc_files = ['README.rdoc', 'CHANGELOG'] - s.homepage = %q{http://github.com/stffn/declarative_authorization} - s.add_dependency('ruby_parser', '~> 3.6.6') + s.homepage = 'http://github.com/stffn/declarative_authorization' s.add_dependency('rails', '>= 4.1.0', '< 5.1.0') + s.add_dependency('ruby_parser', '~> 3.6.6') s.add_development_dependency('test-unit') end diff --git a/garlic_example.rb b/garlic_example.rb index 840af43f..6f8fa6c3 100644 --- a/garlic_example.rb +++ b/garlic_example.rb @@ -1,19 +1,19 @@ garlic do - repo 'rails', :url => 'git://github.com/rails/rails'#, :local => "~/dev/vendor/rails" - repo 'declarative_authorization', :path => '.' + repo 'rails', url: 'git://github.com/rails/rails' # , :local => "~/dev/vendor/rails" + repo 'declarative_authorization', path: '.' target 'edge' - target '2.1-stable', :branch => 'origin/2-1-stable' - target '2.2.0-RC1', :tag => 'v2.2.0' + target '2.1-stable', branch: 'origin/2-1-stable' + target '2.2.0-RC1', tag: 'v2.2.0' all_targets do prepare do - plugin 'declarative_authorization', :clone => true + plugin 'declarative_authorization', clone: true end run do - cd "vendor/plugins/declarative_authorization" do - sh "rake" + cd 'vendor/plugins/declarative_authorization' do + sh 'rake' end end end diff --git a/lib/declarative_authorization.rb b/lib/declarative_authorization.rb index 82e61fea..bce517da 100644 --- a/lib/declarative_authorization.rb +++ b/lib/declarative_authorization.rb @@ -1,11 +1,11 @@ -require File.join(%w{declarative_authorization helper}) -require File.join(%w{declarative_authorization in_controller}) +require File.join(%w[declarative_authorization helper]) +require File.join(%w[declarative_authorization in_controller]) if defined?(ActiveRecord) - require File.join(%w{declarative_authorization in_model}) - require File.join(%w{declarative_authorization obligation_scope}) + require File.join(%w[declarative_authorization in_model]) + require File.join(%w[declarative_authorization obligation_scope]) end -require File.join(%w{declarative_authorization railsengine}) if defined?(::Rails::Engine) +require File.join(%w[declarative_authorization railsengine]) if defined?(::Rails::Engine) ActionController::Base.send :include, Authorization::AuthorizationInController ActionController::Base.helper Authorization::AuthorizationHelper diff --git a/lib/declarative_authorization/authorization.rb b/lib/declarative_authorization/authorization.rb index 398b4a04..fbcffabc 100644 --- a/lib/declarative_authorization/authorization.rb +++ b/lib/declarative_authorization/authorization.rb @@ -1,49 +1,49 @@ # Authorization require File.dirname(__FILE__) + '/reader.rb' -require "set" -require "forwardable" +require 'set' +require 'forwardable' module Authorization # An exception raised if anything goes wrong in the Authorization realm - class AuthorizationError < StandardError ; end + class AuthorizationError < StandardError; end # NotAuthorized is raised if the current user is not allowed to perform # the given operation possibly on a specific object. - class NotAuthorized < AuthorizationError ; end + class NotAuthorized < AuthorizationError; end # AttributeAuthorizationError is more specific than NotAuthorized, signaling # that the access was denied on the grounds of attribute conditions. - class AttributeAuthorizationError < NotAuthorized ; end + class AttributeAuthorizationError < NotAuthorized; end # AuthorizationUsageError is used whenever a situation is encountered # in which the application misused the plugin. That is, if, e.g., # authorization rules may not be evaluated. - class AuthorizationUsageError < AuthorizationError ; end + class AuthorizationUsageError < AuthorizationError; end # NilAttributeValueError is raised by Attribute#validate? when it hits a nil attribute value. # The exception is raised to ensure that the entire rule is invalidated. class NilAttributeValueError < AuthorizationError; end - AUTH_DSL_FILES = [Pathname.new(Rails.root || '').join("config", "authorization_rules.rb").to_s] unless defined? AUTH_DSL_FILES + AUTH_DSL_FILES = [Pathname.new(Rails.root || '').join('config', 'authorization_rules.rb').to_s].freeze unless defined? AUTH_DSL_FILES # Controller-independent method for retrieving the current user. # Needed for model security where the current controller is not available. def self.current_user - Thread.current["current_user"] || AnonymousUser.new + Thread.current['current_user'] || AnonymousUser.new end # Controller-independent method for setting the current user. def self.current_user=(user) - Thread.current["current_user"] = user + Thread.current['current_user'] = user end # For use in test cases only def self.ignore_access_control(state = nil) # :nodoc: - Thread.current["ignore_access_control"] = state unless state.nil? - Thread.current["ignore_access_control"] || false + Thread.current['ignore_access_control'] = state unless state.nil? + Thread.current['ignore_access_control'] || false end def self.activate_authorization_rules_browser? # :nodoc: ::Rails.env.development? end - @@dot_path = "dot" + @@dot_path = 'dot' def self.dot_path @@dot_path end @@ -81,7 +81,7 @@ class Engine # authorization configuration of +AUTH_DSL_FILES+. If given, may be either # a Reader object or a path to a configuration file. def initialize(reader = nil) - #@auth_rules = AuthorizationRuleSet.new reader.auth_rules_reader.auth_rules + # @auth_rules = AuthorizationRuleSet.new reader.auth_rules_reader.auth_rules @reader = Reader::DSLReader.factory(reader || AUTH_DSL_FILES) end @@ -141,15 +141,15 @@ def rev_role_hierarchy def permit!(privilege, options = {}) return true if Authorization.ignore_access_control options = { - :object => nil, - :skip_attribute_test => false, - :context => nil, - :bang => true + object: nil, + skip_attribute_test: false, + context: nil, + bang: true }.merge(options) # Make sure we're handling all privileges as symbols. - privilege = privilege.is_a?( Array ) ? - privilege.flatten.collect { |priv| priv.to_sym } : + privilege = privilege.is_a?(Array) ? + privilege.flatten.collect(&:to_sym) : privilege.to_sym # @@ -160,18 +160,22 @@ def permit!(privilege, options = {}) # Example: permit!( :edit, :object => user.posts ) # if Authorization.is_a_association_proxy?(options[:object]) && options[:object].respond_to?(:new) - options[:object] = options[:object].where(nil).new + options[:object] = options[:object].where(nil).new end - options[:context] ||= options[:object] && ( - options[:object].class.respond_to?(:decl_auth_context) ? - options[:object].class.decl_auth_context : - options[:object].class.name.tableize.to_sym - ) rescue NoMethodError + begin + options[:context] ||= options[:object] && ( + options[:object].class.respond_to?(:decl_auth_context) ? + options[:object].class.decl_auth_context : + options[:object].class.name.tableize.to_sym + ) + rescue StandardError + NoMethodError + end user, roles, privileges = user_roles_privleges_from_options(privilege, options) - return true if roles.is_a?(Array) and not (roles & omnipotent_roles).empty? + return true if roles.is_a?(Array) && !(roles & omnipotent_roles).empty? # find a authorization rule that matches for at least one of the roles and # at least one of the given privileges @@ -185,9 +189,9 @@ def permit!(privilege, options = {}) if options[:bang] if rules.empty? - raise NotAuthorized, "No matching rules found for #{privilege} for User with id #{user.try(:id)} " + - "(roles #{roles.inspect}, privileges #{privileges.inspect}, " + - "context #{options[:context].inspect})." + raise NotAuthorized, "No matching rules found for #{privilege} for User with id #{user.try(:id)} " \ + "(roles #{roles.inspect}, privileges #{privileges.inspect}, " \ + "context #{options[:context].inspect})." else raise AttributeAuthorizationError, "#{privilege} not allowed for User with id #{user.try(:id)} on #{(options[:object] || options[:context]).inspect}." end @@ -199,7 +203,7 @@ def permit!(privilege, options = {}) # Calls permit! but doesn't raise authorization errors. If no exception is # raised, permit? returns true and yields to the optional block. def permit?(privilege, options = {}) # :yields: - if permit!(privilege, options.merge(:bang=> false)) + if permit!(privilege, options.merge(bang: false)) yield if block_given? true else @@ -224,12 +228,12 @@ def permit?(privilege, options = {}) # :yields: # [:+user+] See permit! # def obligations(privilege, options = {}) - options = {:context => nil}.merge(options) + options = { context: nil }.merge(options) user, roles, privileges = user_roles_privleges_from_options(privilege, options) - permit!(privilege, :skip_attribute_test => true, :user => user, :context => options[:context]) + permit!(privilege, skip_attribute_test: true, user: user, context: options[:context]) - return [] if roles.is_a?(Array) and not (roles & omnipotent_roles).empty? + return [] if roles.is_a?(Array) && !(roles & omnipotent_roles).empty? attr_validator = AttributeValidator.new(self, user, nil, privilege, options[:context]) matching_auth_rules(roles, privileges, options[:context]).collect do |rule| @@ -255,16 +259,19 @@ def title_for(role) def roles_for(user) user ||= Authorization.current_user raise AuthorizationUsageError, "User object doesn't respond to roles (#{user.try(:id)})" \ - if !user.respond_to?(:role_symbols) and !user.respond_to?(:roles) + if !user.respond_to?(:role_symbols) && !user.respond_to?(:roles) - Rails.logger.info("The use of user.roles is deprecated. Please add a method " + - "role_symbols to your User model.") if defined?(Rails) and Rails.respond_to?(:logger) and !user.respond_to?(:role_symbols) + if defined?(Rails) && Rails.respond_to?(:logger) && !user.respond_to?(:role_symbols) + Rails.logger.info('The use of user.roles is deprecated. Please add a method ' \ + 'role_symbols to your User model.') + end roles = user.respond_to?(:role_symbols) ? user.role_symbols : user.roles - raise AuthorizationUsageError, "User.#{user.respond_to?(:role_symbols) ? 'role_symbols' : 'roles'} " + - "doesn't return an Array of Symbols (#{roles.inspect})" \ - if !roles.is_a?(Array) or (!roles.empty? and !roles[0].is_a?(Symbol)) + if !roles.is_a?(Array) || (!roles.empty? && !roles[0].is_a?(Symbol)) + raise AuthorizationUsageError, "User.#{user.respond_to?(:role_symbols) ? 'role_symbols' : 'roles'} " \ + "doesn't return an Array of Symbols (#{roles.inspect})" + end (roles.empty? ? [Authorization.default_role] : roles) end @@ -277,12 +284,12 @@ def roles_with_hierarchy_for(user) def self.development_reload? if Rails.env.development? mod_time = AUTH_DSL_FILES.map do |m| - begin - File.mtime(m) - rescue - Time.at(0) - end - end.flatten.max + begin + File.mtime(m) + rescue StandardError + Time.at(0) + end + end.flatten.max @@auth_dsl_last_modified ||= mod_time if mod_time > @@auth_dsl_last_modified @@auth_dsl_last_modified = mod_time @@ -295,7 +302,7 @@ def self.development_reload? # yet. If +dsl_file+ is given, it is passed on to Engine.new and # a new instance is always created. def self.instance(dsl_file = nil) - if dsl_file or development_reload? + if dsl_file || development_reload? @@instance = new(dsl_file) else @@instance ||= new @@ -313,23 +320,26 @@ def initialize(engine, user, object = nil, privilege = nil, context = nil) end def evaluate(value_block) - # TODO cache? + # TODO: cache? instance_eval(&value_block) end end private + def user_roles_privleges_from_options(privilege, options) options = { - :user => nil, - :context => nil, - :user_roles => nil + user: nil, + context: nil, + user_roles: nil }.merge(options) user = options[:user] || Authorization.current_user privileges = privilege.is_a?(Array) ? privilege : [privilege] - raise AuthorizationUsageError, "No user object given for user id (#{user.try(:id)}) or " + - "set through Authorization.current_user" unless user + unless user + raise AuthorizationUsageError, "No user object given for user id (#{user.try(:id)}) or " \ + 'set through Authorization.current_user' + end roles = options[:user_roles] || flatten_roles(roles_for(user)) privileges = flatten_privileges privileges, options[:context] @@ -337,8 +347,8 @@ def user_roles_privleges_from_options(privilege, options) end def flatten_roles(roles, flattened_roles = Set.new) - # TODO caching? - roles.reject {|role| flattened_roles.include?(role)}.each do |role| + # TODO: caching? + roles.reject { |role| flattened_roles.include?(role) }.each do |role| flattened_roles << role flatten_roles(role_hierarchy[role], flattened_roles) if role_hierarchy[role] end @@ -347,9 +357,9 @@ def flatten_roles(roles, flattened_roles = Set.new) # Returns the privilege hierarchy flattened for given privileges in context. def flatten_privileges(privileges, context = nil, flattened_privileges = Set.new) - # TODO caching? - raise AuthorizationUsageError, "No context given or inferable from object" unless context - privileges.reject {|priv| flattened_privileges.include?(priv)}.each do |priv| + # TODO: caching? + raise AuthorizationUsageError, 'No context given or inferable from object' unless context + privileges.reject { |priv| flattened_privileges.include?(priv) }.each do |priv| flattened_privileges << priv flatten_privileges(rev_priv_hierarchy[[priv, nil]], context, flattened_privileges) if rev_priv_hierarchy[[priv, nil]] flatten_privileges(rev_priv_hierarchy[[priv, context]], context, flattened_privileges) if rev_priv_hierarchy[[priv, context]] @@ -362,7 +372,6 @@ def matching_auth_rules(roles, privileges, context) end end - class AuthorizationRuleSet include Enumerable extend Forwardable @@ -373,8 +382,8 @@ def initialize(rules = []) reset! end - def initialize_copy(source) - @rules = @rules.collect {|rule| rule.clone} + def initialize_copy(_source) + @rules = @rules.collect(&:clone) reset! end @@ -397,12 +406,13 @@ def <<(rule) end def each(&block) - @rules.each &block + @rules.each block end private + def reset! - @cached_auth_rules =nil + @cached_auth_rules = nil end def cached_auth_rules @@ -420,10 +430,10 @@ def cached_auth_rules class AuthorizationRule attr_reader :attributes, :contexts, :role, :privileges, :join_operator, - :source_file, :source_line + :source_file, :source_line def initialize(role, privileges = [], contexts = nil, join_operator = :or, - options = {}) + options = {}) @role = role @privileges = Set.new(privileges) @contexts = Set.new((contexts && !contexts.is_a?(Array) ? [contexts] : contexts)) @@ -433,10 +443,10 @@ def initialize(role, privileges = [], contexts = nil, join_operator = :or, @source_line = options[:source_line] end - def initialize_copy(from) + def initialize_copy(_from) @privileges = @privileges.clone @contexts = @contexts.clone - @attributes = @attributes.collect {|attribute| attribute.clone } + @attributes = @attributes.collect(&:clone) end def append_privileges(privs) @@ -449,16 +459,16 @@ def append_attribute(attribute) def matches?(roles, privs, context = nil) roles = [roles] unless roles.is_a?(Array) - @contexts.include?(context) and roles.include?(@role) and - not (@privileges & privs).empty? + @contexts.include?(context) && roles.include?(@role) && + !(@privileges & privs).empty? end def validate?(attr_validator, skip_attribute = false) - skip_attribute or @attributes.empty? or + skip_attribute || @attributes.empty? || @attributes.send(@join_operator == :and ? :all? : :any?) do |attr| begin attr.validate?(attr_validator) - rescue NilAttributeValueError => e + rescue NilAttributeValueError nil # Bumping up against a nil attribute value flunks the rule. end end @@ -475,13 +485,13 @@ def obligations(attr_validator) end end - if exceptions.length > 0 and (@join_operator == :and or exceptions.length == @attributes.length) - raise NotAuthorized, "Missing authorization in collecting obligations: #{exceptions.map(&:to_s) * ", "}" + if !exceptions.empty? && ((@join_operator == :and) || (exceptions.length == @attributes.length)) + raise NotAuthorized, "Missing authorization in collecting obligations: #{exceptions.map(&:to_s) * ', '}" end - if @join_operator == :and and !obligations.empty? + if (@join_operator == :and) && !obligations.empty? # cross product of OR'ed obligations in arrays - arrayed_obligations = obligations.map {|obligation| obligation.is_a?(Hash) ? [obligation] : obligation} + arrayed_obligations = obligations.map { |obligation| obligation.is_a?(Hash) ? [obligation] : obligation } merged_obligations = arrayed_obligations.first arrayed_obligations[1..-1].each do |inner_obligations| previous_merged_obligations = merged_obligations @@ -499,7 +509,7 @@ def obligations(attr_validator) end def to_long_s - attributes.collect {|attr| attr.to_long_s } * "; " + attributes.collect(&:to_long_s) * '; ' end end @@ -511,7 +521,7 @@ def initialize(conditions_hash) @conditions_hash = conditions_hash end - def initialize_copy(from) + def initialize_copy(_from) @conditions_hash = deep_hash_clone(@conditions_hash) end @@ -519,8 +529,8 @@ def validate?(attr_validator, object = nil, hash = nil) object ||= attr_validator.object return false unless object - if ( Authorization.is_a_association_proxy?(object) && - object.respond_to?(:empty?) ) + if Authorization.is_a_association_proxy?(object) && + object.respond_to?(:empty?) return false if object.empty? object.each do |member| return true if validate?(attr_validator, member, hash) @@ -535,12 +545,12 @@ def validate?(attr_validator, object = nil, hash = nil) attr_value.any? do |inner_value| validate?(attr_validator, inner_value, value) end - elsif attr_value == nil + elsif attr_value.nil? raise NilAttributeValueError, "Attribute #{attr.inspect} is nil in #{object.inspect}." else validate?(attr_validator, attr_value, value) end - elsif value.is_a?(Array) and value.length == 2 and value.first.is_a?(Symbol) + elsif value.is_a?(Array) && (value.length == 2) && value.first.is_a?(Symbol) evaluated = if value[1].is_a?(Proc) attr_validator.evaluate(value[1]) else @@ -555,41 +565,41 @@ def validate?(attr_validator, object = nil, hash = nil) begin attr_value.include?(evaluated) rescue NoMethodError => e - raise AuthorizationUsageError, "Operator contains requires a " + - "subclass of Enumerable as attribute value, got: #{attr_value.inspect} " + - "contains #{evaluated.inspect}: #{e}" + raise AuthorizationUsageError, 'Operator contains requires a ' \ + "subclass of Enumerable as attribute value, got: #{attr_value.inspect} " \ + "contains #{evaluated.inspect}: #{e}" end when :does_not_contain begin !attr_value.include?(evaluated) rescue NoMethodError => e - raise AuthorizationUsageError, "Operator does_not_contain requires a " + - "subclass of Enumerable as attribute value, got: #{attr_value.inspect} " + - "does_not_contain #{evaluated.inspect}: #{e}" + raise AuthorizationUsageError, 'Operator does_not_contain requires a ' \ + "subclass of Enumerable as attribute value, got: #{attr_value.inspect} " \ + "does_not_contain #{evaluated.inspect}: #{e}" end when :intersects_with begin !(evaluated.to_set & attr_value.to_set).empty? rescue NoMethodError => e - raise AuthorizationUsageError, "Operator intersects_with requires " + - "subclasses of Enumerable, got: #{attr_value.inspect} " + - "intersects_with #{evaluated.inspect}: #{e}" + raise AuthorizationUsageError, 'Operator intersects_with requires ' \ + "subclasses of Enumerable, got: #{attr_value.inspect} " \ + "intersects_with #{evaluated.inspect}: #{e}" end when :is_in begin evaluated.include?(attr_value) rescue NoMethodError => e - raise AuthorizationUsageError, "Operator is_in requires a " + - "subclass of Enumerable as value, got: #{attr_value.inspect} " + - "is_in #{evaluated.inspect}: #{e}" + raise AuthorizationUsageError, 'Operator is_in requires a ' \ + "subclass of Enumerable as value, got: #{attr_value.inspect} " \ + "is_in #{evaluated.inspect}: #{e}" end when :is_not_in begin !evaluated.include?(attr_value) rescue NoMethodError => e - raise AuthorizationUsageError, "Operator is_not_in requires a " + - "subclass of Enumerable as value, got: #{attr_value.inspect} " + - "is_not_in #{evaluated.inspect}: #{e}" + raise AuthorizationUsageError, 'Operator is_not_in requires a ' \ + "subclass of Enumerable as value, got: #{attr_value.inspect} " \ + "is_not_in #{evaluated.inspect}: #{e}" end when :lt attr_value && attr_value < evaluated @@ -603,7 +613,7 @@ def validate?(attr_validator, object = nil, hash = nil) raise AuthorizationError, "Unknown operator #{value[0]}" end else - raise AuthorizationError, "Wrong conditions hash format" + raise AuthorizationError, 'Wrong conditions hash format' end end end @@ -614,10 +624,10 @@ def obligation(attr_validator, hash = nil) hash.each do |attr, value| if value.is_a?(Hash) hash[attr] = obligation(attr_validator, value) - elsif value.is_a?(Array) and value.length == 2 + elsif value.is_a?(Array) && (value.length == 2) hash[attr] = [value[0], attr_validator.evaluate(value[1])] else - raise AuthorizationError, "Wrong conditions hash format" + raise AuthorizationError, 'Wrong conditions hash format' end end hash @@ -625,13 +635,12 @@ def obligation(attr_validator, hash = nil) def to_long_s(hash = nil) if hash - hash.inject({}) do |memo, key_val| + hash.each_with_object({}) do |key_val, memo| key, val = key_val memo[key] = case val - when Array then "#{val[0]} { #{val[1].respond_to?(:to_ruby) ? val[1].to_ruby.gsub(/^proc \{\n?(.*)\n?\}$/m, '\1') : "..."} }" + when Array then "#{val[0]} { #{val[1].respond_to?(:to_ruby) ? val[1].to_ruby.gsub(/^proc \{\n?(.*)\n?\}$/m, '\1') : '...'} }" when Hash then to_long_s(val) end - memo end else "if_attribute #{to_long_s(@conditions_hash).inspect}" @@ -639,18 +648,17 @@ def to_long_s(hash = nil) end protected + def object_attribute_value(object, attr) - begin - object.send(attr) - rescue ArgumentError, NoMethodError => e - raise AuthorizationUsageError, "Error occurred while validating attribute ##{attr} on #{object.inspect}: #{e}.\n" + - "Please check your authorization rules and ensure the attribute is correctly spelled and \n" + - "corresponds to a method on the model you are authorizing for." - end + object.send(attr) + rescue ArgumentError, NoMethodError => e + raise AuthorizationUsageError, "Error occurred while validating attribute ##{attr} on #{object.inspect}: #{e}.\n" \ + "Please check your authorization rules and ensure the attribute is correctly spelled and \n" \ + 'corresponds to a method on the model you are authorizing for.' end def deep_hash_clone(hash) - hash.inject({}) do |memo, (key, val)| + hash.each_with_object({}) do |(key, val), memo| memo[key] = case val when Hash deep_hash_clone(val) @@ -659,7 +667,6 @@ def deep_hash_clone(hash) else val.clone end - memo end end end @@ -675,7 +682,7 @@ def initialize(privilege, attr_or_hash, context = nil) @attr_hash = attr_or_hash end - def initialize_copy(from) + def initialize_copy(_from) @attr_hash = deep_hash_clone(@attr_hash) if @attr_hash.is_a?(Hash) end @@ -692,15 +699,15 @@ def validate?(attr_validator, object = nil, hash_or_attr = nil) raise NilAttributeValueError, "Attribute #{hash_or_attr.inspect} is nil in #{object.inspect}." when Enumerable attr_value.any? do |inner_value| - attr_validator.engine.permit? @privilege, :object => inner_value, :user => attr_validator.user + attr_validator.engine.permit? @privilege, object: inner_value, user: attr_validator.user end else - attr_validator.engine.permit? @privilege, :object => attr_value, :user => attr_validator.user + attr_validator.engine.permit? @privilege, object: attr_value, user: attr_validator.user end when Hash hash_or_attr.all? do |attr, sub_hash| attr_value = object_attribute_value(object, attr) - if attr_value == nil + if attr_value.nil? raise NilAttributeValueError, "Attribute #{attr.inspect} is nil in #{object.inspect}." elsif attr_value.is_a?(Enumerable) attr_value.any? do |inner_value| @@ -711,7 +718,7 @@ def validate?(attr_validator, object = nil, hash_or_attr = nil) end end when NilClass - attr_validator.engine.permit? @privilege, :object => object, :user => attr_validator.user + attr_validator.engine.permit? @privilege, object: object, user: attr_validator.user else raise AuthorizationError, "Wrong conditions hash format: #{hash_or_attr.inspect}" end @@ -730,28 +737,27 @@ def obligation(attr_validator, hash_or_attr = nil, path = []) else context_reflection.klass.name.tableize.to_sym end - rescue # missing model, reflections + rescue StandardError # missing model, reflections hash_or_attr.to_s.pluralize.to_sym end obligations = attr_validator.engine.obligations(@privilege, - :context => @context, - :user => attr_validator.user) + context: @context, + user: attr_validator.user) - obligations.collect {|obl| {hash_or_attr => obl} } + obligations.collect { |obl| { hash_or_attr => obl } } when Hash obligations_array_attrs = [] obligations = - hash_or_attr.inject({}) do |all, pair| - attr, sub_hash = pair - all[attr] = obligation(attr_validator, sub_hash, path + [attr]) - if all[attr].length > 1 - obligations_array_attrs << attr - else - all[attr] = all[attr].first - end - all + hash_or_attr.each_with_object({}) do |pair, all| + attr, sub_hash = pair + all[attr] = obligation(attr_validator, sub_hash, path + [attr]) + if all[attr].length > 1 + obligations_array_attrs << attr + else + all[attr] = all[attr].first end + end obligations = [obligations] obligations_array_attrs.each do |attr| next_array_size = obligations.first[attr].length @@ -766,8 +772,8 @@ def obligation(attr_validator, hash_or_attr = nil, path = []) obligations when NilClass attr_validator.engine.obligations(@privilege, - :context => attr_validator.context, - :user => attr_validator.user) + context: attr_validator.context, + user: attr_validator.user) else raise AuthorizationError, "Wrong conditions hash format: #{hash_or_attr.inspect}" end @@ -778,15 +784,16 @@ def to_long_s end private + def self.reflection_for_path(parent_model, path) reflection = path.empty? ? parent_model : begin parent = reflection_for_path(parent_model, path[0..-2]) - if !parent.respond_to?(:proxy_reflection) and parent.respond_to?(:klass) + if !parent.respond_to?(:proxy_reflection) && parent.respond_to?(:klass) parent.klass.reflect_on_association(path.last) else parent.reflect_on_association(path.last) end - rescue + rescue StandardError parent.reflect_on_association(path.last) end raise "invalid path #{path.inspect}" if reflection.nil? @@ -802,4 +809,3 @@ def initialize(roles = [Authorization.default_role]) end end end - diff --git a/lib/declarative_authorization/development_support/analyzer.rb b/lib/declarative_authorization/development_support/analyzer.rb index d817f52a..21eb23d5 100644 --- a/lib/declarative_authorization/development_support/analyzer.rb +++ b/lib/declarative_authorization/development_support/analyzer.rb @@ -1,18 +1,16 @@ -require File.join(File.dirname(__FILE__), %w{development_support}) +require File.join(File.dirname(__FILE__), %w[development_support]) begin - require "ruby_parser" - #require "parse_tree" - #require "parse_tree_extensions" - require "sexp_processor" + require 'ruby_parser' + # require "parse_tree" + # require "parse_tree_extensions" + require 'sexp_processor' rescue LoadError - raise "Authorization::DevelopmentSupport::Analyzer requires ruby_parser gem" + raise 'Authorization::DevelopmentSupport::Analyzer requires ruby_parser gem' end module Authorization - module DevelopmentSupport - # Ideas for improvement # * moving rules up in the role hierarchy # * merging roles @@ -23,7 +21,7 @@ module DevelopmentSupport class Analyzer < AbstractAnalyzer def analyze(rules) sexp_array = RubyParser.new.parse(rules) - #sexp_array = ParseTree.translate(rules) + # sexp_array = ParseTree.translate(rules) @reports = [] [MergeableRulesProcessor].each do |parser| parser.new(self).analyze(sexp_array) @@ -37,7 +35,7 @@ def analyze(rules) end def reports - @reports or raise "No rules analyzed!" + @reports || raise('No rules analyzed!') end class GeneralRulesAnalyzer @@ -47,15 +45,16 @@ def initialize(analyzer) def analyze mark(:policy, nil) if analyze_policy - roles.select {|role| analyze_role(role) }. - each { |role| mark(:role, role) } - rules.select {|rule| analyze_rule(rule) }. - each { |rule| mark(:rule, rule) } - privileges.select {|privilege| !!analyze_privilege(privilege) }. - each { |privilege| mark(:privilege, privilege) } + roles.select { |role| analyze_role(role) } + .each { |role| mark(:role, role) } + rules.select { |rule| analyze_rule(rule) } + .each { |rule| mark(:rule, rule) } + privileges.select { |privilege| analyze_privilege(privilege) } + .each { |privilege| mark(:privilege, privilege) } end protected + def roles @analyzer.roles end @@ -65,17 +64,22 @@ def rules end def privileges - @privileges ||= rules.collect {|rule| rule.privileges.to_a}.flatten.uniq + @privileges ||= rules.collect { |rule| rule.privileges.to_a }.flatten.uniq end # to be implemented by specific processor def analyze_policy; end + def analyze_role(a_role); end + def analyze_rule(a_rule); end + def analyze_privilege(a_privilege); end + def message(object); end private + def source_line(object) object.source_line if object.respond_to?(:source_line) end @@ -84,9 +88,9 @@ def source_file(object) object.source_file if object.respond_to?(:source_file) end - def mark(type, object) + def mark(_type, object) @analyzer.reports << Report.new(report_type, - source_file(object), source_line(object), message(object)) + source_file(object), source_line(object), message(object)) end # analyzer class name stripped of last word @@ -100,42 +104,43 @@ class RoleExplosionAnalyzer < GeneralRulesAnalyzer SMALL_ROLES_RATIO = 0.2 def analyze_policy - small_roles.length > 1 and small_roles.length.to_f / roles.length.to_f > SMALL_ROLES_RATIO + (small_roles.length > 1) && (small_roles.length.to_f / roles.length.to_f > SMALL_ROLES_RATIO) end - def message(object) - "The ratio of small roles is quite high (> %.0f%%). Consider refactoring." % (SMALL_ROLES_RATIO * 100) + def message(_object) + format('The ratio of small roles is quite high (> %.0f%%). Consider refactoring.', (SMALL_ROLES_RATIO * 100)) end private + def small_roles - roles.select {|role| role.rules.length < SMALL_ROLE_RULES_COUNT } + roles.select { |role| role.rules.length < SMALL_ROLE_RULES_COUNT } end end class InheritingPrivilegesAnalyzer < GeneralRulesAnalyzer def analyze_rule(rule) - rule.privileges.any? {|privilege| rule.privileges.intersects?(privilege.ancestors) } + rule.privileges.any? { |privilege| rule.privileges.intersects?(privilege.ancestors) } end - def message(object) - "At least one privilege inherits from another in this rule." + def message(_object) + 'At least one privilege inherits from another in this rule.' end end class ProposedPrivilegeHierarchyAnalyzer < GeneralRulesAnalyzer - # TODO respect, consider contexts + # TODO: respect, consider contexts def analyze_privilege(privilege) privileges.find do |other_privilege| - other_privilege != privilege and - other_privilege.rules.all? {|rule| rule.privileges.include?(privilege)} + (other_privilege != privilege) && + other_privilege.rules.all? { |rule| rule.privileges.include?(privilege) } end end def message(privilege) other_privilege = analyze_privilege(privilege) - "Privilege #{other_privilege.to_sym} is always used together with #{privilege.to_sym}. " + - "Consider to include #{other_privilege.to_sym} in #{privilege.to_sym}." + "Privilege #{other_privilege.to_sym} is always used together with #{privilege.to_sym}. " \ + "Consider to include #{other_privilege.to_sym} in #{privilege.to_sym}." end end @@ -162,11 +167,11 @@ def process_iter(exp) end def process_arglist(exp) - s(exp.collect {|inner_exp| process(inner_exp).shift}) + s(exp.collect { |inner_exp| process(inner_exp).shift }) end def process_hash(exp) - s(Hash[*exp.collect {|inner_exp| process(inner_exp).shift}]) + s(Hash[*exp.collect { |inner_exp| process(inner_exp).shift }]) end def process_lit(exp) @@ -177,22 +182,20 @@ def process_lit(exp) class MergeableRulesProcessor < GeneralAuthorizationProcessor def analyze_rules if @has_permission - #p @has_permission - permissions_by_context_and_rules = @has_permission.inject({}) do |memo, permission| + # p @has_permission + permissions_by_context_and_rules = @has_permission.each_with_object({}) do |permission, memo| key = [permission[:context], permission[:rules]] memo[key] ||= [] memo[key] << permission - memo end - permissions_by_context_and_rules.each do |key, rules| - if rules.length > 1 - rule_lines = rules.collect {|rule| rule[:line] } - rules.each do |rule| - @analyzer.reports << Report.new(:mergeable_rules, "", rule[:line], - "Similar rules already in line(s) " + - rule_lines.reject {|l| l == rule[:line] } * ", ") - end + permissions_by_context_and_rules.each do |_key, rules| + next unless rules.length > 1 + rule_lines = rules.collect { |rule| rule[:line] } + rules.each do |rule| + @analyzer.reports << Report.new(:mergeable_rules, '', rule[:line], + 'Similar rules already in line(s) ' + + rule_lines.reject { |l| l == rule[:line] } * ', ') end end end @@ -213,11 +216,11 @@ def process_call(exp) context = arglist args_hash = exp[0].nil? ? nil : process(exp.shift).shift @has_permission << { - :context => context, - :rules => [], - :privilege => args_hash && args_hash[:to], + context: context, + rules: [], + privilege: args_hash && args_hash[:to], # a hack: call exp line seems to be wrong - :line => arglist_line + line: arglist_line } s(:call, klass, name) when :to @@ -237,8 +240,8 @@ def process_call(exp) privilege = process(exp.shift) includes = process(exp.shift).shift privelege_hash = { - :privilege => privilege, - :options => includes + privilege: privilege, + options: includes } s(:call, klass, name, privelege_hash) else diff --git a/lib/declarative_authorization/development_support/change_analyzer.rb b/lib/declarative_authorization/development_support/change_analyzer.rb index 980dadce..de766195 100644 --- a/lib/declarative_authorization/development_support/change_analyzer.rb +++ b/lib/declarative_authorization/development_support/change_analyzer.rb @@ -1,13 +1,11 @@ -require File.join(File.dirname(__FILE__), %w{development_support}) +require File.join(File.dirname(__FILE__), %w[development_support]) module Authorization - module DevelopmentSupport # Ideas for improvement # * Algorithm # * Plan by tackling each condition separately # * e.g. two users have a permission through the same role, - # one should lose that # * Consider privilege hierarchy # * Consider merging, splitting roles, role hierarchies # * Add privilege to existing rules @@ -26,19 +24,18 @@ module DevelopmentSupport # * user.login is needed # class ChangeAnalyzer < AbstractAnalyzer - def find_approaches_for(change_action, type, options, &tests) - raise ArgumentError, "Missing options" if !options[:on] or !options[:to] + raise ArgumentError, 'Missing options' if !options[:on] || !options[:to] # * strategy for removing: [remove privilege, add privilege to different role] @seen_states = Set.new # * heuristic: change of failed tests; small number of policy items strategy = case [change_action, type] - when [:remove, :permission] + when %i[remove permission] [:remove_role_from_user, :remove_privilege, :add_privilege, - :add_role, :assign_role_to_user] - when [:add, :permission] - [:add_role, :add_privilege, :assign_role_to_user] + :add_role, :assign_role_to_user] + when %i[add permission] + %i[add_role add_privilege assign_role_to_user] else raise ArgumentError, "Unknown change action/type: #{[change_action, type].inspect}" end @@ -55,9 +52,9 @@ def find_approaches_for(change_action, type, options, &tests) end step_count = 0 - while !candidates.empty? and step_count < 100 + while !candidates.empty? && (step_count < 100) next_step(viable_approaches, candidates, approach_checker, options[:to], - options[:on], strategy) + options[:on], strategy) step_count += 1 end @@ -70,7 +67,8 @@ class ApproachChecker attr_reader :failed_test_count, :users def initialize(analyzer, tests) - @analyzer, @tests = analyzer, tests + @analyzer = analyzer + @tests = tests end def check(engine, users) @@ -95,13 +93,15 @@ def permit?(*args) class Approach attr_reader :steps, :engine, :users def initialize(engine, users, steps) - @engine, @users, @steps = engine, users, steps + @engine = engine + @users = users + @steps = steps end def check(approach_checker) res = approach_checker.check(@engine, @users) @failed_test_count = approach_checker.failed_test_count - #puts "CHECKING #{inspect} (#{res}, #{sort_value})" + # puts "CHECKING #{inspect} (#{res}, #{sort_value})" res end @@ -110,22 +110,22 @@ def clone_for_step(*step_params) end def changes - @steps.select {|step| step.length > 1} + @steps.select { |step| step.length > 1 } end def subset?(other_approach) other_approach.changes.length >= changes.length && - changes.all? {|step| other_approach.changes.any? {|step_2| step_2.eql?(step)} } + changes.all? { |step| other_approach.changes.any? { |step_2| step_2.eql?(step) } } end def state_hash @engine.auth_rules.inject(0) do |memo, rule| memo + rule.privileges.hash + rule.contexts.hash + - rule.attributes.hash + rule.role.hash + rule.attributes.hash + rule.role.hash end + - @users.inject(0) {|memo, user| memo + user.role_symbols.hash } + - @engine.privileges.hash + @engine.privilege_hierarchy.hash + - @engine.roles.hash + @engine.role_hierarchy.hash + @users.inject(0) { |memo, user| memo + user.role_symbols.hash } + + @engine.privileges.hash + @engine.privilege_hierarchy.hash + + @engine.roles.hash + @engine.role_hierarchy.hash end def sort_value @@ -133,9 +133,9 @@ def sort_value end def inspect - "Approach (#{state_hash}): Steps: #{changes.map(&:inspect) * ', '}"# + + "Approach (#{state_hash}): Steps: #{changes.map(&:inspect) * ', '}" # + # "\n Roles: #{AnalyzerEngine.roles(@engine).map(&:to_sym).inspect}; " + - # "\n Users: #{@users.map(&:role_symbols).inspect}" + # "\n Users: #{@users.map(&:role_symbols).inspect}" end def <=>(other) @@ -145,30 +145,32 @@ def <=>(other) class Step < Array def eql?(other) - # TODO use approach.users.index(self[idx]) == + # TODO: use approach.users.index(self[idx]) == # other.approach.users.index(other[idx]) # instead of user.login other.is_a?(Array) && other.length == length && - (0...length).all? {|idx| self[idx].class == other[idx].class && - ((self[idx].respond_to?(:to_sym) && self[idx].to_sym == other[idx].to_sym) || - (self[idx].respond_to?(:login) && self[idx].login == other[idx].login) || - self[idx] == other[idx] ) } + (0...length).all? { |idx| + self[idx].class == other[idx].class && + ((self[idx].respond_to?(:to_sym) && self[idx].to_sym == other[idx].to_sym) || + (self[idx].respond_to?(:login) && self[idx].login == other[idx].login) || + self[idx] == other[idx]) } end def inspect - collect {|info| info.respond_to?(:to_sym) ? info.to_sym : (info.respond_to?(:login) ? info.login : info.class.name)}.inspect + collect { |info| info.respond_to?(:to_sym) ? info.to_sym : (info.respond_to?(:login) ? info.login : info.class.name) }.inspect end end protected + def next_step(viable_approaches, candidates, approach_checker, - privilege, context, strategy) + privilege, context, strategy) candidate = candidates.shift next_in_strategy = strategy[candidate.steps.length % strategy.length] - #if @seen_states.include?([candidate.state_hash, next_in_strategy]) + # if @seen_states.include?([candidate.state_hash, next_in_strategy]) # puts "SKIPPING #{next_in_strategy}; #{candidate.inspect}" - #end + # end return if @seen_states.include?([candidate.state_hash, next_in_strategy]) @seen_states << [candidate.state_hash, next_in_strategy] candidate.steps << [next_in_strategy] @@ -176,13 +178,13 @@ def next_step(viable_approaches, candidates, approach_checker, new_approaches = [] - #puts "#{next_in_strategy} on #{candidate.inspect}" + # puts "#{next_in_strategy} on #{candidate.inspect}" case next_in_strategy when :add_role # ensure non-existent name approach = candidate.clone_for_step(:add_role, :new_role_for_change_analyzer) if AnalyzerEngine.apply_change(approach.engine, approach.changes.last) - #AnalyzerEngine.apply_change(approach.engine, [:add_privilege, privilege, context, :new_role_for_change_analyzer]) + # AnalyzerEngine.apply_change(approach.engine, [:add_privilege, privilege, context, :new_role_for_change_analyzer]) new_approaches << approach end when :assign_role_to_user @@ -229,10 +231,10 @@ def next_step(viable_approaches, candidates, approach_checker, new_approaches.each do |new_approach| if new_approach.check(approach_checker) - unless viable_approaches.any? {|viable_approach| viable_approach.subset?(new_approach) } - #puts "New: #{new_approach.changes.inspect}\n #{viable_approaches.map(&:changes).inspect}" - viable_approaches.delete_if {|viable_approach| new_approach.subset?(viable_approach)} - viable_approaches << new_approach unless viable_approaches.find {|v_a| v_a.state_hash == new_approach.state_hash} + unless viable_approaches.any? { |viable_approach| viable_approach.subset?(new_approach) } + # puts "New: #{new_approach.changes.inspect}\n #{viable_approaches.map(&:changes).inspect}" + viable_approaches.delete_if { |viable_approach| new_approach.subset?(viable_approach) } + viable_approaches << new_approach unless viable_approaches.find { |v_a| v_a.state_hash == new_approach.state_hash } end else candidates << new_approach @@ -243,7 +245,7 @@ def next_step(viable_approaches, candidates, approach_checker, end def relevant_roles(approach) - #return AnalyzerEngine.roles(approach.engine) + # return AnalyzerEngine.roles(approach.engine) (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 diff --git a/lib/declarative_authorization/development_support/change_supporter.rb b/lib/declarative_authorization/development_support/change_supporter.rb index b2cc32dc..247d307c 100644 --- a/lib/declarative_authorization/development_support/change_supporter.rb +++ b/lib/declarative_authorization/development_support/change_supporter.rb @@ -1,7 +1,6 @@ -require File.join(File.dirname(__FILE__), %w{development_support}) +require File.join(File.dirname(__FILE__), %w[development_support]) module Authorization - module DevelopmentSupport # Ideas for improvement # * Algorithm @@ -39,7 +38,6 @@ module DevelopmentSupport # * user.login is needed # class ChangeSupporter < AbstractAnalyzer - # 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 @@ -62,7 +60,7 @@ def find_approaches_for(options, &tests) end checked_candidates = 0 - while !candidates.empty? and checked_candidates < 200 + while !candidates.empty? && (checked_candidates < 200) checked_candidates += next_step(suggestions, candidates, approach_checker) end @@ -74,7 +72,7 @@ def find_approaches_for(options, &tests) # Only groups directly adjacent approaches def group_approaches(approaches) approaches.each_with_object([]) do |approach, grouped| - if grouped.last and grouped.last.approach.similar_to(approach) + if grouped.last && grouped.last.approach.similar_to(approach) grouped.last.similar_approaches << approach else grouped << GroupedApproach.new(approach) @@ -94,7 +92,8 @@ class ApproachChecker attr_reader :users, :failed_tests def initialize(analyzer, tests) - @analyzer, @tests = analyzer, tests + @analyzer = analyzer + @tests = tests end def check(engine, users) @@ -116,14 +115,16 @@ def assert(ok) def permit?(*args) @current_test_args = args @current_permit_result = @current_engine.permit?( - *(args[0...-1] + [args.last.merge(:skip_attribute_test => true)])) + *(args[0...-1] + [args.last.merge(skip_attribute_test: true)]) + ) end end class Test attr_reader :positive, :privilege, :context, :user def initialize(positive, privilege, options = {}) - @positive, @privilege = positive, privilege + @positive = positive + @privilege = privilege @context = options[:context] @user = options[:user] end @@ -132,26 +133,28 @@ def initialize(positive, privilege, options = {}) class Approach attr_reader :steps, :engine, :users, :failed_tests def initialize(engine, users, steps) - @engine, @users, @steps = engine, users, steps + @engine = engine + @users = users + @steps = steps end def check(approach_checker) res = approach_checker.check(@engine, @users) @failed_tests = approach_checker.failed_tests - #puts "CHECKING #{inspect} (#{res}, #{sort_value})" + # puts "CHECKING #{inspect} (#{res}, #{sort_value})" res end def affected_users(original_engine, original_users, privilege, context) - (0...@users.length).select do |i| - original_engine.permit?(privilege, :context => context, - :skip_attribute_test => true, :user => original_users[i]) != - @engine.permit?(privilege, :context => context, - :skip_attribute_test => true, :user => @users[i]) - end.collect {|i| original_users[i]} + (0...@users.length).reject do |i| + original_engine.permit?(privilege, context: context, + skip_attribute_test: true, user: original_users[i]) == + @engine.permit?(privilege, context: context, + skip_attribute_test: true, user: @users[i]) + end.collect { |i| original_users[i] } end - def initialize_copy(other) + def initialize_copy(_other) @engine = @engine.clone @users = @users.clone @steps = @steps.clone @@ -178,7 +181,7 @@ def abstract_actions end def reverse_of_previous?(specific_action) - changes.any? {|step| step.reverse?(specific_action)} + changes.any? { |step| step.reverse?(specific_action) } end def apply(action) @@ -189,17 +192,17 @@ def apply(action) def subset?(other_approach) other_approach.changes.length >= changes.length && - changes.all? {|step| other_approach.changes.any? {|step_2| step_2.eql?(step)} } + changes.all? { |step| other_approach.changes.any? { |step_2| step_2.eql?(step) } } end def state_hash @state_hash ||= @engine.auth_rules.inject(0) do |memo, rule| - memo + rule.privileges.hash + rule.contexts.hash + - rule.attributes.hash + rule.role.hash - end + - @users.inject(0) {|memo, user| memo + user.role_symbols.hash } + - @engine.privileges.hash + @engine.privilege_hierarchy.hash + - @engine.roles.hash + @engine.role_hierarchy.hash + memo + rule.privileges.hash + rule.contexts.hash + + rule.attributes.hash + rule.role.hash + end + + @users.inject(0) { |memo, user| memo + user.role_symbols.hash } + + @engine.privileges.hash + @engine.privilege_hierarchy.hash + + @engine.roles.hash + @engine.role_hierarchy.hash end def sort_value @@ -211,15 +214,15 @@ def weight end def similar_to(other) - other.weight == weight and - other.changes.map {|change| change.class.name}.sort == - changes.map {|change| change.class.name}.sort + (other.weight == weight) && + (other.changes.map { |change| change.class.name }.sort == + changes.map { |change| change.class.name }.sort) end def inspect - "Approach: Steps: #{changes.map(&:inspect) * ', '}"# + - # "\n Roles: #{AnalyzerEngine.roles(@engine).map(&:to_sym).inspect}; " + - # "\n Users: #{@users.map(&:role_symbols).inspect}" + "Approach: Steps: #{changes.map(&:inspect) * ', '}" # + + # "\n Roles: #{AnalyzerEngine.roles(@engine).map(&:to_sym).inspect}; " + + # "\n Users: #{@users.map(&:role_symbols).inspect}" end def <=>(other) @@ -233,29 +236,29 @@ def weight end # returns a list of instances of the action that may be applied - def self.specific_actions(candidate) - raise NotImplementedError, "Not yet?" + def self.specific_actions(_candidate) + raise NotImplementedError, 'Not yet?' end # applies the specific action on the given candidate - def apply(candidate) - raise NotImplementedError, "Not yet?" + def apply(_candidate) + raise NotImplementedError, 'Not yet?' end def eql?(other) - other.class == self.class and hash == other.hash + (other.class == self.class) && (hash == other.hash) end def hash @hash ||= to_a.hash end - def reverse?(other) + def reverse?(_other) false end def inspect - "#{self.class.name.demodulize} #{hash} #{to_a.hash} (#{to_a[1..-1].collect {|info| self.class.readable_info(info)} * ','})" + "#{self.class.name.demodulize} #{hash} #{to_a.hash} (#{to_a[1..-1].collect { |info| self.class.readable_info(info) } * ','})" end def to_a @@ -264,11 +267,11 @@ def to_a def resembles?(spec) min_length = [spec.length, to_a.length].min - to_a[0,min_length] == spec[0,min_length] + to_a[0, min_length] == spec[0, min_length] end def resembles_any?(specs) - specs.any? {|spec| resembles?(spec) } + specs.any? { |spec| resembles?(spec) } end def self.readable_info(info) @@ -286,26 +289,26 @@ def weight end def apply(candidate) - @actions.all? {|action| action.apply(candidate)} + @actions.all? { |action| action.apply(candidate) } end def reverse?(other) - @actions.any? {|action| action.reverse?(other)} + @actions.any? { |action| action.reverse?(other) } end def to_a - @actions.inject([]) {|memo, action| memo += action.to_a.first.is_a?(Enumerable) ? action.to_a : [action.to_a]; memo } + @actions.inject([]) { |memo, action| memo += action.to_a.first.is_a?(Enumerable) ? action.to_a : [action.to_a]; memo } end def hash - @hash ||= @actions.inject(0) {|memo, action| memo += action.hash } + @hash ||= @actions.inject(0) { |memo, action| memo += action.hash } end def resembles?(spec) - @actions.any? {|action| action.resembles?(spec) } or + @actions.any? { |action| action.resembles?(spec) } || to_a.any? do |array| min_length = [spec.length, array.length].min - array[0,min_length] == spec[0,min_length] + array[0, min_length] == spec[0, min_length] end end end @@ -313,12 +316,13 @@ def resembles?(spec) class AssignPrivilegeToRoleAction < AbstractAction def self.specific_actions(candidate) privilege = AnalyzerEngine::Privilege.for_sym( - candidate.failed_tests.first.privilege, candidate.engine) + candidate.failed_tests.first.privilege, candidate.engine + ) context = candidate.failed_tests.first.context user = candidate.failed_tests.first.user ([privilege] + privilege.ancestors).collect do |ancestor_privilege| - user.role_symbols.collect {|role_sym| AnalyzerEngine::Role.for_sym(role_sym, candidate.engine) }. - collect {|role| [role] + role.ancestors}.flatten.uniq.collect do |role| + user.role_symbols.collect { |role_sym| AnalyzerEngine::Role.for_sym(role_sym, candidate.engine) } + .collect { |role| [role] + role.ancestors }.flatten.uniq.collect do |role| # apply checks later if privilege is already present in that role new(ancestor_privilege.to_sym, context, role.to_sym) end @@ -327,7 +331,9 @@ def self.specific_actions(candidate) attr_reader :privilege, :context, :role def initialize(privilege_sym, context, role_sym) - @privilege, @context, @role = privilege_sym, context, role_sym + @privilege = privilege_sym + @context = context + @role = role_sym end def apply(candidate) @@ -335,10 +341,10 @@ def apply(candidate) end def reverse?(other) - other.is_a?(RemovePrivilegeFromRoleAction) and - other.privilege == @privilege and - other.context == @context and - other.role == @role + other.is_a?(RemovePrivilegeFromRoleAction) && + (other.privilege == @privilege) && + (other.context == @context) && + (other.role == @role) end def to_a @@ -358,7 +364,8 @@ def self.specific_actions(candidate) attr_reader :user, :role def initialize(user, role_sym) - @user, @role = user, role_sym + @user = user + @role = role_sym end def apply(candidate) @@ -372,23 +379,23 @@ def apply(candidate) candidate.users[user_index] = cloned_user # possible on real user objects? cloned_user.role_symbols << @role - raise "User#role_symbols immutable or user only shallowly cloned!" if cloned_user.role_symbols == @user.role_symbols + raise 'User#role_symbols immutable or user only shallowly cloned!' if cloned_user.role_symbols == @user.role_symbols true end end def hash - to_a[0,2].hash + @user.login.hash + to_a[0, 2].hash + @user.login.hash end def reverse?(other) - other.is_a?(RemoveRoleFromUserAction) and - other.user.login == @user.login and - other.role == @role + other.is_a?(RemoveRoleFromUserAction) && + (other.user.login == @user.login) && + (other.role == @role) end def resembles?(spec) - super(spec[0,2]) and (spec.length == 2 or spec[2] == @user.login) + super(spec[0, 2]) && ((spec.length == 2) || (spec[2] == @user.login)) end def to_a @@ -399,7 +406,8 @@ def to_a class CreateAndAssignRoleToUserAction < AbstractCompoundAction def self.specific_actions(candidate) privilege = AnalyzerEngine::Privilege.for_sym( - candidate.failed_tests.first.privilege, candidate.engine) + candidate.failed_tests.first.privilege, candidate.engine + ) context = candidate.failed_tests.first.context user = candidate.failed_tests.first.user role = AnalyzerEngine::Role.for_sym(:change_supporter_new_role, candidate.engine) @@ -410,7 +418,10 @@ def self.specific_actions(candidate) attr_reader :user, :privilege, :context, :role def initialize(user, privilege_sym, context_sym, role_sym) - @user, @privilege, @context, @role = user, privilege_sym, context_sym, role_sym + @user = user + @privilege = privilege_sym + @context = context_sym + @role = role_sym @actions = [AddPrivilegeAndAssignRoleToUserAction.new(@user, @privilege, @context, role_sym)] end @@ -434,7 +445,8 @@ def to_a class AddPrivilegeAndAssignRoleToUserAction < AbstractCompoundAction def self.specific_actions(candidate) privilege = AnalyzerEngine::Privilege.for_sym( - candidate.failed_tests.first.privilege, candidate.engine) + candidate.failed_tests.first.privilege, candidate.engine + ) context = candidate.failed_tests.first.context user = candidate.failed_tests.first.user ([privilege] + privilege.ancestors).collect do |ancestor_privilege| @@ -446,7 +458,10 @@ def self.specific_actions(candidate) attr_reader :user, :privilege, :context, :role def initialize(user, privilege_sym, context, role_sym) - @user, @privilege, @context, @role = user, privilege_sym, context, role_sym + @user = user + @privilege = privilege_sym + @context = context + @role = role_sym @actions = [ AssignRoleToUserAction.new(@user, @role), AssignPrivilegeToRoleAction.new(@privilege, @context, @role) @@ -457,12 +472,13 @@ def initialize(user, privilege_sym, context, role_sym) class RemovePrivilegeFromRoleAction < AbstractAction def self.specific_actions(candidate) privilege = AnalyzerEngine::Privilege.for_sym( - candidate.failed_tests.first.privilege, candidate.engine) + candidate.failed_tests.first.privilege, candidate.engine + ) context = candidate.failed_tests.first.context user = candidate.failed_tests.first.user ([privilege] + privilege.ancestors).collect do |ancestor_privilege| - user.role_symbols.collect {|role_sym| AnalyzerEngine::Role.for_sym(role_sym, candidate.engine) }. - collect {|role| [role] + role.ancestors}.flatten.uniq.collect do |role| + user.role_symbols.collect { |role_sym| AnalyzerEngine::Role.for_sym(role_sym, candidate.engine) } + .collect { |role| [role] + role.ancestors }.flatten.uniq.collect do |role| new(ancestor_privilege.to_sym, context, role.to_sym) end end.flatten @@ -470,7 +486,9 @@ def self.specific_actions(candidate) attr_reader :privilege, :context, :role def initialize(privilege_sym, context, role_sym) - @privilege, @context, @role = privilege_sym, context, role_sym + @privilege = privilege_sym + @context = context + @role = role_sym end def apply(candidate) @@ -478,9 +496,9 @@ def apply(candidate) end def reverse?(other) - (other.is_a?(AssignPrivilegeToRoleAction) or - other.is_a?(AbstractCompoundAction)) and - other.reverse?(self) + (other.is_a?(AssignPrivilegeToRoleAction) || + other.is_a?(AbstractCompoundAction)) && + other.reverse?(self) end def to_a @@ -494,16 +512,17 @@ def self.specific_actions(candidate) context = candidate.failed_tests.first.context user = candidate.failed_tests.first.user roles_for_privilege = AnalyzerEngine::Role.all_for_privilege(privilege, context, candidate.engine).map(&:to_sym) - user.role_symbols.collect {|role_sym| AnalyzerEngine::Role.for_sym(role_sym, candidate.engine)}. - select {|role| roles_for_privilege.include?(role.to_sym)}. - collect do |role| + user.role_symbols.collect { |role_sym| AnalyzerEngine::Role.for_sym(role_sym, candidate.engine) } + .select { |role| roles_for_privilege.include?(role.to_sym) } + .collect do |role| new(user, role.to_sym) end end attr_reader :user, :role def initialize(user, role_sym) - @user, @role = user, role_sym + @user = user + @role = role_sym end def apply(candidate) @@ -513,22 +532,22 @@ def apply(candidate) raise "Cannot find #{@user.inspect} in users array" unless user_index candidate.users[user_index] = cloned_user cloned_user.role_symbols.delete(@role) - raise "User#role_symbols immutable or user only shallowly cloned!" if cloned_user.role_symbols == @user.role_symbols + raise 'User#role_symbols immutable or user only shallowly cloned!' if cloned_user.role_symbols == @user.role_symbols true end def hash - to_a[0,2].hash + @user.login.hash + to_a[0, 2].hash + @user.login.hash end def reverse?(other) - (other.is_a?(AssignRoleToUserAction) or - other.is_a?(AbstractCompoundAction)) and - other.reverse?(self) + (other.is_a?(AssignRoleToUserAction) || + other.is_a?(AbstractCompoundAction)) && + other.reverse?(self) end def resembles?(spec) - super(spec[0,2]) and (spec.length == 2 or spec[2] == @user.login) + super(spec[0, 2]) && ((spec.length == 2) || (spec[2] == @user.login)) end def to_a @@ -537,6 +556,7 @@ def to_a end protected + def next_step(viable_approaches, candidates, approach_checker) candidate = candidates.shift @@ -553,9 +573,9 @@ def generate_child_candidates(candidate) 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) + if !specific_action.resembles_any?(@prohibited_actions) && + !child_candidate.reverse_of_previous?(specific_action) && + child_candidate.apply(specific_action) child_candidates << child_candidate end end @@ -580,7 +600,7 @@ def check_child_candidates!(approach_checker, viable_approaches, candidates, chi def superset_of_existing?(candidate) candidate.changes.any? do |action| - (@approaches_by_actions[action] ||= []).any? {|approach| approach.subset?(candidate)} + (@approaches_by_actions[action] ||= []).any? { |approach| approach.subset?(candidate) } end end @@ -610,6 +630,7 @@ def remove_from_approaches_by_action!(candidate) def relevant_roles(approach) self.class.relevant_roles(approach) end + def self.relevant_roles(approach) (AnalyzerEngine.relevant_roles(approach.engine, approach.users) + (approach.engine.roles.include?(:new_role_for_change_analyzer) ? diff --git a/lib/declarative_authorization/development_support/development_support.rb b/lib/declarative_authorization/development_support/development_support.rb index 97dd7611..9963e0c3 100644 --- a/lib/declarative_authorization/development_support/development_support.rb +++ b/lib/declarative_authorization/development_support/development_support.rb @@ -13,28 +13,27 @@ def roles end def rules - roles.collect {|role| role.rules }.flatten + roles.collect(&:rules).flatten end end # Groups utility methods and classes to better work with authorization object # model. module AnalyzerEngine - def self.roles(engine) Role.all(engine) end def self.relevant_roles(engine, users) - users.collect {|user| user.role_symbols.map {|role_sym| Role.for_sym(role_sym, engine)}}. - flatten.uniq.collect {|role| [role] + role.ancestors}.flatten.uniq + users.collect { |user| user.role_symbols.map { |role_sym| Role.for_sym(role_sym, engine) } } + .flatten.uniq.collect { |role| [role] + role.ancestors }.flatten.uniq end - def self.rule_for_permission(engine, privilege, context, role) - AnalyzerEngine.roles(engine). - find {|cloned_role| cloned_role.to_sym == role.to_sym}.rules.find do |rule| - rule.contexts.include?(context) and rule.privileges.include?(privilege) - end + def self.rule_for_permission(engine, privilege, context, role) + AnalyzerEngine.roles(engine) + .find { |cloned_role| cloned_role.to_sym == role.to_sym }.rules.find do |rule| + rule.contexts.include?(context) && rule.privileges.include?(privilege) + end end def self.apply_change(engine, change) @@ -48,18 +47,18 @@ def self.apply_change(engine, change) true end when :add_privilege - privilege, context, role = change[1,3] + privilege, context, role = change[1, 3] role = Role.for_sym(role.to_sym, engine) privilege = Privilege.for_sym(privilege.to_sym, engine) - if ([privilege] + privilege.ancestors).any? {|ancestor_privilege| ([role] + role.ancestors).any? {|ancestor_role| !ancestor_role.rules_for_permission(ancestor_privilege, context).empty?}} + if ([privilege] + privilege.ancestors).any? { |ancestor_privilege| ([role] + role.ancestors).any? { |ancestor_role| !ancestor_role.rules_for_permission(ancestor_privilege, context).empty? } } false else engine.auth_rules << AuthorizationRule.new(role.to_sym, - [privilege.to_sym], [context]) + [privilege.to_sym], [context]) true end when :remove_privilege - privilege, context, role = change[1,3] + privilege, context, role = change[1, 3] role = Role.for_sym(role.to_sym, engine) privilege = Privilege.for_sym(privilege.to_sym, engine) rules_with_priv = role.rules_for_permission(privilege, context) @@ -87,6 +86,7 @@ def initialize(role, rules, engine) def source_line @rules.empty? ? nil : @rules.first.source_line end + def source_file @rules.empty? ? nil : @rules.first.source_file end @@ -94,21 +94,23 @@ def source_file # ancestors' privileges are included in in the current role def ancestors(role_symbol = nil) role_symbol ||= @role - (@engine.role_hierarchy[role_symbol] || []). - collect {|lower_role| ancestors(lower_role) }.flatten + + (@engine.role_hierarchy[role_symbol] || []) + .collect { |lower_role| ancestors(lower_role) }.flatten + (role_symbol == @role ? [] : [Role.for_sym(role_symbol, @engine)]) end + def descendants(role_symbol = nil) role_symbol ||= @role - (@engine.rev_role_hierarchy[role_symbol] || []). - collect {|higher_role| descendants(higher_role) }.flatten + + (@engine.rev_role_hierarchy[role_symbol] || []) + .collect { |higher_role| descendants(higher_role) }.flatten + (role_symbol == @role ? [] : [Role.for_sym(role_symbol, @engine)]) end def rules - @rules ||= @engine.auth_rules.select {|rule| rule.role == @role}. - collect {|rule| Rule.new(rule, @engine)} + @rules ||= @engine.auth_rules.select { |rule| rule.role == @role } + .collect { |rule| Rule.new(rule, @engine) } end + def rules_for_permission(privilege, context) rules.select do |rule| rule.matches?([@role], [privilege.to_sym], context) @@ -118,40 +120,43 @@ def rules_for_permission(privilege, context) def to_sym @role end + def self.for_sym(role_sym, engine) @@role_objects[[role_sym, engine]] ||= new(role_sym, nil, engine) end def self.all(engine) - rules_by_role = engine.auth_rules.inject({}) do |memo, rule| + rules_by_role = engine.auth_rules.each_with_object({}) do |rule, memo| memo[rule.role] ||= [] memo[rule.role] << rule - memo end engine.roles.collect do |role| - new(role, (rules_by_role[role] || []). - collect {|rule| Rule.new(rule, engine)}, engine) + new(role, (rules_by_role[role] || []) + .collect { |rule| Rule.new(rule, engine) }, engine) end end + def self.all_for_privilege(privilege, context, engine) privilege = privilege.is_a?(Symbol) ? Privilege.for_sym(privilege, engine) : privilege privilege_symbols = ([privilege] + privilege.ancestors).map(&:to_sym) - all(engine).select {|role| role.rules.any? {|rule| rule.matches?([role.to_sym], privilege_symbols, context)}}. - collect {|role| [role] + role.descendants}.flatten.uniq + all(engine).select { |role| role.rules.any? { |rule| rule.matches?([role.to_sym], privilege_symbols, context) } } + .collect { |role| [role] + role.descendants }.flatten.uniq end end class Rule @@rule_objects = {} - delegate :source_line, :source_file, :contexts, :matches?, :to => :@rule + delegate :source_line, :source_file, :contexts, :matches?, to: :@rule attr_reader :rule def initialize(rule, engine) @rule = rule @engine = engine end + def privileges - PrivilegesSet.new(self, @engine, @rule.privileges.collect {|privilege| Privilege.for_sym(privilege, @engine) }) + PrivilegesSet.new(self, @engine, @rule.privileges.collect { |privilege| Privilege.for_sym(privilege, @engine) }) end + def self.for_rule(rule, engine) @@rule_objects[[rule, engine]] ||= new(rule, engine) end @@ -169,24 +174,27 @@ def initialize(privilege, engine) def ancestors(priv_symbol = nil) priv_symbol ||= @privilege # context-specific? - (@engine.rev_priv_hierarchy[[priv_symbol, nil]] || []). - collect {|higher_priv| ancestors(higher_priv) }.flatten + + (@engine.rev_priv_hierarchy[[priv_symbol, nil]] || []) + .collect { |higher_priv| ancestors(higher_priv) }.flatten + (priv_symbol == @privilege ? [] : [Privilege.for_sym(priv_symbol, @engine)]) end + def descendants(priv_symbol = nil) priv_symbol ||= @privilege # context-specific? - (@engine.privilege_hierarchy[priv_symbol] || []). - collect {|lower_priv, context| descendants(lower_priv) }.flatten + + (@engine.privilege_hierarchy[priv_symbol] || []) + .collect { |lower_priv, _context| descendants(lower_priv) }.flatten + (priv_symbol == @privilege ? [] : [Privilege.for_sym(priv_symbol, @engine)]) end def rules @rules ||= find_rules_for_privilege end + def source_line rules.empty? ? nil : rules.first.source_line end + def source_file rules.empty? ? nil : rules.first.source_file end @@ -194,14 +202,16 @@ def source_file def to_sym @privilege end + def self.for_sym(privilege_sym, engine) @@privilege_objects[[privilege_sym, engine]] ||= new(privilege_sym, engine) end private + def find_rules_for_privilege - @engine.auth_rules.select {|rule| rule.privileges.include?(@privilege)}. - collect {|rule| Rule.for_rule(rule, @engine)} + @engine.auth_rules.select { |rule| rule.privileges.include?(@privilege) } + .collect { |rule| Rule.for_rule(rule, @engine) } end end @@ -213,6 +223,7 @@ def initialize(*args) end super(*args) end + def include?(privilege) if privilege.is_a?(Symbol) super(privilege_from_symbol(privilege)) @@ -220,6 +231,7 @@ def include?(privilege) super end end + def delete(privilege) @rule.rule.privileges.delete(privilege.to_sym) if privilege.is_a?(Symbol) @@ -230,10 +242,11 @@ def delete(privilege) end def intersects?(privileges) - intersection(privileges).length > 0 + !intersection(privileges).empty? end private + def privilege_from_symbol(privilege_sym) Privilege.for_sym(privilege_sym, @engine) end diff --git a/lib/declarative_authorization/helper.rb b/lib/declarative_authorization/helper.rb index 71c8273a..3b3ba213 100644 --- a/lib/declarative_authorization/helper.rb +++ b/lib/declarative_authorization/helper.rb @@ -3,7 +3,6 @@ module Authorization module AuthorizationHelper - # If the current user meets the given privilege, permitted_to? returns true # and yields to the optional block. The attribute checks that are defined # in the authorization rules are only evaluated if an object is given @@ -57,8 +56,8 @@ def has_role_with_hierarchy?(*roles, &block) controller.has_role_with_hierarchy?(*roles, &block) end - def has_any_role?(*roles,&block) - controller.has_any_role?(*roles,&block) + def has_any_role?(*roles, &block) + controller.has_any_role?(*roles, &block) end def has_any_role_with_hierarchy?(*roles, &block) diff --git a/lib/declarative_authorization/in_controller.rb b/lib/declarative_authorization/in_controller.rb index dd1af751..43d2804f 100644 --- a/lib/declarative_authorization/in_controller.rb +++ b/lib/declarative_authorization/in_controller.rb @@ -3,7 +3,6 @@ module Authorization module AuthorizationInController - def self.included(base) # :nodoc: base.extend(ClassMethods) end @@ -21,6 +20,7 @@ def self.included(base) # :nodoc: def self.failed_auto_loading_is_not_found? @@failed_auto_loading_is_not_found end + def self.failed_auto_loading_is_not_found=(new_value) @@failed_auto_loading_is_not_found = new_value end @@ -59,58 +59,59 @@ def permitted_to!(privilege, object_or_sym = nil, options = {}) # content should only be shown to some users without being concerned # with authorization. E.g. to only show the most relevant menu options # to a certain group of users. That is what has_role? should be used for. - def has_role?(*roles, &block) + def has_role?(*roles) user_roles = authorization_engine.roles_for(current_user) result = roles.all? do |role| user_roles.include?(role) end - yield if result and block_given? + yield if result && block_given? result end # Intended to be used where you want to allow users with any single listed role to view # the content in question - def has_any_role?(*roles,&block) + def has_any_role?(*roles) user_roles = authorization_engine.roles_for(current_user) result = roles.any? do |role| user_roles.include?(role) end - yield if result and block_given? + yield if result && block_given? result end # As has_role? except checks all roles included in the role hierarchy - def has_role_with_hierarchy?(*roles, &block) + def has_role_with_hierarchy?(*roles) user_roles = authorization_engine.roles_with_hierarchy_for(current_user) result = roles.all? do |role| user_roles.include?(role) end - yield if result and block_given? + yield if result && block_given? result end # As has_any_role? except checks all roles included in the role hierarchy - def has_any_role_with_hierarchy?(*roles, &block) + def has_any_role_with_hierarchy?(*roles) user_roles = authorization_engine.roles_with_hierarchy_for(current_user) result = roles.any? do |role| user_roles.include?(role) end - yield if result and block_given? + yield if result && block_given? result end protected + def filter_access_filter # :nodoc: permissions = self.class.all_filter_access_permissions - all_permissions = permissions.select {|p| p.actions.include?(:all)} - matching_permissions = permissions.select {|p| p.matches?(action_name)} + all_permissions = permissions.select { |p| p.actions.include?(:all) } + matching_permissions = permissions.select { |p| p.matches?(action_name) } allowed = false auth_exception = nil begin allowed = if !matching_permissions.empty? - matching_permissions.all? {|perm| perm.permit!(self)} + matching_permissions.all? { |perm| perm.permit!(self) } elsif !all_permissions.empty? - all_permissions.all? {|perm| perm.permit!(self)} + all_permissions.all? { |perm| perm.permit!(self) } else !DEFAULT_DENY end @@ -119,9 +120,9 @@ def filter_access_filter # :nodoc: end unless allowed - if all_permissions.empty? and matching_permissions.empty? - logger.warn "Permission denied: No matching filter access " + - "rule found for #{self.class.controller_name}.#{action_name}" + if all_permissions.empty? && matching_permissions.empty? + logger.warn 'Permission denied: No matching filter access ' \ + "rule found for #{self.class.controller_name}.#{action_name}" elsif auth_exception logger.info "Permission denied: #{auth_exception}" end @@ -129,8 +130,8 @@ def filter_access_filter # :nodoc: # permission_denied needs to render or redirect send(:permission_denied) else - send(:render, :text => "You are not allowed to access this action.", - :status => :forbidden) + send(:render, text: 'You are not allowed to access this action.', + status: :forbidden) end end end @@ -147,16 +148,16 @@ def load_parent_controller_object(parent_context_without_namespace) # :nodoc: instance_variable_set(instance_var, model.find(params[:"#{parent_context_without_namespace.to_s.singularize}_id"])) end - def new_controller_object_from_params(context_without_namespace, parent_context_without_namespace, strong_params) # :nodoc: + def new_controller_object_from_params(context_without_namespace, parent_context_without_namespace, _strong_params) # :nodoc: model_or_proxy = parent_context_without_namespace ? instance_variable_get(:"@#{parent_context_without_namespace.to_s.singularize}").send(context_without_namespace.to_sym) : context_without_namespace.to_s.classify.constantize instance_var = :"@#{context_without_namespace.to_s.singularize}" instance_variable_set(instance_var, - model_or_proxy.new(params[context_without_namespace.to_s.singularize])) + model_or_proxy.new(params[context_without_namespace.to_s.singularize])) end - def new_blank_controller_object(context_without_namespace, parent_context_without_namespace, strong_params, model) # :nodoc: + def new_blank_controller_object(context_without_namespace, parent_context_without_namespace, _strong_params, model) # :nodoc: if model model_or_proxy = model.to_s.classify.constantize else @@ -166,10 +167,10 @@ def new_blank_controller_object(context_without_namespace, parent_context_withou end instance_var = :"@#{context_without_namespace.to_s.singularize}" instance_variable_set(instance_var, - model_or_proxy.new()) + model_or_proxy.new) end - def new_controller_object_for_collection(context_without_namespace, parent_context_without_namespace, strong_params) # :nodoc: + def new_controller_object_for_collection(context_without_namespace, parent_context_without_namespace, _strong_params) # :nodoc: model_or_proxy = parent_context_without_namespace ? instance_variable_get(:"@#{parent_context_without_namespace.to_s.singularize}").send(context_without_namespace.to_sym) : context_without_namespace.to_s.classify.constantize @@ -181,16 +182,16 @@ def options_for_permit(object_or_sym = nil, options = {}, bang = true) context = object = nil if object_or_sym.nil? context = self.class.decl_auth_context - elsif !Authorization.is_a_association_proxy?(object_or_sym) and object_or_sym.is_a?(Symbol) + elsif !Authorization.is_a_association_proxy?(object_or_sym) && object_or_sym.is_a?(Symbol) context = object_or_sym else object = object_or_sym end - result = {:object => object, - :context => context, - :skip_attribute_test => object.nil?, - :bang => bang}.merge(options) + result = { object: object, + context: context, + skip_attribute_test: object.nil?, + bang: bang }.merge(options) result[:user] = current_user unless result.key?(:user) result end @@ -236,10 +237,10 @@ module ClassMethods # authorization rules are enforced because for some actions (collections, # +new+, +create+), there is no object to evaluate conditions against. To # allow attribute checks on all actions, it is a common pattern to provide - # custom objects through +before_filters+: + # custom objects through +before_actions+: # class BranchesController < ApplicationController - # before_filter :load_company - # before_filter :new_branch_from_company_and_params, + # before_action :load_company + # before_action :new_branch_from_company_and_params, # :only => [:index, :new, :create] # filter_access_to :all, :attribute_check => true # @@ -248,7 +249,7 @@ module ClassMethods # @branch = @company.branches.new(params[:branch]) # end # end - # NOTE: +before_filters+ need to be defined before the first + # NOTE: +before_actions+ need to be defined before the first # +filter_access_to+ call. # # For further customization, a custom filter expression may be formulated @@ -297,12 +298,12 @@ module ClassMethods def filter_access_to(*args, &filter_block) options = args.last.is_a?(Hash) ? args.pop : {} options = { - :require => nil, - :context => nil, - :attribute_check => false, - :model => nil, - :load_method => nil, - :strong_parameters => nil + require: nil, + context: nil, + attribute_check: false, + model: nil, + load_method: nil, + strong_parameters: nil }.merge!(options) privilege = options[:require] context = options[:context] @@ -332,7 +333,7 @@ def all_filter_access_permissions # :nodoc: if mod.respond_to?(:filter_access_permissions, true) perms + mod.filter_access_permissions.collect do |p1| - p1.clone.remove_actions(perms.inject(Set.new) {|actions, p2| actions + p2.actions}) + p1.clone.remove_actions(perms.inject(Set.new) { |actions, p2| actions + p2.actions }) end else perms @@ -342,7 +343,7 @@ def all_filter_access_permissions # :nodoc: # To DRY up the filter_access_to statements in restful controllers, # filter_resource_access combines typical filter_access_to and - # before_filter calls, which set up the instance variables. + # before_action calls, which set up the instance variables. # # The simplest case are top-level resource controllers with only the # seven CRUD methods, e.g. @@ -455,7 +456,7 @@ def all_filter_access_permissions # :nodoc: # Allows to add additional new actions to the default resource +new+ actions. # [:+context+] # The context is used to determine the model to load objects from for the - # before_filters and the context of privileges to use in authorization + # before_actions and the context of privileges to use in authorization # checks. # [:+nested_in+] # Specifies the parent controller if the resource is nested in another @@ -480,29 +481,32 @@ def all_filter_access_permissions # :nodoc: # def filter_resource_access(options = {}) options = { - :new => [:new, :create], - :additional_new => nil, - :member => [:show, :edit, :update, :destroy], - :additional_member => nil, - :collection => [:index], - :additional_collection => nil, + new: %i[new create], + additional_new: nil, + member: %i[show edit update destroy], + additional_member: nil, + collection: [:index], + additional_collection: nil, #:new_method_for_collection => nil, # only symbol method name #:new_method => nil, # only symbol method name #:load_method => nil, # only symbol method name - :no_attribute_check => nil, - :context => nil, - :model => nil, - :nested_in => nil, - :strong_parameters => nil + no_attribute_check: nil, + context: nil, + model: nil, + nested_in: nil, + strong_parameters: nil }.merge(options) - options.merge!({ :strong_parameters => true }) if options[:strong_parameters] == nil + options[:strong_parameters] = true if options[:strong_parameters].nil? - new_actions = actions_from_option( options[:new] ).merge( - actions_from_option(options[:additional_new]) ) + new_actions = actions_from_option(options[:new]).merge( + actions_from_option(options[:additional_new]) + ) members = actions_from_option(options[:member]).merge( - actions_from_option(options[:additional_member])) + actions_from_option(options[:additional_member]) + ) collections = actions_from_option(options[:collection]).merge( - actions_from_option(options[:additional_collection])) + actions_from_option(options[:additional_collection]) + ) no_attribute_check_actions = options[:strong_parameters] ? actions_from_option(options[:collection]).merge(actions_from_option([:create])) : collections @@ -510,8 +514,8 @@ def filter_resource_access(options = {}) unless options[:nested_in].blank? load_parent_method = :"load_#{options[:nested_in].to_s.singularize}" - shallow_exceptions = options[:shallow] ? {:except => members.keys} : {} - before_filter shallow_exceptions do |controller| + shallow_exceptions = options[:shallow] ? { except: members.keys } : {} + before_action shallow_exceptions do |controller| if controller.respond_to?(load_parent_method, true) controller.send(load_parent_method) else @@ -520,43 +524,43 @@ def filter_resource_access(options = {}) end new_for_collection_method = :"new_#{controller_name.singularize}_for_collection" - before_filter :only => collections.keys do |controller| + before_action only: collections.keys do |controller| # new_for_collection if controller.respond_to?(new_for_collection_method, true) controller.send(new_for_collection_method) else controller.send(:new_controller_object_for_collection, - options[:context] || controller_name, options[:nested_in], options[:strong_parameters]) + options[:context] || controller_name, options[:nested_in], options[:strong_parameters]) end end end - unless options[:strong_parameters] - new_from_params_method = :"new_#{controller_name.singularize}_from_params" - before_filter :only => new_actions.keys do |controller| + if options[:strong_parameters] + new_object_method = :"new_#{controller_name.singularize}" + before_action only: :new do |controller| # new_from_params - if controller.respond_to?(new_from_params_method, true) - controller.send(new_from_params_method) + if controller.respond_to?(new_object_method, true) + controller.send(new_object_method) else - controller.send(:new_controller_object_from_params, - options[:context] || controller_name, options[:nested_in], options[:strong_parameters]) + controller.send(:new_blank_controller_object, + options[:context] || controller_name, options[:nested_in], options[:strong_parameters], options[:model]) end end else - new_object_method = :"new_#{controller_name.singularize}" - before_filter :only => :new do |controller| + new_from_params_method = :"new_#{controller_name.singularize}_from_params" + before_action only: new_actions.keys do |controller| # new_from_params - if controller.respond_to?(new_object_method, true) - controller.send(new_object_method) + if controller.respond_to?(new_from_params_method, true) + controller.send(new_from_params_method) else - controller.send(:new_blank_controller_object, - options[:context] || controller_name, options[:nested_in], options[:strong_parameters], options[:model]) + controller.send(:new_controller_object_from_params, + options[:context] || controller_name, options[:nested_in], options[:strong_parameters]) end end end load_method = :"load_#{controller_name.singularize}" - before_filter :only => members.keys do |controller| + before_action only: members.keys do |controller| # load controller object if controller.respond_to?(load_method, true) controller.send(load_method) @@ -564,19 +568,18 @@ def filter_resource_access(options = {}) controller.send(:load_controller_object, options[:context] || controller_name, options[:model]) end end - filter_access_to :all, :attribute_check => true, :context => options[:context], :model => options[:model] + filter_access_to :all, attribute_check: true, context: options[:context], model: options[:model] members.merge(new_actions).merge(collections).each do |action, privilege| - if action != privilege or (options[:no_attribute_check] and options[:no_attribute_check].include?(action)) - filter_options = { - :strong_parameters => options[:strong_parameters], - :context => options[:context], - :attribute_check => !options[:no_attribute_check] || !options[:no_attribute_check].include?(action), - :model => options[:model] - } - filter_options[:require] = privilege if action != privilege - filter_access_to(action, filter_options) - end + next unless (action != privilege) || (options[:no_attribute_check] && options[:no_attribute_check].include?(action)) + filter_options = { + strong_parameters: options[:strong_parameters], + context: options[:context], + attribute_check: !options[:no_attribute_check] || !options[:no_attribute_check].include?(action), + model: options[:model] + } + filter_options[:require] = privilege if action != privilege + filter_access_to(action, filter_options) end end @@ -594,6 +597,7 @@ def decl_auth_context end protected + def filter_access_permissions # :nodoc: unless filter_access_permissions? ancestors[1..-1].reverse.each do |mod| @@ -601,7 +605,7 @@ def filter_access_permissions # :nodoc: end end class_variable_set(:@@declarative_authorization_permissions, {}) unless filter_access_permissions? - class_variable_get(:@@declarative_authorization_permissions)[self.name] ||= [] + class_variable_get(:@@declarative_authorization_permissions)[name] ||= [] end def filter_access_permissions? # :nodoc: @@ -613,7 +617,7 @@ def actions_from_option(option) # :nodoc: when nil {} when Symbol, String - {option.to_sym => option.to_sym} + { option.to_sym => option.to_sym } when Hash option when Enumerable @@ -633,8 +637,8 @@ def actions_from_option(option) # :nodoc: class ControllerPermission # :nodoc: attr_reader :actions, :privilege, :context, :attribute_check, :strong_params def initialize(actions, privilege, context, strong_params, attribute_check = false, - load_object_model = nil, load_object_method = nil, - filter_block = nil) + load_object_model = nil, load_object_method = nil, + filter_block = nil) @actions = actions.to_set @privilege = privilege @context = context @@ -650,17 +654,15 @@ def matches?(action_name) end def permit!(contr) - if @filter_block - return contr.instance_eval(&@filter_block) - end + return contr.instance_eval(&@filter_block) if @filter_block object = @attribute_check ? load_object(contr) : nil privilege = @privilege || :"#{contr.action_name}" contr.authorization_engine.permit!(privilege, - :user => contr.send(:current_user), - :object => object, - :skip_attribute_test => !@attribute_check, - :context => @context || contr.class.decl_auth_context) + user: contr.send(:current_user), + object: object, + skip_attribute_test: !@attribute_check, + context: @context || contr.class.decl_auth_context) end def remove_actions(actions) @@ -671,24 +673,24 @@ def remove_actions(actions) private def load_object(contr) - if @load_object_method and @load_object_method.is_a?(Symbol) + if @load_object_method && @load_object_method.is_a?(Symbol) contr.send(@load_object_method) - elsif @load_object_method and @load_object_method.is_a?(Proc) + elsif @load_object_method && @load_object_method.is_a?(Proc) contr.instance_eval(&@load_object_method) else load_object_model = @load_object_model || - (@context ? @context.to_s.classify.constantize : contr.class.controller_name.classify.constantize) + (@context ? @context.to_s.classify.constantize : contr.class.controller_name.classify.constantize) load_object_model = load_object_model.classify.constantize if load_object_model.is_a?(String) instance_var = "@#{load_object_model.name.demodulize.underscore}" object = contr.instance_variable_get(instance_var) unless object begin - object = @strong_params ? load_object_model.find_or_initialize_by(:id => contr.params[:id]) : load_object_model.find(contr.params[:id]) - rescue => e - contr.logger.debug("filter_access_to tried to find " + - "#{load_object_model} from params[:id] " + - "(#{contr.params[:id].inspect}), because attribute_check is enabled " + - "and #{instance_var.to_s} isn't set, but failed: #{e.class.name}: #{e}") + object = @strong_params ? load_object_model.find_or_initialize_by(id: contr.params[:id]) : load_object_model.find(contr.params[:id]) + rescue StandardError => e + contr.logger.debug('filter_access_to tried to find ' \ + "#{load_object_model} from params[:id] " \ + "(#{contr.params[:id].inspect}), because attribute_check is enabled " \ + "and #{instance_var} isn't set, but failed: #{e.class.name}: #{e}") raise if AuthorizationInController.failed_auto_loading_is_not_found? end contr.instance_variable_set(instance_var, object) @@ -698,4 +700,3 @@ def load_object(contr) end end end - diff --git a/lib/declarative_authorization/in_model.rb b/lib/declarative_authorization/in_model.rb index 7d5893ea..97ea5e53 100644 --- a/lib/declarative_authorization/in_model.rb +++ b/lib/declarative_authorization/in_model.rb @@ -3,50 +3,48 @@ require File.dirname(__FILE__) + '/obligation_scope.rb' module Authorization - module AuthorizationInModel - # If the user meets the given privilege, permitted_to? returns true # and yields to the optional block. def permitted_to?(privilege, options = {}, &block) options = { - :user => Authorization.current_user, - :object => self + user: Authorization.current_user, + object: self }.merge(options) Authorization::Engine.instance.permit?(privilege, - {:user => options[:user], - :object => options[:object]}, - &block) + { user: options[:user], + object: options[:object] }, + &block) end # Works similar to the permitted_to? method, but doesn't accept a block # and throws the authorization exceptions, just like Engine#permit! - def permitted_to!(privilege, options = {} ) + def permitted_to!(privilege, options = {}) options = { - :user => Authorization.current_user, - :object => self + user: Authorization.current_user, + object: self }.merge(options) Authorization::Engine.instance.permit!(privilege, - {:user => options[:user], - :object => options[:object]}) + user: options[:user], + object: options[:object]) end def self.included(base) # :nodoc: - #base.extend(ClassMethods) + # base.extend(ClassMethods) base.module_eval do # Builds and returns a scope with joins and conditions satisfying all obligations. - def self.obligation_scope_for( privileges, options = {} ) + def self.obligation_scope_for(privileges, options = {}) options = { - :user => Authorization.current_user, - :context => nil, - :model => self, - :engine => nil, + user: Authorization.current_user, + context: nil, + model: self, + engine: nil }.merge(options) engine = options[:engine] || Authorization::Engine.instance - obligation_scope = ObligationScope.new( options[:model], {} ) - engine.obligations( privileges, :user => options[:user], :context => options[:context] ).each do |obligation| - obligation_scope.parse!( obligation ) + obligation_scope = ObligationScope.new(options[:model], {}) + engine.obligations(privileges, user: options[:user], context: options[:context]).each do |obligation| + obligation_scope.parse!(obligation) end obligation_scope.scope @@ -76,22 +74,22 @@ def self.with_permissions_to(*args) privileges = [privilege] parent_scope = where(nil) context = - if options[:context] - options[:context] - elsif parent_scope.klass.respond_to?(:decl_auth_context) - parent_scope.klass.decl_auth_context - else - parent_scope.klass.name.tableize.to_sym - end + if options[:context] + options[:context] + elsif parent_scope.klass.respond_to?(:decl_auth_context) + parent_scope.klass.decl_auth_context + else + parent_scope.klass.name.tableize.to_sym + end user = options[:user] || Authorization.current_user engine = options[:engine] || Authorization::Engine.instance - engine.permit!(privileges, :user => user, :skip_attribute_test => true, - :context => context) + engine.permit!(privileges, user: user, skip_attribute_test: true, + context: context) - obligation_scope_for( privileges, :user => user, - :context => context, :engine => engine, :model => parent_scope.klass) + obligation_scope_for(privileges, user: user, + context: context, engine: engine, model: parent_scope.klass) end # Activates model security for the current model. Then, CRUD operations @@ -117,23 +115,23 @@ def self.with_permissions_to(*args) # def self.using_access_control(options = {}) options = { - :context => nil, - :include_read => false + context: nil, + include_read: false }.merge(options) class_eval do - [:create, :update, [:destroy, :delete]].each do |action, privilege| + [:create, :update, %i[destroy delete]].each do |action, privilege| send(:"before_#{action}") do |object| Authorization::Engine.instance.permit!(privilege || action, - :object => object, :context => options[:context]) + object: object, context: options[:context]) end end if options[:include_read] # after_find is only called if after_find is implemented after_find do |object| - Authorization::Engine.instance.permit!(:read, :object => object, - :context => options[:context]) + Authorization::Engine.instance.permit!(:read, object: object, + context: options[:context]) end end diff --git a/lib/declarative_authorization/maintenance.rb b/lib/declarative_authorization/maintenance.rb index 73f31d73..120c17ed 100644 --- a/lib/declarative_authorization/maintenance.rb +++ b/lib/declarative_authorization/maintenance.rb @@ -66,38 +66,36 @@ def self.usages_by_controller (!obj.name || obj.name.demodulize != 'ApplicationController') end - controllers.inject({}) do |memo, controller| + controllers.each_with_object({}) do |controller, memo| catchall_permissions = [] permission_by_action = {} controller.all_filter_access_permissions.each do |controller_permissions| catchall_permissions << controller_permissions if controller_permissions.actions.include?(:all) - controller_permissions.actions.reject {|action| action == :all}.each do |action| + controller_permissions.actions.reject { |action| action == :all }.each do |action| permission_by_action[action] = controller_permissions end end actions = controller.public_instance_methods(false) - controller.hidden_actions.to_a - memo[controller] = actions.inject({}) do |actions_memo, action| + memo[controller] = actions.each_with_object({}) do |action, actions_memo| action_sym = action.to_sym actions_memo[action_sym] = if permission_by_action[action_sym] { - :privilege => permission_by_action[action_sym].privilege, - :context => permission_by_action[action_sym].context, - :controller_permissions => [permission_by_action[action_sym]] + privilege: permission_by_action[action_sym].privilege, + context: permission_by_action[action_sym].context, + controller_permissions: [permission_by_action[action_sym]] } elsif !catchall_permissions.empty? { - :privilege => catchall_permissions[0].privilege, - :context => catchall_permissions[0].context, - :controller_permissions => catchall_permissions + privilege: catchall_permissions[0].privilege, + context: catchall_permissions[0].context, + controller_permissions: catchall_permissions } else {} end - actions_memo end - memo end end end @@ -160,7 +158,7 @@ def assert_raise_with_user(user, *args, &block) # should_be_allowed_to :create, :object => car, :context => :vehicles, :user => a_normal_user def should_be_allowed_to(privilege, *args) options = {} - if(args.first.class == Hash) + if args.first.class == Hash options = args.extract_options! else options[args[0].is_a?(Symbol) ? :context : :object] = args[0] @@ -171,7 +169,7 @@ def should_be_allowed_to(privilege, *args) # See should_be_allowed_to def should_not_be_allowed_to(privilege, *args) options = {} - if(args.first.class == Hash) + if args.first.class == Hash options = args.extract_options! else options[args[0].is_a?(Symbol) ? :context : :object] = args[0] @@ -180,8 +178,8 @@ def should_not_be_allowed_to(privilege, *args) end def request_with(user, method, xhr, action, params = {}, - session = {}, flash = {}) - session = session.merge({:user => user, :user_id => user && user.id}) + session = {}, flash = {}) + session = session.merge(user: user, user_id: user && user.id) with_user(user) do if xhr xhr method, action, params, session, flash @@ -192,7 +190,7 @@ def request_with(user, method, xhr, action, params = {}, end def self.included(base) - [:get, :post, :put, :delete].each do |method| + %i[get post put delete].each do |method| base.class_eval <<-EOV, __FILE__, __LINE__ def #{method}_with(user, *args) request_with(user, #{method.inspect}, false, *args) diff --git a/lib/declarative_authorization/obligation_scope.rb b/lib/declarative_authorization/obligation_scope.rb index e96acd7c..87ffe5ea 100644 --- a/lib/declarative_authorization/obligation_scope.rb +++ b/lib/declarative_authorization/obligation_scope.rb @@ -43,22 +43,22 @@ module Authorization # @proxy_options[:conditions] = [ 'foos_bazzes.attr = :foos_bazzes__id_0', { :foos_bazzes__id_0 => 1 } ]+ # class ObligationScope < ActiveRecord::Relation - def initialize(model, options) + def initialize(model, _options) @finder_options = {} - super(model, model.table_name) + super(model, model.table_name) end def scope - # TODO Refactor this. There is certainly a better way. - self.klass.joins(@finder_options[:joins]).includes(@finder_options[:include]).where(@finder_options[:conditions]).references(@finder_options[:include]) + # TODO: Refactor this. There is certainly a better way. + klass.joins(@finder_options[:joins]).includes(@finder_options[:include]).where(@finder_options[:conditions]).references(@finder_options[:include]) end # Consumes the given obligation, converting it into scope join and condition options. - def parse!( obligation ) + def parse!(obligation) @current_obligation = obligation @join_table_joins = Set.new obligation_conditions[@current_obligation] ||= {} - follow_path( obligation ) + follow_path(obligation) rebuild_condition_options! rebuild_join_options! @@ -68,8 +68,8 @@ def parse!( obligation ) # Parses the next step in the association path. If it's an association, we advance down the # path. Otherwise, it's an attribute, and we need to evaluate it as a comparison operation. - def follow_path(steps, past_steps=[]) - if steps.is_a?( Hash ) + def follow_path(steps, past_steps = []) + if steps.is_a?(Hash) steps.each do |step, next_steps| path_to_this_point = [past_steps, step].flatten init_reflections_for past_steps @@ -90,12 +90,10 @@ def follow_path(steps, past_steps=[]) end def top_level_model - self.klass + klass end - def finder_options - @finder_options - end + attr_reader :finder_options # At the end of every association path, we expect to see a comparison of some kind; for # example, +:attr => [ :is, :value ]+. @@ -117,8 +115,8 @@ def add_obligation_condition_for(path, expression) end # Adds the given path to the list of obligation joins, if we haven't seen it before. - def add_obligation_join_for( path ) - map_reflection_for( path ) if reflections[path].nil? + def add_obligation_join_for(path) + map_reflection_for(path) if reflections[path].nil? end # Returns the model associated with the given path. @@ -136,13 +134,13 @@ def model_for(path) # Returns the reflection corresponding to the given path. def reflection_for(path, for_join_table_only = false) - @join_table_joins << path if for_join_table_only and !reflections[path] - reflections[path] ||= map_reflection_for( path ) + @join_table_joins << path if for_join_table_only && !reflections[path] + reflections[path] ||= map_reflection_for(path) end # Returns a proper table alias for the given path. This alias may be used in SQL statements. - def table_alias_for( path ) - table_aliases[path] ||= map_table_alias_for( path ) + def table_alias_for(path) + table_aliases[path] ||= map_table_alias_for(path) end # Attempts to map a reflection for the given path. Raises if already defined. @@ -152,7 +150,7 @@ def map_reflection_for(path) return nil if refls_for_path.empty? reflections[path] = refls_for_path - init_table_alias_for path # Claim a table alias for the path. + init_table_alias_for path # Claim a table alias for the path. # Claim alias for join table # TODO change how this is checked @@ -167,22 +165,22 @@ def map_reflection_for(path) end # Attempts to map a table alias for the given path. Raises if already defined. - def map_table_alias_for( path ) + def map_table_alias_for(path) return "table alias for #{path.inspect} already exists" unless table_aliases[path].nil? - reflection = reflection_for( path ) + reflection = reflection_for(path) table_alias = reflection.table_name - if table_aliases.values.flatten.include?( table_alias ) + if table_aliases.values.flatten.include?(table_alias) max_length = reflection.active_record.connection.table_alias_length # Rails seems to pluralize reflection names - table_alias = "#{reflection.name.to_s.pluralize}_#{reflection.active_record.table_name}".to(max_length-1) + table_alias = "#{reflection.name.to_s.pluralize}_#{reflection.active_record.table_name}".to(max_length - 1) end - while table_aliases.values.include?( table_alias ) + while table_aliases.values.include?(table_alias) if table_alias =~ /\w(_\d+?)$/ - table_index = $1.succ - table_alias = "#{table_alias[0..-(table_index.length+1)]}_#{table_index}" + table_index = Regexp.last_match(1).succ + table_alias = "#{table_alias[0..-(table_index.length + 1)]}_#{table_index}" else - table_alias = "#{table_alias[0..(max_length-3)]}_2" + table_alias = "#{table_alias[0..(max_length - 3)]}_2" end end @@ -219,7 +217,7 @@ def rebuild_condition_options! conditions.each do |path, expressions| models = models_for path - raise "too many models" if models.length > 1 + raise 'too many models' if models.length > 1 model = models.first table_alias_list = table_alias_for(path) @@ -227,11 +225,10 @@ def rebuild_condition_options! parent_is_polymorphic = parent_models.length > 1 parent_models.each do |parent_model| - expressions.each do |expression| attribute, operator, value = expression # prevent unnecessary joins: - if attribute == :id and operator == :is and parent_model.columns_hash["#{path.last}_id"] + if (attribute == :id) && (operator == :is) && parent_model.columns_hash["#{path.last}_id"] attribute_name = :"#{path.last}_id" attribute_table_alias_list = table_alias_for(path[0..-2]) else @@ -244,12 +241,12 @@ def rebuild_condition_options! attribute_table_alias_list.each do |attribute_table_alias| bindvar = "#{attribute_table_alias}__#{attribute_name}_#{obligation_index}".to_sym - sql_attribute = "#{parent_model.connection.quote_table_name(attribute_table_alias)}." + - "#{parent_model.connection.quote_table_name(attribute_name)}" + sql_attribute = "#{parent_model.connection.quote_table_name(attribute_table_alias)}." \ + "#{parent_model.connection.quote_table_name(attribute_name)}" obligation_cond = - if value.nil? and [:is, :is_not].include?(operator) - "#{sql_attribute} IS #{[:contains, :is].include?(operator) ? '' : 'NOT '}NULL" + if value.nil? && %i[is is_not].include?(operator) + "#{sql_attribute} IS #{%i[contains is].include?(operator) ? '' : 'NOT '}NULL" else attribute_operator = case operator when :contains, :is then "= :#{bindvar}" @@ -284,16 +281,16 @@ def rebuild_condition_options! obligation_conds.uniq! obligation_conds << poly_conds_sql if poly_conds_sql - obligation_conds << "1=1" if obligation_conds.empty? + obligation_conds << '1=1' if obligation_conds.empty? conds << "(#{obligation_conds.join(' AND ')})" end - finder_options[:conditions] = [ conds.join( " OR " ), binds ] + finder_options[:conditions] = [conds.join(' OR '), binds] end def attribute_value(value) value.class.respond_to?(:descends_from_active_record?) && value.class.descends_from_active_record? && value.id || - value.is_a?(Array) && value[0].class.respond_to?(:descends_from_active_record?) && value[0].class.descends_from_active_record? && value.map( &:id ) || + value.is_a?(Array) && value[0].class.respond_to?(:descends_from_active_record?) && value[0].class.descends_from_active_record? && value.map(&:id) || value end @@ -304,12 +301,12 @@ def rebuild_join_options! polymorphic_paths = {} reflections.each do |path, refs| - next if path.empty? or @join_table_joins.include?(path) + next if path.empty? || @join_table_joins.include?(path) first_ref = refs.first if polymorphic?(first_ref) # sanity check - raise "Only one polymorphic relation is allowed at each step" if refs.length > 1 + raise 'Only one polymorphic relation is allowed at each step' if refs.length > 1 polymorphic_paths[path] = first_ref.active_record.poly_resource_names end @@ -358,11 +355,11 @@ def rebuild_join_options! elsif conds_len == 1 && polymorphic_paths.empty? # joins in a scope are converted to inner joins finder_options[:joins] = joins - finder_options.delete( :include ) + finder_options.delete(:include) else # polymorphic paths must use left joins (include) # include in a scope is converted to left joins - finder_options.delete( :joins ) + finder_options.delete(:joins) finder_options[:include] = joins end end @@ -394,9 +391,8 @@ def join_to_path(join) # Afaik ObligationScope does not need to inherit the Relation # dynamic methods. This makes debugging typos in this class # much easier. - def method_missing(name, *args) + def method_missing(name, *_args) raise "Method #{name} does not exist" end end end - diff --git a/lib/declarative_authorization/railsengine.rb b/lib/declarative_authorization/railsengine.rb index 75a07a42..c2cf24de 100644 --- a/lib/declarative_authorization/railsengine.rb +++ b/lib/declarative_authorization/railsengine.rb @@ -3,4 +3,4 @@ module Authorization class RailsEngine < Rails::Engine end -end \ No newline at end of file +end diff --git a/lib/declarative_authorization/reader.rb b/lib/declarative_authorization/reader.rb index 091cb86a..aed9401d 100644 --- a/lib/declarative_authorization/reader.rb +++ b/lib/declarative_authorization/reader.rb @@ -37,9 +37,9 @@ module Authorization # module Reader # Signals that the specified file to load was not found. - class DSLFileNotFoundError < Exception; end + class DSLFileNotFoundError < RuntimeError; end # Signals errors that occur while reading and parsing an authorization DSL - class DSLError < Exception; end + class DSLError < RuntimeError; end # Signals errors in the syntax of an authorization DSL. class DSLSyntaxError < DSLError; end @@ -51,7 +51,7 @@ class DSLSyntaxError < DSLError; end class DSLReader attr_reader :privileges_reader, :auth_rules_reader # :nodoc: - def initialize() + def initialize @privileges_reader = PrivilegesReader.new @auth_rules_reader = AuthorizationRulesReader.new end @@ -100,7 +100,7 @@ def load!(dsl_file) # Loads and parses DSL files and returns a new reader def self.load(dsl_files) - # TODO cache reader in production mode? + # TODO: cache reader in production mode? reader = new dsl_files = [dsl_files].flatten dsl_files.each do |file| @@ -132,7 +132,7 @@ def authorization(&block) # The PrivilegeReader handles the part of the authorization DSL in # a +privileges+ block. Here, privilege hierarchies are defined. class PrivilegesReader - # TODO handle privileges with separated context + # TODO: handle privileges with separated context attr_reader :privileges, :privilege_hierarchy # :nodoc: def initialize # :nodoc: @@ -175,7 +175,7 @@ def privilege(privilege, context = nil, options = {}, &block) # Specifies +privileges+ that are to be assigned as lower ones. Only to # be used inside a privilege block. def includes(*privileges) - raise DSLError, "includes only in privilege block" if @current_priv.nil? + raise DSLError, 'includes only in privilege block' if @current_priv.nil? privileges.each do |priv| append_privilege priv @privilege_hierarchy[@current_priv] ||= [] @@ -186,7 +186,7 @@ def includes(*privileges) class AuthorizationRulesReader attr_reader :roles, :role_hierarchy, :auth_rules, - :role_descriptions, :role_titles, :omnipotent_roles # :nodoc: + :role_descriptions, :role_titles, :omnipotent_roles # :nodoc: def initialize # :nodoc: @current_role = nil @@ -201,8 +201,8 @@ def initialize # :nodoc: end def initialize_copy(from) # :nodoc: - [:roles, :role_hierarchy, :auth_rules, - :role_descriptions, :role_titles, :omnipotent_roles].each do |attribute| + %i[roles role_hierarchy auth_rules + role_descriptions role_titles omnipotent_roles].each do |attribute| instance_variable_set(:"@#{attribute}", from.send(attribute).clone) end end @@ -219,7 +219,7 @@ def append_role(role, options = {}) # :nodoc: # has_permissions_on ... # end # - def role(role, options = {}, &block) + def role(role, options = {}) append_role role, options @current_role = role yield @@ -238,7 +238,7 @@ def role(role, options = {}, &block) # end # def includes(*roles) - raise DSLError, "includes only in role blocks" if @current_role.nil? + raise DSLError, 'includes only in role blocks' if @current_role.nil? @role_hierarchy[@current_role] ||= [] @role_hierarchy[@current_role] += roles.flatten end @@ -271,26 +271,26 @@ def includes(*roles) # Join operator to logically connect the constraint statements inside # of the has_permission_on block. May be :+and+ or :+or+. Defaults to :+or+. # - def has_permission_on(*args, &block) + def has_permission_on(*args) options = args.extract_options! context = args.flatten - raise DSLError, "has_permission_on only allowed in role blocks" if @current_role.nil? - options = {:to => [], :join_by => :or}.merge(options) + raise DSLError, 'has_permission_on only allowed in role blocks' if @current_role.nil? + options = { to: [], join_by: :or }.merge(options) privs = options[:to] privs = [privs] unless privs.is_a?(Array) - raise DSLError, "has_permission_on either needs a block or :to option" if !block_given? and privs.empty? + raise DSLError, 'has_permission_on either needs a block or :to option' if !block_given? && privs.empty? file, line = file_and_line_number_from_call_stack rule = AuthorizationRule.new(@current_role, privs, context, options[:join_by], - :source_file => file, :source_line => line) + source_file: file, source_line: line) @auth_rules << rule if block_given? @current_rule = rule yield - raise DSLError, "has_permission_on block content specifies no privileges" if rule.privileges.empty? - # TODO ensure? + raise DSLError, 'has_permission_on block content specifies no privileges' if rule.privileges.empty? + # TODO: ensure? @current_rule = nil end end @@ -300,7 +300,7 @@ def has_permission_on(*args, &block) # has_omnipotence # end def has_omnipotence - raise DSLError, "has_omnipotence only allowed in role blocks" if @current_role.nil? + raise DSLError, 'has_omnipotence only allowed in role blocks' if @current_role.nil? @omnipotent_roles << @current_role end @@ -310,7 +310,7 @@ def has_omnipotence # has_permission_on ... # end def description(text) - raise DSLError, "description only allowed in role blocks" if @current_role.nil? + raise DSLError, 'description only allowed in role blocks' if @current_role.nil? role_descriptions[@current_role] = text end @@ -320,7 +320,7 @@ def description(text) # has_permission_on ... # end def title(text) - raise DSLError, "title only allowed in role blocks" if @current_role.nil? + raise DSLError, 'title only allowed in role blocks' if @current_role.nil? role_titles[@current_role] = text end @@ -333,7 +333,7 @@ def title(text) # end # end def to(*privs) - raise DSLError, "to only allowed in has_permission_on blocks" if @current_rule.nil? + raise DSLError, 'to only allowed in has_permission_on blocks' if @current_rule.nil? @current_rule.append_privileges(privs.flatten) end @@ -392,7 +392,7 @@ def to(*privs) # if_attribute :id => [1,2] # def if_attribute(attr_conditions_hash) - raise DSLError, "if_attribute only in has_permission blocks" if @current_rule.nil? + raise DSLError, 'if_attribute only in has_permission blocks' if @current_rule.nil? parse_attribute_conditions_hash!(attr_conditions_hash) @current_rule.append_attribute Attribute.new(attr_conditions_hash) end @@ -444,12 +444,12 @@ def if_attribute(attr_conditions_hash) # if_permitted_to :read, :branch => :main_company, :context => :companies # def if_permitted_to(privilege, attr_or_hash = nil, options = {}) - raise DSLError, "if_permitted_to only in has_permission blocks" if @current_rule.nil? + raise DSLError, 'if_permitted_to only in has_permission blocks' if @current_rule.nil? options[:context] ||= attr_or_hash.delete(:context) if attr_or_hash.is_a?(Hash) # only :context option in attr_or_hash: - attr_or_hash = nil if attr_or_hash.is_a?(Hash) and attr_or_hash.empty? + attr_or_hash = nil if attr_or_hash.is_a?(Hash) && attr_or_hash.empty? @current_rule.append_attribute AttributeWithPermission.new(privilege, - attr_or_hash, options[:context]) + attr_or_hash, options[:context]) end # In an if_attribute statement, is says that the value has to be @@ -518,6 +518,7 @@ def gte(&block) end private + def parse_attribute_conditions_hash!(hash) merge_hash = {} hash.each do |key, value| @@ -525,7 +526,7 @@ def parse_attribute_conditions_hash!(hash) parse_attribute_conditions_hash!(value) elsif !value.is_a?(Array) merge_hash[key] = [:is, proc { value }] - elsif value.is_a?(Array) and !value[0].is_a?(Symbol) + elsif value.is_a?(Array) && !value[0].is_a?(Symbol) merge_hash[key] = [:is_in, proc { value }] end end @@ -534,10 +535,9 @@ def parse_attribute_conditions_hash!(hash) def file_and_line_number_from_call_stack caller_parts = caller(2).first.split(':') - [caller_parts[0] == "(eval)" ? nil : caller_parts[0], - caller_parts[1] && caller_parts[1].to_i] + [caller_parts[0] == '(eval)' ? nil : caller_parts[0], + caller_parts[1] && caller_parts[1].to_i] end end end end - diff --git a/lib/generators/authorization/install/install_generator.rb b/lib/generators/authorization/install/install_generator.rb index 669da185..0131991a 100644 --- a/lib/generators/authorization/install/install_generator.rb +++ b/lib/generators/authorization/install/install_generator.rb @@ -1,27 +1,26 @@ require 'rails/generators' module Authorization class InstallGenerator < Rails::Generators::Base - include Rails::Generators::Migration source_root File.expand_path('../templates', __FILE__) - argument :name, type: :string, default: "User" - argument :attributes, type: :array, default: ['name:string'], banner: "field[:type] field[:type]" - class_option :create_user, type: :boolean, default: false, desc: "Creates the defined User model with attributes given." - class_option :commit, type: :boolean, default: false, desc: "Performs rake tasks such as migrate and seed." - class_option :user_belongs_to_role, type: :boolean, default: false, desc: "Users have only one role, which can inherit others roles." + argument :name, type: :string, default: 'User' + argument :attributes, type: :array, default: ['name:string'], banner: 'field[:type] field[:type]' + class_option :create_user, type: :boolean, default: false, desc: 'Creates the defined User model with attributes given.' + class_option :commit, type: :boolean, default: false, desc: 'Performs rake tasks such as migrate and seed.' + class_option :user_belongs_to_role, type: :boolean, default: false, desc: 'Users have only one role, which can inherit others roles.' def self.next_migration_number(dirname) if ActiveRecord::Base.timestamped_migrations - Time.now.utc.strftime("%Y%m%d%H%M%S") + Time.now.utc.strftime('%Y%m%d%H%M%S') else - "%.3d" % (current_migration_number(dirname) + 1) + format('%.3d', (current_migration_number(dirname) + 1)) end end def install_decl_auth - habtm_table_name = "#{name.pluralize}" <= "Roles" ? "#{name.pluralize}Roles" : "Roles#{name.pluralize}" unless options[:user_belongs_to_role] - habtm_file_glob = "#{name.pluralize}" <= "Roles" ? 'db/migrate/*create_*_roles*' : 'db/migrate/*create_roles_*' unless options[:user_belongs_to_role] + habtm_table_name = name.pluralize.to_s <= 'Roles' ? "#{name.pluralize}Roles" : "Roles#{name.pluralize}" unless options[:user_belongs_to_role] + habtm_file_glob = name.pluralize.to_s <= 'Roles' ? 'db/migrate/*create_*_roles*' : 'db/migrate/*create_roles_*' unless options[:user_belongs_to_role] generate 'model', "#{name} #{attributes.join(' ')}" if options[:create_user] generate 'model', 'Role title:string' @@ -32,16 +31,16 @@ def install_decl_auth else generate 'migration', "Create#{habtm_table_name} #{name.downcase}:integer role:integer" gsub_file Dir.glob(habtm_file_glob).last, 'integer', 'references' - inject_into_file Dir.glob(habtm_file_glob).last, ", id: false", before: ' do |t|' - inject_into_file "app/models/role.rb", " has_and_belongs_to_many :#{name.downcase.pluralize}\n", after: "ActiveRecord::Base\n" + inject_into_file Dir.glob(habtm_file_glob).last, ', id: false', before: ' do |t|' + inject_into_file 'app/models/role.rb', " has_and_belongs_to_many :#{name.downcase.pluralize}\n", after: "ActiveRecord::Base\n" inject_into_file "app/models/#{name.singularize.downcase}.rb", " has_and_belongs_to_many :roles\n", after: "ActiveRecord::Base\n" end rake 'db:migrate' if options[:commit] if options[:user_belongs_to_role] - inject_into_file "app/models/#{name.singularize.downcase}.rb", before: "\nend" do <<-'RUBY' - + inject_into_file "app/models/#{name.singularize.downcase}.rb", before: "\nend" do + <<-'RUBY' def role_symbols [role.title.to_sym] @@ -49,8 +48,8 @@ def role_symbols RUBY end else - inject_into_file "app/models/#{name.singularize.downcase}.rb", before: "\nend" do <<-'RUBY' - + inject_into_file "app/models/#{name.singularize.downcase}.rb", before: "\nend" do + <<-'RUBY' def role_symbols (roles || []).map {|r| r.title.to_sym} @@ -59,8 +58,8 @@ def role_symbols end end - inject_into_file 'db/seeds.rb', after: ".first)\n" do <<-'RUBY' - + inject_into_file 'db/seeds.rb', after: ".first)\n" do + <<-'RUBY' roles = Role.create([ {title: 'admin'}, {title: 'user'} @@ -71,7 +70,7 @@ def role_symbols rake 'db:seed' if options[:commit] generate 'authorization:rules' - puts "Please run `rake db:migrate` and `rake db:seed` to finish installing." unless options[:commit] + puts 'Please run `rake db:migrate` and `rake db:seed` to finish installing.' unless options[:commit] end end end diff --git a/lib/generators/authorization/rules/rules_generator.rb b/lib/generators/authorization/rules/rules_generator.rb index dd675c5d..1b26bd3e 100644 --- a/lib/generators/authorization/rules/rules_generator.rb +++ b/lib/generators/authorization/rules/rules_generator.rb @@ -1,14 +1,12 @@ require 'rails/generators' module Authorization class RulesGenerator < Rails::Generators::Base - source_root File.expand_path('../templates', __FILE__) def copy_auth_rules + puts 'WARNING - Copying authorization_rules template. Make sure to back up any existing rules before overwriting.' - puts "WARNING - Copying authorization_rules template. Make sure to back up any existing rules before overwriting." - - copy_file "authorization_rules.rb", "config/authorization_rules.rb" + copy_file 'authorization_rules.rb', 'config/authorization_rules.rb' end end -end \ No newline at end of file +end diff --git a/lib/generators/authorization/rules/templates/authorization_rules.rb b/lib/generators/authorization/rules/templates/authorization_rules.rb index 81b63cd8..a05054b9 100644 --- a/lib/generators/authorization/rules/templates/authorization_rules.rb +++ b/lib/generators/authorization/rules/templates/authorization_rules.rb @@ -19,9 +19,9 @@ privileges do # default privilege hierarchies to facilitate RESTful Rails apps - privilege :manage, :includes => [:create, :read, :update, :delete] - privilege :read, :includes => [:index, :show] - privilege :create, :includes => :new - privilege :update, :includes => :edit - privilege :delete, :includes => :destroy + privilege :manage, includes: %i[create read update delete] + privilege :read, includes: %i[index show] + privilege :create, includes: :new + privilege :update, includes: :edit + privilege :delete, includes: :destroy end diff --git a/lib/tasks/authorization_tasks.rake b/lib/tasks/authorization_tasks.rake index 6b9d290e..05890c13 100644 --- a/lib/tasks/authorization_tasks.rake +++ b/lib/tasks/authorization_tasks.rake @@ -1,40 +1,40 @@ namespace :auth do - desc "Lists all privileges used in controllers, views, models" + desc 'Lists all privileges used in controllers, views, models' task :used_privileges do - # TODO note where privileges are used + # TODO: note where privileges are used require File.join(Rails.root, 'config', 'boot.rb') require File.join(Rails.root, 'config', 'environment.rb') controllers = [ApplicationController] Dir.new("#{Rails.root}/app/controllers").entries.each do |controller_file| - if controller_file =~ /_controller/ - controllers << controller_file.gsub(".rb","").camelize.constantize + if controller_file =~ /_controller/ + controllers << controller_file.gsub('.rb', '').camelize.constantize end - end - perms = controllers.select {|c| c.send(:class_variable_defined?, :@@permissions)}. - inject([]) do |all, c| - contr_context = c.name.sub("Controller", "").tableize.to_sym + end + perms = controllers.select { |c| c.send(:class_variable_defined?, :@@permissions) } + .inject([]) do |all, c| + contr_context = c.name.sub('Controller', '').tableize.to_sym contr_perms = c.send(:class_variable_get, :@@permissions).collect do |cp| [cp.privilege, cp.context || contr_context, cp] end - if contr_perms.any? {|cp| cp[0].nil?} - contr_perms += c.send(:action_methods).collect {|am| am.to_sym}. - reject {|am| contr_perms.any? {|cp| cp[2].actions.include?(am)}}. - collect {|am| [am, contr_context]} + if contr_perms.any? { |cp| cp[0].nil? } + contr_perms += c.send(:action_methods).collect(&:to_sym) + .reject { |am| contr_perms.any? { |cp| cp[2].actions.include?(am) } } + .collect { |am| [am, contr_context] } end - all += contr_perms.reject {|cp| cp[0].nil?}.collect {|cp| cp[0..1]} + all += contr_perms.reject { |cp| cp[0].nil? }.collect { |cp| cp[0..1] } end model_all = `grep -l "Base\.using_access_control" #{Rails.root}/config/*.rb #{Rails.root}/config/initializers/*.rb`.split("\n") if model_all.count > 0 - model_files = Dir.glob( "#{Rails.root}/app/models/*.rb").reject do |item| + model_files = Dir.glob("#{Rails.root}/app/models/*.rb").reject do |item| item.match(/_observer\.rb/) end else model_files = `grep -l "^[[:space:]]*using_access_control" #{Rails.root}/app/models/*.rb`.split("\n") end - models_with_ac = model_files.collect {|mf| mf.sub(/^.*\//, "").sub(".rb", "").tableize.to_sym} - model_security_privs = [:create, :read, :update, :delete] - models_with_ac.each {|m| perms += model_security_privs.collect{|msp| [msp, m]}} + models_with_ac = model_files.collect { |mf| mf.sub(/^.*\//, '').sub('.rb', '').tableize.to_sym } + model_security_privs = %i[create read update delete] + models_with_ac.each { |m| perms += model_security_privs.collect { |msp| [msp, m] } } grep_file_pattern = "#{Rails.root}/app/models/*.rb #{Rails.root}/app/views/**/* #{Rails.root}/app/controllers/*.rb" `grep "permitted_to?" #{grep_file_pattern}`.split("\n").each do |ptu| @@ -46,44 +46,44 @@ namespace :auth do context = match[2][1..-1].to_sym else c = (match[2][0..0] == '@' ? match[2][1..-1] : match[2]).pluralize.to_sym - context = c if perms.any? {|p| p[1] == c} + context = c if perms.any? { |p| p[1] == c } end end - if privilege.nil? or context.nil? + if privilege.nil? || context.nil? puts "Could not handle: #{ptu}" else perms << [privilege, context] end end - + `grep ".with_permissions_to" #{grep_file_pattern}`.split("\n").each do |wpt| file, grep_match = wpt.split(':', 2) context = privilege = nil if match = grep_match.match(/(\w+\.)?with_permissions_to(\(:\w+)?/) c = match[1][0..-2].tableize.to_sym if match[1] c ||= File.basename(file, '.rb').tableize.to_sym - context = c if perms.any? {|p| p[1] == c} - privilege = match[2] && match[2][(match[2][0..0]=='(' ? 2 : 1)..-1].to_sym + context = c if perms.any? { |p| p[1] == c } + privilege = match[2] && match[2][(match[2][0..0] == '(' ? 2 : 1)..-1].to_sym privilege ||= :read end - if privilege.nil? or context.nil? + if privilege.nil? || context.nil? puts "Could not handle: #{wpt}" else perms << [privilege, context] end end - + perms.uniq! perm_hash = {} - perms.each do |cp| + perms.each do |cp| perm_hash[cp[1]] ||= [] perm_hash[cp[1]] << cp[0] end - puts "Privileges currently in use:" + puts 'Privileges currently in use:' perm_hash.each do |context, privileges| - puts " #{context.inspect}:\t#{privileges.collect {|p| p.inspect}.sort * ', '}" - #privileges.collect {|p| p.inspect}.sort.each {|p| puts " #{p}"} + puts " #{context.inspect}:\t#{privileges.collect(&:inspect).sort * ', '}" + # privileges.collect {|p| p.inspect}.sort.each {|p| puts " #{p}"} end end end diff --git a/test/authorization_test.rb b/test/authorization_test.rb index 2558771d..a6a161f3 100644 --- a/test/authorization_test.rb +++ b/test/authorization_test.rb @@ -1,78 +1,77 @@ require 'test_helper' class AuthorizationTest < Test::Unit::TestCase - def test_permit reader = Authorization::Reader::DSLReader.new - reader.parse %{ + reader.parse %( authorization do role :test_role do has_permission_on :permissions, :to => :test end end - } + ) engine = Authorization::Engine.new(reader) - assert engine.permit?(:test, :context => :permissions, - :user => MockUser.new(:test_role, :test_role_2)) - assert !engine.permit?(:test_2, :context => :permissions_2, - :user => MockUser.new(:test_role)) - assert !engine.permit?(:test, :context => :permissions, - :user => MockUser.new(:test_role_2)) + assert engine.permit?(:test, context: :permissions, + user: MockUser.new(:test_role, :test_role_2)) + assert !engine.permit?(:test_2, context: :permissions_2, + user: MockUser.new(:test_role)) + assert !engine.permit?(:test, context: :permissions, + user: MockUser.new(:test_role_2)) end def test_permit_context_people reader = Authorization::Reader::DSLReader.new - reader.parse %{ + reader.parse %( authorization do role :test_role do has_permission_on :people, :to => :test end end - } + ) engine = Authorization::Engine.new(reader) - assert engine.permit?(:test, :context => :people, - :user => MockUser.new(:test_role)) + assert engine.permit?(:test, context: :people, + user: MockUser.new(:test_role)) end def test_permit_with_has_omnipotence reader = Authorization::Reader::DSLReader.new - reader.parse %{ + reader.parse %( authorization do role :admin do has_omnipotence end end - } + ) engine = Authorization::Engine.new(reader) - assert engine.permit?(:test, :context => :people, - :user => MockUser.new(:admin)) + assert engine.permit?(:test, context: :people, + user: MockUser.new(:admin)) end def test_permit_multiple_contexts reader = Authorization::Reader::DSLReader.new - reader.parse %{ + reader.parse %( authorization do role :test_role do has_permission_on [:permissions, :permissions_2], :to => :test has_permission_on :permissions_4, :permissions_5, :to => :test end end - } + ) engine = Authorization::Engine.new(reader) - assert engine.permit?(:test, :context => :permissions, - :user => MockUser.new(:test_role)) - assert engine.permit?(:test, :context => :permissions_2, - :user => MockUser.new(:test_role)) - assert !engine.permit?(:test, :context => :permissions_3, - :user => MockUser.new(:test_role)) - - assert engine.permit?(:test, :context => :permissions_4, :user => MockUser.new(:test_role)) - assert engine.permit?(:test, :context => :permissions_5, :user => MockUser.new(:test_role)) + assert engine.permit?(:test, context: :permissions, + user: MockUser.new(:test_role)) + assert engine.permit?(:test, context: :permissions_2, + user: MockUser.new(:test_role)) + assert !engine.permit?(:test, context: :permissions_3, + user: MockUser.new(:test_role)) + + assert engine.permit?(:test, context: :permissions_4, user: MockUser.new(:test_role)) + assert engine.permit?(:test, context: :permissions_5, user: MockUser.new(:test_role)) end def test_permit_with_frozen_roles reader = Authorization::Reader::DSLReader.new - reader.parse %{ + reader.parse %( authorization do role :other_role do includes :test_role @@ -81,30 +80,30 @@ def test_permit_with_frozen_roles has_permission_on :permissions, :to => :test end end - } + ) engine = Authorization::Engine.new(reader) roles = [:other_role].freeze - assert engine.permit?(:test, :context => :permissions, - :user => MockUser.new(:role_symbols => roles)) + assert engine.permit?(:test, context: :permissions, + user: MockUser.new(role_symbols: roles)) end def test_obligations_without_conditions reader = Authorization::Reader::DSLReader.new - reader.parse %{ + reader.parse %( authorization do role :test_role do has_permission_on :permissions, :to => :test end end - } + ) engine = Authorization::Engine.new(reader) - assert_equal [{}], engine.obligations(:test, :context => :permissions, - :user => MockUser.new(:test_role)) + assert_equal [{}], engine.obligations(:test, context: :permissions, + user: MockUser.new(:test_role)) end def test_obligations_with_conditions reader = Authorization::Reader::DSLReader.new - reader.parse %{ + reader.parse %( authorization do role :test_role do has_permission_on :permissions, :to => :test do @@ -112,16 +111,16 @@ def test_obligations_with_conditions end end end - } + ) engine = Authorization::Engine.new(reader) - assert_equal [{:attr => [:is, 1]}], - engine.obligations(:test, :context => :permissions, - :user => MockUser.new(:test_role, :attr => 1)) + assert_equal [{ attr: [:is, 1] }], + engine.obligations(:test, context: :permissions, + user: MockUser.new(:test_role, attr: 1)) end def test_obligations_with_omnipotence reader = Authorization::Reader::DSLReader.new - reader.parse %{ + reader.parse %( authorization do role :admin do has_omnipotence @@ -132,16 +131,16 @@ def test_obligations_with_omnipotence end end end - } + ) engine = Authorization::Engine.new(reader) assert_equal [], - engine.obligations(:test, :context => :permissions, - :user => MockUser.new(:test_role, :admin, :attr => 1)) + engine.obligations(:test, context: :permissions, + user: MockUser.new(:test_role, :admin, attr: 1)) end def test_obligations_with_anded_conditions reader = Authorization::Reader::DSLReader.new - reader.parse %{ + reader.parse %( authorization do role :test_role do has_permission_on :permissions, :to => :test, :join_by => :and do @@ -150,16 +149,16 @@ def test_obligations_with_anded_conditions end end end - } + ) engine = Authorization::Engine.new(reader) - assert_equal [{:attr => [:is, 1], :attr_2 => [:is, 2]}], - engine.obligations(:test, :context => :permissions, - :user => MockUser.new(:test_role, :attr => 1, :attr_2 => 2)) + assert_equal [{ attr: [:is, 1], attr_2: [:is, 2] }], + engine.obligations(:test, context: :permissions, + user: MockUser.new(:test_role, attr: 1, attr_2: 2)) end def test_obligations_with_deep_anded_conditions reader = Authorization::Reader::DSLReader.new - reader.parse %{ + reader.parse %( authorization do role :test_role do has_permission_on :permissions, :to => :test, :join_by => :and do @@ -168,16 +167,16 @@ def test_obligations_with_deep_anded_conditions end end end - } + ) engine = Authorization::Engine.new(reader) - assert_equal [{:attr => { :deeper_attr => [:is, 1], :deeper_attr_2 => [:is, 2] } }], - engine.obligations(:test, :context => :permissions, - :user => MockUser.new(:test_role, :deeper_attr => 1, :deeper_attr_2 => 2)) + assert_equal [{ attr: { deeper_attr: [:is, 1], deeper_attr_2: [:is, 2] } }], + engine.obligations(:test, context: :permissions, + user: MockUser.new(:test_role, deeper_attr: 1, deeper_attr_2: 2)) end def test_obligations_with_has_many reader = Authorization::Reader::DSLReader.new - reader.parse %{ + reader.parse %( authorization do role :test_role do has_permission_on :permissions, :to => :test do @@ -185,16 +184,16 @@ def test_obligations_with_has_many end end end - } + ) engine = Authorization::Engine.new(reader) - assert_equal [{:attrs => {:deeper_attr => [:is, 1]}}], - engine.obligations(:test, :context => :permissions, - :user => MockUser.new(:test_role, :deeper_attr => 1)) + assert_equal [{ attrs: { deeper_attr: [:is, 1] } }], + engine.obligations(:test, context: :permissions, + user: MockUser.new(:test_role, deeper_attr: 1)) end def test_obligations_with_conditions_and_empty reader = Authorization::Reader::DSLReader.new - reader.parse %{ + reader.parse %( authorization do role :test_role do has_permission_on :permissions, :to => :test @@ -203,16 +202,16 @@ def test_obligations_with_conditions_and_empty end end end - } + ) engine = Authorization::Engine.new(reader) - assert_equal [{}, {:attr => [:is, 1]}], - engine.obligations(:test, :context => :permissions, - :user => MockUser.new(:test_role, :attr => 1)) + assert_equal [{}, { attr: [:is, 1] }], + engine.obligations(:test, context: :permissions, + user: MockUser.new(:test_role, attr: 1)) end def test_obligations_with_permissions reader = Authorization::Reader::DSLReader.new - reader.parse %{ + reader.parse %( authorization do role :test_role do has_permission_on :permissions, :to => :test do @@ -230,22 +229,22 @@ def test_obligations_with_permissions end end end - } + ) engine = Authorization::Engine.new(reader) - assert_equal [{:permission => {:attr => [:is, 1]}}], - engine.obligations(:test, :context => :permission_children, - :user => MockUser.new(:test_role, :attr => 1)) - assert_equal [{:permission => {:attr => [:is, 1]}}], - engine.obligations(:test, :context => :permission_children_2, - :user => MockUser.new(:test_role, :attr => 1)) - assert_equal [{:permission_child => {:permission => {:attr => [:is, 1]}}}], - engine.obligations(:test, :context => :permission_children_children, - :user => MockUser.new(:test_role, :attr => 1)) + assert_equal [{ permission: { attr: [:is, 1] } }], + engine.obligations(:test, context: :permission_children, + user: MockUser.new(:test_role, attr: 1)) + assert_equal [{ permission: { attr: [:is, 1] } }], + engine.obligations(:test, context: :permission_children_2, + user: MockUser.new(:test_role, attr: 1)) + assert_equal [{ permission_child: { permission: { attr: [:is, 1] } } }], + engine.obligations(:test, context: :permission_children_children, + user: MockUser.new(:test_role, attr: 1)) end def test_obligations_with_has_many_permissions reader = Authorization::Reader::DSLReader.new - reader.parse %{ + reader.parse %( authorization do role :test_role do has_permission_on :permissions, :to => :test do @@ -263,22 +262,22 @@ def test_obligations_with_has_many_permissions end end end - } + ) engine = Authorization::Engine.new(reader) - assert_equal [{:permissions => {:attr => [:is, 1]}}], - engine.obligations(:test, :context => :permission_children, - :user => MockUser.new(:test_role, :attr => 1)) - assert_equal [{:permissions => {:attr => [:is, 1]}}], - engine.obligations(:test, :context => :permission_children_2, - :user => MockUser.new(:test_role, :attr => 1)) - assert_equal [{:permission_child => {:permissions => {:attr => [:is, 1]}}}], - engine.obligations(:test, :context => :permission_children_children, - :user => MockUser.new(:test_role, :attr => 1)) + assert_equal [{ permissions: { attr: [:is, 1] } }], + engine.obligations(:test, context: :permission_children, + user: MockUser.new(:test_role, attr: 1)) + assert_equal [{ permissions: { attr: [:is, 1] } }], + engine.obligations(:test, context: :permission_children_2, + user: MockUser.new(:test_role, attr: 1)) + assert_equal [{ permission_child: { permissions: { attr: [:is, 1] } } }], + engine.obligations(:test, context: :permission_children_children, + user: MockUser.new(:test_role, attr: 1)) end def test_obligations_with_permissions_multiple reader = Authorization::Reader::DSLReader.new - reader.parse %{ + reader.parse %( authorization do role :test_role do has_permission_on :permissions, :to => :test do @@ -290,17 +289,17 @@ def test_obligations_with_permissions_multiple end end end - } + ) engine = Authorization::Engine.new(reader) - assert_equal [{:permission_child => {:permission => {:attr => [:is, 1]}}}, - {:permission_child => {:permission => {:attr => [:is, 2]}}}], - engine.obligations(:test, :context => :permission_children_children, - :user => MockUser.new(:test_role)) + assert_equal [{ permission_child: { permission: { attr: [:is, 1] } } }, + { permission_child: { permission: { attr: [:is, 2] } } }], + engine.obligations(:test, context: :permission_children_children, + user: MockUser.new(:test_role)) end def test_obligations_with_permissions_and_anded_conditions reader = Authorization::Reader::DSLReader.new - reader.parse %{ + reader.parse %( authorization do role :test_role do has_permission_on :permission_children, :to => :test, :join_by => :and do @@ -312,70 +311,70 @@ def test_obligations_with_permissions_and_anded_conditions end end end - } + ) engine = Authorization::Engine.new(reader) - assert_equal [{:test_attr => [:is, 1], :permission => {:test_attr => [:is, 1]}}], - engine.obligations(:test, :context => :permission_children, - :user => MockUser.new(:test_role)) + assert_equal [{ test_attr: [:is, 1], permission: { test_attr: [:is, 1] } }], + engine.obligations(:test, context: :permission_children, + user: MockUser.new(:test_role)) end def test_guest_user reader = Authorization::Reader::DSLReader.new - reader.parse %{ + reader.parse %( authorization do role :guest do has_permission_on :permissions, :to => :test end end - } + ) engine = Authorization::Engine.new(reader) -#test intermittently fails - assert engine.permit?(:test, :context => :permissions) - assert !engine.permit?(:test, :context => :permissions_2) + # test intermittently fails + assert engine.permit?(:test, context: :permissions) + assert !engine.permit?(:test, context: :permissions_2) end def test_default_role previous_default_role = Authorization.default_role Authorization.default_role = :anonymous reader = Authorization::Reader::DSLReader.new - reader.parse %{ + reader.parse %( authorization do role :anonymous do has_permission_on :permissions, :to => :test end end - } + ) engine = Authorization::Engine.new(reader) -#test intermittently fails - assert engine.permit?(:test, :context => :permissions) - assert !engine.permit?(:test, :context => :permissions, - :user => MockUser.new(:guest)) + # test intermittently fails + assert engine.permit?(:test, context: :permissions) + assert !engine.permit?(:test, context: :permissions, + user: MockUser.new(:guest)) # reset the default role, so that it does not mess up other tests Authorization.default_role = previous_default_role end def test_invalid_user_model reader = Authorization::Reader::DSLReader.new - reader.parse %{ + reader.parse %( authorization do role :guest do has_permission_on :permissions, :to => :test end end - } + ) engine = Authorization::Engine.new(reader) assert_raises(Authorization::AuthorizationUsageError) do - engine.permit?(:test, :context => :permissions, :user => MockUser.new(1, 2)) + engine.permit?(:test, context: :permissions, user: MockUser.new(1, 2)) end assert_raises(Authorization::AuthorizationUsageError) do - engine.permit?(:test, :context => :permissions, :user => MockDataObject.new) + engine.permit?(:test, context: :permissions, user: MockDataObject.new) end end def test_role_hierarchy reader = Authorization::Reader::DSLReader.new - reader.parse %{ + reader.parse %( authorization do role :test_role do includes :lower_role @@ -385,15 +384,15 @@ def test_role_hierarchy has_permission_on :permissions, :to => :lower end end - } + ) engine = Authorization::Engine.new(reader) - assert engine.permit?(:lower, :context => :permissions, - :user => MockUser.new(:test_role)) + assert engine.permit?(:lower, context: :permissions, + user: MockUser.new(:test_role)) end def test_role_hierarchy_infinity reader = Authorization::Reader::DSLReader.new - reader.parse %{ + reader.parse %( authorization do role :test_role do includes :lower_role @@ -404,15 +403,15 @@ def test_role_hierarchy_infinity has_permission_on :permissions, :to => :lower end end - } + ) engine = Authorization::Engine.new(reader) - assert engine.permit?(:lower, :context => :permissions, - :user => MockUser.new(:test_role)) + assert engine.permit?(:lower, context: :permissions, + user: MockUser.new(:test_role)) end def test_privilege_hierarchy reader = Authorization::Reader::DSLReader.new - reader.parse %{ + reader.parse %( privileges do privilege :test, :permissions do includes :lower @@ -423,15 +422,15 @@ def test_privilege_hierarchy has_permission_on :permissions, :to => :test end end - } + ) engine = Authorization::Engine.new(reader) - assert engine.permit?(:lower, :context => :permissions, - :user => MockUser.new(:test_role)) + assert engine.permit?(:lower, context: :permissions, + user: MockUser.new(:test_role)) end def test_privilege_hierarchy_without_context reader = Authorization::Reader::DSLReader.new - reader.parse %{ + reader.parse %( privileges do privilege :read do includes :list, :show @@ -442,15 +441,15 @@ def test_privilege_hierarchy_without_context has_permission_on :permissions, :to => :read end end - } + ) engine = Authorization::Engine.new(reader) - assert engine.permit?(:list, :context => :permissions, - :user => MockUser.new(:test_role)) + assert engine.permit?(:list, context: :permissions, + user: MockUser.new(:test_role)) end def test_attribute_is reader = Authorization::Reader::DSLReader.new - reader.parse %| + reader.parse %( authorization do role :test_role do has_permission_on :permissions, :to => :test do @@ -459,22 +458,22 @@ def test_attribute_is end end end - | + ) engine = Authorization::Engine.new(reader) - assert engine.permit?(:test, :context => :permissions, - :user => MockUser.new(:test_role, :test_attr => 1), - :object => MockDataObject.new(:test_attr => 1)) - assert engine.permit?(:test, :context => :permissions, - :user => MockUser.new(:test_role, :test_attr => 2), - :object => MockDataObject.new(:test_attr => 3)) - assert((not(engine.permit?(:test, :context => :permissions, - :user => MockUser.new(:test_role, :test_attr => 2), - :object => MockDataObject.new(:test_attr => 1))))) + assert engine.permit?(:test, context: :permissions, + user: MockUser.new(:test_role, test_attr: 1), + object: MockDataObject.new(test_attr: 1)) + assert engine.permit?(:test, context: :permissions, + user: MockUser.new(:test_role, test_attr: 2), + object: MockDataObject.new(test_attr: 3)) + assert(!engine.permit?(:test, context: :permissions, + user: MockUser.new(:test_role, test_attr: 2), + object: MockDataObject.new(test_attr: 1))) end def test_attribute_is_not reader = Authorization::Reader::DSLReader.new - reader.parse %| + reader.parse %( authorization do role :test_role do has_permission_on :permissions, :to => :test do @@ -482,19 +481,19 @@ def test_attribute_is_not end end end - | + ) engine = Authorization::Engine.new(reader) - assert !engine.permit?(:test, :context => :permissions, - :user => MockUser.new(:test_role, :test_attr => 1), - :object => MockDataObject.new(:test_attr => 1)) - assert engine.permit?(:test, :context => :permissions, - :user => MockUser.new(:test_role, :test_attr => 2), - :object => MockDataObject.new(:test_attr => 1)) + assert !engine.permit?(:test, context: :permissions, + user: MockUser.new(:test_role, test_attr: 1), + object: MockDataObject.new(test_attr: 1)) + assert engine.permit?(:test, context: :permissions, + user: MockUser.new(:test_role, test_attr: 2), + object: MockDataObject.new(test_attr: 1)) end def test_attribute_contains reader = Authorization::Reader::DSLReader.new - reader.parse %| + reader.parse %( authorization do role :test_role do has_permission_on :permissions, :to => :test do @@ -502,19 +501,19 @@ def test_attribute_contains end end end - | + ) engine = Authorization::Engine.new(reader) - assert engine.permit?(:test, :context => :permissions, - :user => MockUser.new(:test_role, :test_attr => 1), - :object => MockDataObject.new(:test_attr => [1,2])) - assert !engine.permit?(:test, :context => :permissions, - :user => MockUser.new(:test_role, :test_attr => 3), - :object => MockDataObject.new(:test_attr => [1,2])) + assert engine.permit?(:test, context: :permissions, + user: MockUser.new(:test_role, test_attr: 1), + object: MockDataObject.new(test_attr: [1, 2])) + assert !engine.permit?(:test, context: :permissions, + user: MockUser.new(:test_role, test_attr: 3), + object: MockDataObject.new(test_attr: [1, 2])) end def test_attribute_does_not_contain reader = Authorization::Reader::DSLReader.new - reader.parse %| + reader.parse %( authorization do role :test_role do has_permission_on :permissions, :to => :test do @@ -522,19 +521,19 @@ def test_attribute_does_not_contain end end end - | + ) engine = Authorization::Engine.new(reader) - assert !engine.permit?(:test, :context => :permissions, - :user => MockUser.new(:test_role, :test_attr => 1), - :object => MockDataObject.new(:test_attr => [1,2])) - assert engine.permit?(:test, :context => :permissions, - :user => MockUser.new(:test_role, :test_attr => 3), - :object => MockDataObject.new(:test_attr => [1,2])) + assert !engine.permit?(:test, context: :permissions, + user: MockUser.new(:test_role, test_attr: 1), + object: MockDataObject.new(test_attr: [1, 2])) + assert engine.permit?(:test, context: :permissions, + user: MockUser.new(:test_role, test_attr: 3), + object: MockDataObject.new(test_attr: [1, 2])) end def test_attribute_in_array reader = Authorization::Reader::DSLReader.new - reader.parse %| + reader.parse %( authorization do role :test_role do has_permission_on :permissions, :to => :test do @@ -543,22 +542,22 @@ def test_attribute_in_array end end end - | + ) engine = Authorization::Engine.new(reader) - assert engine.permit?(:test, :context => :permissions, - :user => MockUser.new(:test_role), - :object => MockDataObject.new(:test_attr => 1)) - assert engine.permit?(:test, :context => :permissions, - :user => MockUser.new(:test_role), - :object => MockDataObject.new(:test_attr => 3)) - assert !engine.permit?(:test, :context => :permissions, - :user => MockUser.new(:test_role), - :object => MockDataObject.new(:test_attr => 4)) + assert engine.permit?(:test, context: :permissions, + user: MockUser.new(:test_role), + object: MockDataObject.new(test_attr: 1)) + assert engine.permit?(:test, context: :permissions, + user: MockUser.new(:test_role), + object: MockDataObject.new(test_attr: 3)) + assert !engine.permit?(:test, context: :permissions, + user: MockUser.new(:test_role), + object: MockDataObject.new(test_attr: 4)) end def test_attribute_not_in_array reader = Authorization::Reader::DSLReader.new - reader.parse %| + reader.parse %( authorization do role :test_role do has_permission_on :permissions, :to => :test do @@ -566,19 +565,19 @@ def test_attribute_not_in_array end end end - | + ) engine = Authorization::Engine.new(reader) - assert !engine.permit?(:test, :context => :permissions, - :user => MockUser.new(:test_role), - :object => MockDataObject.new(:test_attr => 1)) - assert engine.permit?(:test, :context => :permissions, - :user => MockUser.new(:test_role), - :object => MockDataObject.new(:test_attr => 4)) + assert !engine.permit?(:test, context: :permissions, + user: MockUser.new(:test_role), + object: MockDataObject.new(test_attr: 1)) + assert engine.permit?(:test, context: :permissions, + user: MockUser.new(:test_role), + object: MockDataObject.new(test_attr: 4)) end def test_attribute_intersects_with reader = Authorization::Reader::DSLReader.new - reader.parse %{ + reader.parse %( authorization do role :test_role do has_permission_on :permissions, :to => :test do @@ -591,30 +590,30 @@ def test_attribute_intersects_with end end end - } + ) engine = Authorization::Engine.new(reader) assert_raises Authorization::AuthorizationUsageError do - engine.permit?(:test, :context => :permissions, - :user => MockUser.new(:test_role), - :object => MockDataObject.new(:test_attrs => 1 )) + engine.permit?(:test, context: :permissions, + user: MockUser.new(:test_role), + object: MockDataObject.new(test_attrs: 1)) end assert_raises Authorization::AuthorizationUsageError do - engine.permit?(:test, :context => :permissions, - :user => MockUser.new(:test_role_2), - :object => MockDataObject.new(:test_attrs => [1, 2] )) + engine.permit?(:test, context: :permissions, + user: MockUser.new(:test_role_2), + object: MockDataObject.new(test_attrs: [1, 2])) end - assert engine.permit?(:test, :context => :permissions, - :user => MockUser.new(:test_role), - :object => MockDataObject.new(:test_attrs => [1,3] )) - assert !engine.permit?(:test, :context => :permissions, - :user => MockUser.new(:test_role), - :object => MockDataObject.new(:test_attrs => [3,4] )) + assert engine.permit?(:test, context: :permissions, + user: MockUser.new(:test_role), + object: MockDataObject.new(test_attrs: [1, 3])) + assert !engine.permit?(:test, context: :permissions, + user: MockUser.new(:test_role), + object: MockDataObject.new(test_attrs: [3, 4])) end def test_attribute_lte reader = Authorization::Reader::DSLReader.new - reader.parse %| + reader.parse %( authorization do role :test_role do has_permission_on :permissions, :to => :test do @@ -623,29 +622,29 @@ def test_attribute_lte end end end - | + ) engine = Authorization::Engine.new(reader) # object < user -> pass - assert engine.permit?(:test, :context => :permissions, - :user => MockUser.new(:test_role, :test_attr => 2), - :object => MockDataObject.new(:test_attr => 1)) + assert engine.permit?(:test, context: :permissions, + user: MockUser.new(:test_role, test_attr: 2), + object: MockDataObject.new(test_attr: 1)) # object > user && object = control -> pass - assert engine.permit?(:test, :context => :permissions, - :user => MockUser.new(:test_role, :test_attr => 2), - :object => MockDataObject.new(:test_attr => 3)) + assert engine.permit?(:test, context: :permissions, + user: MockUser.new(:test_role, test_attr: 2), + object: MockDataObject.new(test_attr: 3)) # object = user -> pass - assert engine.permit?(:test, :context => :permissions, - :user => MockUser.new(:test_role, :test_attr => 1), - :object => MockDataObject.new(:test_attr => 1)) + assert engine.permit?(:test, context: :permissions, + user: MockUser.new(:test_role, test_attr: 1), + object: MockDataObject.new(test_attr: 1)) # object > user -> fail - assert((not(engine.permit?(:test, :context => :permissions, - :user => MockUser.new(:test_role, :test_attr => 1), - :object => MockDataObject.new(:test_attr => 2))))) + assert(!engine.permit?(:test, context: :permissions, + user: MockUser.new(:test_role, test_attr: 1), + object: MockDataObject.new(test_attr: 2))) end def test_attribute_gt reader = Authorization::Reader::DSLReader.new - reader.parse %| + reader.parse %( authorization do role :test_role do has_permission_on :permissions, :to => :test do @@ -654,29 +653,29 @@ def test_attribute_gt end end end - | + ) engine = Authorization::Engine.new(reader) # object > user -> pass - assert engine.permit?(:test, :context => :permissions, - :user => MockUser.new(:test_role, :test_attr => 1), - :object => MockDataObject.new(:test_attr => 2)) + assert engine.permit?(:test, context: :permissions, + user: MockUser.new(:test_role, test_attr: 1), + object: MockDataObject.new(test_attr: 2)) # object < user && object = control -> pass - assert engine.permit?(:test, :context => :permissions, - :user => MockUser.new(:test_role, :test_attr => 4), - :object => MockDataObject.new(:test_attr => 3)) + assert engine.permit?(:test, context: :permissions, + user: MockUser.new(:test_role, test_attr: 4), + object: MockDataObject.new(test_attr: 3)) # object = user -> fail - assert((not(engine.permit?(:test, :context => :permissions, - :user => MockUser.new(:test_role, :test_attr => 1), - :object => MockDataObject.new(:test_attr => 1))))) + assert(!engine.permit?(:test, context: :permissions, + user: MockUser.new(:test_role, test_attr: 1), + object: MockDataObject.new(test_attr: 1))) # object < user -> fail - assert((not(engine.permit?(:test, :context => :permissions, - :user => MockUser.new(:test_role, :test_attr => 2), - :object => MockDataObject.new(:test_attr => 1))))) + assert(!engine.permit?(:test, context: :permissions, + user: MockUser.new(:test_role, test_attr: 2), + object: MockDataObject.new(test_attr: 1))) end def test_attribute_gte reader = Authorization::Reader::DSLReader.new - reader.parse %| + reader.parse %( authorization do role :test_role do has_permission_on :permissions, :to => :test do @@ -685,29 +684,29 @@ def test_attribute_gte end end end - | + ) engine = Authorization::Engine.new(reader) # object > user -> pass - assert engine.permit?(:test, :context => :permissions, - :user => MockUser.new(:test_role, :test_attr => 1), - :object => MockDataObject.new(:test_attr => 2)) + assert engine.permit?(:test, context: :permissions, + user: MockUser.new(:test_role, test_attr: 1), + object: MockDataObject.new(test_attr: 2)) # object < user && object = control -> pass - assert engine.permit?(:test, :context => :permissions, - :user => MockUser.new(:test_role, :test_attr => 4), - :object => MockDataObject.new(:test_attr => 3)) + assert engine.permit?(:test, context: :permissions, + user: MockUser.new(:test_role, test_attr: 4), + object: MockDataObject.new(test_attr: 3)) # object = user -> pass - assert engine.permit?(:test, :context => :permissions, - :user => MockUser.new(:test_role, :test_attr => 1), - :object => MockDataObject.new(:test_attr => 1)) + assert engine.permit?(:test, context: :permissions, + user: MockUser.new(:test_role, test_attr: 1), + object: MockDataObject.new(test_attr: 1)) # object < user -> fail - assert((not(engine.permit?(:test, :context => :permissions, - :user => MockUser.new(:test_role, :test_attr => 2), - :object => MockDataObject.new(:test_attr => 1))))) + assert(!engine.permit?(:test, context: :permissions, + user: MockUser.new(:test_role, test_attr: 2), + object: MockDataObject.new(test_attr: 1))) end def test_attribute_deep reader = Authorization::Reader::DSLReader.new - reader.parse %| + reader.parse %( authorization do role :test_role do has_permission_on :permissions, :to => :test do @@ -715,24 +714,22 @@ def test_attribute_deep end end end - | + ) engine = Authorization::Engine.new(reader) - assert engine.permit?(:test, :context => :permissions, - :user => MockUser.new(:test_role), - :object => MockDataObject.new(:test_attr_1 => - MockDataObject.new(:test_attr_2 => [1,2]))) - assert !engine.permit?(:test, :context => :permissions, - :user => MockUser.new(:test_role), - :object => MockDataObject.new(:test_attr_1 => - MockDataObject.new(:test_attr_2 => [3,4]))) - assert_equal [{:test_attr_1 => {:test_attr_2 => [:contains, 1]}}], - engine.obligations(:test, :context => :permissions, - :user => MockUser.new(:test_role)) + assert engine.permit?(:test, context: :permissions, + user: MockUser.new(:test_role), + object: MockDataObject.new(test_attr_1: MockDataObject.new(test_attr_2: [1, 2]))) + assert !engine.permit?(:test, context: :permissions, + user: MockUser.new(:test_role), + object: MockDataObject.new(test_attr_1: MockDataObject.new(test_attr_2: [3, 4]))) + assert_equal [{ test_attr_1: { test_attr_2: [:contains, 1] } }], + engine.obligations(:test, context: :permissions, + user: MockUser.new(:test_role)) end def test_attribute_has_many reader = Authorization::Reader::DSLReader.new - reader.parse %| + reader.parse %( authorization do role :test_role do has_permission_on :companies, :to => :read do @@ -740,24 +737,24 @@ def test_attribute_has_many end end end - | + ) engine = Authorization::Engine.new(reader) - company = MockDataObject.new(:branches => [ - MockDataObject.new(:city => 'Barcelona'), - MockDataObject.new(:city => 'Paris') - ]) - assert engine.permit!(:read, :context => :companies, - :user => MockUser.new(:test_role, :city => 'Paris'), - :object => company) - assert !engine.permit?(:read, :context => :companies, - :user => MockUser.new(:test_role, :city => 'London'), - :object => company) + company = MockDataObject.new(branches: [ + MockDataObject.new(city: 'Barcelona'), + MockDataObject.new(city: 'Paris') + ]) + assert engine.permit!(:read, context: :companies, + user: MockUser.new(:test_role, city: 'Paris'), + object: company) + assert !engine.permit?(:read, context: :companies, + user: MockUser.new(:test_role, city: 'London'), + object: company) end def test_attribute_non_block reader = Authorization::Reader::DSLReader.new - reader.parse %| + reader.parse %( authorization do role :test_role do has_permission_on :permissions, :to => :test do @@ -765,19 +762,19 @@ def test_attribute_non_block end end end - | + ) engine = Authorization::Engine.new(reader) - assert engine.permit?(:test, :context => :permissions, - :user => MockUser.new(:test_role), - :object => MockDataObject.new(:test_attr => 1)) - assert !engine.permit?(:test, :context => :permissions, - :user => MockUser.new(:test_role), - :object => MockDataObject.new(:test_attr => 2)) + assert engine.permit?(:test, context: :permissions, + user: MockUser.new(:test_role), + object: MockDataObject.new(test_attr: 1)) + assert !engine.permit?(:test, context: :permissions, + user: MockUser.new(:test_role), + object: MockDataObject.new(test_attr: 2)) end def test_attribute_multiple reader = Authorization::Reader::DSLReader.new - reader.parse %{ + reader.parse %( authorization do role :test_role do has_permission_on :permissions, :to => :test do @@ -786,24 +783,24 @@ def test_attribute_multiple end end end - } + ) engine = Authorization::Engine.new(reader) - assert engine.permit?(:test, :context => :permissions, - :user => MockUser.new(:test_role), - :object => MockDataObject.new(:test_attr => 1)) - assert engine.permit?(:test, :context => :permissions, - :user => MockUser.new(:test_role), - :object => MockDataObject.new(:test_attr => 2)) + assert engine.permit?(:test, context: :permissions, + user: MockUser.new(:test_role), + object: MockDataObject.new(test_attr: 1)) + assert engine.permit?(:test, context: :permissions, + user: MockUser.new(:test_role), + object: MockDataObject.new(test_attr: 2)) end class PermissionMock < MockDataObject def self.name - "Permission" + 'Permission' end end def test_attribute_with_permissions reader = Authorization::Reader::DSLReader.new - reader.parse %{ + reader.parse %( authorization do role :test_role do has_permission_on :permissions, :to => :test do @@ -814,22 +811,22 @@ def test_attribute_with_permissions end end end - } + ) engine = Authorization::Engine.new(reader) - perm_data_attr_1 = PermissionMock.new({:test_attr => 1}) - perm_data_attr_2 = PermissionMock.new({:test_attr => 2}) - assert engine.permit?(:test, :context => :permission_children, - :user => MockUser.new(:test_role), - :object => MockDataObject.new(:permission => perm_data_attr_1)) - assert !engine.permit?(:test, :context => :permission_children, - :user => MockUser.new(:test_role), - :object => MockDataObject.new(:permission => perm_data_attr_2)) + perm_data_attr_1 = PermissionMock.new(test_attr: 1) + perm_data_attr_2 = PermissionMock.new(test_attr: 2) + assert engine.permit?(:test, context: :permission_children, + user: MockUser.new(:test_role), + object: MockDataObject.new(permission: perm_data_attr_1)) + assert !engine.permit?(:test, context: :permission_children, + user: MockUser.new(:test_role), + object: MockDataObject.new(permission: perm_data_attr_2)) end def test_attribute_with_has_many_permissions reader = Authorization::Reader::DSLReader.new - reader.parse %{ + reader.parse %( authorization do role :test_role do has_permission_on :permissions, :to => :test do @@ -840,22 +837,22 @@ def test_attribute_with_has_many_permissions end end end - } + ) engine = Authorization::Engine.new(reader) - perm_data_attr_1 = PermissionMock.new({:test_attr => 1}) - perm_data_attr_2 = PermissionMock.new({:test_attr => 2}) - assert engine.permit?(:test, :context => :permission_children, - :user => MockUser.new(:test_role), - :object => MockDataObject.new(:permissions => [perm_data_attr_1])) - assert !engine.permit?(:test, :context => :permission_children, - :user => MockUser.new(:test_role), - :object => MockDataObject.new(:permissions => [perm_data_attr_2])) + perm_data_attr_1 = PermissionMock.new(test_attr: 1) + perm_data_attr_2 = PermissionMock.new(test_attr: 2) + assert engine.permit?(:test, context: :permission_children, + user: MockUser.new(:test_role), + object: MockDataObject.new(permissions: [perm_data_attr_1])) + assert !engine.permit?(:test, context: :permission_children, + user: MockUser.new(:test_role), + object: MockDataObject.new(permissions: [perm_data_attr_2])) end def test_attribute_with_deep_permissions reader = Authorization::Reader::DSLReader.new - reader.parse %{ + reader.parse %( authorization do role :test_role do has_permission_on :permissions, :to => :test do @@ -866,24 +863,22 @@ def test_attribute_with_deep_permissions end end end - } + ) engine = Authorization::Engine.new(reader) - perm_data_attr_1 = PermissionMock.new({:test_attr => 1}) - perm_data_attr_2 = PermissionMock.new({:test_attr => 2}) - assert engine.permit?(:test, :context => :permission_children, - :user => MockUser.new(:test_role), - :object => MockDataObject.new(:shallow_permission => - MockDataObject.new(:permission => perm_data_attr_1))) - assert !engine.permit?(:test, :context => :permission_children, - :user => MockUser.new(:test_role), - :object => MockDataObject.new(:shallow_permission => - MockDataObject.new(:permission => perm_data_attr_2))) + perm_data_attr_1 = PermissionMock.new(test_attr: 1) + perm_data_attr_2 = PermissionMock.new(test_attr: 2) + assert engine.permit?(:test, context: :permission_children, + user: MockUser.new(:test_role), + object: MockDataObject.new(shallow_permission: MockDataObject.new(permission: perm_data_attr_1))) + assert !engine.permit?(:test, context: :permission_children, + user: MockUser.new(:test_role), + object: MockDataObject.new(shallow_permission: MockDataObject.new(permission: perm_data_attr_2))) end def test_attribute_with_deep_has_many_permissions reader = Authorization::Reader::DSLReader.new - reader.parse %{ + reader.parse %( authorization do role :test_role do has_permission_on :permissions, :to => :test do @@ -894,24 +889,22 @@ def test_attribute_with_deep_has_many_permissions end end end - } + ) engine = Authorization::Engine.new(reader) - perm_data_attr_1 = PermissionMock.new({:test_attr => 1}) - perm_data_attr_2 = PermissionMock.new({:test_attr => 2}) - assert engine.permit?(:test, :context => :permission_children, - :user => MockUser.new(:test_role), - :object => MockDataObject.new(:shallow_permissions => - [MockDataObject.new(:permission => perm_data_attr_1)])) - assert !engine.permit?(:test, :context => :permission_children, - :user => MockUser.new(:test_role), - :object => MockDataObject.new(:shallow_permissions => - [MockDataObject.new(:permission => perm_data_attr_2)])) + perm_data_attr_1 = PermissionMock.new(test_attr: 1) + perm_data_attr_2 = PermissionMock.new(test_attr: 2) + assert engine.permit?(:test, context: :permission_children, + user: MockUser.new(:test_role), + object: MockDataObject.new(shallow_permissions: [MockDataObject.new(permission: perm_data_attr_1)])) + assert !engine.permit?(:test, context: :permission_children, + user: MockUser.new(:test_role), + object: MockDataObject.new(shallow_permissions: [MockDataObject.new(permission: perm_data_attr_2)])) end def test_attribute_with_permissions_nil reader = Authorization::Reader::DSLReader.new - reader.parse %{ + reader.parse %( authorization do role :test_role do has_permission_on :permissions, :to => :test do @@ -922,21 +915,21 @@ def test_attribute_with_permissions_nil end end end - } + ) engine = Authorization::Engine.new(reader) - engine.permit?(:test, :context => :permission_children, - :user => MockUser.new(:test_role), - :object => MockDataObject.new(:permission => nil)) + engine.permit?(:test, context: :permission_children, + user: MockUser.new(:test_role), + object: MockDataObject.new(permission: nil)) - assert !engine.permit?(:test, :context => :permission_children, - :user => MockUser.new(:test_role), - :object => MockDataObject.new(:permission => nil)) + assert !engine.permit?(:test, context: :permission_children, + user: MockUser.new(:test_role), + object: MockDataObject.new(permission: nil)) end def test_attribute_with_permissions_on_self reader = Authorization::Reader::DSLReader.new - reader.parse %{ + reader.parse %( authorization do role :test_role do has_permission_on :permissions, :to => :test do @@ -947,22 +940,22 @@ def test_attribute_with_permissions_on_self end end end - } + ) engine = Authorization::Engine.new(reader) - perm_data_attr_1 = PermissionMock.new({:test_attr => 1}) - perm_data_attr_2 = PermissionMock.new({:test_attr => 2}) - assert engine.permit?(:another_test, :context => :permissions, - :user => MockUser.new(:test_role), - :object => perm_data_attr_1) - assert !engine.permit?(:another_test, :context => :permissions, - :user => MockUser.new(:test_role), - :object => perm_data_attr_2) + perm_data_attr_1 = PermissionMock.new(test_attr: 1) + perm_data_attr_2 = PermissionMock.new(test_attr: 2) + assert engine.permit?(:another_test, context: :permissions, + user: MockUser.new(:test_role), + object: perm_data_attr_1) + assert !engine.permit?(:another_test, context: :permissions, + user: MockUser.new(:test_role), + object: perm_data_attr_2) end def test_attribute_with_permissions_on_self_with_context reader = Authorization::Reader::DSLReader.new - reader.parse %{ + reader.parse %( authorization do role :test_role do has_permission_on :permissions, :to => :test do @@ -973,22 +966,22 @@ def test_attribute_with_permissions_on_self_with_context end end end - } + ) engine = Authorization::Engine.new(reader) - perm_data_attr_1 = PermissionMock.new({:test_attr => 1}) - perm_data_attr_2 = PermissionMock.new({:test_attr => 2}) - assert engine.permit?(:another_test, :context => :permissions, - :user => MockUser.new(:test_role), - :object => perm_data_attr_1) - assert !engine.permit?(:another_test, :context => :permissions, - :user => MockUser.new(:test_role), - :object => perm_data_attr_2) + perm_data_attr_1 = PermissionMock.new(test_attr: 1) + perm_data_attr_2 = PermissionMock.new(test_attr: 2) + assert engine.permit?(:another_test, context: :permissions, + user: MockUser.new(:test_role), + object: perm_data_attr_1) + assert !engine.permit?(:another_test, context: :permissions, + user: MockUser.new(:test_role), + object: perm_data_attr_2) end def test_attribute_with_permissions_and_anded_rules reader = Authorization::Reader::DSLReader.new - reader.parse %{ + reader.parse %( authorization do role :test_role do has_permission_on :permissions, :to => :test do @@ -1000,25 +993,25 @@ def test_attribute_with_permissions_and_anded_rules end end end - } + ) engine = Authorization::Engine.new(reader) - perm_data_attr_1 = PermissionMock.new({:test_attr => 1}) - perm_data_attr_2 = PermissionMock.new({:test_attr => 2}) - assert engine.permit?(:test, :context => :permission_children, - :user => MockUser.new(:test_role), - :object => MockDataObject.new(:permission => perm_data_attr_1, :test_attr => 1)) - assert !engine.permit?(:test, :context => :permission_children, - :user => MockUser.new(:test_role), - :object => MockDataObject.new(:permission => perm_data_attr_2, :test_attr => 1)) - assert !engine.permit?(:test, :context => :permission_children, - :user => MockUser.new(:test_role), - :object => MockDataObject.new(:permission => perm_data_attr_1, :test_attr => 2)) + perm_data_attr_1 = PermissionMock.new(test_attr: 1) + perm_data_attr_2 = PermissionMock.new(test_attr: 2) + assert engine.permit?(:test, context: :permission_children, + user: MockUser.new(:test_role), + object: MockDataObject.new(permission: perm_data_attr_1, test_attr: 1)) + assert !engine.permit?(:test, context: :permission_children, + user: MockUser.new(:test_role), + object: MockDataObject.new(permission: perm_data_attr_2, test_attr: 1)) + assert !engine.permit?(:test, context: :permission_children, + user: MockUser.new(:test_role), + object: MockDataObject.new(permission: perm_data_attr_1, test_attr: 2)) end def test_attribute_with_anded_rules reader = Authorization::Reader::DSLReader.new - reader.parse %{ + reader.parse %( authorization do role :test_role do has_permission_on :permissions, :to => :test, :join_by => :and do @@ -1027,20 +1020,20 @@ def test_attribute_with_anded_rules end end end - } + ) engine = Authorization::Engine.new(reader) - assert engine.permit?(:test, :context => :permissions, - :user => MockUser.new(:test_role), - :object => MockDataObject.new(:test_attr => 1, :test_attr_2 => 2)) - assert !engine.permit?(:test, :context => :permissions, - :user => MockUser.new(:test_role), - :object => MockDataObject.new(:test_attr => 1, :test_attr_2 => 3)) + assert engine.permit?(:test, context: :permissions, + user: MockUser.new(:test_role), + object: MockDataObject.new(test_attr: 1, test_attr_2: 2)) + assert !engine.permit?(:test, context: :permissions, + user: MockUser.new(:test_role), + object: MockDataObject.new(test_attr: 1, test_attr_2: 3)) end def test_raise_on_if_attribute_hash_on_collection reader = Authorization::Reader::DSLReader.new - reader.parse %{ + reader.parse %( authorization do role :test_role do has_permission_on :permissions, :to => :test do @@ -1048,58 +1041,58 @@ def test_raise_on_if_attribute_hash_on_collection end end end - } + ) engine = Authorization::Engine.new(reader) assert_raises Authorization::AuthorizationUsageError do - engine.permit?(:test, :context => :permissions, - :user => MockUser.new(:test_role), - :object => MockDataObject.new(:test_attrs => [1, 2, 3])) + engine.permit?(:test, context: :permissions, + user: MockUser.new(:test_role), + object: MockDataObject.new(test_attrs: [1, 2, 3])) end end def test_role_title_description reader = Authorization::Reader::DSLReader.new - reader.parse %{ + reader.parse %( authorization do role :test_role, :title => 'Test Role' do description "Test Role Description" end end - } + ) engine = Authorization::Engine.new(reader) assert engine.roles.include?(:test_role) - assert_equal "Test Role", engine.role_titles[:test_role] - assert_equal "Test Role", engine.title_for(:test_role) + assert_equal 'Test Role', engine.role_titles[:test_role] + assert_equal 'Test Role', engine.title_for(:test_role) assert_nil engine.title_for(:test_role_2) - assert_equal "Test Role Description", engine.role_descriptions[:test_role] - assert_equal "Test Role Description", engine.description_for(:test_role) + assert_equal 'Test Role Description', engine.role_descriptions[:test_role] + assert_equal 'Test Role Description', engine.description_for(:test_role) assert_nil engine.description_for(:test_role_2) end def test_multithread reader = Authorization::Reader::DSLReader.new - reader.parse %{ + reader.parse %( authorization do role :test_role do has_permission_on :permissions, :to => :test end end - } + ) engine = Authorization::Engine.new(reader) Authorization.current_user = MockUser.new(:test_role) - assert engine.permit?(:test, :context => :permissions) + assert engine.permit?(:test, context: :permissions) Thread.new do Authorization.current_user = MockUser.new(:test_role2) - assert !engine.permit?(:test, :context => :permissions) + assert !engine.permit?(:test, context: :permissions) end - assert engine.permit?(:test, :context => :permissions) + assert engine.permit?(:test, context: :permissions) Authorization.current_user = nil end def test_clone reader = Authorization::Reader::DSLReader.new - reader.parse %{ + reader.parse %( authorization do role :test_role do has_permission_on :permissions, :to => :test do @@ -1109,14 +1102,13 @@ def test_clone end end end - } + ) engine = Authorization::Engine.new(reader) cloned_engine = engine.clone refute_equal engine.auth_rules.first.contexts.object_id, - cloned_engine.auth_rules.first.contexts.object_id + cloned_engine.auth_rules.first.contexts.object_id refute_equal engine.auth_rules.first.attributes.first.send(:instance_variable_get, :@conditions_hash)[:attr].object_id, - cloned_engine.auth_rules.first.attributes.first.send(:instance_variable_get, :@conditions_hash)[:attr].object_id + cloned_engine.auth_rules.first.attributes.first.send(:instance_variable_get, :@conditions_hash)[:attr].object_id end end - diff --git a/test/controller_filter_resource_access_test.rb b/test/controller_filter_resource_access_test.rb index b65c965a..728e71e4 100644 --- a/test/controller_filter_resource_access_test.rb +++ b/test/controller_filter_resource_access_test.rb @@ -2,17 +2,17 @@ class BasicResource < MockDataObject def self.name - "BasicResource" + 'BasicResource' end end class BasicResourcesController < MocksController - filter_resource_access :strong_parameters => false + filter_resource_access strong_parameters: false define_resource_actions end class BasicResourcesControllerTest < ActionController::TestCase def test_basic_filter_index reader = Authorization::Reader::DSLReader.new - reader.parse %{ + reader.parse %( authorization do role :allowed_role do has_permission_on :basic_resources, :to => :index do @@ -20,7 +20,7 @@ def test_basic_filter_index end end end - } + ) allowed_user = MockUser.new(:allowed_role) request!(MockUser.new(:another_role), :index, reader) @@ -31,7 +31,7 @@ def test_basic_filter_index def test_basic_filter_show_with_id reader = Authorization::Reader::DSLReader.new - reader.parse %{ + reader.parse %( authorization do role :allowed_role do has_permission_on :basic_resources, :to => :show do @@ -39,18 +39,18 @@ def test_basic_filter_show_with_id end end end - } + ) allowed_user = MockUser.new(:allowed_role) - request!(allowed_user, :show, reader, :id => "2") + request!(allowed_user, :show, reader, id: '2') assert !@controller.authorized? - request!(allowed_user, :show, reader, :id => "1", :clear => [:@basic_resource]) + request!(allowed_user, :show, reader, id: '1', clear: [:@basic_resource]) assert @controller.authorized? end def test_basic_filter_new_with_params reader = Authorization::Reader::DSLReader.new - reader.parse %{ + reader.parse %( authorization do role :allowed_role do has_permission_on :basic_resources, :to => :new do @@ -58,39 +58,40 @@ def test_basic_filter_new_with_params end end end - } + ) allowed_user = MockUser.new(:allowed_role) - request!(allowed_user, :new, reader, :basic_resource => {:id => "2"}) + request!(allowed_user, :new, reader, basic_resource: { id: '2' }) assert !@controller.authorized? - request!(allowed_user, :new, reader, :basic_resource => {:id => "1"}, - :clear => [:@basic_resource]) + request!(allowed_user, :new, reader, basic_resource: { id: '1' }, + clear: [:@basic_resource]) assert @controller.authorized? end end - class NestedResource < MockDataObject def initialize(attributes = {}) if attributes[:id] - attributes[:parent_mock] ||= ParentMock.new(:id => attributes[:id]) + attributes[:parent_mock] ||= ParentMock.new(id: attributes[:id]) end super(attributes) end + def self.name - "NestedResource" + 'NestedResource' end end class ShallowNestedResource < MockDataObject def initialize(attributes = {}) if attributes[:id] - attributes[:parent_mock] ||= ParentMock.new(:id => attributes[:id]) + attributes[:parent_mock] ||= ParentMock.new(id: attributes[:id]) end super(attributes) end + def self.name - "ShallowNestedResource" + 'ShallowNestedResource' end end @@ -100,24 +101,26 @@ def nested_resources def initialize(parent_mock) @parent_mock = parent_mock end + def new(attributes = {}) - NestedResource.new(attributes.merge(:parent_mock => @parent_mock)) + NestedResource.new(attributes.merge(parent_mock: @parent_mock)) end end.new(self) end - alias :shallow_nested_resources :nested_resources + alias shallow_nested_resources nested_resources def ==(other) id == other.id end + def self.name - "ParentMock" + 'ParentMock' end end class NestedResourcesController < MocksController - filter_resource_access :nested_in => :parent_mocks, :strong_parameters => false + filter_resource_access nested_in: :parent_mocks, strong_parameters: false define_resource_actions end class NestedResourcesControllerTest < ActionController::TestCase @@ -134,13 +137,13 @@ def test_nested_filter_index } allowed_user = MockUser.new(:allowed_role) - request!(MockUser.new(:another_role), :index, reader, :parent_mock_id => "2") + request!(MockUser.new(:another_role), :index, reader, parent_mock_id: '2') assert !@controller.authorized? - request!(allowed_user, :index, reader, :parent_mock_id => "2", - :clear => [:@nested_resource, :@parent_mock]) + request!(allowed_user, :index, reader, parent_mock_id: '2', + clear: %i[@nested_resource @parent_mock]) assert !@controller.authorized? - request!(allowed_user, :index, reader, :parent_mock_id => "1", - :clear => [:@nested_resource, :@parent_mock]) + request!(allowed_user, :index, reader, parent_mock_id: '1', + clear: %i[@nested_resource @parent_mock]) assert @controller.authorized? end @@ -157,10 +160,10 @@ def test_nested_filter_show_with_id } allowed_user = MockUser.new(:allowed_role) - request!(allowed_user, :show, reader, :id => "2", :parent_mock_id => "2") + request!(allowed_user, :show, reader, id: '2', parent_mock_id: '2') assert !@controller.authorized? - request!(allowed_user, :show, reader, :id => "1", :parent_mock_id => "1", - :clear => [:@nested_resource, :@parent_mock]) + request!(allowed_user, :show, reader, id: '1', parent_mock_id: '1', + clear: %i[@nested_resource @parent_mock]) assert @controller.authorized? end @@ -177,21 +180,21 @@ def test_nested_filter_new_with_params } allowed_user = MockUser.new(:allowed_role) - request!(allowed_user, :new, reader, :parent_mock_id => "2", - :nested_resource => {:id => "2"}) + request!(allowed_user, :new, reader, parent_mock_id: '2', + nested_resource: { id: '2' }) assert !@controller.authorized? - request!(allowed_user, :new, reader, :parent_mock_id => "1", - :nested_resource => {:id => "1"}, - :clear => [:@nested_resource, :@parent_mock]) + request!(allowed_user, :new, reader, parent_mock_id: '1', + nested_resource: { id: '1' }, + clear: %i[@nested_resource @parent_mock]) assert @controller.authorized? end end class ShallowNestedResourcesController < MocksController - filter_resource_access :nested_in => :parent_mocks, - :shallow => true, - :additional_member => :additional_member_action, - :strong_parameters => false + filter_resource_access nested_in: :parent_mocks, + shallow: true, + additional_member: :additional_member_action, + strong_parameters: false define_resource_actions define_action_methods :additional_member_action end @@ -209,13 +212,13 @@ def test_nested_filter_index } allowed_user = MockUser.new(:allowed_role) - request!(MockUser.new(:another_role), :index, reader, :parent_mock_id => "2") + request!(MockUser.new(:another_role), :index, reader, parent_mock_id: '2') assert !@controller.authorized? - request!(allowed_user, :index, reader, :parent_mock_id => "2", - :clear => [:@shallow_nested_resource, :@parent_mock]) + request!(allowed_user, :index, reader, parent_mock_id: '2', + clear: %i[@shallow_nested_resource @parent_mock]) assert !@controller.authorized? - request!(allowed_user, :index, reader, :parent_mock_id => "1", - :clear => [:@shallow_nested_resource, :@parent_mock]) + request!(allowed_user, :index, reader, parent_mock_id: '1', + clear: %i[@shallow_nested_resource @parent_mock]) assert assigns(:parent_mock) assert @controller.authorized? end @@ -233,10 +236,10 @@ def test_nested_filter_show_with_id } allowed_user = MockUser.new(:allowed_role) - request!(allowed_user, :show, reader, :id => "2", :parent_mock_id => "2") + request!(allowed_user, :show, reader, id: '2', parent_mock_id: '2') assert !@controller.authorized? - request!(allowed_user, :show, reader, :id => "1", - :clear => [:@shallow_nested_resource, :@parent_mock]) + request!(allowed_user, :show, reader, id: '1', + clear: %i[@shallow_nested_resource @parent_mock]) assert !assigns(:parent_mock) assert assigns(:shallow_nested_resource) assert @controller.authorized? @@ -255,12 +258,12 @@ def test_nested_filter_new_with_params } allowed_user = MockUser.new(:allowed_role) - request!(allowed_user, :new, reader, :parent_mock_id => "2", - :shallow_nested_resource => {:id => "2"}) + request!(allowed_user, :new, reader, parent_mock_id: '2', + shallow_nested_resource: { id: '2' }) assert !@controller.authorized? - request!(allowed_user, :new, reader, :parent_mock_id => "1", - :shallow_nested_resource => {:id => "1"}, - :clear => [:@shallow_nested_resource, :@parent_mock]) + request!(allowed_user, :new, reader, parent_mock_id: '1', + shallow_nested_resource: { id: '1' }, + clear: %i[@shallow_nested_resource @parent_mock]) assert assigns(:parent_mock) assert assigns(:shallow_nested_resource) assert @controller.authorized? @@ -279,29 +282,28 @@ def test_nested_filter_additional_member_action_with_id } allowed_user = MockUser.new(:allowed_role) - request!(allowed_user, :additional_member_action, reader, :id => "2", :parent_mock_id => "2") + request!(allowed_user, :additional_member_action, reader, id: '2', parent_mock_id: '2') assert !@controller.authorized? - request!(allowed_user, :additional_member_action, reader, :id => "1", - :clear => [:@shallow_nested_resource, :@parent_mock]) + request!(allowed_user, :additional_member_action, reader, id: '1', + clear: %i[@shallow_nested_resource @parent_mock]) assert !assigns(:parent_mock) assert assigns(:shallow_nested_resource) assert @controller.authorized? end end - class CustomMembersCollectionsResourceController < MocksController def self.controller_name - "basic_resources" + 'basic_resources' end - filter_resource_access :member => [[:other_show, :read]], - :collection => {:search => :read}, :new => [:other_new], :strong_parameters => false + filter_resource_access member: [%i[other_show read]], + collection: { search: :read }, new: [:other_new], strong_parameters: false define_action_methods :other_new, :search, :other_show end class CustomMembersCollectionsResourceControllerTest < ActionController::TestCase def test_custom_members_filter_search reader = Authorization::Reader::DSLReader.new - reader.parse %{ + reader.parse %( authorization do role :allowed_role do has_permission_on :basic_resources, :to => :read do @@ -309,7 +311,7 @@ def test_custom_members_filter_search end end end - } + ) request!(MockUser.new(:another_role), :search, reader) assert !@controller.authorized? @@ -319,7 +321,7 @@ def test_custom_members_filter_search def test_custom_members_filter_other_show reader = Authorization::Reader::DSLReader.new - reader.parse %{ + reader.parse %( authorization do role :allowed_role do has_permission_on :basic_resources, :to => :read do @@ -327,18 +329,18 @@ def test_custom_members_filter_other_show end end end - } + ) allowed_user = MockUser.new(:allowed_role) - request!(allowed_user, :other_show, reader, :id => "2") + request!(allowed_user, :other_show, reader, id: '2') assert !@controller.authorized? - request!(allowed_user, :other_show, reader, :id => "1", :clear => [:@basic_resource]) + request!(allowed_user, :other_show, reader, id: '1', clear: [:@basic_resource]) assert @controller.authorized? end def test_custom_members_filter_other_new reader = Authorization::Reader::DSLReader.new - reader.parse %{ + reader.parse %( authorization do role :allowed_role do has_permission_on :basic_resources, :to => :other_new do @@ -346,31 +348,30 @@ def test_custom_members_filter_other_new end end end - } + ) allowed_user = MockUser.new(:allowed_role) - request!(allowed_user, :other_new, reader, :basic_resource => {:id => "2"}) + request!(allowed_user, :other_new, reader, basic_resource: { id: '2' }) assert !@controller.authorized? - request!(allowed_user, :other_new, reader, :basic_resource => {:id => "1"}, - :clear => [:@basic_resource]) + request!(allowed_user, :other_new, reader, basic_resource: { id: '1' }, + clear: [:@basic_resource]) assert @controller.authorized? end end - class AdditionalMembersCollectionsResourceController < MocksController def self.controller_name - "basic_resources" + 'basic_resources' end - filter_resource_access :additional_member => :other_show, - :additional_collection => [:search], :additional_new => {:other_new => :new}, :strong_parameters => false + filter_resource_access additional_member: :other_show, + additional_collection: [:search], additional_new: { other_new: :new }, strong_parameters: false define_resource_actions define_action_methods :other_new, :search, :other_show end class AdditionalMembersCollectionsResourceControllerTest < ActionController::TestCase def test_additional_members_filter_search_index reader = Authorization::Reader::DSLReader.new - reader.parse %{ + reader.parse %( authorization do role :allowed_role do has_permission_on :basic_resources, :to => [:search, :index] do @@ -378,7 +379,7 @@ def test_additional_members_filter_search_index end end end - } + ) request!(MockUser.new(:another_role), :search, reader) assert !@controller.authorized? @@ -392,7 +393,7 @@ def test_additional_members_filter_search_index def test_additional_members_filter_other_show reader = Authorization::Reader::DSLReader.new - reader.parse %{ + reader.parse %( authorization do role :allowed_role do has_permission_on :basic_resources, :to => [:show, :other_show] do @@ -400,22 +401,22 @@ def test_additional_members_filter_other_show end end end - } + ) allowed_user = MockUser.new(:allowed_role) - request!(allowed_user, :other_show, reader, :id => "2") + request!(allowed_user, :other_show, reader, id: '2') assert !@controller.authorized? - request!(allowed_user, :show, reader, :id => "2", :clear => [:@basic_resource]) + request!(allowed_user, :show, reader, id: '2', clear: [:@basic_resource]) assert !@controller.authorized? - request!(allowed_user, :other_show, reader, :id => "1", :clear => [:@basic_resource]) + request!(allowed_user, :other_show, reader, id: '1', clear: [:@basic_resource]) assert @controller.authorized? - request!(allowed_user, :show, reader, :id => "1", :clear => [:@basic_resource]) + request!(allowed_user, :show, reader, id: '1', clear: [:@basic_resource]) assert @controller.authorized? end def test_additional_members_filter_other_new reader = Authorization::Reader::DSLReader.new - reader.parse %{ + reader.parse %( authorization do role :allowed_role do has_permission_on :basic_resources, :to => :new do @@ -423,38 +424,36 @@ def test_additional_members_filter_other_new end end end - } + ) allowed_user = MockUser.new(:allowed_role) - request!(allowed_user, :other_new, reader, :basic_resource => {:id => "2"}) + request!(allowed_user, :other_new, reader, basic_resource: { id: '2' }) assert !@controller.authorized? - request!(allowed_user, :new, reader, :basic_resource => {:id => "2"}, - :clear => [:@basic_resource]) + request!(allowed_user, :new, reader, basic_resource: { id: '2' }, + clear: [:@basic_resource]) assert !@controller.authorized? - request!(allowed_user, :other_new, reader, :basic_resource => {:id => "1"}, - :clear => [:@basic_resource]) + request!(allowed_user, :other_new, reader, basic_resource: { id: '1' }, + clear: [:@basic_resource]) assert @controller.authorized? - request!(allowed_user, :new, reader, :basic_resource => {:id => "1"}, - :clear => [:@basic_resource]) + request!(allowed_user, :new, reader, basic_resource: { id: '1' }, + clear: [:@basic_resource]) assert @controller.authorized? end end - class CustomMethodsResourceController < MocksController # not implemented yet end - class ExplicitContextResourceController < MocksController - filter_resource_access :context => :basic_resources, :strong_parameters => false + filter_resource_access context: :basic_resources, strong_parameters: false define_resource_actions end class ExplicitContextResourceControllerTest < ActionController::TestCase def test_explicit_context_filter_index reader = Authorization::Reader::DSLReader.new - reader.parse %{ + reader.parse %( authorization do role :allowed_role do has_permission_on :basic_resources, :to => :index do @@ -462,7 +461,7 @@ def test_explicit_context_filter_index end end end - } + ) allowed_user = MockUser.new(:allowed_role) request!(MockUser.new(:another_role), :index, reader) @@ -473,7 +472,7 @@ def test_explicit_context_filter_index def test_explicit_context_filter_show_with_id reader = Authorization::Reader::DSLReader.new - reader.parse %{ + reader.parse %( authorization do role :allowed_role do has_permission_on :basic_resources, :to => :show do @@ -481,18 +480,18 @@ def test_explicit_context_filter_show_with_id end end end - } + ) allowed_user = MockUser.new(:allowed_role) - request!(allowed_user, :show, reader, :id => "2") + request!(allowed_user, :show, reader, id: '2') assert !@controller.authorized? - request!(allowed_user, :show, reader, :id => "1", :clear => [:@basic_resource]) + request!(allowed_user, :show, reader, id: '1', clear: [:@basic_resource]) assert @controller.authorized? end def test_explicit_context_filter_new_with_params reader = Authorization::Reader::DSLReader.new - reader.parse %{ + reader.parse %( authorization do role :allowed_role do has_permission_on :basic_resources, :to => :new do @@ -500,31 +499,32 @@ def test_explicit_context_filter_new_with_params end end end - } + ) allowed_user = MockUser.new(:allowed_role) - request!(allowed_user, :new, reader, :basic_resource => {:id => "2"}) + request!(allowed_user, :new, reader, basic_resource: { id: '2' }) assert !@controller.authorized? - request!(allowed_user, :new, reader, :basic_resource => {:id => "1"}, - :clear => [:@basic_resource]) + request!(allowed_user, :new, reader, basic_resource: { id: '1' }, + clear: [:@basic_resource]) assert @controller.authorized? end end class StrongResource < MockDataObject def self.name - "StrongResource" + 'StrongResource' end end class StrongResourcesController < MocksController def self.controller_name - "strong_resources" + 'strong_resources' end - filter_resource_access :strong_parameters => true + filter_resource_access strong_parameters: true define_resource_actions private + def strong_resource_params params.require(:strong_resource).permit(:test_param1, :test_param2) end @@ -532,7 +532,7 @@ def strong_resource_params class StrongResourcesControllerTest < ActionController::TestCase def test_still_authorized_with_strong_params reader = Authorization::Reader::DSLReader.new - reader.parse %{ + reader.parse %( authorization do role :allowed_role do has_permission_on :strong_resources, :to => :show do @@ -540,28 +540,28 @@ def test_still_authorized_with_strong_params end end end - } + ) allowed_user = MockUser.new(:allowed_role) - request!(allowed_user, :show, reader, :id => "2") + request!(allowed_user, :show, reader, id: '2') assert !@controller.authorized? - request!(allowed_user, :show, reader, :id => "1", :clear => [:@strong_resource]) + request!(allowed_user, :show, reader, id: '1', clear: [:@strong_resource]) assert @controller.authorized? end def test_new_strong_resource reader = Authorization::Reader::DSLReader.new - reader.parse %{ + reader.parse %( authorization do role :allowed_role do has_permission_on :strong_resources, :to => :new end end - } + ) allowed_user = MockUser.new(:allowed_role) - request!(allowed_user, :new, reader, :strong_resource => {:id => "1"}, - :clear => [:@strong_resource]) + request!(allowed_user, :new, reader, strong_resource: { id: '1' }, + clear: [:@strong_resource]) assert @controller.authorized? # allowed_user = MockUser.new(:allowed_role) @@ -570,4 +570,3 @@ def test_new_strong_resource # assert assigns :strong_resource end end - diff --git a/test/controller_test.rb b/test/controller_test.rb index 0027820e..5637ed00 100644 --- a/test/controller_test.rb +++ b/test/controller_test.rb @@ -1,9 +1,8 @@ require 'test_helper' - class LoadMockObject < MockDataObject def self.name - "LoadMockObject" + 'LoadMockObject' end end @@ -13,24 +12,24 @@ class ActionController::Base class << self def before_actions filters = _process_action_callbacks.select { |c| c.kind == :before } - filters.map! { |c| c.raw_filter } + filters.map!(&:raw_filter) end - alias_method :before_filters, :before_actions + alias before_actions before_actions end end class SpecificMocksController < MocksController - filter_access_to :test_action, :require => :test, :context => :permissions - filter_access_to :test_action_2, :require => :test, :context => :permissions_2 + filter_access_to :test_action, require: :test, context: :permissions + filter_access_to :test_action_2, require: :test, context: :permissions_2 filter_access_to :show - filter_access_to :edit, :create, :require => :test, :context => :permissions - filter_access_to :edit_2, :require => :test, :context => :permissions, - :attribute_check => true, :model => LoadMockObject - filter_access_to :new, :require => :test, :context => :permissions + filter_access_to :edit, :create, require: :test, context: :permissions + filter_access_to :edit_2, require: :test, context: :permissions, + attribute_check: true, model: LoadMockObject + filter_access_to :new, require: :test, context: :permissions - filter_access_to [:action_group_action_1, :action_group_action_2] + filter_access_to %i[action_group_action_1 action_group_action_2] define_action_methods :test_action, :test_action_2, :show, :edit, :create, - :edit_2, :new, :unprotected_action, :action_group_action_1, :action_group_action_2 + :edit_2, :new, :unprotected_action, :action_group_action_1, :action_group_action_2 end class BasicControllerTest < ActionController::TestCase @@ -39,77 +38,77 @@ class BasicControllerTest < ActionController::TestCase def test_filter_access_to_receiving_an_explicit_array reader = Authorization::Reader::DSLReader.new - reader.parse %{ + reader.parse %( authorization do role :test_action_group_2 do has_permission_on :specific_mocks, :to => :action_group_action_2 end end - } + ) - request!(MockUser.new(:test_action_group_2), "action_group_action_2", reader) + request!(MockUser.new(:test_action_group_2), 'action_group_action_2', reader) assert @controller.authorized? - request!(MockUser.new(:test_action_group_2), "action_group_action_1", reader) + request!(MockUser.new(:test_action_group_2), 'action_group_action_1', reader) assert !@controller.authorized? - request!(nil, "action_group_action_2", reader) + request!(nil, 'action_group_action_2', reader) assert !@controller.authorized? end def test_filter_access - assert !@controller.class.before_filters.empty? + assert !@controller.class.before_actions.empty? reader = Authorization::Reader::DSLReader.new - reader.parse %{ + reader.parse %( authorization do role :test_role do has_permission_on :permissions, :to => :test has_permission_on :specific_mocks, :to => :show end end - } + ) - request!(MockUser.new(:test_role), "test_action", reader) + request!(MockUser.new(:test_role), 'test_action', reader) assert @controller.authorized? - request!(MockUser.new(:test_role), "test_action_2", reader) + request!(MockUser.new(:test_role), 'test_action_2', reader) assert !@controller.authorized? - request!(MockUser.new(:test_role_2), "test_action", reader) + request!(MockUser.new(:test_role_2), 'test_action', reader) assert_response :forbidden assert !@controller.authorized? - request!(MockUser.new(:test_role), "show", reader) + request!(MockUser.new(:test_role), 'show', reader) assert @controller.authorized? end def test_filter_access_multi_actions reader = Authorization::Reader::DSLReader.new - reader.parse %{ + reader.parse %( authorization do role :test_role do has_permission_on :permissions, :to => :test end end - } - request!(MockUser.new(:test_role), "create", reader) + ) + request!(MockUser.new(:test_role), 'create', reader) assert @controller.authorized? end def test_filter_access_unprotected_actions reader = Authorization::Reader::DSLReader.new - reader.parse %{ + reader.parse %( authorization do role :test_role do end end - } - request!(MockUser.new(:test_role), "unprotected_action", reader) + ) + request!(MockUser.new(:test_role), 'unprotected_action', reader) assert @controller.authorized? end def test_filter_access_priv_hierarchy reader = Authorization::Reader::DSLReader.new - reader.parse %{ + reader.parse %( privileges do privilege :read do includes :list, :show @@ -120,14 +119,14 @@ def test_filter_access_priv_hierarchy has_permission_on :specific_mocks, :to => :read end end - } - request!(MockUser.new(:test_role), "show", reader) + ) + request!(MockUser.new(:test_role), 'show', reader) assert @controller.authorized? end def test_filter_access_skip_attribute_test reader = Authorization::Reader::DSLReader.new - reader.parse %{ + reader.parse %( authorization do role :test_role do has_permission_on :permissions, :to => :test do @@ -135,14 +134,14 @@ def test_filter_access_skip_attribute_test end end end - } - request!(MockUser.new(:test_role), "new", reader) + ) + request!(MockUser.new(:test_role), 'new', reader) assert @controller.authorized? end def test_existing_instance_var_remains_unchanged reader = Authorization::Reader::DSLReader.new - reader.parse %{ + reader.parse %( authorization do role :test_role do has_permission_on :permissions, :to => :test do @@ -150,25 +149,25 @@ def test_existing_instance_var_remains_unchanged end end end - } - mock_object = MockDataObject.new(:id => 5) + ) + mock_object = MockDataObject.new(id: 5) @controller.send(:instance_variable_set, :"@load_mock_object", - mock_object) - request!(MockUser.new(:test_role), "edit_2", reader) + mock_object) + request!(MockUser.new(:test_role), 'edit_2', reader) assert_equal mock_object, - @controller.send(:instance_variable_get, :"@load_mock_object") + @controller.send(:instance_variable_get, :"@load_mock_object") assert @controller.authorized? end def test_permitted_to_without_context reader = Authorization::Reader::DSLReader.new - reader.parse %{ + reader.parse %( authorization do role :test_role do has_permission_on :specific_mocks, :to => :test end end - } + ) @controller.current_user = MockUser.new(:test_role) @controller.authorization_engine = Authorization::Engine.new(reader) assert @controller.permitted_to?(:test) @@ -179,52 +178,50 @@ def teardown end end - ################## class AllMocksController < MocksController filter_access_to :all - filter_access_to :view, :require => :test, :context => :permissions + filter_access_to :view, require: :test, context: :permissions define_action_methods :show, :view end class AllActionsControllerTest < ActionController::TestCase tests AllMocksController def test_filter_access_all reader = Authorization::Reader::DSLReader.new - reader.parse %{ + reader.parse %( authorization do role :test_role do has_permission_on :permissions, :to => :test has_permission_on :all_mocks, :to => :show end end - } + ) - request!(MockUser.new(:test_role), "show", reader) + request!(MockUser.new(:test_role), 'show', reader) assert @controller.authorized? - request!(MockUser.new(:test_role), "view", reader) + request!(MockUser.new(:test_role), 'view', reader) assert @controller.authorized? - request!(MockUser.new(:test_role_2), "show", reader) + request!(MockUser.new(:test_role_2), 'show', reader) assert !@controller.authorized? end end - ################## class LoadMockObjectsController < MocksController - before_filter { @@load_method_call_count = 0 } - filter_access_to :show, :attribute_check => true, :model => LoadMockObject - filter_access_to :edit, :attribute_check => true - filter_access_to :update, :delete, :attribute_check => true, - :load_method => proc {MockDataObject.new(:test => 1)} + before_action { @@load_method_call_count = 0 } + filter_access_to :show, attribute_check: true, model: LoadMockObject + filter_access_to :edit, attribute_check: true + filter_access_to :update, :delete, attribute_check: true, + load_method: proc { MockDataObject.new(test: 1) } filter_access_to :create do permitted_to! :edit, :load_mock_objects end - filter_access_to :view, :attribute_check => true, :load_method => :load_method + filter_access_to :view, attribute_check: true, load_method: :load_method def load_method self.class.load_method_called - MockDataObject.new(:test => 2) + MockDataObject.new(test: 2) end define_action_methods :show, :edit, :update, :delete, :create, :view @@ -232,6 +229,7 @@ def self.load_method_called @@load_method_call_count ||= 0 @@load_method_call_count += 1 end + def self.load_method_call_count @@load_method_call_count || 0 end @@ -241,7 +239,7 @@ class LoadObjectControllerTest < ActionController::TestCase def test_filter_access_with_object_load reader = Authorization::Reader::DSLReader.new - reader.parse %{ + reader.parse %( authorization do role :test_role do has_permission_on :load_mock_objects, :to => [:show, :edit] do @@ -250,24 +248,24 @@ def test_filter_access_with_object_load end end end - } + ) - request!(MockUser.new(:test_role), "show", reader, :id => 2) + request!(MockUser.new(:test_role), 'show', reader, id: 2) assert !@controller.authorized? - request!(MockUser.new(:test_role), "show", reader, :id => 1, - :clear => [:@load_mock_object]) + request!(MockUser.new(:test_role), 'show', reader, id: 1, + clear: [:@load_mock_object]) assert @controller.authorized? - request!(MockUser.new(:test_role), "edit", reader, :id => 1, - :clear => [:@load_mock_object]) + request!(MockUser.new(:test_role), 'edit', reader, id: 1, + clear: [:@load_mock_object]) assert @controller.authorized? assert @controller.instance_variable_defined?(:@load_mock_object) end def test_filter_access_object_load_without_param reader = Authorization::Reader::DSLReader.new - reader.parse %{ + reader.parse %( authorization do role :test_role do has_permission_on :load_mock_objects, :to => [:show, :edit] do @@ -275,14 +273,14 @@ def test_filter_access_object_load_without_param end end end - } + ) - assert_raises StandardError, "No id param supplied" do - request!(MockUser.new(:test_role), "show", reader) + assert_raises StandardError, 'No id param supplied' do + request!(MockUser.new(:test_role), 'show', reader) end Authorization::AuthorizationInController.failed_auto_loading_is_not_found = false - request!(MockUser.new(:test_role), "show", reader) + request!(MockUser.new(:test_role), 'show', reader) assert !@controller.authorized? Authorization::AuthorizationInController.failed_auto_loading_is_not_found = true @@ -290,7 +288,7 @@ def test_filter_access_object_load_without_param def test_filter_access_with_object_load_custom reader = Authorization::Reader::DSLReader.new - reader.parse %{ + reader.parse %( authorization do role :test_role do has_permission_on :load_mock_objects, :to => :view do @@ -304,26 +302,26 @@ def test_filter_access_with_object_load_custom end end end - } + ) - request!(MockUser.new(:test_role), "delete", reader) + request!(MockUser.new(:test_role), 'delete', reader) assert !@controller.authorized? - request!(MockUser.new(:test_role), "view", reader) + request!(MockUser.new(:test_role), 'view', reader) assert @controller.authorized? assert_equal 1, @controller.class.load_method_call_count - request!(MockUser.new(:test_role_2), "view", reader) + request!(MockUser.new(:test_role_2), 'view', reader) assert !@controller.authorized? assert_equal 1, @controller.class.load_method_call_count - request!(MockUser.new(:test_role), "update", reader) + request!(MockUser.new(:test_role), 'update', reader) assert @controller.authorized? end def test_filter_access_custom reader = Authorization::Reader::DSLReader.new - reader.parse %{ + reader.parse %( authorization do role :test_role do has_permission_on :load_mock_objects, :to => :edit @@ -332,43 +330,41 @@ def test_filter_access_custom has_permission_on :load_mock_objects, :to => :create end end - } + ) - request!(MockUser.new(:test_role), "create", reader) + request!(MockUser.new(:test_role), 'create', reader) assert @controller.authorized? - request!(MockUser.new(:test_role_2), "create", reader) + request!(MockUser.new(:test_role_2), 'create', reader) assert !@controller.authorized? end end - ################## class AccessOverwritesController < MocksController filter_access_to :test_action, :test_action_2, - :require => :test, :context => :permissions_2 - filter_access_to :test_action, :require => :test, :context => :permissions + require: :test, context: :permissions_2 + filter_access_to :test_action, require: :test, context: :permissions define_action_methods :test_action, :test_action_2 end class AccessOverwritesControllerTest < ActionController::TestCase def test_filter_access_overwrite reader = Authorization::Reader::DSLReader.new - reader.parse %{ + reader.parse %( authorization do role :test_role do has_permission_on :permissions, :to => :test end end - } - request!(MockUser.new(:test_role), "test_action_2", reader) + ) + request!(MockUser.new(:test_role), 'test_action_2', reader) assert !@controller.authorized? - request!(MockUser.new(:test_role), "test_action", reader) + request!(MockUser.new(:test_role), 'test_action', reader) assert @controller.authorized? end end - ################## class PeopleController < MocksController filter_access_to :all @@ -379,26 +375,25 @@ class PluralizationControllerTest < ActionController::TestCase def test_filter_access_people_controller reader = Authorization::Reader::DSLReader.new - reader.parse %{ + reader.parse %( authorization do role :test_role do has_permission_on :people, :to => :show end end - } - request!(MockUser.new(:test_role), "show", reader) + ) + request!(MockUser.new(:test_role), 'show', reader) assert @controller.authorized? end end - ################## class CommonController < MocksController - filter_access_to :delete, :context => :common + filter_access_to :delete, context: :common filter_access_to :all end class CommonChild1Controller < CommonController - filter_access_to :all, :context => :context_1 + filter_access_to :all, context: :context_1 end class CommonChild2Controller < CommonController filter_access_to :delete @@ -408,16 +403,16 @@ class HierachicalControllerTest < ActionController::TestCase tests CommonChild2Controller def test_controller_hierarchy reader = Authorization::Reader::DSLReader.new - reader.parse %{ + reader.parse %( authorization do role :test_role do has_permission_on :mocks, :to => [:delete, :show] end end - } - request!(MockUser.new(:test_role), "show", reader) + ) + request!(MockUser.new(:test_role), 'show', reader) assert !@controller.authorized? - request!(MockUser.new(:test_role), "delete", reader) + request!(MockUser.new(:test_role), 'delete', reader) assert !@controller.authorized? end end @@ -426,7 +421,7 @@ def test_controller_hierarchy module Name class SpacedThingsController < MocksController filter_access_to :show - filter_access_to :update, :context => :spaced_things + filter_access_to :update, context: :spaced_things define_action_methods :show, :update end end @@ -434,7 +429,7 @@ class NameSpacedControllerTest < ActionController::TestCase tests Name::SpacedThingsController def test_context reader = Authorization::Reader::DSLReader.new - reader.parse %{ + reader.parse %( authorization do role :permitted_role do has_permission_on :name_spaced_things, :to => :show @@ -445,14 +440,14 @@ def test_context has_permission_on :spaced_things, :to => :show end end - } - request!(MockUser.new(:permitted_role), "show", reader) + ) + request!(MockUser.new(:permitted_role), 'show', reader) assert @controller.authorized? - request!(MockUser.new(:prohibited_role), "show", reader) + request!(MockUser.new(:prohibited_role), 'show', reader) assert !@controller.authorized? - request!(MockUser.new(:permitted_role), "update", reader) + request!(MockUser.new(:permitted_role), 'update', reader) assert @controller.authorized? - request!(MockUser.new(:prohibited_role), "update", reader) + request!(MockUser.new(:prohibited_role), 'update', reader) assert !@controller.authorized? end end @@ -461,7 +456,7 @@ module Deep module NameSpaced class ThingsController < MocksController filter_access_to :show - filter_access_to :update, :context => :things + filter_access_to :update, context: :things define_action_methods :show, :update end end @@ -470,7 +465,7 @@ class DeepNameSpacedControllerTest < ActionController::TestCase tests Deep::NameSpaced::ThingsController def test_context reader = Authorization::Reader::DSLReader.new - reader.parse %{ + reader.parse %( authorization do role :permitted_role do has_permission_on :deep_name_spaced_things, :to => :show @@ -481,14 +476,14 @@ def test_context has_permission_on :things, :to => :show end end - } - request!(MockUser.new(:permitted_role), "show", reader) + ) + request!(MockUser.new(:permitted_role), 'show', reader) assert @controller.authorized? - request!(MockUser.new(:prohibited_role), "show", reader) + request!(MockUser.new(:prohibited_role), 'show', reader) assert !@controller.authorized? - request!(MockUser.new(:permitted_role), "update", reader) + request!(MockUser.new(:permitted_role), 'update', reader) assert @controller.authorized? - request!(MockUser.new(:prohibited_role), "update", reader) + request!(MockUser.new(:prohibited_role), 'update', reader) assert !@controller.authorized? end end diff --git a/test/development_support/analyzer_test.rb b/test/development_support/analyzer_test.rb index 8863f88a..598b3451 100644 --- a/test/development_support/analyzer_test.rb +++ b/test/development_support/analyzer_test.rb @@ -2,276 +2,272 @@ auth_analyzer_loadable = false begin - require File.join(File.dirname(__FILE__), %w{.. .. lib declarative_authorization development_support analyzer}) + require File.join(File.dirname(__FILE__), %w[.. .. lib declarative_authorization development_support analyzer]) auth_analyzer_loadable = true -rescue - puts "Could not load Authorization::DevelopmentSupport::Analyzer. Disabling AuthorizationRulesAnalyzerTest." +rescue StandardError + puts 'Could not load Authorization::DevelopmentSupport::Analyzer. Disabling AuthorizationRulesAnalyzerTest.' end if auth_analyzer_loadable -class AuthorizationRulesAnalyzerTest < Test::Unit::TestCase - - def test_analyzing_complex_rules - engine, analyzer = engine_analyzer_for %{ - authorization do - role :guest do - has_permission_on :conferences, :to => :read do - if_attribute :published => true - end - has_permission_on :talks, :to => :read do - if_permitted_to :read, :conference + class AuthorizationRulesAnalyzerTest < Test::Unit::TestCase + def test_analyzing_complex_rules + engine, analyzer = engine_analyzer_for %( + authorization do + role :guest do + has_permission_on :conferences, :to => :read do + if_attribute :published => true + end + has_permission_on :talks, :to => :read do + if_permitted_to :read, :conference + end + has_permission_on :users, :to => :create + has_permission_on :authorization_rules, :to => :read + has_permission_on :authorization_usages, :to => :read end - has_permission_on :users, :to => :create - has_permission_on :authorization_rules, :to => :read - has_permission_on :authorization_usages, :to => :read - end - - role :user do - includes :guest - has_permission_on :conference_attendees, :to => :create do - if_attribute :user => is {user}, - :conference => { :published => true } + role :user do + includes :guest + has_permission_on :conference_attendees, :to => :create do + if_attribute :user => is {user}, + :conference => { :published => true } + end + has_permission_on :conference_attendees, :to => :delete do + if_attribute :user => is {user}, + :conference => { :attendees => contains {user} } + end + has_permission_on :talk_attendees, :to => :create do + if_attribute :talk => { :conference => { :attendees => contains {user} }} + end + has_permission_on :talk_attendees, :to => :delete do + if_attribute :user => is {user}, + :talk => { :conference => { :attendees => contains {user} }} + end end - has_permission_on :conference_attendees, :to => :delete do - if_attribute :user => is {user}, - :conference => { :attendees => contains {user} } + role :conference_organizer do + has_permission_on :conferences do + to :manage + # if... + end + has_permission_on [:conference_attendees, :talks, :talk_attendees], :to => :manage end - has_permission_on :talk_attendees, :to => :create do - if_attribute :talk => { :conference => { :attendees => contains {user} }} - end - has_permission_on :talk_attendees, :to => :delete do - if_attribute :user => is {user}, - :talk => { :conference => { :attendees => contains {user} }} - end - end - - role :conference_organizer do - has_permission_on :conferences do - to :manage - # if... + role :admin do + has_permission_on [:conferences, :users, :talks], :to => :manage + has_permission_on :authorization_rules, :to => :read + has_permission_on :authorization_usages, :to => :read end - has_permission_on [:conference_attendees, :talks, :talk_attendees], :to => :manage end - - role :admin do - has_permission_on [:conferences, :users, :talks], :to => :manage - has_permission_on :authorization_rules, :to => :read - has_permission_on :authorization_usages, :to => :read + privileges do + privilege :manage, :includes => [:create, :read, :update, :delete] + privilege :read, :includes => [:index, :show] + privilege :create, :includes => :new + privilege :update, :includes => :edit + privilege :delete, :includes => :destroy end - end - - privileges do - privilege :manage, :includes => [:create, :read, :update, :delete] - privilege :read, :includes => [:index, :show] - privilege :create, :includes => :new - privilege :update, :includes => :edit - privilege :delete, :includes => :destroy - end - } + ) end - def test_mergeable_rules_without_constraints - engine, analyzer = engine_analyzer_for %{ - authorization do - role :test_role do - has_permission_on :permissions, :to => :test - has_permission_on :permissions, :to => :test2 + def test_mergeable_rules_without_constraints + engine, analyzer = engine_analyzer_for %( + authorization do + role :test_role do + has_permission_on :permissions, :to => :test + has_permission_on :permissions, :to => :test2 + end end - end - } + ) - reports = analyzer.reports.select {|rpt| rpt.type == :mergeable_rules} - assert !reports.empty? - assert reports.find {|report| report.line == 4} - end + reports = analyzer.reports.select { |rpt| rpt.type == :mergeable_rules } + assert !reports.empty? + assert reports.find { |report| report.line == 4 } + end - def test_mergeable_rules_with_in_block_to - engine, analyzer = engine_analyzer_for %{ - authorization do - role :test_role do - has_permission_on :permissions do - to :test + def test_mergeable_rules_with_in_block_to + engine, analyzer = engine_analyzer_for %( + authorization do + role :test_role do + has_permission_on :permissions do + to :test + end end end - end - } - end + ) + end - def test_no_mergeable_rules_with_constraints - engine, analyzer = engine_analyzer_for %{ - authorization do - role :test_role do - has_permission_on :permissions, :to => :test do - if_attribute :some_attr => is {bla} + def test_no_mergeable_rules_with_constraints + engine, analyzer = engine_analyzer_for %( + authorization do + role :test_role do + has_permission_on :permissions, :to => :test do + if_attribute :some_attr => is {bla} + end + has_permission_on :permissions, :to => :test2 do + if_attribute :some_attr_2 => is {bla} + end end - has_permission_on :permissions, :to => :test2 do - if_attribute :some_attr_2 => is {bla} + end + ) + + assert !analyzer.reports.find { |report| report.type == :mergeable_rules } + end + + def test_no_mergeable_rules_with_if_permitted_to + engine, analyzer = engine_analyzer_for %( + authorization do + role :test_role do + has_permission_on :permissions, :to => :test do + if_attribute :some_attr => is {bla} + end + has_permission_on :permissions, :to => :test2 do + if_attribute :some_attr => is {bla} + if_permitted_to :read, :bla + end end end - end - } + ) - assert !analyzer.reports.find {|report| report.type == :mergeable_rules} - end + assert !analyzer.reports.find { |report| report.type == :mergeable_rules } + end - def test_no_mergeable_rules_with_if_permitted_to - engine, analyzer = engine_analyzer_for %{ - authorization do - role :test_role do - has_permission_on :permissions, :to => :test do - if_attribute :some_attr => is {bla} + def test_role_explosion + engine, analyzer = engine_analyzer_for %( + authorization do + role :test_role do + has_permission_on :permissions, :to => :test + has_permission_on :permissions, :to => :test2 + end + role :test_role_2 do + has_permission_on :permissions, :to => :test + has_permission_on :permissions, :to => :test2 + has_permission_on :permissions, :to => :test3 + has_permission_on :permissions, :to => :test4 end - has_permission_on :permissions, :to => :test2 do - if_attribute :some_attr => is {bla} - if_permitted_to :read, :bla + role :test_role_3 do + has_permission_on :permissions, :to => :test + has_permission_on :permissions, :to => :test2 end end - end - } + ) - assert !analyzer.reports.find {|report| report.type == :mergeable_rules} - end + report = analyzer.reports.find { |rpt| rpt.type == :role_explosion } + assert report + assert_nil report.line + end - def test_role_explosion - engine, analyzer = engine_analyzer_for %{ - authorization do - role :test_role do - has_permission_on :permissions, :to => :test - has_permission_on :permissions, :to => :test2 - end - role :test_role_2 do - has_permission_on :permissions, :to => :test - has_permission_on :permissions, :to => :test2 - has_permission_on :permissions, :to => :test3 - has_permission_on :permissions, :to => :test4 + def test_inheriting_privileges + engine, analyzer = engine_analyzer_for %( + authorization do + role :test_role do + has_permission_on :permissions, :to => [:test, :test_2] + has_permission_on :other_permissions, :to => [:test, :test_3] + end end - role :test_role_3 do - has_permission_on :permissions, :to => :test - has_permission_on :permissions, :to => :test2 + privileges do + privilege :test, :includes => :test_2 end - end - } + ) - report = analyzer.reports.find {|rpt| rpt.type == :role_explosion} - assert report - assert_nil report.line - end + reports = analyzer.reports.select { |report| report.type == :inheriting_privileges } + assert_equal 1, reports.length + assert_equal 4, reports.first.line + end - def test_inheriting_privileges - engine, analyzer = engine_analyzer_for %{ - authorization do - role :test_role do - has_permission_on :permissions, :to => [:test, :test_2] - has_permission_on :other_permissions, :to => [:test, :test_3] + def test_privileges_rules + engine, analyzer = engine_analyzer_for %( + authorization do + role :test_role do + has_permission_on :permissions, :to => [:test, :test_2] + has_permission_on :other_permissions, :to => :test + has_permission_on :other_permissions_2, :to => :test_2 + end end - end - privileges do - privilege :test, :includes => :test_2 - end - } + ) - reports = analyzer.reports.select {|report| report.type == :inheriting_privileges} - assert_equal 1, reports.length - assert_equal 4, reports.first.line - end + priv = Authorization::DevelopmentSupport::AnalyzerEngine::Privilege.for_sym(:test, engine) + assert_equal 2, priv.rules.length + end - def test_privileges_rules - engine, analyzer = engine_analyzer_for %{ - authorization do - role :test_role do - has_permission_on :permissions, :to => [:test, :test_2] - has_permission_on :other_permissions, :to => :test - has_permission_on :other_permissions_2, :to => :test_2 + def test_relevant_roles + reader = Authorization::Reader::DSLReader.new + reader.parse %( + authorization do + role :test_role do + end + role :test_role_2 do + includes :test_role + end + role :test_role_3 do + end + role :test_role_4 do + end + role :irrelevant_role do + end end - end - } + ) + engine = Authorization::Engine.new(reader) - priv = Authorization::DevelopmentSupport::AnalyzerEngine::Privilege.for_sym(:test, engine) - assert_equal 2, priv.rules.length - end + users = [MockUser.new(:test_role_2, :test_role_3), MockUser.new(:test_role_4)] + relevant_roles = Authorization::DevelopmentSupport::AnalyzerEngine.relevant_roles(engine, users) + assert_equal 4, relevant_roles.length + end - def test_relevant_roles - reader = Authorization::Reader::DSLReader.new - reader.parse %{ - authorization do - role :test_role do - end - role :test_role_2 do - includes :test_role - end - role :test_role_3 do - end - role :test_role_4 do - end - role :irrelevant_role do + def test_roles_for_privilege + reader = Authorization::Reader::DSLReader.new + reader.parse %( + authorization do + role :higher_role do + includes :lower_role + end + role :lower_role do + has_permission_on :test_2, :to => :read + end + role :test_role do + has_permission_on :test, :to => :read + end + role :irrelevant_role_1 do + end + role :irrelevant_role_2 do + end + role :irrelevant_role_3 do + end end - end - } - engine = Authorization::Engine.new(reader) + ) + engine = Authorization::Engine.new(reader) - users = [MockUser.new(:test_role_2, :test_role_3), MockUser.new(:test_role_4)] - relevant_roles = Authorization::DevelopmentSupport::AnalyzerEngine.relevant_roles(engine, users) - assert_equal 4, relevant_roles.length - end + assert_equal 1, Authorization::DevelopmentSupport::AnalyzerEngine::Role.all_for_privilege(:read, :test, engine).length + assert_equal 2, Authorization::DevelopmentSupport::AnalyzerEngine::Role.all_for_privilege(:read, :test_2, engine).length + end - def test_roles_for_privilege - reader = Authorization::Reader::DSLReader.new - reader.parse %{ - authorization do - role :higher_role do - includes :lower_role - end - role :lower_role do - has_permission_on :test_2, :to => :read - end - role :test_role do - has_permission_on :test, :to => :read - end - role :irrelevant_role_1 do - end - role :irrelevant_role_2 do - end - role :irrelevant_role_3 do + def test_analyze_for_proposed_privilege_hierarchy + engine, analyzer = engine_analyzer_for %( + authorization do + role :test_role do + has_permission_on :permissions, :to => [:test, :test_2] + has_permission_on :other_permissions_2, :to => :test_2 + end + role :test_role_2 do + has_permission_on :permissions, :to => [:test, :test_2] + has_permission_on :other_permissions, :to => :test_3 + end end - end - } - engine = Authorization::Engine.new(reader) + ) - assert_equal 1, Authorization::DevelopmentSupport::AnalyzerEngine::Role.all_for_privilege(:read, :test, engine).length - assert_equal 2, Authorization::DevelopmentSupport::AnalyzerEngine::Role.all_for_privilege(:read, :test_2, engine).length - end - - def test_analyze_for_proposed_privilege_hierarchy - engine, analyzer = engine_analyzer_for %{ - authorization do - role :test_role do - has_permission_on :permissions, :to => [:test, :test_2] - has_permission_on :other_permissions_2, :to => :test_2 - end - role :test_role_2 do - has_permission_on :permissions, :to => [:test, :test_2] - has_permission_on :other_permissions, :to => :test_3 - end - end - } + reports = analyzer.reports.select { |report| report.type == :proposed_privilege_hierarchy } + assert_equal 1, reports.length + assert_equal 4, reports.first.line + end - reports = analyzer.reports.select {|report| report.type == :proposed_privilege_hierarchy} - assert_equal 1, reports.length - assert_equal 4, reports.first.line - end + protected - protected - def engine_analyzer_for(rules) - reader = Authorization::Reader::DSLReader.new - reader.parse rules - engine = Authorization::Engine.new(reader) + def engine_analyzer_for(rules) + reader = Authorization::Reader::DSLReader.new + reader.parse rules + engine = Authorization::Engine.new(reader) - analyzer = Authorization::DevelopmentSupport::Analyzer.new(engine) - analyzer.analyze rules + analyzer = Authorization::DevelopmentSupport::Analyzer.new(engine) + analyzer.analyze rules - [engine, analyzer] + [engine, analyzer] + end end -end end # Authorization::Analyzer was loaded diff --git a/test/development_support/change_analyzer_test.rb b/test/development_support/change_analyzer_test.rb index e68dc610..df6aace6 100644 --- a/test/development_support/change_analyzer_test.rb +++ b/test/development_support/change_analyzer_test.rb @@ -1,16 +1,14 @@ require 'test_helper' -require File.join(File.dirname(__FILE__), %w{.. .. lib declarative_authorization development_support change_analyzer}) - +require File.join(File.dirname(__FILE__), %w[.. .. lib declarative_authorization development_support change_analyzer]) class ChangeAnalyzerTest < Test::Unit::TestCase - - # TODO further tests + # TODO: further tests # * more than one new role, privilege necessary # def test_adding_permission reader = Authorization::Reader::DSLReader.new - reader.parse %{ + reader.parse %( authorization do role :test_role do end @@ -18,26 +16,26 @@ def test_adding_permission includes :test_role end end - } + ) engine = Authorization::Engine.new(reader) analyzer = Authorization::DevelopmentSupport::ChangeAnalyzer.new(engine) user_to_extend_permissions = MockUser.new(:test_role_2) another_user = MockUser.new(:test_role) - approaches = analyzer.find_approaches_for(:add, :permission, :on => :permissions, - :to => :read, :users => [user_to_extend_permissions, another_user]) do - assert permit?(:read, :context => :permissions, :user => users.first) - assert !permit?(:read, :context => :permissions, :user => users[1]) + approaches = analyzer.find_approaches_for(:add, :permission, on: :permissions, + to: :read, users: [user_to_extend_permissions, another_user]) do + assert permit?(:read, context: :permissions, user: users.first) + assert !permit?(:read, context: :permissions, user: users[1]) end - #approaches.each {|approach| p approach} - assert approaches.any? {|approach| approach.steps.any? {|step| step.first == :add_privilege and step.last.to_sym == :test_role_2}} + # approaches.each {|approach| p approach} + assert approaches.any? { |approach| approach.steps.any? { |step| (step.first == :add_privilege) && (step.last.to_sym == :test_role_2) } } end def test_adding_permission_by_assigning_role reader = Authorization::Reader::DSLReader.new - reader.parse %{ + reader.parse %( authorization do role :test_role do end @@ -45,52 +43,52 @@ def test_adding_permission_by_assigning_role has_permission_on :permissions, :to => :read end end - } + ) engine = Authorization::Engine.new(reader) analyzer = Authorization::DevelopmentSupport::ChangeAnalyzer.new(engine) user_to_extend_permissions = MockUser.new(:test_role) another_user = MockUser.new(:test_role) - approaches = analyzer.find_approaches_for(:add, :permission, :on => :permissions, - :to => :read, :users => [user_to_extend_permissions, another_user]) do - assert permit?(:read, :context => :permissions, :user => users.first) - assert !permit?(:read, :context => :permissions, :user => users[1]) + approaches = analyzer.find_approaches_for(:add, :permission, on: :permissions, + to: :read, users: [user_to_extend_permissions, another_user]) do + assert permit?(:read, context: :permissions, user: users.first) + assert !permit?(:read, context: :permissions, user: users[1]) end refute_equal 0, approaches.length - #assert_equal :role, approaches.first.target_type - #assert_equal :test_role_2, approaches.first.target.to_sym + # assert_equal :role, approaches.first.target_type + # assert_equal :test_role_2, approaches.first.target.to_sym end def test_adding_permission_with_new_role reader = Authorization::Reader::DSLReader.new - reader.parse %{ + reader.parse %( authorization do role :test_role do end end - } + ) engine = Authorization::Engine.new(reader) analyzer = Authorization::DevelopmentSupport::ChangeAnalyzer.new(engine) user_to_extend_permissions = MockUser.new(:test_role) another_user = MockUser.new(:test_role) - approaches = analyzer.find_approaches_for(:add, :permission, :on => :permissions, - :to => :read, :users => [user_to_extend_permissions, another_user]) do - assert permit?(:read, :context => :permissions, :user => users.first) - assert !permit?(:read, :context => :permissions, :user => users[1]) + approaches = analyzer.find_approaches_for(:add, :permission, on: :permissions, + to: :read, users: [user_to_extend_permissions, another_user]) do + assert permit?(:read, context: :permissions, user: users.first) + assert !permit?(:read, context: :permissions, user: users[1]) end refute_equal 0, approaches.length - #assert_equal :role, approaches.first.target_type - #assert_equal :test_role_2, approaches.first.target.to_sym + # assert_equal :role, approaches.first.target_type + # assert_equal :test_role_2, approaches.first.target.to_sym end def test_adding_permission_with_new_role_complex reader = Authorization::Reader::DSLReader.new - reader.parse %{ + reader.parse %( authorization do role :lower_role do end @@ -98,52 +96,52 @@ def test_adding_permission_with_new_role_complex includes :lower_role end end - } + ) engine = Authorization::Engine.new(reader) analyzer = Authorization::DevelopmentSupport::ChangeAnalyzer.new(engine) user_to_extend_permissions = MockUser.new(:test_role) another_user = MockUser.new(:test_role) - approaches = analyzer.find_approaches_for(:add, :permission, :on => :permissions, - :to => :read, :users => [another_user, user_to_extend_permissions]) do - assert permit?(:read, :context => :permissions, :user => users[1]) - assert !permit?(:read, :context => :permissions, :user => users[0]) + approaches = analyzer.find_approaches_for(:add, :permission, on: :permissions, + to: :read, users: [another_user, user_to_extend_permissions]) do + assert permit?(:read, context: :permissions, user: users[1]) + assert !permit?(:read, context: :permissions, user: users[0]) end refute_equal 0, approaches.length - #assert_equal :role, approaches.first.target_type - #assert_equal :test_role_2, approaches.first.target.to_sym + # assert_equal :role, approaches.first.target_type + # assert_equal :test_role_2, approaches.first.target.to_sym end def test_removing_permission reader = Authorization::Reader::DSLReader.new - reader.parse %{ + reader.parse %( authorization do role :test_role do has_permission_on :permissions, :to => :read end end - } + ) engine = Authorization::Engine.new(reader) analyzer = Authorization::DevelopmentSupport::ChangeAnalyzer.new(engine) user_to_remove_permissions_from = MockUser.new(:test_role) - approaches = analyzer.find_approaches_for(:remove, :permission, :on => :permissions, - :to => :read, :users => [user_to_remove_permissions_from]) do - assert !permit?(:read, :context => :permissions, :user => users.first) + approaches = analyzer.find_approaches_for(:remove, :permission, on: :permissions, + to: :read, users: [user_to_remove_permissions_from]) do + assert !permit?(:read, context: :permissions, user: users.first) end # either: remove that privilege from :test_role - assert approaches[0,2].any? {|approach| approach.changes.length == 1 and approach.changes.first.first == :remove_privilege } + assert approaches[0, 2].any? { |approach| (approach.changes.length == 1) && (approach.changes.first.first == :remove_privilege) } # or: remove that role from the user - assert approaches[0,2].any? {|approach| approach.changes.length == 1 and approach.changes.first.first == :remove_role_from_user } + assert approaches[0, 2].any? { |approach| (approach.changes.length == 1) && (approach.changes.first.first == :remove_role_from_user) } end def test_moving_permission reader = Authorization::Reader::DSLReader.new - reader.parse %{ + reader.parse %( authorization do role :test_role_2 do end @@ -151,75 +149,75 @@ def test_moving_permission has_permission_on :permissions, :to => :read end end - } + ) engine = Authorization::Engine.new(reader) analyzer = Authorization::DevelopmentSupport::ChangeAnalyzer.new(engine) user_to_remove_permissions_from = MockUser.new(:test_role) user_to_keep_permission = MockUser.new(:test_role, :test_role_2) - approaches = analyzer.find_approaches_for(:remove, :permission, :on => :permissions, - :to => :read, :users => [user_to_remove_permissions_from, user_to_keep_permission]) do - assert !permit?(:read, :context => :permissions, :user => users.first) - assert permit?(:read, :context => :permissions, :user => users[1]) + approaches = analyzer.find_approaches_for(:remove, :permission, on: :permissions, + to: :read, users: [user_to_remove_permissions_from, user_to_keep_permission]) do + assert !permit?(:read, context: :permissions, user: users.first) + assert permit?(:read, context: :permissions, user: users[1]) end - assert approaches.find {|approach| approach.steps.find {|step| step.first == :remove_privilege}} - assert approaches.find {|approach| approach.steps.find {|step| step.first == :add_privilege}} + assert approaches.find { |approach| approach.steps.find { |step| step.first == :remove_privilege } } + assert approaches.find { |approach| approach.steps.find { |step| step.first == :add_privilege } } end def test_removing_permission_adding_role reader = Authorization::Reader::DSLReader.new - reader.parse %{ + reader.parse %( authorization do role :test_role do has_permission_on :permissions, :to => :read has_permission_on :permissions_2, :to => :read end end - } + ) engine = Authorization::Engine.new(reader) analyzer = Authorization::DevelopmentSupport::ChangeAnalyzer.new(engine) user_to_remove_permissions_from = MockUser.new(:test_role) user_to_keep_permission = MockUser.new(:test_role) - approaches = analyzer.find_approaches_for(:remove, :permission, :on => :permissions, - :to => :read, :users => [user_to_remove_permissions_from, user_to_keep_permission]) do - assert !permit?(:read, :context => :permissions, :user => users.first) - assert permit?(:read, :context => :permissions_2, :user => users.first) - assert permit?(:read, :context => :permissions, :user => users[1]) - assert permit?(:read, :context => :permissions_2, :user => users[1]) + approaches = analyzer.find_approaches_for(:remove, :permission, on: :permissions, + to: :read, users: [user_to_remove_permissions_from, user_to_keep_permission]) do + assert !permit?(:read, context: :permissions, user: users.first) + assert permit?(:read, context: :permissions_2, user: users.first) + assert permit?(:read, context: :permissions, user: users[1]) + assert permit?(:read, context: :permissions_2, user: users[1]) end # solution: add a new role refute_equal 0, approaches.length - assert approaches.any? {|approach| approach.users.first.role_symbols.include?(:test_role) } + assert approaches.any? { |approach| approach.users.first.role_symbols.include?(:test_role) } end def test_removing_user_role_assignment reader = Authorization::Reader::DSLReader.new - reader.parse %{ + reader.parse %( authorization do role :test_role do has_permission_on :permissions, :to => :read end end - } + ) engine = Authorization::Engine.new(reader) analyzer = Authorization::DevelopmentSupport::ChangeAnalyzer.new(engine) user_to_remove_permissions_from = MockUser.new(:test_role) user_to_keep_permission = MockUser.new(:test_role) - approaches = analyzer.find_approaches_for(:remove, :permission, :on => :permissions, - :to => :read, :users => [user_to_remove_permissions_from, user_to_keep_permission]) do - assert !permit?(:read, :context => :permissions, :user => users.first) - assert permit?(:read, :context => :permissions, :user => users[1]) + approaches = analyzer.find_approaches_for(:remove, :permission, on: :permissions, + to: :read, users: [user_to_remove_permissions_from, user_to_keep_permission]) do + assert !permit?(:read, context: :permissions, user: users.first) + assert permit?(:read, context: :permissions, user: users[1]) end # solutions: remove user-role assignment for first user refute_equal 0, approaches.length - assert approaches.any? {|approach| approach.users.first.role_symbols.empty? } + assert approaches.any? { |approach| approach.users.first.role_symbols.empty? } end end diff --git a/test/development_support/change_supporter_test.rb b/test/development_support/change_supporter_test.rb index 3bf81209..ecda3b10 100644 --- a/test/development_support/change_supporter_test.rb +++ b/test/development_support/change_supporter_test.rb @@ -1,12 +1,10 @@ require 'test_helper' -require File.join(File.dirname(__FILE__), %w{.. .. lib declarative_authorization development_support change_supporter}) - - -class ChangeSupporterTest < Test::Unit::TestCase +require File.join(File.dirname(__FILE__), %w[.. .. lib declarative_authorization development_support change_supporter]) +class ChangeSupporterTest def test_adding_permission reader = Authorization::Reader::DSLReader.new - reader.parse %{ + reader.parse %( authorization do role :test_role do end @@ -14,24 +12,24 @@ def test_adding_permission includes :test_role end end - } + ) engine = Authorization::Engine.new(reader) analyzer = Authorization::DevelopmentSupport::ChangeSupporter.new(engine) user_to_extend_permissions = MockUser.new(:test_role_2) another_user = MockUser.new(:test_role) - approaches = analyzer.find_approaches_for(:users => [user_to_extend_permissions, another_user]) do - assert permit?(:read, :context => :permissions, :user => users.first) - assert !permit?(:read, :context => :permissions, :user => users[1]) + approaches = analyzer.find_approaches_for(users: [user_to_extend_permissions, another_user]) do + assert permit?(:read, context: :permissions, user: users.first) + assert !permit?(:read, context: :permissions, user: users[1]) end - assert approaches.any? {|approach| approach.steps.any? {|step| step.class == Authorization::DevelopmentSupport::ChangeSupporter::AssignPrivilegeToRoleAction}} + assert approaches.any? { |approach| approach.steps.any? { |step| step.class == Authorization::DevelopmentSupport::ChangeSupporter::AssignPrivilegeToRoleAction } } end def test_adding_permission_with_privilege_hierarchy reader = Authorization::Reader::DSLReader.new - reader.parse %{ + reader.parse %( authorization do role :test_role do end @@ -39,25 +37,25 @@ def test_adding_permission_with_privilege_hierarchy privileges do privilege :manage, :includes => [:create, :read] end - } + ) engine = Authorization::Engine.new(reader) analyzer = Authorization::DevelopmentSupport::ChangeSupporter.new(engine) user_to_extend_permissions = MockUser.new(:test_role) - approaches = analyzer.find_approaches_for(:users => [user_to_extend_permissions]) do - assert permit?(:read, :context => :permissions, :user => users.first) + approaches = analyzer.find_approaches_for(users: [user_to_extend_permissions]) do + assert permit?(:read, context: :permissions, user: users.first) end - assert approaches.any? {|approach| - approach.steps.first.class == Authorization::DevelopmentSupport::ChangeSupporter::AssignPrivilegeToRoleAction and - approach.steps.first.privilege == :manage + assert approaches.any? { |approach| + (approach.steps.first.class == Authorization::DevelopmentSupport::ChangeSupporter::AssignPrivilegeToRoleAction) && + (approach.steps.first.privilege == :manage) } end def test_adding_permission_by_assigning_role reader = Authorization::Reader::DSLReader.new - reader.parse %{ + reader.parse %( authorization do role :test_role do end @@ -65,24 +63,24 @@ def test_adding_permission_by_assigning_role has_permission_on :permissions, :to => :read end end - } + ) engine = Authorization::Engine.new(reader) analyzer = Authorization::DevelopmentSupport::ChangeSupporter.new(engine) user_to_extend_permissions = MockUser.new(:test_role) another_user = MockUser.new(:test_role) - approaches = analyzer.find_approaches_for(:users => [user_to_extend_permissions, another_user]) do - assert permit?(:read, :context => :permissions, :user => users.first) - assert !permit?(:read, :context => :permissions, :user => users[1]) + approaches = analyzer.find_approaches_for(users: [user_to_extend_permissions, another_user]) do + assert permit?(:read, context: :permissions, user: users.first) + assert !permit?(:read, context: :permissions, user: users[1]) end - assert approaches.any? {|approach| approach.changes.first.class == Authorization::DevelopmentSupport::ChangeSupporter::AssignRoleToUserAction} + assert approaches.any? { |approach| approach.changes.first.class == Authorization::DevelopmentSupport::ChangeSupporter::AssignRoleToUserAction } end def test_adding_permission_by_assigning_role_with_privilege_hierarchy reader = Authorization::Reader::DSLReader.new - reader.parse %{ + reader.parse %( authorization do role :test_role do has_permission_on :permissions, :to => :manage @@ -91,22 +89,22 @@ def test_adding_permission_by_assigning_role_with_privilege_hierarchy privileges do privilege :manage, :includes => [:create, :read] end - } + ) engine = Authorization::Engine.new(reader) analyzer = Authorization::DevelopmentSupport::ChangeSupporter.new(engine) - user_to_extend_permissions = MockUser.new() + user_to_extend_permissions = MockUser.new - approaches = analyzer.find_approaches_for(:users => [user_to_extend_permissions]) do - assert permit?(:read, :context => :permissions, :user => users.first) + approaches = analyzer.find_approaches_for(users: [user_to_extend_permissions]) do + assert permit?(:read, context: :permissions, user: users.first) end - assert approaches.any? {|approach| approach.changes.first.class == Authorization::DevelopmentSupport::ChangeSupporter::AssignRoleToUserAction} + assert approaches.any? { |approach| approach.changes.first.class == Authorization::DevelopmentSupport::ChangeSupporter::AssignRoleToUserAction } end def test_adding_permission_by_assigning_role_many reader = Authorization::Reader::DSLReader.new - reader.parse %{ + reader.parse %( authorization do role :test_role do end @@ -134,46 +132,46 @@ def test_adding_permission_by_assigning_role_many role :irrelevant_test_role_10 do end end - } + ) engine = Authorization::Engine.new(reader) analyzer = Authorization::DevelopmentSupport::ChangeSupporter.new(engine) user_to_extend_permissions = MockUser.new(:test_role) another_user = MockUser.new(:test_role) - approaches = analyzer.find_approaches_for(:users => [user_to_extend_permissions, another_user]) do - assert permit?(:read, :context => :permissions, :user => users.first) - assert !permit?(:read, :context => :permissions, :user => users[1]) + approaches = analyzer.find_approaches_for(users: [user_to_extend_permissions, another_user]) do + assert permit?(:read, context: :permissions, user: users.first) + assert !permit?(:read, context: :permissions, user: users[1]) end - assert approaches.any? {|approach| approach.changes.first.class == Authorization::DevelopmentSupport::ChangeSupporter::AssignRoleToUserAction} + assert approaches.any? { |approach| approach.changes.first.class == Authorization::DevelopmentSupport::ChangeSupporter::AssignRoleToUserAction } end def test_adding_permission_with_new_role reader = Authorization::Reader::DSLReader.new - reader.parse %{ + reader.parse %( authorization do role :test_role do end end - } + ) engine = Authorization::Engine.new(reader) analyzer = Authorization::DevelopmentSupport::ChangeSupporter.new(engine) user_to_extend_permissions = MockUser.new(:test_role) another_user = MockUser.new(:test_role) - approaches = analyzer.find_approaches_for(:users => [user_to_extend_permissions, another_user]) do - assert permit?(:read, :context => :permissions, :user => users.first) - assert !permit?(:read, :context => :permissions, :user => users[1]) + approaches = analyzer.find_approaches_for(users: [user_to_extend_permissions, another_user]) do + assert permit?(:read, context: :permissions, user: users.first) + assert !permit?(:read, context: :permissions, user: users[1]) end - assert approaches.any? {|approach| approach.changes.first.class == Authorization::DevelopmentSupport::ChangeSupporter::CreateAndAssignRoleToUserAction} + assert approaches.any? { |approach| approach.changes.first.class == Authorization::DevelopmentSupport::ChangeSupporter::CreateAndAssignRoleToUserAction } end def test_adding_permission_with_new_role_complex reader = Authorization::Reader::DSLReader.new - reader.parse %{ + reader.parse %( authorization do role :lower_role do end @@ -181,45 +179,45 @@ def test_adding_permission_with_new_role_complex includes :lower_role end end - } + ) engine = Authorization::Engine.new(reader) analyzer = Authorization::DevelopmentSupport::ChangeSupporter.new(engine) user_to_extend_permissions = MockUser.new(:test_role) another_user = MockUser.new(:test_role) - approaches = analyzer.find_approaches_for(:users => [another_user, user_to_extend_permissions]) do - assert permit?(:read, :context => :permissions, :user => users[1]) - assert !permit?(:read, :context => :permissions, :user => users[0]) + approaches = analyzer.find_approaches_for(users: [another_user, user_to_extend_permissions]) do + assert permit?(:read, context: :permissions, user: users[1]) + assert !permit?(:read, context: :permissions, user: users[0]) end - assert approaches.any? {|approach| approach.changes.first.class == Authorization::DevelopmentSupport::ChangeSupporter::CreateAndAssignRoleToUserAction} + assert approaches.any? { |approach| approach.changes.first.class == Authorization::DevelopmentSupport::ChangeSupporter::CreateAndAssignRoleToUserAction } end def test_adding_permission_with_assigning_role_and_adding_permission reader = Authorization::Reader::DSLReader.new - reader.parse %{ + reader.parse %( authorization do role :test_role do end end - } + ) engine = Authorization::Engine.new(reader) analyzer = Authorization::DevelopmentSupport::ChangeSupporter.new(engine) - user_to_extend_permissions = MockUser.new() + user_to_extend_permissions = MockUser.new - approaches = analyzer.find_approaches_for(:users => [user_to_extend_permissions]) do - assert permit?(:read, :context => :permissions, :user => users.first) + approaches = analyzer.find_approaches_for(users: [user_to_extend_permissions]) do + assert permit?(:read, context: :permissions, user: users.first) end refute_equal 0, approaches.length - assert approaches.any? {|approach| approach.changes.first.class == Authorization::DevelopmentSupport::ChangeSupporter::AddPrivilegeAndAssignRoleToUserAction} + assert approaches.any? { |approach| approach.changes.first.class == Authorization::DevelopmentSupport::ChangeSupporter::AddPrivilegeAndAssignRoleToUserAction } end def test_adding_permission_with_assigning_role_and_adding_permission_with_hierarchy reader = Authorization::Reader::DSLReader.new - reader.parse %{ + reader.parse %( authorization do role :higher_role do includes :test_role @@ -231,50 +229,50 @@ def test_adding_permission_with_assigning_role_and_adding_permission_with_hierar privileges do privilege :manage, :includes => [:create, :read] end - } + ) engine = Authorization::Engine.new(reader) analyzer = Authorization::DevelopmentSupport::ChangeSupporter.new(engine) user_to_extend_permissions = MockUser.new - approaches = analyzer.find_approaches_for(:users => [user_to_extend_permissions]) do - assert permit?(:read, :context => :permissions, :user => users.first) + approaches = analyzer.find_approaches_for(users: [user_to_extend_permissions]) do + assert permit?(:read, context: :permissions, user: users.first) end # Don't try to assign any permissions to higher_role, it already has the # necessary permissions through the hierarchies - assert !approaches.any? {|approach| + assert approaches.none? { |approach| approach.steps.first.class == Authorization::DevelopmentSupport::ChangeSupporter::AddPrivilegeAndAssignRoleToUserAction } end def test_removing_permission reader = Authorization::Reader::DSLReader.new - reader.parse %{ + reader.parse %( authorization do role :test_role do has_permission_on :permissions, :to => :read end end - } + ) engine = Authorization::Engine.new(reader) analyzer = Authorization::DevelopmentSupport::ChangeSupporter.new(engine) user_to_remove_permissions_from = MockUser.new(:test_role) - approaches = analyzer.find_approaches_for(:users => [user_to_remove_permissions_from]) do - assert !permit?(:read, :context => :permissions, :user => users.first) + approaches = analyzer.find_approaches_for(users: [user_to_remove_permissions_from]) do + assert !permit?(:read, context: :permissions, user: users.first) end # either: remove that privilege from :test_role - assert approaches[0,2].any? {|approach| approach.changes.length == 1 and approach.changes.first.class == Authorization::DevelopmentSupport::ChangeSupporter::RemovePrivilegeFromRoleAction } + assert approaches[0, 2].any? { |approach| (approach.changes.length == 1) && (approach.changes.first.class == Authorization::DevelopmentSupport::ChangeSupporter::RemovePrivilegeFromRoleAction) } # or: remove that role from the user - assert approaches[0,2].any? {|approach| approach.changes.length == 1 and approach.changes.first.class == Authorization::DevelopmentSupport::ChangeSupporter::RemoveRoleFromUserAction } + assert approaches[0, 2].any? { |approach| (approach.changes.length == 1) && (approach.changes.first.class == Authorization::DevelopmentSupport::ChangeSupporter::RemoveRoleFromUserAction) } end def test_removing_permission_privilege_hierarchy reader = Authorization::Reader::DSLReader.new - reader.parse %{ + reader.parse %( authorization do role :test_role do has_permission_on :permissions, :to => :manage @@ -283,22 +281,22 @@ def test_removing_permission_privilege_hierarchy privileges do privilege :manage, :includes => [:create, :read] end - } + ) engine = Authorization::Engine.new(reader) analyzer = Authorization::DevelopmentSupport::ChangeSupporter.new(engine) user_to_remove_permissions_from = MockUser.new(:test_role) - approaches = analyzer.find_approaches_for(:users => [user_to_remove_permissions_from]) do - assert !permit?(:read, :context => :permissions, :user => users.first) + approaches = analyzer.find_approaches_for(users: [user_to_remove_permissions_from]) do + assert !permit?(:read, context: :permissions, user: users.first) end - assert approaches[0,2].any? {|approach| approach.changes.length == 1 and approach.changes.first.class == Authorization::DevelopmentSupport::ChangeSupporter::RemovePrivilegeFromRoleAction } + assert approaches[0, 2].any? { |approach| (approach.changes.length == 1) && (approach.changes.first.class == Authorization::DevelopmentSupport::ChangeSupporter::RemovePrivilegeFromRoleAction) } end def test_removing_permission_with_constraint reader = Authorization::Reader::DSLReader.new - reader.parse %{ + reader.parse %( authorization do role :test_role do has_permission_on :permissions, :to => :read do @@ -306,25 +304,25 @@ def test_removing_permission_with_constraint end end end - } + ) engine = Authorization::Engine.new(reader) analyzer = Authorization::DevelopmentSupport::ChangeSupporter.new(engine) user_to_remove_permissions_from = MockUser.new(:test_role) - approaches = analyzer.find_approaches_for(:users => [user_to_remove_permissions_from]) do - assert !permit?(:read, :context => :permissions, :user => users.first) + approaches = analyzer.find_approaches_for(users: [user_to_remove_permissions_from]) do + assert !permit?(:read, context: :permissions, user: users.first) end # either: remove that privilege from :test_role - assert approaches[0,2].any? {|approach| approach.changes.length == 1 and approach.changes.first.class == Authorization::DevelopmentSupport::ChangeSupporter::RemovePrivilegeFromRoleAction } + assert approaches[0, 2].any? { |approach| (approach.changes.length == 1) && (approach.changes.first.class == Authorization::DevelopmentSupport::ChangeSupporter::RemovePrivilegeFromRoleAction) } # or: remove that role from the user - assert approaches[0,2].any? {|approach| approach.changes.length == 1 and approach.changes.first.class == Authorization::DevelopmentSupport::ChangeSupporter::RemoveRoleFromUserAction } + assert approaches[0, 2].any? { |approach| (approach.changes.length == 1) && (approach.changes.first.class == Authorization::DevelopmentSupport::ChangeSupporter::RemoveRoleFromUserAction) } end def test_moving_permission reader = Authorization::Reader::DSLReader.new - reader.parse %{ + reader.parse %( authorization do role :test_role_2 do end @@ -332,76 +330,76 @@ def test_moving_permission has_permission_on :permissions, :to => :read end end - } + ) engine = Authorization::Engine.new(reader) analyzer = Authorization::DevelopmentSupport::ChangeSupporter.new(engine) user_to_remove_permissions_from = MockUser.new(:test_role) user_to_keep_permission = MockUser.new(:test_role, :test_role_2) - approaches = analyzer.find_approaches_for(:users => [user_to_remove_permissions_from, user_to_keep_permission]) do - assert !permit?(:read, :context => :permissions, :user => users.first) - assert permit?(:read, :context => :permissions, :user => users[1]) + approaches = analyzer.find_approaches_for(users: [user_to_remove_permissions_from, user_to_keep_permission]) do + assert !permit?(:read, context: :permissions, user: users.first) + assert permit?(:read, context: :permissions, user: users[1]) end - assert approaches.any? {|approach| approach.steps.find {|step| step.class == Authorization::DevelopmentSupport::ChangeSupporter::RemovePrivilegeFromRoleAction}} - assert approaches.any? {|approach| approach.steps.find {|step| step.class == Authorization::DevelopmentSupport::ChangeSupporter::AssignPrivilegeToRoleAction}} + assert approaches.any? { |approach| approach.steps.find { |step| step.class == Authorization::DevelopmentSupport::ChangeSupporter::RemovePrivilegeFromRoleAction } } + assert approaches.any? { |approach| approach.steps.find { |step| step.class == Authorization::DevelopmentSupport::ChangeSupporter::AssignPrivilegeToRoleAction } } end def test_removing_permission_adding_role reader = Authorization::Reader::DSLReader.new - reader.parse %{ + reader.parse %( authorization do role :test_role do has_permission_on :permissions, :to => :read has_permission_on :permissions_2, :to => :read end end - } + ) engine = Authorization::Engine.new(reader) analyzer = Authorization::DevelopmentSupport::ChangeSupporter.new(engine) user_to_remove_permissions_from = MockUser.new(:test_role) user_to_keep_permission = MockUser.new(:test_role) - approaches = analyzer.find_approaches_for(:users => [user_to_remove_permissions_from, user_to_keep_permission]) do - assert !permit?(:read, :context => :permissions, :user => users.first) - assert permit?(:read, :context => :permissions_2, :user => users.first) - assert permit?(:read, :context => :permissions, :user => users[1]) - assert permit?(:read, :context => :permissions_2, :user => users[1]) + approaches = analyzer.find_approaches_for(users: [user_to_remove_permissions_from, user_to_keep_permission]) do + assert !permit?(:read, context: :permissions, user: users.first) + assert permit?(:read, context: :permissions_2, user: users.first) + assert permit?(:read, context: :permissions, user: users[1]) + assert permit?(:read, context: :permissions_2, user: users[1]) end # solution: add a new role - assert approaches.any? {|approach| approach.users.first.role_symbols.include?(:test_role) } + assert approaches.any? { |approach| approach.users.first.role_symbols.include?(:test_role) } end def test_removing_user_role_assignment reader = Authorization::Reader::DSLReader.new - reader.parse %{ + reader.parse %( authorization do role :test_role do has_permission_on :permissions, :to => :read end end - } + ) engine = Authorization::Engine.new(reader) analyzer = Authorization::DevelopmentSupport::ChangeSupporter.new(engine) user_to_remove_permissions_from = MockUser.new(:test_role) user_to_keep_permission = MockUser.new(:test_role) - approaches = analyzer.find_approaches_for(:users => [user_to_remove_permissions_from, user_to_keep_permission]) do - assert !permit?(:read, :context => :permissions, :user => users.first) - assert permit?(:read, :context => :permissions, :user => users[1]) + approaches = analyzer.find_approaches_for(users: [user_to_remove_permissions_from, user_to_keep_permission]) do + assert !permit?(:read, context: :permissions, user: users.first) + assert permit?(:read, context: :permissions, user: users[1]) end # solutions: remove user-role assignment for first user - assert approaches.any? {|approach| approach.users.first.role_symbols.empty? } + assert approaches.any? { |approach| approach.users.first.role_symbols.empty? } end def test_removing_user_role_assignment_hierarchy reader = Authorization::Reader::DSLReader.new - reader.parse %{ + reader.parse %( authorization do role :higher_role do includes :test_role @@ -410,25 +408,25 @@ def test_removing_user_role_assignment_hierarchy has_permission_on :permissions, :to => :read end end - } + ) engine = Authorization::Engine.new(reader) analyzer = Authorization::DevelopmentSupport::ChangeSupporter.new(engine) user_to_remove_permissions_from = MockUser.new(:higher_role) user_to_keep_permission = MockUser.new(:higher_role) - approaches = analyzer.find_approaches_for(:users => [user_to_remove_permissions_from, user_to_keep_permission]) do - assert !permit?(:read, :context => :permissions, :user => users.first) - assert permit?(:read, :context => :permissions, :user => users[1]) + approaches = analyzer.find_approaches_for(users: [user_to_remove_permissions_from, user_to_keep_permission]) do + assert !permit?(:read, context: :permissions, user: users.first) + assert permit?(:read, context: :permissions, user: users[1]) end # solutions: remove user-role assignment for first user - assert approaches.any? {|approach| !approach.users.first.role_symbols.include?(:higher_role) } + assert approaches.any? { |approach| !approach.users.first.role_symbols.include?(:higher_role) } end def test_removing_user_role_assignment_many reader = Authorization::Reader::DSLReader.new - reader.parse %{ + reader.parse %( authorization do role :test_role do has_permission_on :permissions, :to => :read @@ -454,52 +452,52 @@ def test_removing_user_role_assignment_many role :irrelevant_test_role_10 do end end - } + ) engine = Authorization::Engine.new(reader) analyzer = Authorization::DevelopmentSupport::ChangeSupporter.new(engine) - roles = [:test_role] + (1..10).collect {|i| :"irrelevant_test_role_#{i}"} + roles = [:test_role] + (1..10).collect { |i| :"irrelevant_test_role_#{i}" } user_to_remove_permissions_from = MockUser.new(*roles) user_to_keep_permission = MockUser.new(*roles.clone) - approaches = analyzer.find_approaches_for(:users => [user_to_remove_permissions_from, user_to_keep_permission]) do - assert !permit?(:read, :context => :permissions, :user => users.first) - assert permit?(:read, :context => :permissions, :user => users[1]) + approaches = analyzer.find_approaches_for(users: [user_to_remove_permissions_from, user_to_keep_permission]) do + assert !permit?(:read, context: :permissions, user: users.first) + assert permit?(:read, context: :permissions, user: users[1]) end # solutions: remove user-role assignment for first user - assert approaches.any? {|approach| !approach.users.first.role_symbols.include?(:test_role) } + assert approaches.any? { |approach| !approach.users.first.role_symbols.include?(:test_role) } end def test_no_superset_approaches reader = Authorization::Reader::DSLReader.new - reader.parse %{ + reader.parse %( authorization do role :test_role do has_permission_on :permissions, :to => :read end end - } + ) engine = Authorization::Engine.new(reader) analyzer = Authorization::DevelopmentSupport::ChangeSupporter.new(engine) user_to_remove_permission_from = MockUser.new(:test_role) user_to_remove_permission_from_2 = MockUser.new(:test_role) - approaches = analyzer.find_approaches_for(:users => [user_to_remove_permission_from, user_to_remove_permission_from_2]) do - assert !permit?(:read, :context => :permissions, :user => users.first) - assert !permit?(:read, :context => :permissions, :user => users[1]) + approaches = analyzer.find_approaches_for(users: [user_to_remove_permission_from, user_to_remove_permission_from_2]) do + assert !permit?(:read, context: :permissions, user: users.first) + assert !permit?(:read, context: :permissions, user: users[1]) end - assert !approaches.any? {|approach| - approach.steps.any? {|step| step.class == Authorization::DevelopmentSupport::ChangeSupporter::RemoveRoleFromUserAction} and - approach.steps.any? {|step| step.class == Authorization::DevelopmentSupport::ChangeSupporter::RemovePrivilegeFromRoleAction} + assert approaches.none? { |approach| + approach.steps.any? { |step| step.class == Authorization::DevelopmentSupport::ChangeSupporter::RemoveRoleFromUserAction } && + approach.steps.any? { |step| step.class == Authorization::DevelopmentSupport::ChangeSupporter::RemovePrivilegeFromRoleAction } } end def test_prohibited_actions_role_to_user reader = Authorization::Reader::DSLReader.new - reader.parse %{ + reader.parse %( authorization do role :test_role do has_permission_on :permissions, :to => :read @@ -507,24 +505,24 @@ def test_prohibited_actions_role_to_user role :test_role_2 do end end - } + ) engine = Authorization::Engine.new(reader) analyzer = Authorization::DevelopmentSupport::ChangeSupporter.new(engine) user_to_extend_permissions = MockUser.new(:test_role_2) - approaches = analyzer.find_approaches_for(:users => [user_to_extend_permissions], - :prohibited_actions => [[:assign_role_to_user, :test_role, user_to_extend_permissions.login]]) do #, 'other_attendee' - assert permit?(:read, :context => :permissions, :user => users.first) + approaches = analyzer.find_approaches_for(users: [user_to_extend_permissions], + prohibited_actions: [[:assign_role_to_user, :test_role, user_to_extend_permissions.login]]) do # , 'other_attendee' + assert permit?(:read, context: :permissions, user: users.first) end refute_equal 0, approaches.length - assert !approaches.any? {|approach| approach.steps.any? {|step| step.class == Authorization::DevelopmentSupport::ChangeSupporter::AssignRoleToUserAction}} + assert approaches.none? { |approach| approach.steps.any? { |step| step.class == Authorization::DevelopmentSupport::ChangeSupporter::AssignRoleToUserAction } } end def test_prohibited_actions_role_to_any_user reader = Authorization::Reader::DSLReader.new - reader.parse %{ + reader.parse %( authorization do role :test_role do has_permission_on :permissions, :to => :read @@ -532,24 +530,24 @@ def test_prohibited_actions_role_to_any_user role :test_role_2 do end end - } + ) engine = Authorization::Engine.new(reader) analyzer = Authorization::DevelopmentSupport::ChangeSupporter.new(engine) user_to_extend_permissions = MockUser.new(:test_role_2) - approaches = analyzer.find_approaches_for(:users => [user_to_extend_permissions], - :prohibited_actions => [[:assign_role_to_user, :test_role]]) do - assert permit?(:read, :context => :permissions, :user => users.first) + approaches = analyzer.find_approaches_for(users: [user_to_extend_permissions], + prohibited_actions: [%i[assign_role_to_user test_role]]) do + assert permit?(:read, context: :permissions, user: users.first) end refute_equal 0, approaches.length - assert !approaches.any? {|approach| approach.steps.any? {|step| step.class == Authorization::DevelopmentSupport::ChangeSupporter::AssignRoleToUserAction and step.role == :test_role }} + assert approaches.none? { |approach| approach.steps.any? { |step| (step.class == Authorization::DevelopmentSupport::ChangeSupporter::AssignRoleToUserAction) && (step.role == :test_role) } } end def test_prohibited_actions_permission_to_role reader = Authorization::Reader::DSLReader.new - reader.parse %{ + reader.parse %( authorization do role :test_role do has_permission_on :permissions, :to => :read @@ -557,47 +555,47 @@ def test_prohibited_actions_permission_to_role role :test_role_2 do end end - } + ) engine = Authorization::Engine.new(reader) analyzer = Authorization::DevelopmentSupport::ChangeSupporter.new(engine) user_to_extend_permissions = MockUser.new(:test_role_2) - approaches = analyzer.find_approaches_for(:users => [user_to_extend_permissions], - :prohibited_actions => [[:add_privilege, :read, :permissions, :test_role_2]]) do #, 'other_attendee' - assert permit?(:read, :context => :permissions, :user => users.first) + approaches = analyzer.find_approaches_for(users: [user_to_extend_permissions], + prohibited_actions: [%i[add_privilege read permissions test_role_2]]) do # , 'other_attendee' + assert permit?(:read, context: :permissions, user: users.first) end refute_equal 0, approaches.length - assert !approaches.any? {|approach| approach.steps.any? {|step| step.class == Authorization::DevelopmentSupport::ChangeSupporter::AssignPrivilegeToRoleAction}} + assert approaches.none? { |approach| approach.steps.any? { |step| step.class == Authorization::DevelopmentSupport::ChangeSupporter::AssignPrivilegeToRoleAction } } end def test_prohibited_actions_remove_role reader = Authorization::Reader::DSLReader.new - reader.parse %{ + reader.parse %( authorization do role :test_role do has_permission_on :permissions, :to => :read end end - } + ) engine = Authorization::Engine.new(reader) analyzer = Authorization::DevelopmentSupport::ChangeSupporter.new(engine) user_to_remove_permission = MockUser.new(:test_role) - approaches = analyzer.find_approaches_for(:users => [user_to_remove_permission], - :prohibited_actions => [[:remove_role_from_user, :test_role, user_to_remove_permission.login]]) do - assert !permit?(:read, :context => :permissions, :user => users.first) + approaches = analyzer.find_approaches_for(users: [user_to_remove_permission], + prohibited_actions: [[:remove_role_from_user, :test_role, user_to_remove_permission.login]]) do + assert !permit?(:read, context: :permissions, user: users.first) end refute_equal 0, approaches.length - assert !approaches.any? {|approach| approach.steps.any? {|step| step.class == Authorization::DevelopmentSupport::ChangeSupporter::RemoveRoleFromUserAction}} + assert approaches.none? { |approach| approach.steps.any? { |step| step.class == Authorization::DevelopmentSupport::ChangeSupporter::RemoveRoleFromUserAction } } end def test_affected_users reader = Authorization::Reader::DSLReader.new - reader.parse %{ + reader.parse %( authorization do role :test_role do end @@ -605,7 +603,7 @@ def test_affected_users includes :test_role end end - } + ) engine = Authorization::Engine.new(reader) analyzer = Authorization::DevelopmentSupport::ChangeSupporter.new(engine) @@ -613,19 +611,19 @@ def test_affected_users another_user = MockUser.new(:test_role) all_users = [user_to_extend_permissions, another_user] - approaches = analyzer.find_approaches_for(:users => all_users) do - assert permit?(:read, :context => :permissions, :user => users[0]) - assert !permit?(:read, :context => :permissions, :user => users[1]) + approaches = analyzer.find_approaches_for(users: all_users) do + assert permit?(:read, context: :permissions, user: users[0]) + assert !permit?(:read, context: :permissions, user: users[1]) end - assert approaches.any? {|approach| - approach.steps.any? {|step| step.class == Authorization::DevelopmentSupport::ChangeSupporter::AssignPrivilegeToRoleAction} && + assert approaches.any? { |approach| + approach.steps.any? { |step| step.class == Authorization::DevelopmentSupport::ChangeSupporter::AssignPrivilegeToRoleAction } && approach.affected_users(engine, all_users, :read, :permissions).length == 1 } end def test_affected_users_with_user_change reader = Authorization::Reader::DSLReader.new - reader.parse %{ + reader.parse %( authorization do role :test_role do end @@ -633,7 +631,7 @@ def test_affected_users_with_user_change has_permission_on :permissions, :to => :read end end - } + ) engine = Authorization::Engine.new(reader) analyzer = Authorization::DevelopmentSupport::ChangeSupporter.new(engine) @@ -641,19 +639,19 @@ def test_affected_users_with_user_change another_user = MockUser.new(:test_role) all_users = [user_to_extend_permissions, another_user] - approaches = analyzer.find_approaches_for(:users => all_users) do - assert permit?(:read, :context => :permissions, :user => users.first) - assert !permit?(:read, :context => :permissions, :user => users[1]) + approaches = analyzer.find_approaches_for(users: all_users) do + assert permit?(:read, context: :permissions, user: users.first) + assert !permit?(:read, context: :permissions, user: users[1]) end - assert approaches.any? {|approach| + assert approaches.any? { |approach| approach.changes.first.class == Authorization::DevelopmentSupport::ChangeSupporter::AssignRoleToUserAction && - approach.affected_users(engine, all_users, :read, :permissions).length == 1 } + approach.affected_users(engine, all_users, :read, :permissions).length == 1 } end def test_group_approaches reader = Authorization::Reader::DSLReader.new - reader.parse %{ + reader.parse %( authorization do role :test_role do includes :test_role_2 @@ -662,20 +660,20 @@ def test_group_approaches has_permission_on :permissions, :to => :read end end - } + ) engine = Authorization::Engine.new(reader) analyzer = Authorization::DevelopmentSupport::ChangeSupporter.new(engine) - user_to_extend_permissions = MockUser.new() - another_user = MockUser.new() + user_to_extend_permissions = MockUser.new + another_user = MockUser.new all_users = [user_to_extend_permissions, another_user] - approaches = analyzer.find_approaches_for(:users => all_users) do - assert permit?(:read, :context => :permissions, :user => users.first) + approaches = analyzer.find_approaches_for(users: all_users) do + assert permit?(:read, context: :permissions, user: users.first) end assert approaches.first.similar_to(approaches[1]), - "First two approaches should be similar" + 'First two approaches should be similar' grouped_approaches = analyzer.group_approaches(approaches) assert_equal 2, grouped_approaches.length diff --git a/test/dsl_reader_test.rb b/test/dsl_reader_test.rb index cc05565c..cae6e3d5 100644 --- a/test/dsl_reader_test.rb +++ b/test/dsl_reader_test.rb @@ -3,58 +3,58 @@ class DSLReaderTest < Test::Unit::TestCase def test_privileges reader = Authorization::Reader::DSLReader.new - reader.parse %{ + reader.parse %( privileges do privilege :test_priv do includes :lower_priv end end - } + ) assert_equal 2, reader.privileges_reader.privileges.length assert_equal [[:lower_priv, nil]], - reader.privileges_reader.privilege_hierarchy[:test_priv] + reader.privileges_reader.privilege_hierarchy[:test_priv] end def test_privileges_with_context reader = Authorization::Reader::DSLReader.new - reader.parse %{ + reader.parse %( privileges do privilege :test_priv, :test_context do includes :lower_priv end end - } - assert_equal [[:lower_priv, :test_context]], - reader.privileges_reader.privilege_hierarchy[:test_priv] + ) + assert_equal [%i[lower_priv test_context]], + reader.privileges_reader.privilege_hierarchy[:test_priv] end def test_privileges_one_line reader = Authorization::Reader::DSLReader.new - reader.parse %{ + reader.parse %( privileges do privilege :test_priv, :test_context, :includes => :lower_priv privilege :test_priv_2, :test_context, :includes => [:lower_priv] privilege :test_priv_3, :includes => [:lower_priv] end - } - assert_equal [[:lower_priv, :test_context]], - reader.privileges_reader.privilege_hierarchy[:test_priv] - assert_equal [[:lower_priv, :test_context]], - reader.privileges_reader.privilege_hierarchy[:test_priv_2] + ) + assert_equal [%i[lower_priv test_context]], + reader.privileges_reader.privilege_hierarchy[:test_priv] + assert_equal [%i[lower_priv test_context]], + reader.privileges_reader.privilege_hierarchy[:test_priv_2] assert_equal [[:lower_priv, nil]], - reader.privileges_reader.privilege_hierarchy[:test_priv_3] + reader.privileges_reader.privilege_hierarchy[:test_priv_3] end def test_auth_role reader = Authorization::Reader::DSLReader.new - reader.parse %{ + reader.parse %( authorization do role :test_role do includes :lesser_role has_permission_on :items, :to => :read end end - } + ) assert_equal 1, reader.auth_rules_reader.roles.length assert_equal [:lesser_role], reader.auth_rules_reader.role_hierarchy[:test_role] assert_equal 1, reader.auth_rules_reader.auth_rules.length @@ -62,7 +62,7 @@ def test_auth_role def test_auth_role_permit_on reader = Authorization::Reader::DSLReader.new - reader.parse %| + reader.parse %( authorization do role :test_role do has_permission_on :test_context do @@ -71,7 +71,7 @@ def test_auth_role_permit_on end end end - | + ) assert_equal 1, reader.auth_rules_reader.roles.length assert_equal 1, reader.auth_rules_reader.auth_rules.length assert reader.auth_rules_reader.auth_rules[0].matches?(:test_role, [:test_perm], :test_context) @@ -80,7 +80,7 @@ def test_auth_role_permit_on def test_permit_block reader = Authorization::Reader::DSLReader.new - reader.parse %| + reader.parse %( authorization do role :test_role do has_permission_on :perms, :to => :test do @@ -97,7 +97,7 @@ def test_permit_block end end end - | + ) assert_equal 1, reader.auth_rules_reader.roles.length assert_equal 1, reader.auth_rules_reader.auth_rules.length assert reader.auth_rules_reader.auth_rules[0].matches?(:test_role, [:test], :perms) @@ -105,13 +105,13 @@ def test_permit_block def test_has_permission_to_with_context reader = Authorization::Reader::DSLReader.new - reader.parse %| + reader.parse %( authorization do role :test_role do has_permission_on :perms, :to => :test end end - | + ) assert_equal 1, reader.auth_rules_reader.roles.length assert_equal 1, reader.auth_rules_reader.auth_rules.length assert reader.auth_rules_reader.auth_rules[0].matches?(:test_role, [:test], :perms) @@ -119,43 +119,43 @@ def test_has_permission_to_with_context def test_context reader = Authorization::Reader::DSLReader.new - reader.parse %{ + reader.parse %( contexts do context :high_level_context do includes :low_level_context_1, :low_level_context_2 end end - } + ) end def test_dsl_error reader = Authorization::Reader::DSLReader.new assert_raises(Authorization::Reader::DSLError) do - reader.parse %{ + reader.parse %( authorization do includes :lesser_role end - } + ) end end def test_syntax_error reader = Authorization::Reader::DSLReader.new assert_raises(Authorization::Reader::DSLSyntaxError) do - reader.parse %{ + reader.parse %( authorizations do end - } + ) end end def test_syntax_error_2 reader = Authorization::Reader::DSLReader.new assert_raises(Authorization::Reader::DSLSyntaxError) do - reader.parse %{ + reader.parse %( authorizations end - } + ) end end @@ -165,14 +165,13 @@ def test_factory_returns_self end def test_factory_loads_file - reader = Authorization::Reader::DSLReader.factory((DA_ROOT + "authorization_rules.dist.rb").to_s) + reader = Authorization::Reader::DSLReader.factory((DA_ROOT + 'authorization_rules.dist.rb').to_s) assert_equal(Authorization::Reader::DSLReader, reader.class) end def test_load_file_not_found assert_raises(Authorization::Reader::DSLFileNotFoundError) do - Authorization::Reader::DSLReader.new.load!("nonexistent_file.rb") + Authorization::Reader::DSLReader.new.load!('nonexistent_file.rb') end end end - diff --git a/test/helper_test.rb b/test/helper_test.rb index 6ad55118..ced85293 100644 --- a/test/helper_test.rb +++ b/test/helper_test.rb @@ -1,9 +1,8 @@ require 'test_helper' -require File.join(File.dirname(__FILE__), %w{.. lib declarative_authorization helper}) - +require File.join(File.dirname(__FILE__), %w[.. lib declarative_authorization helper]) class HelperMocksController < MocksController - filter_access_to :action, :require => :show, :context => :mocks + filter_access_to :action, require: :show, context: :mocks define_action_methods :action end class HelperTest < ActionController::TestCase @@ -13,7 +12,7 @@ class HelperTest < ActionController::TestCase def test_permit reader = Authorization::Reader::DSLReader.new - reader.parse %{ + reader.parse %( authorization do role :test_role do has_permission_on :mocks, :to => :show @@ -22,7 +21,7 @@ def test_permit has_permission_on :mocks, :to => :update end end - } + ) user = MockUser.new(:test_role) request!(user, :action, reader) @@ -44,7 +43,7 @@ def test_permit def test_permit_with_object reader = Authorization::Reader::DSLReader.new - reader.parse %{ + reader.parse %( authorization do role :test_role do has_permission_on :mocks do @@ -53,10 +52,10 @@ def test_permit_with_object end end end - } - user = MockUser.new(:test_role, :test_attr => 1) - mock = MockDataObject.new(:test_attr => 1) - mock_2 = MockDataObject.new(:test_attr => 2) + ) + user = MockUser.new(:test_role, test_attr: 1) + mock = MockDataObject.new(test_attr: 1) + mock_2 = MockDataObject.new(test_attr: 2) request!(user, :action, reader) assert permitted_to?(:show, mock) @@ -66,7 +65,7 @@ def test_permit_with_object def test_permit_with_object_and_context reader = Authorization::Reader::DSLReader.new - reader.parse %{ + reader.parse %( authorization do role :test_role do has_permission_on :other_mocks do @@ -75,25 +74,25 @@ def test_permit_with_object_and_context end end end - } - user = MockUser.new(:test_role, :test_attr => 1) - mock = MockDataObject.new(:test_attr => 1) - mock_2 = MockDataObject.new(:test_attr => 2) + ) + user = MockUser.new(:test_role, test_attr: 1) + mock = MockDataObject.new(test_attr: 1) + mock_2 = MockDataObject.new(test_attr: 2) request!(user, :action, reader) - assert permitted_to?(:show, mock, :context => :other_mocks) - assert !permitted_to?(:show, mock_2, :context => :other_mocks) + assert permitted_to?(:show, mock, context: :other_mocks) + assert !permitted_to?(:show, mock_2, context: :other_mocks) end def test_has_role reader = Authorization::Reader::DSLReader.new - reader.parse %{ + reader.parse %( authorization do role :test_role do has_permission_on :mocks, :to => :show end end - } + ) user = MockUser.new(:test_role) request!(user, :action, reader) @@ -116,13 +115,13 @@ def test_has_role def test_has_any_role reader = Authorization::Reader::DSLReader.new - reader.parse %{ + reader.parse %( authorization do role :test_role do has_permission_on :mocks, :to => :show end end - } + ) user = MockUser.new(:test_role) request!(user, :action, reader) @@ -143,7 +142,7 @@ def test_has_any_role assert !block_evaled block_evaled = false - has_any_role?(:test_role,:test_role2) do + has_any_role?(:test_role, :test_role2) do block_evaled = true end assert block_evaled @@ -151,12 +150,12 @@ def test_has_any_role def test_has_role_with_guest_user reader = Authorization::Reader::DSLReader.new - reader.parse %{ + reader.parse %( authorization do end - } + ) request!(nil, :action, reader) -#test intermittently fails + # test intermittently fails assert !has_role?(:test_role) block_evaled = false @@ -168,7 +167,7 @@ def test_has_role_with_guest_user def test_has_role_with_hierarchy reader = Authorization::Reader::DSLReader.new - reader.parse %{ + reader.parse %( authorization do role :test_role do has_permission_on :mocks, :to => :show @@ -176,12 +175,11 @@ def test_has_role_with_hierarchy role :other_role do has_permission_on :another_mocks, :to => :show end - role :root do includes :test_role end end - } + ) user = MockUser.new(:root) request!(user, :action, reader) @@ -204,7 +202,7 @@ def test_has_role_with_hierarchy def test_has_any_role_with_hierarchy reader = Authorization::Reader::DSLReader.new - reader.parse %{ + reader.parse %( authorization do role :test_role do has_permission_on :mocks, :to => :show @@ -212,19 +210,18 @@ def test_has_any_role_with_hierarchy role :other_role do has_permission_on :another_mocks, :to => :show end - role :root do includes :test_role end end - } + ) user = MockUser.new(:root) request!(user, :action, reader) assert has_any_role_with_hierarchy?(:test_role) assert !has_any_role_with_hierarchy?(:other_role) - assert has_any_role_with_hierarchy?(:test_role,:other_role) + assert has_any_role_with_hierarchy?(:test_role, :other_role) block_evaled = false has_any_role_with_hierarchy?(:test_role) do @@ -239,7 +236,7 @@ def test_has_any_role_with_hierarchy assert !block_evaled block_evaled = false - has_any_role_with_hierarchy?(:test_role,:test_role2) do + has_any_role_with_hierarchy?(:test_role, :test_role2) do block_evaled = true end assert block_evaled diff --git a/test/maintenance_test.rb b/test/maintenance_test.rb index 274adfd3..55ea47ea 100644 --- a/test/maintenance_test.rb +++ b/test/maintenance_test.rb @@ -1,5 +1,5 @@ require 'test_helper' -require File.join(File.dirname(__FILE__), %w{.. lib declarative_authorization maintenance}) +require File.join(File.dirname(__FILE__), %w[.. lib declarative_authorization maintenance]) class MaintenanceTest < Test::Unit::TestCase include Authorization::TestHelper @@ -9,38 +9,37 @@ def test_usages_by_controllers usage_test_controller.send(:define_method, :an_action) {} usage_test_controller.filter_access_to :an_action - assert Authorization::Maintenance::Usage::usages_by_controller. - include?(usage_test_controller) + assert Authorization::Maintenance::Usage.usages_by_controller + .include?(usage_test_controller) end def test_without_access_control reader = Authorization::Reader::DSLReader.new - reader.parse %{ + reader.parse %( authorization do role :test_role do has_permission_on :permissions, :to => :test end end - } + ) engine = Authorization::Engine.new(reader) - assert !engine.permit?(:test_2, :context => :permissions, - :user => MockUser.new(:test_role)) - Authorization::Maintenance::without_access_control do - assert engine.permit!(:test_2, :context => :permissions, - :user => MockUser.new(:test_role)) + assert !engine.permit?(:test_2, context: :permissions, + user: MockUser.new(:test_role)) + Authorization::Maintenance.without_access_control do + assert engine.permit!(:test_2, context: :permissions, + user: MockUser.new(:test_role)) end without_access_control do - assert engine.permit?(:test_2, :context => :permissions, - :user => MockUser.new(:test_role)) + assert engine.permit?(:test_2, context: :permissions, + user: MockUser.new(:test_role)) end - Authorization::Maintenance::without_access_control do - Authorization::Maintenance::without_access_control do - assert engine.permit?(:test_2, :context => :permissions, - :user => MockUser.new(:test_role)) + Authorization::Maintenance.without_access_control do + Authorization::Maintenance.without_access_control do + assert engine.permit?(:test_2, context: :permissions, + user: MockUser.new(:test_role)) end - assert engine.permit?(:test_2, :context => :permissions, - :user => MockUser.new(:test_role)) + assert engine.permit?(:test_2, context: :permissions, + user: MockUser.new(:test_role)) end end - end diff --git a/test/model_test.rb b/test/model_test.rb index 49c3902d..2e06bd24 100644 --- a/test/model_test.rb +++ b/test/model_test.rb @@ -1,41 +1,41 @@ require 'test_helper' -require File.join(File.dirname(__FILE__), %w{.. lib declarative_authorization in_model}) +require File.join(File.dirname(__FILE__), %w[.. lib declarative_authorization in_model]) ActiveRecord::Base.send :include, Authorization::AuthorizationInModel -#ActiveRecord::Base.logger = Logger.new(STDOUT) +# ActiveRecord::Base.logger = Logger.new(STDOUT) -options = {:adapter => 'sqlite3', :timeout => 500, :database => ':memory:'} +options = { adapter: 'sqlite3', timeout: 500, database: ':memory:' } ActiveRecord::Base.establish_connection(options) ActiveRecord::Base.configurations = { 'sqlite3_ar_integration' => options } ActiveRecord::Base.connection -File.read(File.dirname(__FILE__) + "/schema.sql").split(';').each do |sql| +File.read(File.dirname(__FILE__) + '/schema.sql').split(';').each do |sql| ActiveRecord::Base.connection.execute(sql) unless sql.blank? end class TestModel < ActiveRecord::Base has_many :test_attrs - has_many :test_another_attrs, :class_name => "TestAttr", :foreign_key => :test_another_model_id - has_many :test_attr_throughs, :through => :test_attrs - has_one :test_attr_has_one, :class_name => "TestAttr" + has_many :test_another_attrs, class_name: 'TestAttr', foreign_key: :test_another_model_id + has_many :test_attr_throughs, through: :test_attrs + has_one :test_attr_has_one, class_name: 'TestAttr' has_many :branches # :conditions is deprecated in Rails 4.1 - has_many :test_attrs_with_attr, lambda { where(:attr => 1) }, :class_name => "TestAttr" - has_many :test_attr_throughs_with_attr, lambda { where("test_attrs.attr = 1") }, :through => :test_attrs, - :class_name => "TestAttrThrough", :source => :test_attr_throughs + has_many :test_attrs_with_attr, -> { where(attr: 1) }, class_name: 'TestAttr' + has_many :test_attr_throughs_with_attr, -> { where('test_attrs.attr = 1') }, through: :test_attrs, + class_name: 'TestAttrThrough', source: :test_attr_throughs - has_one :test_attr_throughs_with_attr_and_has_one, lambda { where("test_attrs.attr = 1") }, :through => :test_attrs, - :class_name => "TestAttrThrough", :source => :test_attr_throughs + has_one :test_attr_throughs_with_attr_and_has_one, -> { where('test_attrs.attr = 1') }, through: :test_attrs, + class_name: 'TestAttrThrough', source: :test_attr_throughs - scope :with_content, lambda { where("test_models.content IS NOT NULL") } + scope :with_content, -> { where('test_models.content IS NOT NULL') } # Primary key test - has_many :test_attrs_with_primary_id, :class_name => "TestAttr", - :primary_key => :test_attr_through_id, :foreign_key => :test_attr_through_id + has_many :test_attrs_with_primary_id, class_name: 'TestAttr', + primary_key: :test_attr_through_id, foreign_key: :test_attr_through_id has_many :test_attr_throughs_with_primary_id, - :through => :test_attrs_with_primary_id, :class_name => "TestAttrThrough", - :source => :n_way_join_item + through: :test_attrs_with_primary_id, class_name: 'TestAttrThrough', + source: :n_way_join_item # for checking for unnecessary queries mattr_accessor :query_count @@ -48,13 +48,13 @@ def self.find(*args) class NWayJoinItem < ActiveRecord::Base has_many :test_attrs - has_many :others, :through => :test_attrs, :source => :n_way_join_item + has_many :others, through: :test_attrs, source: :n_way_join_item end class TestAttr < ActiveRecord::Base belongs_to :test_model - belongs_to :test_another_model, :class_name => "TestModel", :foreign_key => :test_another_model_id - belongs_to :test_a_third_model, :class_name => "TestModel", :foreign_key => :test_a_third_model_id + belongs_to :test_another_model, class_name: 'TestModel', foreign_key: :test_another_model_id + belongs_to :test_a_third_model, class_name: 'TestModel', foreign_key: :test_a_third_model_id belongs_to :n_way_join_item belongs_to :test_attr belongs_to :branch @@ -78,12 +78,12 @@ class TestModelSecurityModel < ActiveRecord::Base using_access_control end class TestModelSecurityModelWithFind < ActiveRecord::Base - self.table_name = "test_model_security_models" + self.table_name = 'test_model_security_models' has_many :test_attrs belongs_to :test_attr - using_access_control :include_read => true, - :context => :test_model_security_models + using_access_control include_read: true, + context: :test_model_security_models end class Branch < ActiveRecord::Base @@ -109,7 +109,7 @@ class Country < ActiveRecord::Base class NamedScopeModelTest < Test::Unit::TestCase def test_multiple_deep_ored_belongs_to reader = Authorization::Reader::DSLReader.new - reader.parse %{ + reader.parse %( authorization do role :test_role do has_permission_on :test_attrs, :to => :read do @@ -118,17 +118,16 @@ def test_multiple_deep_ored_belongs_to end end end - } + ) Authorization::Engine.instance(reader) test_model_1 = TestModel.create! test_model_2 = TestModel.create! - test_attr_1 = TestAttr.create! :test_model_id => test_model_1.id, - :test_another_model_id => test_model_2.id - - user = MockUser.new(:test_role, :id => test_attr_1) - assert_equal 1, TestAttr.with_permissions_to(:read, :user => user).references(:test_attrs, :test_attrs_test_models, :test_attrs_test_models_2).length + test_attr_1 = TestAttr.create! test_model_id: test_model_1.id, + test_another_model_id: test_model_2.id + user = MockUser.new(:test_role, id: test_attr_1) + assert_equal 1, TestAttr.with_permissions_to(:read, user: user).references(:test_attrs, :test_attrs_test_models, :test_attrs_test_models_2).length TestAttr.delete_all TestModel.delete_all @@ -136,7 +135,7 @@ def test_multiple_deep_ored_belongs_to def test_with_belongs_to_and_has_many_with_contains reader = Authorization::Reader::DSLReader.new - reader.parse %{ + reader.parse %( authorization do role :test_role do has_permission_on :test_attrs, :to => :read do @@ -144,18 +143,18 @@ def test_with_belongs_to_and_has_many_with_contains end end end - } + ) Authorization::Engine.instance(reader) test_attr_1 = TestAttr.create! test_model_1 = TestModel.create! test_model_1.test_attrs.create! - user = MockUser.new(:test_role, :test_attr_value => test_model_1.test_attrs.first.id ) - assert_equal 1, TestAttr.with_permissions_to( :read, :context => :test_attrs, :user => user ).length - assert_equal 1, TestAttr.with_permissions_to( :read, :user => user ).length + user = MockUser.new(:test_role, test_attr_value: test_model_1.test_attrs.first.id) + assert_equal 1, TestAttr.with_permissions_to(:read, context: :test_attrs, user: user).length + assert_equal 1, TestAttr.with_permissions_to(:read, user: user).length assert_raises Authorization::NotAuthorized do - TestAttr.with_permissions_to( :update_test_attrs, :user => user ) + TestAttr.with_permissions_to(:update_test_attrs, user: user) end TestAttr.delete_all TestModel.delete_all @@ -163,7 +162,7 @@ def test_with_belongs_to_and_has_many_with_contains def test_with_nested_has_many reader = Authorization::Reader::DSLReader.new - reader.parse %{ + reader.parse %( authorization do role :test_role do has_permission_on :companies, :to => :read do @@ -171,20 +170,20 @@ def test_with_nested_has_many end end end - } + ) Authorization::Engine.instance(reader) allowed_company = Company.create! - allowed_company.branches.create!.test_attrs.create!(:attr => 1) - allowed_company.branches.create!.test_attrs.create!(:attr => 2) + allowed_company.branches.create!.test_attrs.create!(attr: 1) + allowed_company.branches.create!.test_attrs.create!(attr: 2) prohibited_company = Company.create! - prohibited_company.branches.create!.test_attrs.create!(:attr => 3) + prohibited_company.branches.create!.test_attrs.create!(attr: 3) - user = MockUser.new(:test_role, :test_attr_value => 1) - prohibited_user = MockUser.new(:test_role, :test_attr_value => 4) - assert_equal 1, Company.with_permissions_to(:read, :user => user).length - assert_equal 0, Company.with_permissions_to(:read, :user => prohibited_user).length + user = MockUser.new(:test_role, test_attr_value: 1) + prohibited_user = MockUser.new(:test_role, test_attr_value: 4) + assert_equal 1, Company.with_permissions_to(:read, user: user).length + assert_equal 0, Company.with_permissions_to(:read, user: prohibited_user).length Company.delete_all Branch.delete_all @@ -193,7 +192,7 @@ def test_with_nested_has_many def test_with_nested_has_many_through reader = Authorization::Reader::DSLReader.new - reader.parse %{ + reader.parse %( authorization do role :test_role do has_permission_on :test_models, :to => :read do @@ -201,23 +200,23 @@ def test_with_nested_has_many_through end end end - } + ) Authorization::Engine.instance(reader) TestModel.delete_all TestAttrThrough.delete_all TestAttr.delete_all allowed_model = TestModel.create! - allowed_model.test_attrs.create!(:attr => 1).test_attr_throughs.create! - allowed_model.test_attrs.create!(:attr => 2).test_attr_throughs.create! + allowed_model.test_attrs.create!(attr: 1).test_attr_throughs.create! + allowed_model.test_attrs.create!(attr: 2).test_attr_throughs.create! prohibited_model = TestModel.create! - prohibited_model.test_attrs.create!(:attr => 3).test_attr_throughs.create! + prohibited_model.test_attrs.create!(attr: 3).test_attr_throughs.create! - user = MockUser.new(:test_role, :test_attr_value => 1) - prohibited_user = MockUser.new(:test_role, :test_attr_value => 4) - assert_equal 1, TestModel.with_permissions_to(:read, :user => user).length - assert_equal 0, TestModel.with_permissions_to(:read, :user => prohibited_user).length + user = MockUser.new(:test_role, test_attr_value: 1) + prohibited_user = MockUser.new(:test_role, test_attr_value: 4) + assert_equal 1, TestModel.with_permissions_to(:read, user: user).length + assert_equal 0, TestModel.with_permissions_to(:read, user: prohibited_user).length TestModel.delete_all TestAttrThrough.delete_all @@ -226,7 +225,7 @@ def test_with_nested_has_many_through def test_with_is reader = Authorization::Reader::DSLReader.new - reader.parse %{ + reader.parse %( authorization do role :test_role do has_permission_on :test_models, :to => :read do @@ -234,25 +233,25 @@ def test_with_is end end end - } + ) Authorization::Engine.instance(reader) test_model_1 = TestModel.create! TestModel.create! - user = MockUser.new(:test_role, :test_attr_value => test_model_1.id) + user = MockUser.new(:test_role, test_attr_value: test_model_1.id) assert_equal 1, TestModel.with_permissions_to(:read, - :context => :test_models, :user => user).length - assert_equal 1, TestModel.with_permissions_to(:read, :user => user).length + context: :test_models, user: user).length + assert_equal 1, TestModel.with_permissions_to(:read, user: user).length assert_raises Authorization::NotAuthorized do - TestModel.with_permissions_to(:update_test_models, :user => user) + TestModel.with_permissions_to(:update_test_models, user: user) end TestModel.delete_all end def test_named_scope_on_proxy reader = Authorization::Reader::DSLReader.new - reader.parse %{ + reader.parse %( authorization do role :test_role do has_permission_on :test_attrs, :to => :read do @@ -260,7 +259,7 @@ def test_named_scope_on_proxy end end end - } + ) Authorization::Engine.instance(reader) test_model_1 = TestModel.create! @@ -268,15 +267,15 @@ def test_named_scope_on_proxy test_model_1.test_attrs.create! TestAttr.create! - user = MockUser.new(:test_role, :test_attr_value => test_attr_1.id) - assert_equal 1, test_model_1.test_attrs.with_permissions_to(:read, :user => user).length + user = MockUser.new(:test_role, test_attr_value: test_attr_1.id) + assert_equal 1, test_model_1.test_attrs.with_permissions_to(:read, user: user).length TestModel.delete_all TestAttr.delete_all end def test_named_scope_on_named_scope reader = Authorization::Reader::DSLReader.new - reader.parse %{ + reader.parse %( authorization do role :test_role do has_permission_on :test_models, :to => :read do @@ -287,26 +286,26 @@ def test_named_scope_on_named_scope end end end - } + ) Authorization::Engine.instance(reader) country = Country.create! - model_1 = TestModel.create!(:test_attr_through_id => 1, :content => "Content") + model_1 = TestModel.create!(test_attr_through_id: 1, content: 'Content') country.test_models << model_1 - TestModel.create!(:test_attr_through_id => 1) - TestModel.create!(:test_attr_through_id => 2, :content => "Content") + TestModel.create!(test_attr_through_id: 1) + TestModel.create!(test_attr_through_id: 2, content: 'Content') user = MockUser.new(:test_role) - # TODO implement query_count for Rails 3 + # TODO: implement query_count for Rails 3 TestModel.query_count = 0 - assert_equal 2, TestModel.with_permissions_to(:read, :user => user).length + assert_equal 2, TestModel.with_permissions_to(:read, user: user).length TestModel.query_count = 0 - assert_equal 1, TestModel.with_content.with_permissions_to(:read, :user => user).length + assert_equal 1, TestModel.with_content.with_permissions_to(:read, user: user).length TestModel.query_count = 0 - assert_equal 1, country.test_models.with_permissions_to(:read, :user => user).length + assert_equal 1, country.test_models.with_permissions_to(:read, user: user).length TestModel.delete_all Country.delete_all @@ -314,7 +313,7 @@ def test_named_scope_on_named_scope def test_with_modified_context reader = Authorization::Reader::DSLReader.new - reader.parse %{ + reader.parse %( authorization do role :test_role do has_permission_on :companies, :to => :read do @@ -322,20 +321,20 @@ def test_with_modified_context end end end - } + ) Authorization::Engine.instance(reader) test_company = SmallCompany.create! - user = MockUser.new(:test_role, :test_company_id => test_company.id) + user = MockUser.new(:test_role, test_company_id: test_company.id) assert_equal 1, SmallCompany.with_permissions_to(:read, - :user => user).length + user: user).length SmallCompany.delete_all end def test_with_is_nil reader = Authorization::Reader::DSLReader.new - reader.parse %{ + reader.parse %( authorization do role :test_role do has_permission_on :test_models, :to => :read do @@ -348,22 +347,22 @@ def test_with_is_nil end end end - } + ) Authorization::Engine.instance(reader) test_model_1 = TestModel.create! - test_model_2 = TestModel.create! :content => "Content" + test_model_2 = TestModel.create! content: 'Content' assert_equal test_model_1, TestModel.with_permissions_to(:read, - :context => :test_models, :user => MockUser.new(:test_role)).first + context: :test_models, user: MockUser.new(:test_role)).first assert_equal test_model_2, TestModel.with_permissions_to(:read, - :context => :test_models, :user => MockUser.new(:test_role_not_nil)).first + context: :test_models, user: MockUser.new(:test_role_not_nil)).first TestModel.delete_all end def test_with_not_is reader = Authorization::Reader::DSLReader.new - reader.parse %{ + reader.parse %( authorization do role :test_role do has_permission_on :test_models, :to => :read do @@ -371,21 +370,21 @@ def test_with_not_is end end end - } + ) Authorization::Engine.instance(reader) TestModel.delete_all test_model_1 = TestModel.create! TestModel.create! - user = MockUser.new(:test_role, :test_attr_value => test_model_1.id) - assert_equal 1, TestModel.with_permissions_to(:read, :user => user).length + user = MockUser.new(:test_role, test_attr_value: test_model_1.id) + assert_equal 1, TestModel.with_permissions_to(:read, user: user).length TestModel.delete_all end def test_with_lt reader = Authorization::Reader::DSLReader.new - reader.parse %{ + reader.parse %( authorization do role :test_role do has_permission_on :test_models, :to => :read do @@ -393,25 +392,25 @@ def test_with_lt end end end - } + ) Authorization::Engine.instance(reader) test_model_1 = TestModel.create! TestModel.create! - user = MockUser.new(:test_role, :test_attr_value => test_model_1.id + 1) + user = MockUser.new(:test_role, test_attr_value: test_model_1.id + 1) assert_equal 1, TestModel.with_permissions_to(:read, - :context => :test_models, :user => user).length - assert_equal 1, TestModel.with_permissions_to(:read, :user => user).length + context: :test_models, user: user).length + assert_equal 1, TestModel.with_permissions_to(:read, user: user).length assert_raises Authorization::NotAuthorized do - TestModel.with_permissions_to(:update_test_models, :user => user) + TestModel.with_permissions_to(:update_test_models, user: user) end TestModel.delete_all end def test_with_lte reader = Authorization::Reader::DSLReader.new - reader.parse %{ + reader.parse %( authorization do role :test_role do has_permission_on :test_models, :to => :read do @@ -419,25 +418,25 @@ def test_with_lte end end end - } + ) Authorization::Engine.instance(reader) test_model_1 = TestModel.create! 2.times { TestModel.create! } - user = MockUser.new(:test_role, :test_attr_value => test_model_1.id + 1) + user = MockUser.new(:test_role, test_attr_value: test_model_1.id + 1) assert_equal 2, TestModel.with_permissions_to(:read, - :context => :test_models, :user => user).length - assert_equal 2, TestModel.with_permissions_to(:read, :user => user).length + context: :test_models, user: user).length + assert_equal 2, TestModel.with_permissions_to(:read, user: user).length assert_raises Authorization::NotAuthorized do - TestModel.with_permissions_to(:update_test_models, :user => user) + TestModel.with_permissions_to(:update_test_models, user: user) end TestModel.delete_all end def test_with_gt reader = Authorization::Reader::DSLReader.new - reader.parse %{ + reader.parse %( authorization do role :test_role do has_permission_on :test_models, :to => :read do @@ -445,25 +444,25 @@ def test_with_gt end end end - } + ) Authorization::Engine.instance(reader) TestModel.create! test_model_1 = TestModel.create! - user = MockUser.new(:test_role, :test_attr_value => test_model_1.id - 1) + user = MockUser.new(:test_role, test_attr_value: test_model_1.id - 1) assert_equal 1, TestModel.with_permissions_to(:read, - :context => :test_models, :user => user).length - assert_equal 1, TestModel.with_permissions_to(:read, :user => user).length + context: :test_models, user: user).length + assert_equal 1, TestModel.with_permissions_to(:read, user: user).length assert_raises Authorization::NotAuthorized do - TestModel.with_permissions_to(:update_test_models, :user => user) + TestModel.with_permissions_to(:update_test_models, user: user) end TestModel.delete_all end def test_with_gte reader = Authorization::Reader::DSLReader.new - reader.parse %{ + reader.parse %( authorization do role :test_role do has_permission_on :test_models, :to => :read do @@ -471,46 +470,46 @@ def test_with_gte end end end - } + ) Authorization::Engine.instance(reader) 2.times { TestModel.create! } test_model_1 = TestModel.create! - user = MockUser.new(:test_role, :test_attr_value => test_model_1.id - 1) + user = MockUser.new(:test_role, test_attr_value: test_model_1.id - 1) assert_equal 2, TestModel.with_permissions_to(:read, - :context => :test_models, :user => user).length - assert_equal 2, TestModel.with_permissions_to(:read, :user => user).length + context: :test_models, user: user).length + assert_equal 2, TestModel.with_permissions_to(:read, user: user).length assert_raises Authorization::NotAuthorized do - TestModel.with_permissions_to(:update_test_models, :user => user) + TestModel.with_permissions_to(:update_test_models, user: user) end TestModel.delete_all end def test_with_empty_obligations reader = Authorization::Reader::DSLReader.new - reader.parse %{ + reader.parse %( authorization do role :test_role do has_permission_on :test_models, :to => :read end end - } + ) Authorization::Engine.instance(reader) TestModel.create! user = MockUser.new(:test_role) - assert_equal 1, TestModel.with_permissions_to(:read, :user => user).length + assert_equal 1, TestModel.with_permissions_to(:read, user: user).length assert_raises Authorization::NotAuthorized do - TestModel.with_permissions_to(:update, :user => user) + TestModel.with_permissions_to(:update, user: user) end TestModel.delete_all end def test_multiple_obligations reader = Authorization::Reader::DSLReader.new - reader.parse %{ + reader.parse %( authorization do role :test_role do has_permission_on :test_models, :to => :read do @@ -521,49 +520,48 @@ def test_multiple_obligations end end end - } + ) Authorization::Engine.instance(reader) test_model_1 = TestModel.create! test_model_2 = TestModel.create! - user = MockUser.new(:test_role, :test_attr_value => test_model_1.id, - :test_attr_value_2 => test_model_2.id) - assert_equal 2, TestModel.with_permissions_to(:read, :user => user).length + user = MockUser.new(:test_role, test_attr_value: test_model_1.id, + test_attr_value_2: test_model_2.id) + assert_equal 2, TestModel.with_permissions_to(:read, user: user).length TestModel.delete_all end def test_multiple_roles reader = Authorization::Reader::DSLReader.new - reader.parse %{ + reader.parse %( authorization do role :test_role do has_permission_on :test_attrs, :to => :read do if_attribute :attr => [1,2] end end - role :test_role_2 do has_permission_on :test_attrs, :to => :read do if_attribute :attr => [2,3] end end end - } + ) Authorization::Engine.instance(reader) - TestAttr.create! :attr => 1 - TestAttr.create! :attr => 2 - TestAttr.create! :attr => 3 + TestAttr.create! attr: 1 + TestAttr.create! attr: 2 + TestAttr.create! attr: 3 user = MockUser.new(:test_role) - assert_equal 2, TestAttr.with_permissions_to(:read, :user => user).length + assert_equal 2, TestAttr.with_permissions_to(:read, user: user).length TestAttr.delete_all end def test_multiple_and_empty_obligations reader = Authorization::Reader::DSLReader.new - reader.parse %{ + reader.parse %( authorization do role :test_role do has_permission_on :test_models, :to => :read do @@ -572,20 +570,20 @@ def test_multiple_and_empty_obligations has_permission_on :test_models, :to => :read end end - } + ) Authorization::Engine.instance(reader) test_model_1 = TestModel.create! TestModel.create! - user = MockUser.new(:test_role, :test_attr_value => test_model_1.id) - assert_equal 2, TestModel.with_permissions_to(:read, :user => user).length + user = MockUser.new(:test_role, test_attr_value: test_model_1.id) + assert_equal 2, TestModel.with_permissions_to(:read, user: user).length TestModel.delete_all end def test_multiple_attributes reader = Authorization::Reader::DSLReader.new - reader.parse %{ + reader.parse %( authorization do role :test_role do has_permission_on :test_models, :to => :read do @@ -593,21 +591,21 @@ def test_multiple_attributes end end end - } + ) Authorization::Engine.instance(reader) - test_model_1 = TestModel.create! :content => 'bla' - TestModel.create! :content => 'bla' + test_model_1 = TestModel.create! content: 'bla' + TestModel.create! content: 'bla' TestModel.create! - user = MockUser.new(:test_role, :test_attr_value => test_model_1.id) - assert_equal 1, TestModel.with_permissions_to(:read, :user => user).length + user = MockUser.new(:test_role, test_attr_value: test_model_1.id) + assert_equal 1, TestModel.with_permissions_to(:read, user: user).length TestModel.delete_all end def test_multiple_belongs_to reader = Authorization::Reader::DSLReader.new - reader.parse %{ + reader.parse %( authorization do role :test_role do has_permission_on :test_attrs, :to => :read do @@ -616,19 +614,19 @@ def test_multiple_belongs_to end end end - } + ) Authorization::Engine.instance(reader) - test_attr_1 = TestAttr.create! :test_model_id => 1, :test_another_model_id => 2 + test_attr_1 = TestAttr.create! test_model_id: 1, test_another_model_id: 2 - user = MockUser.new(:test_role, :id => 1) - assert_equal 1, TestAttr.with_permissions_to(:read, :user => user).length + user = MockUser.new(:test_role, id: 1) + assert_equal 1, TestAttr.with_permissions_to(:read, user: user).length TestAttr.delete_all end def test_with_is_and_priv_hierarchy reader = Authorization::Reader::DSLReader.new - reader.parse %{ + reader.parse %( privileges do privilege :read do includes :list, :show @@ -641,23 +639,23 @@ def test_with_is_and_priv_hierarchy end end end - } + ) Authorization::Engine.instance(reader) test_model_1 = TestModel.create! TestModel.create! - user = MockUser.new(:test_role, :test_attr_value => test_model_1.id) + user = MockUser.new(:test_role, test_attr_value: test_model_1.id) assert_equal 1, TestModel.with_permissions_to(:list, - :context => :test_models, :user => user).length - assert_equal 1, TestModel.with_permissions_to(:list, :user => user).length + context: :test_models, user: user).length + assert_equal 1, TestModel.with_permissions_to(:list, user: user).length TestModel.delete_all end def test_with_is_and_belongs_to reader = Authorization::Reader::DSLReader.new - reader.parse %{ + reader.parse %( authorization do role :test_role do has_permission_on :test_attrs, :to => :read do @@ -665,16 +663,16 @@ def test_with_is_and_belongs_to end end end - } + ) Authorization::Engine.instance(reader) test_model_1 = TestModel.create! test_model_1.test_attrs.create! TestModel.create!.test_attrs.create! - user = MockUser.new(:test_role, :test_model => test_model_1) + user = MockUser.new(:test_role, test_model: test_model_1) assert_equal 1, TestAttr.with_permissions_to(:read, - :context => :test_attrs, :user => user).length + context: :test_attrs, user: user).length TestModel.delete_all TestAttr.delete_all @@ -682,7 +680,7 @@ def test_with_is_and_belongs_to def test_with_deep_attribute reader = Authorization::Reader::DSLReader.new - reader.parse %{ + reader.parse %( authorization do role :test_role do has_permission_on :test_attrs, :to => :read do @@ -690,16 +688,16 @@ def test_with_deep_attribute end end end - } + ) Authorization::Engine.instance(reader) test_model_1 = TestModel.create! test_model_1.test_attrs.create! TestModel.create!.test_attrs.create! - user = MockUser.new(:test_role, :test_model_id => test_model_1.id) + user = MockUser.new(:test_role, test_model_id: test_model_1.id) assert_equal 1, TestAttr.with_permissions_to(:read, - :context => :test_attrs, :user => user).length + context: :test_attrs, user: user).length TestModel.delete_all TestAttr.delete_all @@ -707,7 +705,7 @@ def test_with_deep_attribute def test_with_multiple_conditions reader = Authorization::Reader::DSLReader.new - reader.parse %{ + reader.parse %( authorization do role :test_role do has_permission_on :test_attrs, :to => :read do @@ -716,16 +714,16 @@ def test_with_multiple_conditions end end end - } + ) Authorization::Engine.instance(reader) - test_model_1 = TestModel.create!(content: "pickle") + test_model_1 = TestModel.create!(content: 'pickle') test_model_1.test_attrs.create! TestModel.create!.test_attrs.create! - user = MockUser.new(:test_role, :test_model_id => test_model_1.id) + user = MockUser.new(:test_role, test_model_id: test_model_1.id) assert_equal 1, TestAttr.with_permissions_to(:read, - :context => :test_attrs, :user => user).length + context: :test_attrs, user: user).length TestModel.delete_all TestAttr.delete_all @@ -733,7 +731,7 @@ def test_with_multiple_conditions def test_with_anded_rules reader = Authorization::Reader::DSLReader.new - reader.parse %{ + reader.parse %( authorization do role :test_role do has_permission_on :test_attrs, :to => :read, :join_by => :and do @@ -742,17 +740,17 @@ def test_with_anded_rules end end end - } + ) Authorization::Engine.instance(reader) test_model_1 = TestModel.create! - test_model_1.test_attrs.create!(:attr => 1) - TestModel.create!.test_attrs.create!(:attr => 1) + test_model_1.test_attrs.create!(attr: 1) + TestModel.create!.test_attrs.create!(attr: 1) TestModel.create!.test_attrs.create! - user = MockUser.new(:test_role, :test_model => test_model_1) + user = MockUser.new(:test_role, test_model: test_model_1) assert_equal 1, TestAttr.with_permissions_to(:read, - :context => :test_attrs, :user => user).length + context: :test_attrs, user: user).length TestModel.delete_all TestAttr.delete_all @@ -760,7 +758,7 @@ def test_with_anded_rules def test_with_contains reader = Authorization::Reader::DSLReader.new - reader.parse %{ + reader.parse %( authorization do role :test_role do has_permission_on :test_models, :to => :read do @@ -768,7 +766,7 @@ def test_with_contains end end end - } + ) Authorization::Engine.instance(reader) test_model_1 = TestModel.create! @@ -778,9 +776,9 @@ def test_with_contains test_model_2.test_attrs.create! user = MockUser.new(:test_role, - :id => test_model_1.test_attrs.first.id) - assert_equal 1, TestModel.with_permissions_to(:read, :user => user).length - assert_equal 1, TestModel.with_permissions_to(:read, :user => user).where(:id => test_model_1.id).length + id: test_model_1.test_attrs.first.id) + assert_equal 1, TestModel.with_permissions_to(:read, user: user).length + assert_equal 1, TestModel.with_permissions_to(:read, user: user).where(id: test_model_1.id).length TestModel.delete_all TestAttr.delete_all @@ -788,7 +786,7 @@ def test_with_contains def test_with_does_not_contain reader = Authorization::Reader::DSLReader.new - reader.parse %{ + reader.parse %( authorization do role :test_role do has_permission_on :test_models, :to => :read do @@ -796,7 +794,7 @@ def test_with_does_not_contain end end end - } + ) Authorization::Engine.instance(reader) test_model_1 = TestModel.create! @@ -805,8 +803,8 @@ def test_with_does_not_contain test_model_2.test_attrs.create! user = MockUser.new(:test_role, - :id => test_model_1.test_attrs.first.id) - assert_equal 1, TestModel.with_permissions_to(:read, :user => user).length + id: test_model_1.test_attrs.first.id) + assert_equal 1, TestModel.with_permissions_to(:read, user: user).length TestModel.delete_all TestAttr.delete_all @@ -814,7 +812,7 @@ def test_with_does_not_contain def test_with_contains_conditions reader = Authorization::Reader::DSLReader.new - reader.parse %{ + reader.parse %( authorization do role :test_role do has_permission_on :test_models, :to => :read do @@ -822,34 +820,34 @@ def test_with_contains_conditions end end end - } + ) Authorization::Engine.instance(reader) test_model_1 = TestModel.create! test_model_2 = TestModel.create! test_model_1.test_attrs_with_attr.create! - test_model_1.test_attrs.create!(:attr => 2) + test_model_1.test_attrs.create!(attr: 2) test_model_2.test_attrs_with_attr.create! - test_model_2.test_attrs.create!(:attr => 2) + test_model_2.test_attrs.create!(attr: 2) - #assert_equal 1, test_model_1.test_attrs_with_attr.length + # assert_equal 1, test_model_1.test_attrs_with_attr.length user = MockUser.new(:test_role, - :id => test_model_1.test_attrs.first.id) - assert_equal 1, TestModel.with_permissions_to(:read, :user => user).length + id: test_model_1.test_attrs.first.id) + assert_equal 1, TestModel.with_permissions_to(:read, user: user).length user = MockUser.new(:test_role, - :id => test_model_1.test_attrs.last.id) - assert_equal 0, TestModel.with_permissions_to(:read, :user => user).length + id: test_model_1.test_attrs.last.id) + assert_equal 0, TestModel.with_permissions_to(:read, user: user).length TestModel.delete_all TestAttr.delete_all end - # TODO fails in Rails 3 because TestModel.scoped.joins(:test_attr_throughs_with_attr) + # TODO: fails in Rails 3 because TestModel.scoped.joins(:test_attr_throughs_with_attr) # does not work - if Rails.version < "3" + if Rails.version < '3' def test_with_contains_through_conditions reader = Authorization::Reader::DSLReader.new - reader.parse %{ + reader.parse %( authorization do role :test_role do has_permission_on :test_models, :to => :read do @@ -857,23 +855,23 @@ def test_with_contains_through_conditions end end end - } + ) Authorization::Engine.instance(reader) test_model_1 = TestModel.create! test_model_2 = TestModel.create! - test_model_1.test_attrs.create!(:attr => 1).test_attr_throughs.create! - test_model_1.test_attrs.create!(:attr => 2).test_attr_throughs.create! - test_model_2.test_attrs.create!(:attr => 1).test_attr_throughs.create! - test_model_2.test_attrs.create!(:attr => 2).test_attr_throughs.create! + test_model_1.test_attrs.create!(attr: 1).test_attr_throughs.create! + test_model_1.test_attrs.create!(attr: 2).test_attr_throughs.create! + test_model_2.test_attrs.create!(attr: 1).test_attr_throughs.create! + test_model_2.test_attrs.create!(attr: 2).test_attr_throughs.create! - #assert_equal 1, test_model_1.test_attrs_with_attr.length + # assert_equal 1, test_model_1.test_attrs_with_attr.length user = MockUser.new(:test_role, - :id => test_model_1.test_attr_throughs.first.id) - assert_equal 1, TestModel.with_permissions_to(:read, :user => user).length + id: test_model_1.test_attr_throughs.first.id) + assert_equal 1, TestModel.with_permissions_to(:read, user: user).length user = MockUser.new(:test_role, - :id => test_model_1.test_attr_throughs.last.id) - assert_equal 0, TestModel.with_permissions_to(:read, :user => user).length + id: test_model_1.test_attr_throughs.last.id) + assert_equal 0, TestModel.with_permissions_to(:read, user: user).length TestModel.delete_all TestAttrThrough.delete_all @@ -881,10 +879,10 @@ def test_with_contains_through_conditions end end - if Rails.version < "3" + if Rails.version < '3' def test_with_contains_habtm reader = Authorization::Reader::DSLReader.new - reader.parse %{ + reader.parse %( authorization do role :test_role do has_permission_on :test_models, :to => :read do @@ -892,21 +890,21 @@ def test_with_contains_habtm end end end - } + ) Authorization::Engine.instance(reader) - # TODO habtm currently not working in Rails 3 + # TODO: habtm currently not working in Rails 3 test_model_1 = TestModel.create! test_model_2 = TestModel.create! test_attr_through_1 = TestAttrThrough.create! test_attr_through_2 = TestAttrThrough.create! - TestAttr.create! :test_model_id => test_model_1.id, :test_attr_through_id => test_attr_through_1.id - TestAttr.create! :test_model_id => test_model_2.id, :test_attr_through_id => test_attr_through_2.id + TestAttr.create! test_model_id: test_model_1.id, test_attr_through_id: test_attr_through_1.id + TestAttr.create! test_model_id: test_model_2.id, test_attr_through_id: test_attr_through_2.id user = MockUser.new(:test_role, - :test_attr_through_id => test_model_1.test_attr_throughs_habtm.first.id) - assert_equal 1, TestModel.with_permissions_to(:read, :user => user).length - assert_equal test_model_1, TestModel.with_permissions_to(:read, :user => user)[0] + test_attr_through_id: test_model_1.test_attr_throughs_habtm.first.id) + assert_equal 1, TestModel.with_permissions_to(:read, user: user).length + assert_equal test_model_1, TestModel.with_permissions_to(:read, user: user)[0] TestModel.delete_all TestAttrThrough.delete_all @@ -916,7 +914,7 @@ def test_with_contains_habtm def test_with_contains_through_primary_key reader = Authorization::Reader::DSLReader.new - reader.parse %{ + reader.parse %( authorization do role :test_role do has_permission_on :test_models, :to => :read do @@ -924,7 +922,7 @@ def test_with_contains_through_primary_key end end end - } + ) Authorization::Engine.instance(reader) TestModel.delete_all TestAttrThrough.delete_all @@ -932,23 +930,22 @@ def test_with_contains_through_primary_key test_attr_through_1 = TestAttrThrough.create! test_item = NWayJoinItem.create! - test_model_1 = TestModel.create!(:test_attr_through_id => test_attr_through_1.id) - test_attr_1 = TestAttr.create!(:test_attr_through_id => test_attr_through_1.id, - :n_way_join_item_id => test_item.id) + test_model_1 = TestModel.create!(test_attr_through_id: test_attr_through_1.id) + test_attr_1 = TestAttr.create!(test_attr_through_id: test_attr_through_1.id, + n_way_join_item_id: test_item.id) user = MockUser.new(:test_role, - :id => test_attr_through_1.id) - assert_equal 1, TestModel.with_permissions_to(:read, :user => user).length + id: test_attr_through_1.id) + assert_equal 1, TestModel.with_permissions_to(:read, user: user).length TestModel.delete_all TestAttrThrough.delete_all TestAttr.delete_all end - def test_with_intersects_with reader = Authorization::Reader::DSLReader.new - reader.parse %{ + reader.parse %( authorization do role :test_role do has_permission_on :test_models, :to => :read do @@ -956,7 +953,7 @@ def test_with_intersects_with end end end - } + ) Authorization::Engine.instance(reader) test_model_1 = TestModel.create! @@ -967,12 +964,12 @@ def test_with_intersects_with test_model_2.test_attrs.create! user = MockUser.new(:test_role, - :test_attrs => [test_model_1.test_attrs.first, TestAttr.create!]) - assert_equal 1, TestModel.with_permissions_to(:read, :user => user).length + test_attrs: [test_model_1.test_attrs.first, TestAttr.create!]) + assert_equal 1, TestModel.with_permissions_to(:read, user: user).length user = MockUser.new(:test_role, - :test_attrs => [TestAttr.create!]) - assert_equal 0, TestModel.with_permissions_to(:read, :user => user).length + test_attrs: [TestAttr.create!]) + assert_equal 0, TestModel.with_permissions_to(:read, user: user).length TestModel.delete_all TestAttr.delete_all @@ -980,7 +977,7 @@ def test_with_intersects_with def test_with_is_and_has_one reader = Authorization::Reader::DSLReader.new - reader.parse %{ + reader.parse %( authorization do :test_attr_has_one role :test_role do has_permission_on :test_models, :to => :read do @@ -988,16 +985,16 @@ def test_with_is_and_has_one end end end - } + ) Authorization::Engine.instance(reader) test_model_1 = TestModel.create! test_attr_1 = test_model_1.test_attrs.create! TestModel.create!.test_attrs.create! - user = MockUser.new(:test_role, :test_attr => test_attr_1) + user = MockUser.new(:test_role, test_attr: test_attr_1) assert_equal 1, TestModel.with_permissions_to(:read, - :context => :test_models, :user => user).length + context: :test_models, user: user).length TestModel.delete_all TestAttr.delete_all @@ -1005,7 +1002,7 @@ def test_with_is_and_has_one def test_with_is_in reader = Authorization::Reader::DSLReader.new - reader.parse %{ + reader.parse %( authorization do role :test_role do has_permission_on :test_attrs, :to => :read do @@ -1013,7 +1010,7 @@ def test_with_is_in end end end - } + ) Authorization::Engine.instance(reader) test_model_1 = TestModel.create! @@ -1021,10 +1018,10 @@ def test_with_is_in test_model_1.test_attrs.create! TestModel.create!.test_attrs.create! - user = MockUser.new(:test_role, :test_model => test_model_1, - :test_model_2 => test_model_2) + user = MockUser.new(:test_role, test_model: test_model_1, + test_model_2: test_model_2) assert_equal 1, TestAttr.with_permissions_to(:read, - :context => :test_attrs, :user => user).length + context: :test_attrs, user: user).length TestModel.delete_all TestAttr.delete_all @@ -1032,7 +1029,7 @@ def test_with_is_in def test_with_not_is_in reader = Authorization::Reader::DSLReader.new - reader.parse %{ + reader.parse %( authorization do role :test_role do has_permission_on :test_attrs, :to => :read do @@ -1040,7 +1037,7 @@ def test_with_not_is_in end end end - } + ) Authorization::Engine.instance(reader) TestModel.delete_all TestAttr.delete_all @@ -1050,10 +1047,10 @@ def test_with_not_is_in test_model_1.test_attrs.create! TestModel.create!.test_attrs.create! - user = MockUser.new(:test_role, :test_model => test_model_1, - :test_model_2 => test_model_2) + user = MockUser.new(:test_role, test_model: test_model_1, + test_model_2: test_model_2) assert_equal 1, TestAttr.with_permissions_to(:read, - :context => :test_attrs, :user => user).length + context: :test_attrs, user: user).length TestModel.delete_all TestAttr.delete_all @@ -1061,7 +1058,7 @@ def test_with_not_is_in def test_with_if_permitted_to reader = Authorization::Reader::DSLReader.new - reader.parse %{ + reader.parse %( authorization do role :test_role do has_permission_on :test_models, :to => :read do @@ -1072,21 +1069,21 @@ def test_with_if_permitted_to end end end - } + ) Authorization::Engine.instance(reader) test_model_1 = TestModel.create! test_attr_1 = test_model_1.test_attrs.create! - user = MockUser.new(:test_role, :id => test_attr_1.id) - assert_equal 1, TestAttr.with_permissions_to(:read, :user => user).length + user = MockUser.new(:test_role, id: test_attr_1.id) + assert_equal 1, TestAttr.with_permissions_to(:read, user: user).length TestModel.delete_all TestAttr.delete_all end def test_with_anded_if_permitted_to reader = Authorization::Reader::DSLReader.new - reader.parse %{ + reader.parse %( authorization do role :base_role do has_permission_on :test_attrs, :to => :read, :join_by => :and do @@ -1107,25 +1104,25 @@ def test_with_anded_if_permitted_to end end end - } + ) Authorization::Engine.instance(reader) - test_model_1 = TestModel.create!(:content => "first test") - test_model_1.test_attrs.create!(:attr => 1) - test_model_for_second_role = TestModel.create!(:country_id => 2) - test_model_for_second_role.test_attrs.create!(:attr => 1) - test_model_for_second_role.test_attrs.create!(:attr => 2) + test_model_1 = TestModel.create!(content: 'first test') + test_model_1.test_attrs.create!(attr: 1) + test_model_for_second_role = TestModel.create!(country_id: 2) + test_model_for_second_role.test_attrs.create!(attr: 1) + test_model_for_second_role.test_attrs.create!(attr: 2) user = MockUser.new(:first_role) - assert Authorization::Engine.instance.permit?(:read, :object => test_model_1.test_attrs.first, :user => user) - assert_equal 1, TestAttr.with_permissions_to(:read, :user => user).length + assert Authorization::Engine.instance.permit?(:read, object: test_model_1.test_attrs.first, user: user) + assert_equal 1, TestAttr.with_permissions_to(:read, user: user).length user_with_both_roles = MockUser.new(:first_role, :second_role) - assert Authorization::Engine.instance.permit?(:read, :object => test_model_1.test_attrs.first, :user => user_with_both_roles) - assert Authorization::Engine.instance.permit?(:read, :object => test_model_for_second_role.test_attrs.first, :user => user_with_both_roles) - #p Authorization::Engine.instance.obligations(:read, :user => user_with_both_roles, :context => :test_attrs) + assert Authorization::Engine.instance.permit?(:read, object: test_model_1.test_attrs.first, user: user_with_both_roles) + assert Authorization::Engine.instance.permit?(:read, object: test_model_for_second_role.test_attrs.first, user: user_with_both_roles) + # p Authorization::Engine.instance.obligations(:read, :user => user_with_both_roles, :context => :test_attrs) - assert_equal 2, TestAttr.with_permissions_to(:read, :user => user_with_both_roles).references(:test_attrs, :test_models).length + assert_equal 2, TestAttr.with_permissions_to(:read, user: user_with_both_roles).references(:test_attrs, :test_models).length TestModel.delete_all TestAttr.delete_all @@ -1133,7 +1130,7 @@ def test_with_anded_if_permitted_to def test_with_if_permitted_to_with_no_child_permissions reader = Authorization::Reader::DSLReader.new - reader.parse %{ + reader.parse %( authorization do role :another_role do has_permission_on :test_models, :to => :read do @@ -1152,20 +1149,20 @@ def test_with_if_permitted_to_with_no_child_permissions end end end - } + ) Authorization::Engine.instance(reader) test_model_1 = TestModel.create! test_attr_1 = test_model_1.test_attrs.create! - user = MockUser.new(:only_permitted_to, :another_role, :id => test_attr_1.id) - also_allowed_user = MockUser.new(:additional_if_attribute, :id => test_attr_1.id) - non_allowed_user = MockUser.new(:only_permitted_to, :id => test_attr_1.id) + user = MockUser.new(:only_permitted_to, :another_role, id: test_attr_1.id) + also_allowed_user = MockUser.new(:additional_if_attribute, id: test_attr_1.id) + non_allowed_user = MockUser.new(:only_permitted_to, id: test_attr_1.id) - assert_equal 1, TestAttr.with_permissions_to(:read, :user => user).length - assert_equal 1, TestAttr.with_permissions_to(:read, :user => also_allowed_user).length + assert_equal 1, TestAttr.with_permissions_to(:read, user: user).length + assert_equal 1, TestAttr.with_permissions_to(:read, user: also_allowed_user).length assert_raises Authorization::NotAuthorized do - TestAttr.with_permissions_to(:read, :user => non_allowed_user).find(:all) + TestAttr.with_permissions_to(:read, user: non_allowed_user).find(:all) end TestModel.delete_all @@ -1174,7 +1171,7 @@ def test_with_if_permitted_to_with_no_child_permissions def test_with_if_permitted_to_with_context_from_model reader = Authorization::Reader::DSLReader.new - reader.parse %{ + reader.parse %( authorization do role :test_role do has_permission_on :test_models, :to => :read do @@ -1185,24 +1182,24 @@ def test_with_if_permitted_to_with_context_from_model end end end - } + ) Authorization::Engine.instance(reader) test_model_1 = TestModel.create! test_attr_1 = test_model_1.test_another_attrs.create! - user = MockUser.new(:test_role, :id => test_attr_1.id) - non_allowed_user = MockUser.new(:test_role, :id => 111) + user = MockUser.new(:test_role, id: test_attr_1.id) + non_allowed_user = MockUser.new(:test_role, id: 111) - assert_equal 1, TestAttr.with_permissions_to(:read, :user => user).length - assert_equal 0, TestAttr.with_permissions_to(:read, :user => non_allowed_user).length + assert_equal 1, TestAttr.with_permissions_to(:read, user: user).length + assert_equal 0, TestAttr.with_permissions_to(:read, user: non_allowed_user).length TestModel.delete_all TestAttr.delete_all end def test_with_has_many_if_permitted_to reader = Authorization::Reader::DSLReader.new - reader.parse %{ + reader.parse %( authorization do role :test_role do has_permission_on :test_models, :to => :read do @@ -1213,23 +1210,23 @@ def test_with_has_many_if_permitted_to end end end - } + ) Authorization::Engine.instance(reader) test_model_1 = TestModel.create! - test_attr_1 = test_model_1.test_attrs.create!(:attr => 111) + test_attr_1 = test_model_1.test_attrs.create!(attr: 111) - user = MockUser.new(:test_role, :id => test_attr_1.attr) - non_allowed_user = MockUser.new(:test_role, :id => 333) - assert_equal 1, TestModel.with_permissions_to(:read, :user => user).length - assert_equal 0, TestModel.with_permissions_to(:read, :user => non_allowed_user).length + user = MockUser.new(:test_role, id: test_attr_1.attr) + non_allowed_user = MockUser.new(:test_role, id: 333) + assert_equal 1, TestModel.with_permissions_to(:read, user: user).length + assert_equal 0, TestModel.with_permissions_to(:read, user: non_allowed_user).length TestModel.delete_all TestAttr.delete_all end def test_with_deep_has_many_if_permitted_to reader = Authorization::Reader::DSLReader.new - reader.parse %{ + reader.parse %( authorization do role :test_role do has_permission_on :branches, :to => :read do @@ -1240,17 +1237,17 @@ def test_with_deep_has_many_if_permitted_to end end end - } + ) Authorization::Engine.instance(reader) readable_company = Company.create! - readable_company.test_attrs.create!(:branch => Branch.create!(:name => "A Branch")) + readable_company.test_attrs.create!(branch: Branch.create!(name: 'A Branch')) forbidden_company = Company.create! - forbidden_company.test_attrs.create!(:branch => Branch.create!(:name => "Different Branch")) + forbidden_company.test_attrs.create!(branch: Branch.create!(name: 'Different Branch')) user = MockUser.new(:test_role) - assert_equal 1, Company.with_permissions_to(:read, :user => user).length + assert_equal 1, Company.with_permissions_to(:read, user: user).length Company.delete_all Branch.delete_all TestAttr.delete_all @@ -1258,7 +1255,7 @@ def test_with_deep_has_many_if_permitted_to def test_with_if_permitted_to_and_empty_obligations reader = Authorization::Reader::DSLReader.new - reader.parse %{ + reader.parse %( authorization do role :test_role do has_permission_on :test_models, :to => :read @@ -1267,21 +1264,21 @@ def test_with_if_permitted_to_and_empty_obligations end end end - } + ) Authorization::Engine.instance(reader) test_model_1 = TestModel.create! test_attr_1 = test_model_1.test_attrs.create! user = MockUser.new(:test_role) - assert_equal 1, TestAttr.with_permissions_to(:read, :user => user).length + assert_equal 1, TestAttr.with_permissions_to(:read, user: user).length TestModel.delete_all TestAttr.delete_all end def test_with_if_permitted_to_nil reader = Authorization::Reader::DSLReader.new - reader.parse %{ + reader.parse %( authorization do role :test_role do has_permission_on :test_models, :to => :read do @@ -1292,19 +1289,19 @@ def test_with_if_permitted_to_nil end end end - } + ) Authorization::Engine.instance(reader) test_attr_1 = TestAttr.create! - user = MockUser.new(:test_role, :id => test_attr_1.id) - assert_equal 0, TestAttr.with_permissions_to(:read, :user => user).length + user = MockUser.new(:test_role, id: test_attr_1.id) + assert_equal 0, TestAttr.with_permissions_to(:read, user: user).length TestAttr.delete_all end def test_with_if_permitted_to_self reader = Authorization::Reader::DSLReader.new - reader.parse %{ + reader.parse %( authorization do role :test_role do has_permission_on :test_models, :to => :read do @@ -1315,22 +1312,22 @@ def test_with_if_permitted_to_self end end end - } + ) Authorization::Engine.instance(reader) test_model_1 = TestModel.create! test_attr_1 = test_model_1.test_attrs.create! test_attr_2 = TestAttr.create! - user = MockUser.new(:test_role, :id => test_attr_1.id) - assert_equal 1, TestModel.with_permissions_to(:update, :user => user).length + user = MockUser.new(:test_role, id: test_attr_1.id) + assert_equal 1, TestModel.with_permissions_to(:update, user: user).length TestAttr.delete_all TestModel.delete_all end def test_with_has_many_and_reoccuring_tables reader = Authorization::Reader::DSLReader.new - reader.parse %{ + reader.parse %( authorization do role :test_role do has_permission_on :test_attrs, :to => :read do @@ -1339,27 +1336,27 @@ def test_with_has_many_and_reoccuring_tables end end end - } + ) Authorization::Engine.instance(reader) test_attr_1 = TestAttr.create!( - :test_model => TestModel.create!(:content => 'test_1_1'), - :test_another_model => TestModel.create!(:content => 'test_1_2') - ) + test_model: TestModel.create!(content: 'test_1_1'), + test_another_model: TestModel.create!(content: 'test_1_2') + ) test_attr_2 = TestAttr.create!( - :test_model => TestModel.create!(:content => 'test_2_1'), - :test_another_model => TestModel.create!(:content => 'test_2_2') - ) + test_model: TestModel.create!(content: 'test_2_1'), + test_another_model: TestModel.create!(content: 'test_2_2') + ) user = MockUser.new(:test_role) - assert_equal 1, TestAttr.with_permissions_to(:read, :user => user).length + assert_equal 1, TestAttr.with_permissions_to(:read, user: user).length TestModel.delete_all TestAttr.delete_all end def test_with_ored_rules_and_reoccuring_tables reader = Authorization::Reader::DSLReader.new - reader.parse %{ + reader.parse %( authorization do role :test_role do has_permission_on :test_attrs, :to => :read do @@ -1372,21 +1369,21 @@ def test_with_ored_rules_and_reoccuring_tables end end end - } + ) Authorization::Engine.instance(reader) test_attr_1 = TestAttr.create!( - :test_model => TestModel.create!(:content => 'test_1_1'), - :test_another_model => TestModel.create!(:content => 'test_1_2') - ) + test_model: TestModel.create!(content: 'test_1_1'), + test_another_model: TestModel.create!(content: 'test_1_2') + ) test_attr_2 = TestAttr.create!( - :test_model => TestModel.create!(:content => 'test_2_1'), - :test_another_model => TestModel.create!(:content => 'test_2_2') - ) + test_model: TestModel.create!(content: 'test_2_1'), + test_another_model: TestModel.create!(content: 'test_2_2') + ) test_attr_2.test_model.test_attrs.create! - user = MockUser.new(:test_role, :test_attr => test_attr_2.test_model.test_attrs.last) - assert_equal 2, TestAttr.with_permissions_to(:read, :user => user).references(:test_attrs, :test_models, :test_models_test_attrs, :test_attrs_test_models).length + user = MockUser.new(:test_role, test_attr: test_attr_2.test_model.test_attrs.last) + assert_equal 2, TestAttr.with_permissions_to(:read, user: user).references(:test_attrs, :test_models, :test_models_test_attrs, :test_attrs_test_models).length TestModel.delete_all TestAttr.delete_all @@ -1394,7 +1391,7 @@ def test_with_ored_rules_and_reoccuring_tables def test_with_many_ored_rules_and_reoccuring_tables reader = Authorization::Reader::DSLReader.new - reader.parse %{ + reader.parse %( authorization do role :test_role do has_permission_on :test_attrs, :to => :read do @@ -1407,24 +1404,24 @@ def test_with_many_ored_rules_and_reoccuring_tables end end end - } + ) Authorization::Engine.instance(reader) - country = Country.create!(:name => 'country_1') + country = Country.create!(name: 'country_1') country.test_models.create! test_attr_1 = TestAttr.create!( - :branch => Branch.create!(:name => 'branch_1', - :company => Company.create!(:name => 'company_1', - :country => country)) - ) + branch: Branch.create!(name: 'branch_1', + company: Company.create!(name: 'company_1', + country: country)) + ) test_attr_2 = TestAttr.create!( - :company => Company.create!(:name => 'company_2', - :country => country) - ) + company: Company.create!(name: 'company_2', + country: country) + ) - user = MockUser.new(:test_role, :test_model => country.test_models.first) + user = MockUser.new(:test_role, test_model: country.test_models.first) - assert_equal 2, TestAttr.with_permissions_to(:read, :user => user).references(:test_attrs, :test_models, :test_models_countries).length + assert_equal 2, TestAttr.with_permissions_to(:read, user: user).references(:test_attrs, :test_models, :test_models_countries).length TestModel.delete_all TestAttr.delete_all @@ -1434,7 +1431,7 @@ def test_with_many_ored_rules_and_reoccuring_tables class ModelTest < Test::Unit::TestCase def test_permit_with_has_one_raises_no_name_error reader = Authorization::Reader::DSLReader.new - reader.parse %{ + reader.parse %( authorization do :test_attr_has_one role :test_role do has_permission_on :test_attrs, :to => :update do @@ -1442,16 +1439,16 @@ def test_permit_with_has_one_raises_no_name_error end end end - } + ) instance = Authorization::Engine.instance(reader) test_model = TestModel.create! test_attr = test_model.create_test_attr_has_one assert !test_attr.new_record? - user = MockUser.new(:test_role, :test_attr => test_attr) + user = MockUser.new(:test_role, test_attr: test_attr) - assert instance.permit?(:update, :user => user, :object => test_model.test_attr_has_one) + assert instance.permit?(:update, user: user, object: test_model.test_attr_has_one) TestModel.delete_all TestAttr.delete_all @@ -1459,7 +1456,7 @@ def test_permit_with_has_one_raises_no_name_error def test_model_security_write_allowed reader = Authorization::Reader::DSLReader.new - reader.parse %{ + reader.parse %( authorization do role :test_role do has_permission_on :test_model_security_models do @@ -1468,12 +1465,12 @@ def test_model_security_write_allowed end end end - } + ) Authorization::Engine.instance(reader) Authorization.current_user = MockUser.new(:test_role) assert(object = TestModelSecurityModel.create) - object.update_attributes(:attr_2 => 2) + object.update_attributes(attr_2: 2) object.reload assert_equal 2, object.attr_2 object.destroy @@ -1484,7 +1481,7 @@ def test_model_security_write_allowed def test_model_security_write_not_allowed_no_privilege reader = Authorization::Reader::DSLReader.new - reader.parse %{ + reader.parse %( authorization do role :test_role do has_permission_on :test_model_security_models do @@ -1495,7 +1492,7 @@ def test_model_security_write_not_allowed_no_privilege role :test_role_restricted do end end - } + ) Authorization::Engine.instance(reader) Authorization.current_user = MockUser.new(:test_role) @@ -1503,13 +1500,13 @@ def test_model_security_write_not_allowed_no_privilege Authorization.current_user = MockUser.new(:test_role_restricted) assert_raises Authorization::NotAuthorized do - object.update_attributes(:attr_2 => 2) + object.update_attributes(attr_2: 2) end end def test_model_security_write_not_allowed_wrong_attribute_value reader = Authorization::Reader::DSLReader.new - reader.parse %{ + reader.parse %( authorization do role :test_role_unrestricted do has_permission_on :test_model_security_models do @@ -1523,29 +1520,29 @@ def test_model_security_write_not_allowed_wrong_attribute_value end end end - } + ) Authorization::Engine.instance(reader) Authorization.current_user = MockUser.new(:test_role) assert(object = TestModelSecurityModel.create) assert_raises Authorization::AttributeAuthorizationError do - TestModelSecurityModel.create :attr => 2 + TestModelSecurityModel.create attr: 2 end object = TestModelSecurityModel.create assert_raises Authorization::AttributeAuthorizationError do - object.update_attributes(:attr => 2) + object.update_attributes(attr: 2) end object.reload - object.update_attributes(:attr_2 => 1) + object.update_attributes(attr_2: 1) assert_raises Authorization::AttributeAuthorizationError do - object.update_attributes(:attr => 2) + object.update_attributes(attr: 2) end end def test_model_security_with_and_without_find_restrictions reader = Authorization::Reader::DSLReader.new - reader.parse %{ + reader.parse %( authorization do role :test_role_unrestricted do has_permission_on :test_model_security_models do @@ -1559,12 +1556,12 @@ def test_model_security_with_and_without_find_restrictions end end end - } + ) Authorization::Engine.instance(reader) Authorization.current_user = MockUser.new(:test_role_unrestricted) - object = TestModelSecurityModel.create :attr => 2 - object_with_find = TestModelSecurityModelWithFind.create :attr => 2 + object = TestModelSecurityModel.create attr: 2 + object_with_find = TestModelSecurityModelWithFind.create attr: 2 Authorization.current_user = MockUser.new(:test_role) object.class.find(object.id) assert_raises Authorization::AttributeAuthorizationError do @@ -1574,7 +1571,7 @@ def test_model_security_with_and_without_find_restrictions def test_model_security_with_read_restrictions_and_exists reader = Authorization::Reader::DSLReader.new - reader.parse %{ + reader.parse %( authorization do role :test_role do has_permission_on :test_model_security_models do @@ -1583,22 +1580,22 @@ def test_model_security_with_read_restrictions_and_exists end end end - } + ) Authorization::Engine.instance(reader) test_attr = TestAttr.create - Authorization.current_user = MockUser.new(:test_role, :test_attr => test_attr) - object_with_find = TestModelSecurityModelWithFind.create :test_attr => test_attr + Authorization.current_user = MockUser.new(:test_role, test_attr: test_attr) + object_with_find = TestModelSecurityModelWithFind.create test_attr: test_attr object_with_find.class.find(object_with_find.id) assert_equal 1, test_attr.test_model_security_model_with_finds.length # Raises error since AR does not populate the object - #assert test_attr.test_model_security_model_with_finds.exists?(object_with_find) + # assert test_attr.test_model_security_model_with_finds.exists?(object_with_find) end def test_model_security_delete_unallowed reader = Authorization::Reader::DSLReader.new - reader.parse %{ + reader.parse %( authorization do role :test_role_unrestricted do has_permission_on :test_model_security_models do @@ -1612,11 +1609,11 @@ def test_model_security_delete_unallowed end end end - } + ) Authorization::Engine.instance(reader) Authorization.current_user = MockUser.new(:test_role_unrestricted) - object = TestModelSecurityModel.create :attr => 2 + object = TestModelSecurityModel.create attr: 2 Authorization.current_user = MockUser.new(:test_role) assert_raises Authorization::AttributeAuthorizationError do @@ -1626,7 +1623,7 @@ def test_model_security_delete_unallowed def test_model_security_changing_critical_attribute_unallowed reader = Authorization::Reader::DSLReader.new - reader.parse %{ + reader.parse %( authorization do role :test_role_unrestricted do has_permission_on :test_model_security_models do @@ -1640,25 +1637,25 @@ def test_model_security_changing_critical_attribute_unallowed end end end - } + ) Authorization::Engine.instance(reader) Authorization.current_user = MockUser.new(:test_role_unrestricted) - object = TestModelSecurityModel.create :attr => 2 + object = TestModelSecurityModel.create attr: 2 Authorization.current_user = MockUser.new(:test_role) - # TODO before not checked yet - #assert_raises Authorization::AuthorizationError do + # TODO: before not checked yet + # assert_raises Authorization::AuthorizationError do # object.update_attributes(:attr => 1) - #end + # end end def test_model_security_no_role_unallowed reader = Authorization::Reader::DSLReader.new - reader.parse %{ + reader.parse %( authorization do end - } + ) Authorization::Engine.instance(reader) Authorization.current_user = MockUser.new(:test_role_2) @@ -1669,7 +1666,7 @@ def test_model_security_no_role_unallowed def test_model_security_with_assoc reader = Authorization::Reader::DSLReader.new - reader.parse %{ + reader.parse %( authorization do role :test_role do has_permission_on :test_model_security_models do @@ -1678,14 +1675,14 @@ def test_model_security_with_assoc end end end - } + ) Authorization::Engine.instance(reader) test_attr = TestAttr.create test_attr.role_symbols << :test_role Authorization.current_user = test_attr - assert(object = TestModelSecurityModel.create(:test_attrs => [test_attr])) - object.update_attributes(:attr_2 => 2) + assert(object = TestModelSecurityModel.create(test_attrs: [test_attr])) + object.update_attributes(attr_2: 2) without_access_control do object.reload @@ -1699,7 +1696,7 @@ def test_model_security_with_assoc def test_model_security_with_update_attrbributes reader = Authorization::Reader::DSLReader.new - reader.parse %{ + reader.parse %( authorization do role :test_role do has_permission_on :test_model_security_models, :to => :update do @@ -1707,19 +1704,19 @@ def test_model_security_with_update_attrbributes end end end - } + ) Authorization::Engine.instance(reader) params = { - :model_data => { :attr => 11 } + model_data: { attr: 11 } } - test_attr = TestAttr.create!(:branch => Branch.create!) + test_attr = TestAttr.create!(branch: Branch.create!) test_model = without_access_control do - TestModelSecurityModel.create!(:test_attrs => [test_attr]) + TestModelSecurityModel.create!(test_attrs: [test_attr]) end - with_user MockUser.new(:test_role, :branch => test_attr.branch) do + with_user MockUser.new(:test_role, branch: test_attr.branch) do test_model.update_attributes(params[:model_data]) end without_access_control do @@ -1738,7 +1735,7 @@ def test_using_access_control def test_authorization_permit_association_proxy reader = Authorization::Reader::DSLReader.new - reader.parse %{ + reader.parse %( authorization do role :test_role do has_permission_on :test_attrs, :to => :read do @@ -1746,57 +1743,57 @@ def test_authorization_permit_association_proxy end end end - } + ) engine = Authorization::Engine.instance(reader) - test_model = TestModel.create(:content => "content") - assert engine.permit?(:read, :object => test_model.test_attrs, - :user => MockUser.new(:test_role)) - assert !engine.permit?(:read, :object => TestAttr.new, - :user => MockUser.new(:test_role)) + test_model = TestModel.create(content: 'content') + assert engine.permit?(:read, object: test_model.test_attrs, + user: MockUser.new(:test_role)) + assert !engine.permit?(:read, object: TestAttr.new, + user: MockUser.new(:test_role)) TestModel.delete_all end def test_authorization_permit_nested_association_proxy - reader = Authorization::Reader::DSLReader.new - reader.parse %{ - authorization do - role :test_role do - has_permission_on :branches, :to => :read do - if_attribute :test_model => { :test_attrs => {:attr => 1 } } - end - end - end - } - engine = Authorization::Engine.instance(reader) - - test_model = TestModel.create! - test_model.test_attrs.create!(:attr => 0) - test_attr = test_model.test_attrs.create!(:attr => 1) - test_model.test_attrs.create!(:attr => 3) - test_branch = Branch.create!(:test_model => test_model) - - test_model_2 = TestModel.create! - test_attr_2 = test_model_2.test_attrs.create!(:attr => 2) - test_branch_2 = Branch.create!(:test_model => test_model_2) - - test_model_3 = TestModel.create! - test_branch_3 = Branch.create!(:test_model => test_model_3) - - assert engine.permit?(:read, :object => test_branch, - :user => MockUser.new(:test_role)) - assert !engine.permit?(:read, :object => test_branch_2, - :user => MockUser.new(:test_role)) - assert !engine.permit?(:read, :object => test_branch_3, - :user => MockUser.new(:test_role)) - TestModel.delete_all - Branch.delete_all - TestAttr.delete_all + reader = Authorization::Reader::DSLReader.new + reader.parse %( + authorization do + role :test_role do + has_permission_on :branches, :to => :read do + if_attribute :test_model => { :test_attrs => {:attr => 1 } } + end + end + end + ) + engine = Authorization::Engine.instance(reader) + + test_model = TestModel.create! + test_model.test_attrs.create!(attr: 0) + test_attr = test_model.test_attrs.create!(attr: 1) + test_model.test_attrs.create!(attr: 3) + test_branch = Branch.create!(test_model: test_model) + + test_model_2 = TestModel.create! + test_attr_2 = test_model_2.test_attrs.create!(attr: 2) + test_branch_2 = Branch.create!(test_model: test_model_2) + + test_model_3 = TestModel.create! + test_branch_3 = Branch.create!(test_model: test_model_3) + + assert engine.permit?(:read, object: test_branch, + user: MockUser.new(:test_role)) + assert !engine.permit?(:read, object: test_branch_2, + user: MockUser.new(:test_role)) + assert !engine.permit?(:read, object: test_branch_3, + user: MockUser.new(:test_role)) + TestModel.delete_all + Branch.delete_all + TestAttr.delete_all end def test_multiple_roles_with_has_many_through reader = Authorization::Reader::DSLReader.new - reader.parse %{ + reader.parse %( authorization do role :test_role_1 do has_permission_on :test_models, :to => :read do @@ -1804,7 +1801,6 @@ def test_multiple_roles_with_has_many_through :content => 'test_1' end end - role :test_role_2 do has_permission_on :test_models, :to => :read do if_attribute :test_attr_throughs_2 => contains {user.test_attr_through_2_id}, @@ -1812,22 +1808,22 @@ def test_multiple_roles_with_has_many_through end end end - } + ) Authorization::Engine.instance(reader) TestModel.delete_all TestAttr.delete_all TestAttrThrough.delete_all - test_model_1 = TestModel.create! :content => 'test_1' - test_model_2 = TestModel.create! :content => 'test_2' + test_model_1 = TestModel.create! content: 'test_1' + test_model_2 = TestModel.create! content: 'test_2' test_model_1.test_attrs.create!.test_attr_throughs.create! test_model_2.test_attrs.create!.test_attr_throughs.create! user = MockUser.new(:test_role_1, :test_role_2, - :test_attr_through_id => test_model_1.test_attr_throughs.first.id, - :test_attr_through_2_id => test_model_2.test_attr_throughs.first.id) + test_attr_through_id: test_model_1.test_attr_throughs.first.id, + test_attr_through_2_id: test_model_2.test_attr_throughs.first.id) - assert_equal 2, TestModel.with_permissions_to(:read, :user => user).references(:test_models, :test_attr_throughs).length + assert_equal 2, TestModel.with_permissions_to(:read, user: user).references(:test_models, :test_attr_throughs).length TestModel.delete_all TestAttr.delete_all TestAttrThrough.delete_all @@ -1835,7 +1831,7 @@ def test_multiple_roles_with_has_many_through def test_model_permitted_to reader = Authorization::Reader::DSLReader.new - reader.parse %{ + reader.parse %( authorization do role :test_role do has_permission_on :companies, :to => :read do @@ -1843,55 +1839,55 @@ def test_model_permitted_to end end end - } + ) Authorization::Engine.instance(reader) user = MockUser.new(:test_role) - allowed_read_company = Company.new(:name => 'company_1') - prohibited_company = Company.new(:name => 'company_2') + allowed_read_company = Company.new(name: 'company_1') + prohibited_company = Company.new(name: 'company_2') - assert allowed_read_company.permitted_to?(:read, :user => user) - assert !allowed_read_company.permitted_to?(:update, :user => user) - assert !prohibited_company.permitted_to?(:read, :user => user) + assert allowed_read_company.permitted_to?(:read, user: user) + assert !allowed_read_company.permitted_to?(:update, user: user) + assert !prohibited_company.permitted_to?(:read, user: user) executed_block = false - allowed_read_company.permitted_to?(:read, :user => user) do + allowed_read_company.permitted_to?(:read, user: user) do executed_block = true end assert executed_block executed_block = false - prohibited_company.permitted_to?(:read, :user => user) do + prohibited_company.permitted_to?(:read, user: user) do executed_block = true end assert !executed_block - allowed_read_company.permitted_to!(:read, :user => user) + allowed_read_company.permitted_to!(:read, user: user) assert_raises Authorization::NotAuthorized do - prohibited_company.permitted_to!(:update, :user => user) + prohibited_company.permitted_to!(:update, user: user) end assert_raises Authorization::AttributeAuthorizationError do - prohibited_company.permitted_to!(:read, :user => user) + prohibited_company.permitted_to!(:read, user: user) end end def test_model_permitted_to_with_modified_context reader = Authorization::Reader::DSLReader.new - reader.parse %{ + reader.parse %( authorization do role :test_role do has_permission_on :companies, :to => :read end end - } + ) Authorization::Engine.instance(reader) user = MockUser.new(:test_role) - allowed_read_company = SmallCompany.new(:name => 'small_company_1') + allowed_read_company = SmallCompany.new(name: 'small_company_1') - assert allowed_read_company.permitted_to?(:read, :user => user) - assert !allowed_read_company.permitted_to?(:update, :user => user) + assert allowed_read_company.permitted_to?(:read, user: user) + assert !allowed_read_company.permitted_to?(:update, user: user) end def teardown diff --git a/test/test_helper.rb b/test/test_helper.rb index 574046f7..0152cd10 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -6,24 +6,23 @@ begin # rails 3 require 'rails/all' - rescue LoadError +rescue LoadError # rails 2.3 - %w(action_pack action_controller active_record active_support initializer).each {|f| require f} + %w[action_pack action_controller active_record active_support initializer].each { |f| require f } end Bundler.require require 'minitest/autorun' - puts "Testing against rails #{Rails::VERSION::STRING}" RAILS_ROOT = File.dirname(__FILE__) -DA_ROOT = Pathname.new(File.expand_path("..", File.dirname(__FILE__))) +DA_ROOT = Pathname.new(File.expand_path('..', File.dirname(__FILE__))) -require DA_ROOT + File.join(%w{lib declarative_authorization authorization}) -require DA_ROOT + File.join(%w{lib declarative_authorization in_controller}) -require DA_ROOT + File.join(%w{lib declarative_authorization maintenance}) +require DA_ROOT + File.join(%w[lib declarative_authorization authorization]) +require DA_ROOT + File.join(%w[lib declarative_authorization in_controller]) +require DA_ROOT + File.join(%w[lib declarative_authorization maintenance]) class MockDataObject def initialize(attrs = {}) @@ -44,27 +43,27 @@ def self.table_name end def self.name - "Mock" + 'Mock' end def self.find(*args) - raise StandardError, "Couldn't find #{self.name} with id #{args[0].inspect}" unless args[0] - new :id => args[0] + raise StandardError, "Couldn't find #{name} with id #{args[0].inspect}" unless args[0] + new id: args[0] end def self.find_or_initialize_by(args) - raise StandardError, "Syntax error: find_or_initialize by expects a hash: User.find_or_initialize_by(:id => @user.id)" unless args.is_a?(Hash) - new :id => args[:id] + raise StandardError, 'Syntax error: find_or_initialize by expects a hash: User.find_or_initialize_by(:id => @user.id)' unless args.is_a?(Hash) + new id: args[:id] end end class MockUser < MockDataObject def initialize(*roles) options = roles.last.is_a?(::Hash) ? roles.pop : {} - super({:role_symbols => roles, :login => hash}.merge(options)) + super({ role_symbols: roles, login: hash }.merge(options)) end - def initialize_copy(other) + def initialize_copy(_other) @role_symbols = @role_symbols.clone end end @@ -81,7 +80,7 @@ def self.define_action_methods(*methods) methods.each do |method| define_method method do @authorized = true - render :text => 'nothing' + render text: 'nothing' end end end @@ -90,10 +89,10 @@ def self.define_resource_actions define_action_methods :index, :show, :edit, :update, :new, :create, :destroy end - def logger(*args) + def logger(*_args) Class.new do def warn(*args) - #p args + # p args end alias_method :info, :warn alias_method :debug, :warn @@ -107,7 +106,7 @@ def warn?; end class TestApp class Application < ::Rails::Application config.eager_load = false - config.secret_key_base = "testingpurposesonly" + config.secret_key_base = 'testingpurposesonly' config.active_support.deprecation = :stderr database_path = File.expand_path('../database.yml', __FILE__) config.paths['config/database'] = database_path @@ -116,23 +115,15 @@ class Application < ::Rails::Application end class ApplicationController < ActionController::Base end -#Rails::Application.routes.draw do -if Rails.version.start_with? '4' - Rails.application.routes.draw do - match '/name/spaced_things(/:action)' => 'name/spaced_things', :via => [:get, :post, :put, :patch, :delete] - match '/deep/name_spaced/things(/:action)' => 'deep/name_spaced/things', :via => [:get, :post, :put, :patch, :delete] - match '/:controller(/:action(/:id))', :via => [:get, :post, :put, :patch, :delete] - end - class TestApp - class Application < ::Rails::Application - config.secret_key_base = 'thisstringdoesnothing' - end - end -else - Rails.application.routes.draw do - get '/name/spaced_things(/:action)' => 'name/spaced_things' - get '/deep/name_spaced/things(/:action)' => 'deep/name_spaced/things' - get '/:controller(/:action(/:id))' + +Rails.application.routes.draw do + match '/name/spaced_things(/:action)' => 'name/spaced_things', :via => %i[get post put patch delete] + match '/deep/name_spaced/things(/:action)' => 'deep/name_spaced/things', :via => %i[get post put patch delete] + match '/:controller(/:action(/:id))', via: %i[get post put patch delete] +end +class TestApp + class Application < ::Rails::Application + config.secret_key_base = 'thisstringdoesnothing' end end @@ -147,7 +138,6 @@ class Test::Unit::TestCase < Minitest::Test include Authorization::TestHelper end - class ActiveSupport::TestCase include Authorization::TestHelper @@ -163,8 +153,7 @@ def request!(user, action, reader, params = {}) end def setup - #@routes = Rails::Application.routes + # @routes = Rails::Application.routes @routes = Rails.application.routes end end - From 52e6877200ab18715729af8769716f2f8d9047a8 Mon Sep 17 00:00:00 2001 From: Xymist Date: Fri, 18 May 2018 15:03:26 +0100 Subject: [PATCH 29/55] More test failures --- Gemfile | 7 + Gemfile.lock | 135 ++++++++++++++ .../authorization.rb | 2 +- lib/declarative_authorization/maintenance.rb | 23 +-- .../obligation_scope.rb | 176 +++++++++--------- 5 files changed, 241 insertions(+), 102 deletions(-) create mode 100644 Gemfile create mode 100644 Gemfile.lock diff --git a/Gemfile b/Gemfile new file mode 100644 index 00000000..733d02f9 --- /dev/null +++ b/Gemfile @@ -0,0 +1,7 @@ +source 'https://rubygems.org' + +gem 'rails', '~> 5.0.0' +gem 'sqlite3' +gem 'rdoc' +gem 'rails-controller-testing' +gemspec :path => '.' diff --git a/Gemfile.lock b/Gemfile.lock new file mode 100644 index 00000000..763d618d --- /dev/null +++ b/Gemfile.lock @@ -0,0 +1,135 @@ +PATH + remote: . + specs: + declarative_authorization (1.0.0.pre) + rails (>= 4.1.0, < 5.1.0) + ruby_parser (~> 3.6.6) + +GEM + remote: https://rubygems.org/ + specs: + actioncable (5.0.7) + actionpack (= 5.0.7) + nio4r (>= 1.2, < 3.0) + websocket-driver (~> 0.6.1) + actionmailer (5.0.7) + actionpack (= 5.0.7) + actionview (= 5.0.7) + activejob (= 5.0.7) + mail (~> 2.5, >= 2.5.4) + rails-dom-testing (~> 2.0) + actionpack (5.0.7) + actionview (= 5.0.7) + activesupport (= 5.0.7) + rack (~> 2.0) + rack-test (~> 0.6.3) + rails-dom-testing (~> 2.0) + rails-html-sanitizer (~> 1.0, >= 1.0.2) + actionview (5.0.7) + activesupport (= 5.0.7) + builder (~> 3.1) + erubis (~> 2.7.0) + rails-dom-testing (~> 2.0) + rails-html-sanitizer (~> 1.0, >= 1.0.3) + activejob (5.0.7) + activesupport (= 5.0.7) + globalid (>= 0.3.6) + activemodel (5.0.7) + activesupport (= 5.0.7) + activerecord (5.0.7) + activemodel (= 5.0.7) + activesupport (= 5.0.7) + arel (~> 7.0) + activesupport (5.0.7) + concurrent-ruby (~> 1.0, >= 1.0.2) + i18n (>= 0.7, < 2) + minitest (~> 5.1) + tzinfo (~> 1.1) + arel (7.1.4) + builder (3.2.3) + concurrent-ruby (1.0.5) + crass (1.0.4) + erubis (2.7.0) + globalid (0.4.1) + activesupport (>= 4.2.0) + i18n (1.0.1) + concurrent-ruby (~> 1.0) + loofah (2.2.2) + crass (~> 1.0.2) + nokogiri (>= 1.5.9) + mail (2.7.0) + mini_mime (>= 0.1.1) + method_source (0.9.0) + mini_mime (1.0.0) + mini_portile2 (2.3.0) + minitest (5.11.3) + nio4r (2.3.1) + nokogiri (1.8.2) + mini_portile2 (~> 2.3.0) + power_assert (1.1.1) + rack (2.0.5) + rack-test (0.6.3) + rack (>= 1.0) + rails (5.0.7) + actioncable (= 5.0.7) + actionmailer (= 5.0.7) + actionpack (= 5.0.7) + actionview (= 5.0.7) + activejob (= 5.0.7) + activemodel (= 5.0.7) + activerecord (= 5.0.7) + activesupport (= 5.0.7) + bundler (>= 1.3.0) + railties (= 5.0.7) + sprockets-rails (>= 2.0.0) + rails-controller-testing (1.0.2) + actionpack (~> 5.x, >= 5.0.1) + actionview (~> 5.x, >= 5.0.1) + activesupport (~> 5.x) + rails-dom-testing (2.0.3) + activesupport (>= 4.2.0) + nokogiri (>= 1.6) + rails-html-sanitizer (1.0.4) + loofah (~> 2.2, >= 2.2.2) + railties (5.0.7) + actionpack (= 5.0.7) + activesupport (= 5.0.7) + method_source + rake (>= 0.8.7) + thor (>= 0.18.1, < 2.0) + rake (12.3.1) + rdoc (6.0.4) + ruby_parser (3.6.6) + sexp_processor (~> 4.1) + sexp_processor (4.11.0) + sprockets (3.7.1) + concurrent-ruby (~> 1.0) + rack (> 1, < 3) + sprockets-rails (3.2.1) + actionpack (>= 4.0) + activesupport (>= 4.0) + sprockets (>= 3.0.0) + sqlite3 (1.3.13) + test-unit (3.2.8) + power_assert + thor (0.20.0) + thread_safe (0.3.6) + tzinfo (1.2.5) + thread_safe (~> 0.1) + websocket-driver (0.6.5) + websocket-extensions (>= 0.1.0) + websocket-extensions (0.1.3) + +PLATFORMS + ruby + +DEPENDENCIES + declarative_authorization! + rails (~> 5.0.0) + rails-controller-testing + rdoc + sqlite3 + test-unit + +BUNDLED WITH + 1.16.1 diff --git a/lib/declarative_authorization/authorization.rb b/lib/declarative_authorization/authorization.rb index fbcffabc..f5a97c97 100644 --- a/lib/declarative_authorization/authorization.rb +++ b/lib/declarative_authorization/authorization.rb @@ -406,7 +406,7 @@ def <<(rule) end def each(&block) - @rules.each block + @rules.each(&block) end private diff --git a/lib/declarative_authorization/maintenance.rb b/lib/declarative_authorization/maintenance.rb index 120c17ed..c0518ec9 100644 --- a/lib/declarative_authorization/maintenance.rb +++ b/lib/declarative_authorization/maintenance.rb @@ -66,36 +66,37 @@ def self.usages_by_controller (!obj.name || obj.name.demodulize != 'ApplicationController') end - controllers.each_with_object({}) do |controller, memo| + controllers.inject({}) do |memo, controller| catchall_permissions = [] permission_by_action = {} controller.all_filter_access_permissions.each do |controller_permissions| catchall_permissions << controller_permissions if controller_permissions.actions.include?(:all) - controller_permissions.actions.reject { |action| action == :all }.each do |action| + controller_permissions.actions.reject {|action| action == :all}.each do |action| permission_by_action[action] = controller_permissions end end - - actions = controller.public_instance_methods(false) - controller.hidden_actions.to_a - memo[controller] = actions.each_with_object({}) do |action, actions_memo| + actions = controller.public_instance_methods(false) - controller.private_methods + memo[controller] = actions.inject({}) do |actions_memo, action| action_sym = action.to_sym actions_memo[action_sym] = if permission_by_action[action_sym] { - privilege: permission_by_action[action_sym].privilege, - context: permission_by_action[action_sym].context, - controller_permissions: [permission_by_action[action_sym]] + :privilege => permission_by_action[action_sym].privilege, + :context => permission_by_action[action_sym].context, + :controller_permissions => [permission_by_action[action_sym]] } elsif !catchall_permissions.empty? { - privilege: catchall_permissions[0].privilege, - context: catchall_permissions[0].context, - controller_permissions: catchall_permissions + :privilege => catchall_permissions[0].privilege, + :context => catchall_permissions[0].context, + :controller_permissions => catchall_permissions } else {} end + actions_memo end + memo end end end diff --git a/lib/declarative_authorization/obligation_scope.rb b/lib/declarative_authorization/obligation_scope.rb index 87ffe5ea..b5589cdf 100644 --- a/lib/declarative_authorization/obligation_scope.rb +++ b/lib/declarative_authorization/obligation_scope.rb @@ -45,12 +45,21 @@ module Authorization class ObligationScope < ActiveRecord::Relation def initialize(model, _options) @finder_options = {} - super(model, model.table_name) + if Rails.version >= "5.2" + super(model, table: model.table_name) + elsif Rails.version >= "5" + super(model, model.table_name, nil) + else + super(model, model.table_name) + end end def scope # TODO: Refactor this. There is certainly a better way. - klass.joins(@finder_options[:joins]).includes(@finder_options[:include]).where(@finder_options[:conditions]).references(@finder_options[:include]) + klass.joins(@finder_options[:joins]) + .includes(@finder_options[:include]) + .where(@finder_options[:conditions]) + .references(@finder_options[:include]) end # Consumes the given obligation, converting it into scope join and condition options. @@ -68,21 +77,22 @@ def parse!(obligation) # Parses the next step in the association path. If it's an association, we advance down the # path. Otherwise, it's an attribute, and we need to evaluate it as a comparison operation. - def follow_path(steps, past_steps = []) - if steps.is_a?(Hash) + def follow_path( steps, past_steps = [] ) + if steps.is_a?( Hash ) steps.each do |step, next_steps| path_to_this_point = [past_steps, step].flatten - init_reflections_for past_steps - follow_path(next_steps, path_to_this_point) - # follow_comparison( next_steps, past_steps, step ) + reflection = reflection_for( path_to_this_point ) rescue nil + if reflection + follow_path( next_steps, path_to_this_point ) + else + follow_comparison( next_steps, past_steps, step ) + end end - elsif steps.is_a?(Array) && steps.length == 2 - init_reflections_for past_steps - - if reflections_for(past_steps) - follow_comparison(steps, past_steps, :id) + elsif steps.is_a?( Array ) && steps.length == 2 + if reflection_for( past_steps ) + follow_comparison( steps, past_steps, :id ) else - follow_comparison(steps, past_steps[0..-2], past_steps[-1]) + follow_comparison( steps, past_steps[0..-2], past_steps[-1] ) end else raise "invalid obligation path #{[past_steps, steps].inspect}" @@ -144,21 +154,29 @@ def table_alias_for(path) end # Attempts to map a reflection for the given path. Raises if already defined. - def map_reflection_for(path) - refls_for_path = reflections_for_path path + def map_reflection_for( path ) + raise "reflection for #{path.inspect} already exists" unless reflections[path].nil? - return nil if refls_for_path.empty? - reflections[path] = refls_for_path + reflection = path.empty? ? top_level_model : begin + parent = reflection_for( path[0..-2] ) + if !Authorization.is_a_association_proxy?(parent) and parent.respond_to?(:klass) + parent.klass.reflect_on_association( path.last ) + else + parent.reflect_on_association( path.last ) + end + rescue + parent.reflect_on_association( path.last ) + end + raise "invalid path #{path.inspect}" if reflection.nil? - init_table_alias_for path # Claim a table alias for the path. + reflections[path] = reflection + map_table_alias_for( path ) # Claim a table alias for the path. # Claim alias for join table # TODO change how this is checked - refls_for_path.each do |reflection| - if !Authorization.is_a_association_proxy?(reflection) && reflection.is_a?(ActiveRecord::Reflection::ThroughReflection) - join_table_path = path[0..-2] + [reflection.options[:through]] - init_reflections_for(join_table_path, true) - end + if !Authorization.is_a_association_proxy?(reflection) and !reflection.respond_to?(:proxy_scope) and reflection.is_a?(ActiveRecord::Reflection::ThroughReflection) + join_table_path = path[0..-2] + [reflection.options[:through]] + reflection_for(join_table_path, true) end reflection @@ -211,81 +229,59 @@ def table_aliases def rebuild_condition_options! conds = [] binds = {} - obligation_conditions.each_with_index do |(_, conditions), obligation_index| + used_paths = Set.new + delete_paths = Set.new + obligation_conditions.each_with_index do |array, obligation_index| + obligation, conditions = array obligation_conds = [] - obligation_conds_poly = [] - conditions.each do |path, expressions| - models = models_for path - raise 'too many models' if models.length > 1 - model = models.first - - table_alias_list = table_alias_for(path) - parent_models = (path.length > 1 ? models_for(path[0..-2]) : [top_level_model]) - parent_is_polymorphic = parent_models.length > 1 - - parent_models.each do |parent_model| - expressions.each do |expression| - attribute, operator, value = expression - # prevent unnecessary joins: - if (attribute == :id) && (operator == :is) && parent_model.columns_hash["#{path.last}_id"] - attribute_name = :"#{path.last}_id" - attribute_table_alias_list = table_alias_for(path[0..-2]) - else - attribute_name = model.columns_hash["#{attribute}_id"] && :"#{attribute}_id" || - model.columns_hash[attribute.to_s] && attribute || - model.primary_key - attribute_table_alias_list = table_alias_list - end - - attribute_table_alias_list.each do |attribute_table_alias| - bindvar = "#{attribute_table_alias}__#{attribute_name}_#{obligation_index}".to_sym - - sql_attribute = "#{parent_model.connection.quote_table_name(attribute_table_alias)}." \ - "#{parent_model.connection.quote_table_name(attribute_name)}" - - obligation_cond = - if value.nil? && %i[is is_not].include?(operator) - "#{sql_attribute} IS #{%i[contains is].include?(operator) ? '' : 'NOT '}NULL" - else - attribute_operator = case operator - when :contains, :is then "= :#{bindvar}" - when :does_not_contain, :is_not then "<> :#{bindvar}" - when :is_in, :intersects_with then "IN (:#{bindvar})" - when :is_not_in then "NOT IN (:#{bindvar})" - when :lt then "< :#{bindvar}" - when :lte then "<= :#{bindvar}" - when :gt then "> :#{bindvar}" - when :gte then ">= :#{bindvar}" - else raise AuthorizationUsageError, "Unknown operator: #{operator}" - end - - binds[bindvar] = attribute_value(value) - "#{sql_attribute} #{attribute_operator}" - end - - if parent_is_polymorphic && attribute == :id - obligation_conds_poly << obligation_cond - else - obligation_conds << obligation_cond - end - end + model = model_for( path ) + table_alias = table_alias_for(path) + parent_model = (path.length > 1 ? model_for(path[0..-2]) : top_level_model) + expressions.each do |expression| + attribute, operator, value = expression + # prevent unnecessary joins: + if attribute == :id and operator == :is and parent_model.columns_hash["#{path.last}_id"] + attribute_name = :"#{path.last}_id" + attribute_table_alias = table_alias_for(path[0..-2]) + used_paths << path[0..-2] + delete_paths << path + else + attribute_name = model.columns_hash["#{attribute}_id"] && :"#{attribute}_id" || + model.columns_hash[attribute.to_s] && attribute || + model.primary_key + attribute_table_alias = table_alias + used_paths << path + end + bindvar = "#{attribute_table_alias}__#{attribute_name}_#{obligation_index}".to_sym + + sql_attribute = "#{parent_model.connection.quote_table_name(attribute_table_alias)}." + + "#{parent_model.connection.quote_table_name(attribute_name)}" + if value.nil? and [:is, :is_not].include?(operator) + obligation_conds << "#{sql_attribute} IS #{[:contains, :is].include?(operator) ? '' : 'NOT '}NULL" + else + attribute_operator = case operator + when :contains, :is then "= :#{bindvar}" + when :does_not_contain, :is_not then "<> :#{bindvar}" + when :is_in, :intersects_with then "IN (:#{bindvar})" + when :is_not_in then "NOT IN (:#{bindvar})" + when :lt then "< :#{bindvar}" + when :lte then "<= :#{bindvar}" + when :gt then "> :#{bindvar}" + when :gte then ">= :#{bindvar}" + else raise AuthorizationUsageError, "Unknown operator: #{operator}" + end + obligation_conds << "#{sql_attribute} #{attribute_operator}" + binds[bindvar] = attribute_value(value) end end end - - # join conditions directly connecting a parent to its polymorphic children by OR - poly_conds_sql = obligation_conds_poly.empty? ? nil : "(#{obligation_conds_poly.uniq.join(' OR ')})" - - # remove any duplicate ordinary conditions (defined multiple times because of polymorphism) - obligation_conds.uniq! - - obligation_conds << poly_conds_sql if poly_conds_sql - obligation_conds << '1=1' if obligation_conds.empty? + obligation_conds << "1=1" if obligation_conds.empty? conds << "(#{obligation_conds.join(' AND ')})" end + (delete_paths - used_paths).each {|path| reflections.delete(path)} - finder_options[:conditions] = [conds.join(' OR '), binds] + finder_options[:conditions] = [ conds.join( " OR " ), binds ] end def attribute_value(value) From 09619b2621797e34873fcc5ce0e594a62eef0348 Mon Sep 17 00:00:00 2001 From: Xymist Date: Fri, 18 May 2018 15:09:19 +0100 Subject: [PATCH 30/55] Up dependency to Rails 5.2 --- Gemfile | 2 +- Gemfile.lock | 96 +++++++++++++++++-------------- declarative_authorization.gemspec | 2 +- 3 files changed, 54 insertions(+), 46 deletions(-) diff --git a/Gemfile b/Gemfile index 733d02f9..cd3d7e21 100644 --- a/Gemfile +++ b/Gemfile @@ -1,6 +1,6 @@ source 'https://rubygems.org' -gem 'rails', '~> 5.0.0' +gem 'rails', '~> 5.2.0' gem 'sqlite3' gem 'rdoc' gem 'rails-controller-testing' diff --git a/Gemfile.lock b/Gemfile.lock index 763d618d..5b06ae03 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -2,54 +2,58 @@ PATH remote: . specs: declarative_authorization (1.0.0.pre) - rails (>= 4.1.0, < 5.1.0) + rails (>= 4.1.0, <= 5.2.0) ruby_parser (~> 3.6.6) GEM remote: https://rubygems.org/ specs: - actioncable (5.0.7) - actionpack (= 5.0.7) - nio4r (>= 1.2, < 3.0) - websocket-driver (~> 0.6.1) - actionmailer (5.0.7) - actionpack (= 5.0.7) - actionview (= 5.0.7) - activejob (= 5.0.7) + actioncable (5.2.0) + actionpack (= 5.2.0) + nio4r (~> 2.0) + websocket-driver (>= 0.6.1) + actionmailer (5.2.0) + actionpack (= 5.2.0) + actionview (= 5.2.0) + activejob (= 5.2.0) mail (~> 2.5, >= 2.5.4) rails-dom-testing (~> 2.0) - actionpack (5.0.7) - actionview (= 5.0.7) - activesupport (= 5.0.7) + actionpack (5.2.0) + actionview (= 5.2.0) + activesupport (= 5.2.0) rack (~> 2.0) - rack-test (~> 0.6.3) + rack-test (>= 0.6.3) rails-dom-testing (~> 2.0) rails-html-sanitizer (~> 1.0, >= 1.0.2) - actionview (5.0.7) - activesupport (= 5.0.7) + actionview (5.2.0) + activesupport (= 5.2.0) builder (~> 3.1) - erubis (~> 2.7.0) + erubi (~> 1.4) rails-dom-testing (~> 2.0) rails-html-sanitizer (~> 1.0, >= 1.0.3) - activejob (5.0.7) - activesupport (= 5.0.7) + activejob (5.2.0) + activesupport (= 5.2.0) globalid (>= 0.3.6) - activemodel (5.0.7) - activesupport (= 5.0.7) - activerecord (5.0.7) - activemodel (= 5.0.7) - activesupport (= 5.0.7) - arel (~> 7.0) - activesupport (5.0.7) + activemodel (5.2.0) + activesupport (= 5.2.0) + activerecord (5.2.0) + activemodel (= 5.2.0) + activesupport (= 5.2.0) + arel (>= 9.0) + activestorage (5.2.0) + actionpack (= 5.2.0) + activerecord (= 5.2.0) + marcel (~> 0.3.1) + activesupport (5.2.0) concurrent-ruby (~> 1.0, >= 1.0.2) i18n (>= 0.7, < 2) minitest (~> 5.1) tzinfo (~> 1.1) - arel (7.1.4) + arel (9.0.0) builder (3.2.3) concurrent-ruby (1.0.5) crass (1.0.4) - erubis (2.7.0) + erubi (1.7.1) globalid (0.4.1) activesupport (>= 4.2.0) i18n (1.0.1) @@ -59,7 +63,10 @@ GEM nokogiri (>= 1.5.9) mail (2.7.0) mini_mime (>= 0.1.1) + marcel (0.3.2) + mimemagic (~> 0.3.2) method_source (0.9.0) + mimemagic (0.3.2) mini_mime (1.0.0) mini_portile2 (2.3.0) minitest (5.11.3) @@ -68,19 +75,20 @@ GEM mini_portile2 (~> 2.3.0) power_assert (1.1.1) rack (2.0.5) - rack-test (0.6.3) - rack (>= 1.0) - rails (5.0.7) - actioncable (= 5.0.7) - actionmailer (= 5.0.7) - actionpack (= 5.0.7) - actionview (= 5.0.7) - activejob (= 5.0.7) - activemodel (= 5.0.7) - activerecord (= 5.0.7) - activesupport (= 5.0.7) + rack-test (1.0.0) + rack (>= 1.0, < 3) + rails (5.2.0) + actioncable (= 5.2.0) + actionmailer (= 5.2.0) + actionpack (= 5.2.0) + actionview (= 5.2.0) + activejob (= 5.2.0) + activemodel (= 5.2.0) + activerecord (= 5.2.0) + activestorage (= 5.2.0) + activesupport (= 5.2.0) bundler (>= 1.3.0) - railties (= 5.0.7) + railties (= 5.2.0) sprockets-rails (>= 2.0.0) rails-controller-testing (1.0.2) actionpack (~> 5.x, >= 5.0.1) @@ -91,9 +99,9 @@ GEM nokogiri (>= 1.6) rails-html-sanitizer (1.0.4) loofah (~> 2.2, >= 2.2.2) - railties (5.0.7) - actionpack (= 5.0.7) - activesupport (= 5.0.7) + railties (5.2.0) + actionpack (= 5.2.0) + activesupport (= 5.2.0) method_source rake (>= 0.8.7) thor (>= 0.18.1, < 2.0) @@ -116,7 +124,7 @@ GEM thread_safe (0.3.6) tzinfo (1.2.5) thread_safe (~> 0.1) - websocket-driver (0.6.5) + websocket-driver (0.7.0) websocket-extensions (>= 0.1.0) websocket-extensions (0.1.3) @@ -125,7 +133,7 @@ PLATFORMS DEPENDENCIES declarative_authorization! - rails (~> 5.0.0) + rails (~> 5.2.0) rails-controller-testing rdoc sqlite3 diff --git a/declarative_authorization.gemspec b/declarative_authorization.gemspec index 53af6360..97f42755 100644 --- a/declarative_authorization.gemspec +++ b/declarative_authorization.gemspec @@ -10,7 +10,7 @@ Gem::Specification.new do |s| s.has_rdoc = true s.extra_rdoc_files = ['README.rdoc', 'CHANGELOG'] s.homepage = 'http://github.com/stffn/declarative_authorization' - s.add_dependency('rails', '>= 4.1.0', '< 5.1.0') + s.add_dependency('rails', '>= 4.1.0', '<= 5.2.0') s.add_dependency('ruby_parser', '~> 3.6.6') s.add_development_dependency('test-unit') end From 1471ca1d72742321d6ab1f45b45742d29b2534db Mon Sep 17 00:00:00 2001 From: Xymist Date: Fri, 18 May 2018 15:12:50 +0100 Subject: [PATCH 31/55] Test syntax no longer accepts positional arguments --- test/test_helper.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/test_helper.rb b/test/test_helper.rb index 0152cd10..5c9d9388 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -149,7 +149,7 @@ def request!(user, action, reader, params = {}) ((params.delete(:clear) || []) + [:@authorized]).each do |var| @controller.instance_variable_set(var, nil) end - get action, params + get action, params: params end def setup From b6bf0a9ba7afd589c1b3f71e54ceb1e19c453394 Mon Sep 17 00:00:00 2001 From: Xymist Date: Fri, 18 May 2018 15:42:31 +0100 Subject: [PATCH 32/55] Permit more recent ruby_parser --- declarative_authorization.gemspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/declarative_authorization.gemspec b/declarative_authorization.gemspec index 97f42755..42239d2a 100644 --- a/declarative_authorization.gemspec +++ b/declarative_authorization.gemspec @@ -11,6 +11,6 @@ Gem::Specification.new do |s| s.extra_rdoc_files = ['README.rdoc', 'CHANGELOG'] s.homepage = 'http://github.com/stffn/declarative_authorization' s.add_dependency('rails', '>= 4.1.0', '<= 5.2.0') - s.add_dependency('ruby_parser', '~> 3.6.6') + s.add_dependency('ruby_parser', '>= 3.6.6') s.add_development_dependency('test-unit') end From ef88fa0ac14c8c1b2e60e4b3c6240a1eb417b5ea Mon Sep 17 00:00:00 2001 From: Xymist Date: Fri, 18 May 2018 15:58:05 +0100 Subject: [PATCH 33/55] Fix recursive call --- lib/declarative_authorization/in_controller.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/declarative_authorization/in_controller.rb b/lib/declarative_authorization/in_controller.rb index 43d2804f..dae897be 100644 --- a/lib/declarative_authorization/in_controller.rb +++ b/lib/declarative_authorization/in_controller.rb @@ -600,7 +600,7 @@ def decl_auth_context def filter_access_permissions # :nodoc: unless filter_access_permissions? - ancestors[1..-1].reverse.each do |mod| + (ancestors - [self] ).reverse.each do |mod| mod.filter_access_permissions if mod.respond_to?(:filter_access_permissions, true) end end From b222212f497a4928ede387c3bcb701d9d630429b Mon Sep 17 00:00:00 2001 From: Aaron Huntsman Date: Wed, 23 May 2018 08:10:14 -0400 Subject: [PATCH 34/55] lock minitest to 5.10.3 --- gemfiles/5.0.gemfile | 1 + 1 file changed, 1 insertion(+) diff --git a/gemfiles/5.0.gemfile b/gemfiles/5.0.gemfile index 8df04b29..b4a2aeef 100644 --- a/gemfiles/5.0.gemfile +++ b/gemfiles/5.0.gemfile @@ -3,4 +3,5 @@ source 'https://rubygems.org' gem 'rails', '~> 5.0.0' gem 'sqlite3' gem 'rdoc' +gem 'minitest', '5.10.3' gemspec :path => '..' From 077ecac2c48dc56861f29cf365cd571c1381fce7 Mon Sep 17 00:00:00 2001 From: satyendra-cis Date: Thu, 24 May 2018 20:22:22 +0530 Subject: [PATCH 35/55] ActiveRecord::Reflection issue fix - Added fix for the ActiveRecord::Reflection assocation class issues - Updated text render syntax according to rails 5 --- lib/declarative_authorization/in_controller.rb | 2 +- lib/declarative_authorization/obligation_scope.rb | 4 ++-- test/test_helper.rb | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/declarative_authorization/in_controller.rb b/lib/declarative_authorization/in_controller.rb index dae897be..e9da7ed7 100644 --- a/lib/declarative_authorization/in_controller.rb +++ b/lib/declarative_authorization/in_controller.rb @@ -130,7 +130,7 @@ def filter_access_filter # :nodoc: # permission_denied needs to render or redirect send(:permission_denied) else - send(:render, text: 'You are not allowed to access this action.', + send(:render, plain: 'You are not allowed to access this action.', status: :forbidden) end end diff --git a/lib/declarative_authorization/obligation_scope.rb b/lib/declarative_authorization/obligation_scope.rb index b5589cdf..ca8204b2 100644 --- a/lib/declarative_authorization/obligation_scope.rb +++ b/lib/declarative_authorization/obligation_scope.rb @@ -299,10 +299,10 @@ def rebuild_join_options! reflections.each do |path, refs| next if path.empty? || @join_table_joins.include?(path) - first_ref = refs.first + first_ref = refs if polymorphic?(first_ref) # sanity check - raise 'Only one polymorphic relation is allowed at each step' if refs.length > 1 + raise 'Only one polymorphic relation is allowed at each step' if refs.class == "Array" && refs.length > 1 polymorphic_paths[path] = first_ref.active_record.poly_resource_names end diff --git a/test/test_helper.rb b/test/test_helper.rb index 5c9d9388..2f1ab0ef 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -80,7 +80,7 @@ def self.define_action_methods(*methods) methods.each do |method| define_method method do @authorized = true - render text: 'nothing' + render plain: 'nothing' end end end From 50e43b1c6a1deafc50f665359b44fb9b73f66096 Mon Sep 17 00:00:00 2001 From: Aaron Huntsman Date: Wed, 30 May 2018 09:33:07 -0400 Subject: [PATCH 36/55] before_filter to before_action; syntax fixes --- .../authorization.rb | 5 ++-- .../in_controller.rb | 27 +++++++++--------- .../obligation_scope.rb | 3 +- test/controller_test.rb | 2 +- test/development_support/analyzer_test.rb | 18 ++++++------ test/model_test.rb | 28 +++++++++---------- 6 files changed, 40 insertions(+), 43 deletions(-) diff --git a/lib/declarative_authorization/authorization.rb b/lib/declarative_authorization/authorization.rb index 398b4a04..cb8f5642 100644 --- a/lib/declarative_authorization/authorization.rb +++ b/lib/declarative_authorization/authorization.rb @@ -397,7 +397,7 @@ def <<(rule) end def each(&block) - @rules.each &block + @rules.each(&block) end private @@ -458,7 +458,7 @@ def validate?(attr_validator, skip_attribute = false) @attributes.send(@join_operator == :and ? :all? : :any?) do |attr| begin attr.validate?(attr_validator) - rescue NilAttributeValueError => e + rescue NilAttributeValueError nil # Bumping up against a nil attribute value flunks the rule. end end @@ -802,4 +802,3 @@ def initialize(roles = [Authorization.default_role]) end end end - diff --git a/lib/declarative_authorization/in_controller.rb b/lib/declarative_authorization/in_controller.rb index 77029b2e..61998fe8 100644 --- a/lib/declarative_authorization/in_controller.rb +++ b/lib/declarative_authorization/in_controller.rb @@ -236,10 +236,10 @@ module ClassMethods # authorization rules are enforced because for some actions (collections, # +new+, +create+), there is no object to evaluate conditions against. To # allow attribute checks on all actions, it is a common pattern to provide - # custom objects through +before_filters+: + # custom objects through +before_actions+: # class BranchesController < ApplicationController - # before_filter :load_company - # before_filter :new_branch_from_company_and_params, + # before_action :load_company + # before_action :new_branch_from_company_and_params, # :only => [:index, :new, :create] # filter_access_to :all, :attribute_check => true # @@ -248,7 +248,7 @@ module ClassMethods # @branch = @company.branches.new(params[:branch]) # end # end - # NOTE: +before_filters+ need to be defined before the first + # NOTE: +before_actions+ need to be defined before the first # +filter_access_to+ call. # # For further customization, a custom filter expression may be formulated @@ -310,8 +310,8 @@ def filter_access_to(*args, &filter_block) # prevent setting filter_access_filter multiple times #todo, something better - skip_before_filter :filter_access_filter rescue nil - before_filter :filter_access_filter + skip_before_action :filter_access_filter rescue nil + before_action :filter_access_filter filter_access_permissions.each do |perm| perm.remove_actions(actions) @@ -343,7 +343,7 @@ def all_filter_access_permissions # :nodoc: # To DRY up the filter_access_to statements in restful controllers, # filter_resource_access combines typical filter_access_to and - # before_filter calls, which set up the instance variables. + # before_action calls, which set up the instance variables. # # The simplest case are top-level resource controllers with only the # seven CRUD methods, e.g. @@ -456,7 +456,7 @@ def all_filter_access_permissions # :nodoc: # Allows to add additional new actions to the default resource +new+ actions. # [:+context+] # The context is used to determine the model to load objects from for the - # before_filters and the context of privileges to use in authorization + # before_actions and the context of privileges to use in authorization # checks. # [:+nested_in+] # Specifies the parent controller if the resource is nested in another @@ -512,7 +512,7 @@ def filter_resource_access(options = {}) unless options[:nested_in].blank? load_parent_method = :"load_#{options[:nested_in].to_s.singularize}" shallow_exceptions = options[:shallow] ? {:except => members.keys} : {} - before_filter shallow_exceptions do |controller| + before_action shallow_exceptions do |controller| if controller.respond_to?(load_parent_method, true) controller.send(load_parent_method) else @@ -521,7 +521,7 @@ def filter_resource_access(options = {}) end new_for_collection_method = :"new_#{controller_name.singularize}_for_collection" - before_filter :only => collections.keys do |controller| + before_action :only => collections.keys do |controller| # new_for_collection if controller.respond_to?(new_for_collection_method, true) controller.send(new_for_collection_method) @@ -534,7 +534,7 @@ def filter_resource_access(options = {}) unless options[:strong_parameters] new_from_params_method = :"new_#{controller_name.singularize}_from_params" - before_filter :only => new_actions.keys do |controller| + before_action :only => new_actions.keys do |controller| # new_from_params if controller.respond_to?(new_from_params_method, true) controller.send(new_from_params_method) @@ -545,7 +545,7 @@ def filter_resource_access(options = {}) end else new_object_method = :"new_#{controller_name.singularize}" - before_filter :only => :new do |controller| + before_action :only => :new do |controller| # new_from_params if controller.respond_to?(new_object_method, true) controller.send(new_object_method) @@ -557,7 +557,7 @@ def filter_resource_access(options = {}) end load_method = :"load_#{controller_name.singularize}" - before_filter :only => members.keys do |controller| + before_action :only => members.keys do |controller| # load controller object if controller.respond_to?(load_method, true) controller.send(load_method) @@ -699,4 +699,3 @@ def load_object(contr) end end end - diff --git a/lib/declarative_authorization/obligation_scope.rb b/lib/declarative_authorization/obligation_scope.rb index 5b9597de..5d6546b3 100644 --- a/lib/declarative_authorization/obligation_scope.rb +++ b/lib/declarative_authorization/obligation_scope.rb @@ -223,7 +223,7 @@ def rebuild_condition_options! used_paths = Set.new delete_paths = Set.new obligation_conditions.each_with_index do |array, obligation_index| - obligation, conditions = array + _, conditions = array obligation_conds = [] conditions.each do |path, expressions| model = model_for( path ) @@ -339,4 +339,3 @@ def join_to_path(join) end end end - diff --git a/test/controller_test.rb b/test/controller_test.rb index 0027820e..2cec8f63 100644 --- a/test/controller_test.rb +++ b/test/controller_test.rb @@ -213,7 +213,7 @@ def test_filter_access_all ################## class LoadMockObjectsController < MocksController - before_filter { @@load_method_call_count = 0 } + before_action { @@load_method_call_count = 0 } filter_access_to :show, :attribute_check => true, :model => LoadMockObject filter_access_to :edit, :attribute_check => true filter_access_to :update, :delete, :attribute_check => true, diff --git a/test/development_support/analyzer_test.rb b/test/development_support/analyzer_test.rb index 8863f88a..981771cb 100644 --- a/test/development_support/analyzer_test.rb +++ b/test/development_support/analyzer_test.rb @@ -13,7 +13,7 @@ class AuthorizationRulesAnalyzerTest < Test::Unit::TestCase def test_analyzing_complex_rules - engine, analyzer = engine_analyzer_for %{ + engine_analyzer_for %{ authorization do role :guest do has_permission_on :conferences, :to => :read do @@ -72,7 +72,7 @@ def test_analyzing_complex_rules end def test_mergeable_rules_without_constraints - engine, analyzer = engine_analyzer_for %{ + _, analyzer = engine_analyzer_for %{ authorization do role :test_role do has_permission_on :permissions, :to => :test @@ -87,7 +87,7 @@ def test_mergeable_rules_without_constraints end def test_mergeable_rules_with_in_block_to - engine, analyzer = engine_analyzer_for %{ + engine_analyzer_for %{ authorization do role :test_role do has_permission_on :permissions do @@ -99,7 +99,7 @@ def test_mergeable_rules_with_in_block_to end def test_no_mergeable_rules_with_constraints - engine, analyzer = engine_analyzer_for %{ + _, analyzer = engine_analyzer_for %{ authorization do role :test_role do has_permission_on :permissions, :to => :test do @@ -116,7 +116,7 @@ def test_no_mergeable_rules_with_constraints end def test_no_mergeable_rules_with_if_permitted_to - engine, analyzer = engine_analyzer_for %{ + _, analyzer = engine_analyzer_for %{ authorization do role :test_role do has_permission_on :permissions, :to => :test do @@ -134,7 +134,7 @@ def test_no_mergeable_rules_with_if_permitted_to end def test_role_explosion - engine, analyzer = engine_analyzer_for %{ + _, analyzer = engine_analyzer_for %{ authorization do role :test_role do has_permission_on :permissions, :to => :test @@ -159,7 +159,7 @@ def test_role_explosion end def test_inheriting_privileges - engine, analyzer = engine_analyzer_for %{ + _, analyzer = engine_analyzer_for %{ authorization do role :test_role do has_permission_on :permissions, :to => [:test, :test_2] @@ -177,7 +177,7 @@ def test_inheriting_privileges end def test_privileges_rules - engine, analyzer = engine_analyzer_for %{ + engine, _ = engine_analyzer_for %{ authorization do role :test_role do has_permission_on :permissions, :to => [:test, :test_2] @@ -243,7 +243,7 @@ def test_roles_for_privilege end def test_analyze_for_proposed_privilege_hierarchy - engine, analyzer = engine_analyzer_for %{ + _, analyzer = engine_analyzer_for %{ authorization do role :test_role do has_permission_on :permissions, :to => [:test, :test_2] diff --git a/test/model_test.rb b/test/model_test.rb index 49c3902d..7a4874cb 100644 --- a/test/model_test.rb +++ b/test/model_test.rb @@ -147,7 +147,7 @@ def test_with_belongs_to_and_has_many_with_contains } Authorization::Engine.instance(reader) - test_attr_1 = TestAttr.create! + TestAttr.create! test_model_1 = TestModel.create! test_model_1.test_attrs.create! @@ -619,7 +619,7 @@ def test_multiple_belongs_to } Authorization::Engine.instance(reader) - test_attr_1 = TestAttr.create! :test_model_id => 1, :test_another_model_id => 2 + TestAttr.create! :test_model_id => 1, :test_another_model_id => 2 user = MockUser.new(:test_role, :id => 1) assert_equal 1, TestAttr.with_permissions_to(:read, :user => user).length @@ -932,8 +932,8 @@ def test_with_contains_through_primary_key test_attr_through_1 = TestAttrThrough.create! test_item = NWayJoinItem.create! - test_model_1 = TestModel.create!(:test_attr_through_id => test_attr_through_1.id) - test_attr_1 = TestAttr.create!(:test_attr_through_id => test_attr_through_1.id, + TestModel.create!(:test_attr_through_id => test_attr_through_1.id) + TestAttr.create!(:test_attr_through_id => test_attr_through_1.id, :n_way_join_item_id => test_item.id) user = MockUser.new(:test_role, @@ -1271,7 +1271,7 @@ def test_with_if_permitted_to_and_empty_obligations Authorization::Engine.instance(reader) test_model_1 = TestModel.create! - test_attr_1 = test_model_1.test_attrs.create! + test_model_1.test_attrs.create! user = MockUser.new(:test_role) assert_equal 1, TestAttr.with_permissions_to(:read, :user => user).length @@ -1320,7 +1320,7 @@ def test_with_if_permitted_to_self test_model_1 = TestModel.create! test_attr_1 = test_model_1.test_attrs.create! - test_attr_2 = TestAttr.create! + TestAttr.create! user = MockUser.new(:test_role, :id => test_attr_1.id) assert_equal 1, TestModel.with_permissions_to(:update, :user => user).length @@ -1342,11 +1342,11 @@ def test_with_has_many_and_reoccuring_tables } Authorization::Engine.instance(reader) - test_attr_1 = TestAttr.create!( + TestAttr.create!( :test_model => TestModel.create!(:content => 'test_1_1'), :test_another_model => TestModel.create!(:content => 'test_1_2') ) - test_attr_2 = TestAttr.create!( + TestAttr.create!( :test_model => TestModel.create!(:content => 'test_2_1'), :test_another_model => TestModel.create!(:content => 'test_2_2') ) @@ -1375,7 +1375,7 @@ def test_with_ored_rules_and_reoccuring_tables } Authorization::Engine.instance(reader) - test_attr_1 = TestAttr.create!( + TestAttr.create!( :test_model => TestModel.create!(:content => 'test_1_1'), :test_another_model => TestModel.create!(:content => 'test_1_2') ) @@ -1412,12 +1412,12 @@ def test_with_many_ored_rules_and_reoccuring_tables country = Country.create!(:name => 'country_1') country.test_models.create! - test_attr_1 = TestAttr.create!( + TestAttr.create!( :branch => Branch.create!(:name => 'branch_1', :company => Company.create!(:name => 'company_1', :country => country)) ) - test_attr_2 = TestAttr.create!( + TestAttr.create!( :company => Company.create!(:name => 'company_2', :country => country) ) @@ -1644,7 +1644,7 @@ def test_model_security_changing_critical_attribute_unallowed Authorization::Engine.instance(reader) Authorization.current_user = MockUser.new(:test_role_unrestricted) - object = TestModelSecurityModel.create :attr => 2 + TestModelSecurityModel.create :attr => 2 Authorization.current_user = MockUser.new(:test_role) # TODO before not checked yet @@ -1772,12 +1772,12 @@ def test_authorization_permit_nested_association_proxy test_model = TestModel.create! test_model.test_attrs.create!(:attr => 0) - test_attr = test_model.test_attrs.create!(:attr => 1) + test_model.test_attrs.create!(:attr => 1) test_model.test_attrs.create!(:attr => 3) test_branch = Branch.create!(:test_model => test_model) test_model_2 = TestModel.create! - test_attr_2 = test_model_2.test_attrs.create!(:attr => 2) + test_model_2.test_attrs.create!(:attr => 2) test_branch_2 = Branch.create!(:test_model => test_model_2) test_model_3 = TestModel.create! From 2b36a09ee6f782db87d44bc36097a6ccd2ef169d Mon Sep 17 00:00:00 2001 From: Aaron Huntsman Date: Wed, 30 May 2018 11:36:36 -0400 Subject: [PATCH 37/55] remove assigns from controller tests --- test/controller_filter_resource_access_test.rb | 8 -------- 1 file changed, 8 deletions(-) diff --git a/test/controller_filter_resource_access_test.rb b/test/controller_filter_resource_access_test.rb index b65c965a..bc6188ff 100644 --- a/test/controller_filter_resource_access_test.rb +++ b/test/controller_filter_resource_access_test.rb @@ -216,7 +216,6 @@ def test_nested_filter_index assert !@controller.authorized? request!(allowed_user, :index, reader, :parent_mock_id => "1", :clear => [:@shallow_nested_resource, :@parent_mock]) - assert assigns(:parent_mock) assert @controller.authorized? end @@ -237,8 +236,6 @@ def test_nested_filter_show_with_id assert !@controller.authorized? request!(allowed_user, :show, reader, :id => "1", :clear => [:@shallow_nested_resource, :@parent_mock]) - assert !assigns(:parent_mock) - assert assigns(:shallow_nested_resource) assert @controller.authorized? end @@ -261,8 +258,6 @@ def test_nested_filter_new_with_params request!(allowed_user, :new, reader, :parent_mock_id => "1", :shallow_nested_resource => {:id => "1"}, :clear => [:@shallow_nested_resource, :@parent_mock]) - assert assigns(:parent_mock) - assert assigns(:shallow_nested_resource) assert @controller.authorized? end @@ -283,8 +278,6 @@ def test_nested_filter_additional_member_action_with_id assert !@controller.authorized? request!(allowed_user, :additional_member_action, reader, :id => "1", :clear => [:@shallow_nested_resource, :@parent_mock]) - assert !assigns(:parent_mock) - assert assigns(:shallow_nested_resource) assert @controller.authorized? end end @@ -570,4 +563,3 @@ def test_new_strong_resource # assert assigns :strong_resource end end - From c6d6ac4b993a94f2cc1c1fb718713415acb2d7d8 Mon Sep 17 00:00:00 2001 From: Aaron Huntsman Date: Fri, 1 Jun 2018 13:16:12 -0400 Subject: [PATCH 38/55] fix call to ActiveRecord::Relation initializer --- lib/declarative_authorization/obligation_scope.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/declarative_authorization/obligation_scope.rb b/lib/declarative_authorization/obligation_scope.rb index 5d6546b3..643c6050 100644 --- a/lib/declarative_authorization/obligation_scope.rb +++ b/lib/declarative_authorization/obligation_scope.rb @@ -45,7 +45,7 @@ module Authorization class ObligationScope < ActiveRecord::Relation def initialize(model, options) @finder_options = {} - super(model, model.table_name) + super(model, model.table_name, model.predicate_builder) end def scope From 78ea5143b82b6f77130a6a07b91ee1fded1c8720 Mon Sep 17 00:00:00 2001 From: Aaron Huntsman Date: Fri, 1 Jun 2018 14:01:51 -0400 Subject: [PATCH 39/55] fix more deprecations --- lib/declarative_authorization/authorization.rb | 4 ++-- lib/declarative_authorization/in_controller.rb | 2 +- test/test_helper.rb | 7 +++---- 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/lib/declarative_authorization/authorization.rb b/lib/declarative_authorization/authorization.rb index cb8f5642..77bfef67 100644 --- a/lib/declarative_authorization/authorization.rb +++ b/lib/declarative_authorization/authorization.rb @@ -91,7 +91,7 @@ def initialize_copy(from) # :nodoc: # {[priv, ctx] => [priv, ...]} def rev_priv_hierarchy - if @rev_priv_hierarchy.nil? + if !defined?(@rev_priv_hierarchy) || @rev_priv_hierarchy.nil? @rev_priv_hierarchy = {} privilege_hierarchy.each do |key, value| value.each do |val| @@ -105,7 +105,7 @@ def rev_priv_hierarchy # {[priv, ctx] => [priv, ...]} def rev_role_hierarchy - if @rev_role_hierarchy.nil? + if !defined?(@rev_role_hierarchy) || @rev_role_hierarchy.nil? @rev_role_hierarchy = {} role_hierarchy.each do |higher_role, lower_roles| lower_roles.each do |role| diff --git a/lib/declarative_authorization/in_controller.rb b/lib/declarative_authorization/in_controller.rb index 61998fe8..a7cfc6be 100644 --- a/lib/declarative_authorization/in_controller.rb +++ b/lib/declarative_authorization/in_controller.rb @@ -129,7 +129,7 @@ def filter_access_filter # :nodoc: # permission_denied needs to render or redirect send(:permission_denied) else - send(:render, :text => "You are not allowed to access this action.", + send(:render, :plain => "You are not allowed to access this action.", :status => :forbidden) end end diff --git a/test/test_helper.rb b/test/test_helper.rb index 574046f7..eccbead5 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -30,7 +30,7 @@ def initialize(attrs = {}) attrs.each do |key, value| instance_variable_set(:"@#{key}", value) self.class.class_eval do - attr_reader key + attr_reader key unless method_defined?(key) end end end @@ -81,7 +81,7 @@ def self.define_action_methods(*methods) methods.each do |method| define_method method do @authorized = true - render :text => 'nothing' + render :plain => 'nothing' end end end @@ -159,7 +159,7 @@ def request!(user, action, reader, params = {}) ((params.delete(:clear) || []) + [:@authorized]).each do |var| @controller.instance_variable_set(var, nil) end - get action, params + get action, params: params end def setup @@ -167,4 +167,3 @@ def setup @routes = Rails.application.routes end end - From d8846802f72022df184469dcc5681198b3ed0fd7 Mon Sep 17 00:00:00 2001 From: Aaron Huntsman Date: Fri, 1 Jun 2018 14:21:05 -0400 Subject: [PATCH 40/55] remove hidden_actions --- lib/declarative_authorization/maintenance.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/declarative_authorization/maintenance.rb b/lib/declarative_authorization/maintenance.rb index 73f31d73..34bc2dae 100644 --- a/lib/declarative_authorization/maintenance.rb +++ b/lib/declarative_authorization/maintenance.rb @@ -76,7 +76,7 @@ def self.usages_by_controller end end - actions = controller.public_instance_methods(false) - controller.hidden_actions.to_a + actions = controller.public_instance_methods(false) memo[controller] = actions.inject({}) do |actions_memo, action| action_sym = action.to_sym actions_memo[action_sym] = From d10b850725c828bd51c97de12e6b3f11a3ca40b5 Mon Sep 17 00:00:00 2001 From: Aaron Huntsman Date: Fri, 1 Jun 2018 14:21:47 -0400 Subject: [PATCH 41/55] remove rails 4.2 from test matrix --- .travis.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index f1f63395..d27ee872 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,6 +3,5 @@ script: bundle exec rake test rvm: - 2.4 gemfile: - - gemfiles/4.2.gemfile - gemfiles/5.0.gemfile From 9b7986b0baf5bbfe2439c3606537a61b0c087581 Mon Sep 17 00:00:00 2001 From: satyendra-cis Date: Thu, 7 Jun 2018 16:01:36 +0530 Subject: [PATCH 42/55] Fixed failing test case --- test/model_test.rb | 1 - 1 file changed, 1 deletion(-) diff --git a/test/model_test.rb b/test/model_test.rb index 2e06bd24..5cf35bd1 100644 --- a/test/model_test.rb +++ b/test/model_test.rb @@ -1380,7 +1380,6 @@ def test_with_ored_rules_and_reoccuring_tables test_model: TestModel.create!(content: 'test_2_1'), test_another_model: TestModel.create!(content: 'test_2_2') ) - test_attr_2.test_model.test_attrs.create! user = MockUser.new(:test_role, test_attr: test_attr_2.test_model.test_attrs.last) assert_equal 2, TestAttr.with_permissions_to(:read, user: user).references(:test_attrs, :test_models, :test_models_test_attrs, :test_attrs_test_models).length From e074849cabeb4664adc1e5e6d7dadb35e7ae6f76 Mon Sep 17 00:00:00 2001 From: Xymist Date: Thu, 7 Jun 2018 17:26:53 +0100 Subject: [PATCH 43/55] Update .travis.yml --- .travis.yml | 3 +- Gemfile.lock | 143 -------------------------------- Gemfile => gemfiles/5.2.gemfile | 0 3 files changed, 2 insertions(+), 144 deletions(-) delete mode 100644 Gemfile.lock rename Gemfile => gemfiles/5.2.gemfile (100%) diff --git a/.travis.yml b/.travis.yml index f1f63395..cb158115 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,8 +1,9 @@ language: ruby script: bundle exec rake test rvm: - - 2.4 + - 2.5 gemfile: - gemfiles/4.2.gemfile - gemfiles/5.0.gemfile + - gemfiles/5.2.gemfile diff --git a/Gemfile.lock b/Gemfile.lock deleted file mode 100644 index 5b06ae03..00000000 --- a/Gemfile.lock +++ /dev/null @@ -1,143 +0,0 @@ -PATH - remote: . - specs: - declarative_authorization (1.0.0.pre) - rails (>= 4.1.0, <= 5.2.0) - ruby_parser (~> 3.6.6) - -GEM - remote: https://rubygems.org/ - specs: - actioncable (5.2.0) - actionpack (= 5.2.0) - nio4r (~> 2.0) - websocket-driver (>= 0.6.1) - actionmailer (5.2.0) - actionpack (= 5.2.0) - actionview (= 5.2.0) - activejob (= 5.2.0) - mail (~> 2.5, >= 2.5.4) - rails-dom-testing (~> 2.0) - actionpack (5.2.0) - actionview (= 5.2.0) - activesupport (= 5.2.0) - rack (~> 2.0) - rack-test (>= 0.6.3) - rails-dom-testing (~> 2.0) - rails-html-sanitizer (~> 1.0, >= 1.0.2) - actionview (5.2.0) - activesupport (= 5.2.0) - builder (~> 3.1) - erubi (~> 1.4) - rails-dom-testing (~> 2.0) - rails-html-sanitizer (~> 1.0, >= 1.0.3) - activejob (5.2.0) - activesupport (= 5.2.0) - globalid (>= 0.3.6) - activemodel (5.2.0) - activesupport (= 5.2.0) - activerecord (5.2.0) - activemodel (= 5.2.0) - activesupport (= 5.2.0) - arel (>= 9.0) - activestorage (5.2.0) - actionpack (= 5.2.0) - activerecord (= 5.2.0) - marcel (~> 0.3.1) - activesupport (5.2.0) - concurrent-ruby (~> 1.0, >= 1.0.2) - i18n (>= 0.7, < 2) - minitest (~> 5.1) - tzinfo (~> 1.1) - arel (9.0.0) - builder (3.2.3) - concurrent-ruby (1.0.5) - crass (1.0.4) - erubi (1.7.1) - globalid (0.4.1) - activesupport (>= 4.2.0) - i18n (1.0.1) - concurrent-ruby (~> 1.0) - loofah (2.2.2) - crass (~> 1.0.2) - nokogiri (>= 1.5.9) - mail (2.7.0) - mini_mime (>= 0.1.1) - marcel (0.3.2) - mimemagic (~> 0.3.2) - method_source (0.9.0) - mimemagic (0.3.2) - mini_mime (1.0.0) - mini_portile2 (2.3.0) - minitest (5.11.3) - nio4r (2.3.1) - nokogiri (1.8.2) - mini_portile2 (~> 2.3.0) - power_assert (1.1.1) - rack (2.0.5) - rack-test (1.0.0) - rack (>= 1.0, < 3) - rails (5.2.0) - actioncable (= 5.2.0) - actionmailer (= 5.2.0) - actionpack (= 5.2.0) - actionview (= 5.2.0) - activejob (= 5.2.0) - activemodel (= 5.2.0) - activerecord (= 5.2.0) - activestorage (= 5.2.0) - activesupport (= 5.2.0) - bundler (>= 1.3.0) - railties (= 5.2.0) - sprockets-rails (>= 2.0.0) - rails-controller-testing (1.0.2) - actionpack (~> 5.x, >= 5.0.1) - actionview (~> 5.x, >= 5.0.1) - activesupport (~> 5.x) - rails-dom-testing (2.0.3) - activesupport (>= 4.2.0) - nokogiri (>= 1.6) - rails-html-sanitizer (1.0.4) - loofah (~> 2.2, >= 2.2.2) - railties (5.2.0) - actionpack (= 5.2.0) - activesupport (= 5.2.0) - method_source - rake (>= 0.8.7) - thor (>= 0.18.1, < 2.0) - rake (12.3.1) - rdoc (6.0.4) - ruby_parser (3.6.6) - sexp_processor (~> 4.1) - sexp_processor (4.11.0) - sprockets (3.7.1) - concurrent-ruby (~> 1.0) - rack (> 1, < 3) - sprockets-rails (3.2.1) - actionpack (>= 4.0) - activesupport (>= 4.0) - sprockets (>= 3.0.0) - sqlite3 (1.3.13) - test-unit (3.2.8) - power_assert - thor (0.20.0) - thread_safe (0.3.6) - tzinfo (1.2.5) - thread_safe (~> 0.1) - websocket-driver (0.7.0) - websocket-extensions (>= 0.1.0) - websocket-extensions (0.1.3) - -PLATFORMS - ruby - -DEPENDENCIES - declarative_authorization! - rails (~> 5.2.0) - rails-controller-testing - rdoc - sqlite3 - test-unit - -BUNDLED WITH - 1.16.1 diff --git a/Gemfile b/gemfiles/5.2.gemfile similarity index 100% rename from Gemfile rename to gemfiles/5.2.gemfile From b472f41171c1853c7a1f4ed53f245824f743583d Mon Sep 17 00:00:00 2001 From: Xymist Date: Thu, 7 Jun 2018 17:38:24 +0100 Subject: [PATCH 44/55] Version bump --- declarative_authorization.gemspec | 4 +--- gemfiles/5.2.gemfile | 2 +- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/declarative_authorization.gemspec b/declarative_authorization.gemspec index 42239d2a..a2f08eb7 100644 --- a/declarative_authorization.gemspec +++ b/declarative_authorization.gemspec @@ -1,14 +1,12 @@ Gem::Specification.new do |s| s.name = 'declarative_authorization' - s.version = '1.0.0.pre' + s.version = '1.1.0.pre' s.required_ruby_version = '>= 2.2.0' s.authors = ['Steffen Bartsch'] s.summary = 'declarative_authorization is a Rails plugin for maintainable authorization based on readable authorization rules.' s.email = 'sbartsch@tzi.org' s.files = %w[CHANGELOG MIT-LICENSE README.rdoc Rakefile authorization_rules.dist.rb garlic_example.rb init.rb] + Dir['app/**/*.rb'] + Dir['app/**/*.erb'] + Dir['config/*'] + Dir['lib/*.rb'] + Dir['lib/**/*.rb'] + Dir['lib/tasks/*'] + Dir['test/*'] - s.has_rdoc = true - s.extra_rdoc_files = ['README.rdoc', 'CHANGELOG'] s.homepage = 'http://github.com/stffn/declarative_authorization' s.add_dependency('rails', '>= 4.1.0', '<= 5.2.0') s.add_dependency('ruby_parser', '>= 3.6.6') diff --git a/gemfiles/5.2.gemfile b/gemfiles/5.2.gemfile index cd3d7e21..4bcc89d7 100644 --- a/gemfiles/5.2.gemfile +++ b/gemfiles/5.2.gemfile @@ -4,4 +4,4 @@ gem 'rails', '~> 5.2.0' gem 'sqlite3' gem 'rdoc' gem 'rails-controller-testing' -gemspec :path => '.' +gemspec :path => '..' From 8b7c2316396667ff89821022bb73aaedcd3f013b Mon Sep 17 00:00:00 2001 From: Xymist Date: Thu, 7 Jun 2018 17:48:13 +0100 Subject: [PATCH 45/55] Randomise test order --- config/environments/test.rb | 3 +++ gemfiles/5.0.gemfile | 1 + 2 files changed, 4 insertions(+) create mode 100644 config/environments/test.rb diff --git a/config/environments/test.rb b/config/environments/test.rb new file mode 100644 index 00000000..0531cdc8 --- /dev/null +++ b/config/environments/test.rb @@ -0,0 +1,3 @@ +Rails.application.configure do + config.active_support.test_order = :random +end diff --git a/gemfiles/5.0.gemfile b/gemfiles/5.0.gemfile index 8df04b29..9c8819ec 100644 --- a/gemfiles/5.0.gemfile +++ b/gemfiles/5.0.gemfile @@ -3,4 +3,5 @@ source 'https://rubygems.org' gem 'rails', '~> 5.0.0' gem 'sqlite3' gem 'rdoc' +gem 'rails-controller-testing' gemspec :path => '..' From ea4f1d49af55cd916410442d22cb0adfbf54fb83 Mon Sep 17 00:00:00 2001 From: Xymist Date: Thu, 7 Jun 2018 18:13:27 +0100 Subject: [PATCH 46/55] Fix various warnings --- lib/declarative_authorization/authorization.rb | 6 ++++-- test/development_support/analyzer_test.rb | 18 +++++++++--------- test/test_helper.rb | 11 ++--------- 3 files changed, 15 insertions(+), 20 deletions(-) diff --git a/lib/declarative_authorization/authorization.rb b/lib/declarative_authorization/authorization.rb index f5a97c97..429e4bab 100644 --- a/lib/declarative_authorization/authorization.rb +++ b/lib/declarative_authorization/authorization.rb @@ -83,6 +83,8 @@ class Engine def initialize(reader = nil) # @auth_rules = AuthorizationRuleSet.new reader.auth_rules_reader.auth_rules @reader = Reader::DSLReader.factory(reader || AUTH_DSL_FILES) + @rev_priv_hierarchy ||= {} + @rev_role_hierarchy ||= {} end def initialize_copy(from) # :nodoc: @@ -91,7 +93,7 @@ def initialize_copy(from) # :nodoc: # {[priv, ctx] => [priv, ...]} def rev_priv_hierarchy - if @rev_priv_hierarchy.nil? + if @rev_priv_hierarchy.blank? @rev_priv_hierarchy = {} privilege_hierarchy.each do |key, value| value.each do |val| @@ -105,7 +107,7 @@ def rev_priv_hierarchy # {[priv, ctx] => [priv, ...]} def rev_role_hierarchy - if @rev_role_hierarchy.nil? + if @rev_role_hierarchy.blank? @rev_role_hierarchy = {} role_hierarchy.each do |higher_role, lower_roles| lower_roles.each do |role| diff --git a/test/development_support/analyzer_test.rb b/test/development_support/analyzer_test.rb index 598b3451..7bcd0be6 100644 --- a/test/development_support/analyzer_test.rb +++ b/test/development_support/analyzer_test.rb @@ -12,7 +12,7 @@ class AuthorizationRulesAnalyzerTest < Test::Unit::TestCase def test_analyzing_complex_rules - engine, analyzer = engine_analyzer_for %( + _engine, _analyzer = engine_analyzer_for %( authorization do role :guest do has_permission_on :conferences, :to => :read do @@ -67,7 +67,7 @@ def test_analyzing_complex_rules end def test_mergeable_rules_without_constraints - engine, analyzer = engine_analyzer_for %( + _engine, analyzer = engine_analyzer_for %( authorization do role :test_role do has_permission_on :permissions, :to => :test @@ -82,7 +82,7 @@ def test_mergeable_rules_without_constraints end def test_mergeable_rules_with_in_block_to - engine, analyzer = engine_analyzer_for %( + _engine, _analyzer = engine_analyzer_for %( authorization do role :test_role do has_permission_on :permissions do @@ -94,7 +94,7 @@ def test_mergeable_rules_with_in_block_to end def test_no_mergeable_rules_with_constraints - engine, analyzer = engine_analyzer_for %( + _engine, analyzer = engine_analyzer_for %( authorization do role :test_role do has_permission_on :permissions, :to => :test do @@ -111,7 +111,7 @@ def test_no_mergeable_rules_with_constraints end def test_no_mergeable_rules_with_if_permitted_to - engine, analyzer = engine_analyzer_for %( + _engine, analyzer = engine_analyzer_for %( authorization do role :test_role do has_permission_on :permissions, :to => :test do @@ -129,7 +129,7 @@ def test_no_mergeable_rules_with_if_permitted_to end def test_role_explosion - engine, analyzer = engine_analyzer_for %( + _engine, analyzer = engine_analyzer_for %( authorization do role :test_role do has_permission_on :permissions, :to => :test @@ -154,7 +154,7 @@ def test_role_explosion end def test_inheriting_privileges - engine, analyzer = engine_analyzer_for %( + _engine, analyzer = engine_analyzer_for %( authorization do role :test_role do has_permission_on :permissions, :to => [:test, :test_2] @@ -172,7 +172,7 @@ def test_inheriting_privileges end def test_privileges_rules - engine, analyzer = engine_analyzer_for %( + engine, _analyzer = engine_analyzer_for %( authorization do role :test_role do has_permission_on :permissions, :to => [:test, :test_2] @@ -238,7 +238,7 @@ def test_roles_for_privilege end def test_analyze_for_proposed_privilege_hierarchy - engine, analyzer = engine_analyzer_for %( + _engine, analyzer = engine_analyzer_for %( authorization do role :test_role do has_permission_on :permissions, :to => [:test, :test_2] diff --git a/test/test_helper.rb b/test/test_helper.rb index 2f1ab0ef..5905910e 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -3,15 +3,7 @@ ENV['RAILS_ENV'] = 'test' require 'bundler/setup' -begin - # rails 3 - require 'rails/all' -rescue LoadError - # rails 2.3 - %w[action_pack action_controller active_record active_support initializer].each { |f| require f } -end -Bundler.require - +require 'rails/all' require 'minitest/autorun' puts "Testing against rails #{Rails::VERSION::STRING}" @@ -28,6 +20,7 @@ class MockDataObject def initialize(attrs = {}) attrs.each do |key, value| instance_variable_set(:"@#{key}", value) + next if self.respond_to?(:"#{key}") self.class.class_eval do attr_reader key end From dafccb76681a4ff3bbd990706a60d7aa83f059b5 Mon Sep 17 00:00:00 2001 From: Xymist Date: Thu, 7 Jun 2018 18:45:14 +0100 Subject: [PATCH 47/55] Explicit require of rails-controller-testing --- test/test_helper.rb | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/test/test_helper.rb b/test/test_helper.rb index 5905910e..64b5ae3d 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -1,11 +1,14 @@ -require 'pathname' - ENV['RAILS_ENV'] = 'test' +require 'pathname' require 'bundler/setup' require 'rails/all' require 'minitest/autorun' - +begin + require 'rails-controller-testing' +rescue LoadError + # Not required for Rails 4.2; not present in that Gemfile +end puts "Testing against rails #{Rails::VERSION::STRING}" RAILS_ROOT = File.dirname(__FILE__) From 941319e026cecbe5609d8052891baabeed3aacb5 Mon Sep 17 00:00:00 2001 From: Xymist Date: Thu, 7 Jun 2018 18:58:19 +0100 Subject: [PATCH 48/55] Add Ruby 2.2 and 2.4 to test matrix --- .travis.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.travis.yml b/.travis.yml index cb158115..085471c6 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,8 @@ language: ruby script: bundle exec rake test rvm: + - 2.2 + - 2.4 - 2.5 gemfile: - gemfiles/4.2.gemfile From 6dbd2d1f57df9c8665e3095dc386df00eda3b8f6 Mon Sep 17 00:00:00 2001 From: Xymist Date: Thu, 7 Jun 2018 19:01:22 +0100 Subject: [PATCH 49/55] Cache bundle after first build --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index 085471c6..01101563 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,5 +1,6 @@ language: ruby script: bundle exec rake test +cache: bundler rvm: - 2.2 - 2.4 From c2948bd08f9faa5b193c7423c92cb81cb05b40aa Mon Sep 17 00:00:00 2001 From: Xymist Date: Thu, 7 Jun 2018 19:20:03 +0100 Subject: [PATCH 50/55] Flag unused variables --- .../obligation_scope.rb | 2 +- test/development_support/analyzer_test.rb | 2 +- test/model_test.rb | 28 +++++++++---------- 3 files changed, 16 insertions(+), 16 deletions(-) diff --git a/lib/declarative_authorization/obligation_scope.rb b/lib/declarative_authorization/obligation_scope.rb index ca8204b2..4c5e165d 100644 --- a/lib/declarative_authorization/obligation_scope.rb +++ b/lib/declarative_authorization/obligation_scope.rb @@ -232,7 +232,7 @@ def rebuild_condition_options! used_paths = Set.new delete_paths = Set.new obligation_conditions.each_with_index do |array, obligation_index| - obligation, conditions = array + _obligation, conditions = array obligation_conds = [] conditions.each do |path, expressions| model = model_for( path ) diff --git a/test/development_support/analyzer_test.rb b/test/development_support/analyzer_test.rb index 7bcd0be6..4c61d08d 100644 --- a/test/development_support/analyzer_test.rb +++ b/test/development_support/analyzer_test.rb @@ -64,7 +64,7 @@ def test_analyzing_complex_rules privilege :delete, :includes => :destroy end ) - end + end def test_mergeable_rules_without_constraints _engine, analyzer = engine_analyzer_for %( diff --git a/test/model_test.rb b/test/model_test.rb index 5cf35bd1..cd31092a 100644 --- a/test/model_test.rb +++ b/test/model_test.rb @@ -146,7 +146,7 @@ def test_with_belongs_to_and_has_many_with_contains ) Authorization::Engine.instance(reader) - test_attr_1 = TestAttr.create! + _test_attr_1 = TestAttr.create! test_model_1 = TestModel.create! test_model_1.test_attrs.create! @@ -617,7 +617,7 @@ def test_multiple_belongs_to ) Authorization::Engine.instance(reader) - test_attr_1 = TestAttr.create! test_model_id: 1, test_another_model_id: 2 + _test_attr_1 = TestAttr.create! test_model_id: 1, test_another_model_id: 2 user = MockUser.new(:test_role, id: 1) assert_equal 1, TestAttr.with_permissions_to(:read, user: user).length @@ -930,8 +930,8 @@ def test_with_contains_through_primary_key test_attr_through_1 = TestAttrThrough.create! test_item = NWayJoinItem.create! - test_model_1 = TestModel.create!(test_attr_through_id: test_attr_through_1.id) - test_attr_1 = TestAttr.create!(test_attr_through_id: test_attr_through_1.id, + _test_model_1 = TestModel.create!(test_attr_through_id: test_attr_through_1.id) + _test_attr_1 = TestAttr.create!(test_attr_through_id: test_attr_through_1.id, n_way_join_item_id: test_item.id) user = MockUser.new(:test_role, @@ -1268,7 +1268,7 @@ def test_with_if_permitted_to_and_empty_obligations Authorization::Engine.instance(reader) test_model_1 = TestModel.create! - test_attr_1 = test_model_1.test_attrs.create! + _test_attr_1 = test_model_1.test_attrs.create! user = MockUser.new(:test_role) assert_equal 1, TestAttr.with_permissions_to(:read, user: user).length @@ -1317,7 +1317,7 @@ def test_with_if_permitted_to_self test_model_1 = TestModel.create! test_attr_1 = test_model_1.test_attrs.create! - test_attr_2 = TestAttr.create! + _test_attr_2 = TestAttr.create! user = MockUser.new(:test_role, id: test_attr_1.id) assert_equal 1, TestModel.with_permissions_to(:update, user: user).length @@ -1339,11 +1339,11 @@ def test_with_has_many_and_reoccuring_tables ) Authorization::Engine.instance(reader) - test_attr_1 = TestAttr.create!( + _test_attr_1 = TestAttr.create!( test_model: TestModel.create!(content: 'test_1_1'), test_another_model: TestModel.create!(content: 'test_1_2') ) - test_attr_2 = TestAttr.create!( + _test_attr_2 = TestAttr.create!( test_model: TestModel.create!(content: 'test_2_1'), test_another_model: TestModel.create!(content: 'test_2_2') ) @@ -1372,7 +1372,7 @@ def test_with_ored_rules_and_reoccuring_tables ) Authorization::Engine.instance(reader) - test_attr_1 = TestAttr.create!( + _test_attr_1 = TestAttr.create!( test_model: TestModel.create!(content: 'test_1_1'), test_another_model: TestModel.create!(content: 'test_1_2') ) @@ -1408,12 +1408,12 @@ def test_with_many_ored_rules_and_reoccuring_tables country = Country.create!(name: 'country_1') country.test_models.create! - test_attr_1 = TestAttr.create!( + _test_attr_1 = TestAttr.create!( branch: Branch.create!(name: 'branch_1', company: Company.create!(name: 'company_1', country: country)) ) - test_attr_2 = TestAttr.create!( + _test_attr_2 = TestAttr.create!( company: Company.create!(name: 'company_2', country: country) ) @@ -1640,7 +1640,7 @@ def test_model_security_changing_critical_attribute_unallowed Authorization::Engine.instance(reader) Authorization.current_user = MockUser.new(:test_role_unrestricted) - object = TestModelSecurityModel.create attr: 2 + _object = TestModelSecurityModel.create attr: 2 Authorization.current_user = MockUser.new(:test_role) # TODO: before not checked yet @@ -1768,12 +1768,12 @@ def test_authorization_permit_nested_association_proxy test_model = TestModel.create! test_model.test_attrs.create!(attr: 0) - test_attr = test_model.test_attrs.create!(attr: 1) + _test_attr = test_model.test_attrs.create!(attr: 1) test_model.test_attrs.create!(attr: 3) test_branch = Branch.create!(test_model: test_model) test_model_2 = TestModel.create! - test_attr_2 = test_model_2.test_attrs.create!(attr: 2) + _test_attr_2 = test_model_2.test_attrs.create!(attr: 2) test_branch_2 = Branch.create!(test_model: test_model_2) test_model_3 = TestModel.create! From 8bde2df92418e3907125a908d8c068e2ef654665 Mon Sep 17 00:00:00 2001 From: Xymist Date: Thu, 7 Jun 2018 19:27:48 +0100 Subject: [PATCH 51/55] Update Readme --- Readme.md | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/Readme.md b/Readme.md index 8ad3dcc2..24647212 100644 --- a/Readme.md +++ b/Readme.md @@ -1,16 +1,13 @@ Original docs: [https://github.com/stffn/declarative_authorization/blob/master/README.rdoc](https://github.com/stffn/declarative_authorization/blob/master/README.rdoc) -### Polymorphic associations - -This branch contains polymorphic belongs_to association support. -It relies on a monkey patch to active record which provides the method `poly_resources` -that returns a list of classes that the polymorphic association can point to. +Extends Declarative Authorization with Rails 5.2 and Ruby 2.5 support, aiming for backwards compatibility as far as Rails 4.2 and Ruby 2.2 on a best-effort basis. +Branch r5: [![Build Status](https://travis-ci.org/Xymist/declarative_authorization.svg?branch=r5)](https://travis-ci.org/Xymist/declarative_authorization) ### Running tests for DA ``` -cp gemfiles/3.2.gemfile Gemfile +cp gemfiles/{RAILS_VERSION}.gemfile Gemfile bundle bundle exec rake test From 614fee8b9c5df36367fbc1232d7ae7393ddc0599 Mon Sep 17 00:00:00 2001 From: satyendra-cis Date: Fri, 8 Jun 2018 14:18:02 +0530 Subject: [PATCH 52/55] Added fix for sexp integer type errors --- lib/declarative_authorization/development_support/analyzer.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/declarative_authorization/development_support/analyzer.rb b/lib/declarative_authorization/development_support/analyzer.rb index 21eb23d5..d0473084 100644 --- a/lib/declarative_authorization/development_support/analyzer.rb +++ b/lib/declarative_authorization/development_support/analyzer.rb @@ -163,6 +163,7 @@ def analyze_rules end def process_iter(exp) + exp.delete_if {|x| x.is_a? Integer } s(:iter, process(exp.shift), process(exp.shift), process(exp.shift)) end From 81c0a00450fb7b6f7d6574509db486e5cb21bde3 Mon Sep 17 00:00:00 2001 From: Xymist Date: Thu, 21 Jun 2018 11:43:52 +0100 Subject: [PATCH 53/55] Add Rails 4.2 back in to matrix --- .travis.yml | 1 + gemfiles/4.1.gemfile | 6 ------ gemfiles/4.2.gemfile | 2 +- 3 files changed, 2 insertions(+), 7 deletions(-) delete mode 100644 gemfiles/4.1.gemfile diff --git a/.travis.yml b/.travis.yml index d05a354c..01101563 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,6 +6,7 @@ rvm: - 2.4 - 2.5 gemfile: + - gemfiles/4.2.gemfile - gemfiles/5.0.gemfile - gemfiles/5.2.gemfile diff --git a/gemfiles/4.1.gemfile b/gemfiles/4.1.gemfile deleted file mode 100644 index 85f32ba5..00000000 --- a/gemfiles/4.1.gemfile +++ /dev/null @@ -1,6 +0,0 @@ -source 'https://rubygems.org' - -gem 'rails', '~> 4.1.0' -gem 'sqlite3' -gem 'rdoc' -gemspec :path => '..' diff --git a/gemfiles/4.2.gemfile b/gemfiles/4.2.gemfile index a9d60ab6..9470b331 100644 --- a/gemfiles/4.2.gemfile +++ b/gemfiles/4.2.gemfile @@ -3,4 +3,4 @@ source 'https://rubygems.org' gem 'rails', '~> 4.2.0' gem 'sqlite3' gem 'rdoc' -gemspec :path => '..' +gemspec path: '..' From 043759f316024d114d71edcf3a61ce98b7056ff5 Mon Sep 17 00:00:00 2001 From: Nic Martin Date: Wed, 28 Nov 2018 09:28:52 +0000 Subject: [PATCH 54/55] Allow Rails 5.2.+ Security issues mean Rails 5.2 point release is now 5.2.1.1 Change the dependencies to be more permissive about Rails versions --- declarative_authorization.gemspec | 2 +- gemfiles/5.2.gemfile | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/declarative_authorization.gemspec b/declarative_authorization.gemspec index a2f08eb7..d8e4c2b1 100644 --- a/declarative_authorization.gemspec +++ b/declarative_authorization.gemspec @@ -8,7 +8,7 @@ Gem::Specification.new do |s| s.email = 'sbartsch@tzi.org' s.files = %w[CHANGELOG MIT-LICENSE README.rdoc Rakefile authorization_rules.dist.rb garlic_example.rb init.rb] + Dir['app/**/*.rb'] + Dir['app/**/*.erb'] + Dir['config/*'] + Dir['lib/*.rb'] + Dir['lib/**/*.rb'] + Dir['lib/tasks/*'] + Dir['test/*'] s.homepage = 'http://github.com/stffn/declarative_authorization' - s.add_dependency('rails', '>= 4.1.0', '<= 5.2.0') + s.add_dependency('rails', '>= 4.1.0', '< 6') s.add_dependency('ruby_parser', '>= 3.6.6') s.add_development_dependency('test-unit') end diff --git a/gemfiles/5.2.gemfile b/gemfiles/5.2.gemfile index 4bcc89d7..32956ace 100644 --- a/gemfiles/5.2.gemfile +++ b/gemfiles/5.2.gemfile @@ -1,6 +1,6 @@ source 'https://rubygems.org' -gem 'rails', '~> 5.2.0' +gem 'rails', '~> 5.2' gem 'sqlite3' gem 'rdoc' gem 'rails-controller-testing' From 223e6641ca4c440ffac7719957dea6044b04fe05 Mon Sep 17 00:00:00 2001 From: Rob van Dijk Date: Sun, 14 Apr 2019 17:26:21 +0200 Subject: [PATCH 55/55] Fixes request_with to use Hash --- .gitignore | 7 ++++-- lib/declarative_authorization/maintenance.rb | 4 ++-- test/maintenance_test.rb | 25 ++++++++++++++++++++ test/test_helper.rb | 1 + 4 files changed, 33 insertions(+), 4 deletions(-) diff --git a/.gitignore b/.gitignore index f69fc3be..c9c6a3ac 100644 --- a/.gitignore +++ b/.gitignore @@ -5,5 +5,8 @@ rdoc gemfiles/*.lock log/* *.sublime* - - +.ruby-version +.ruby-gemset +.idea +Gemfile +Gemfile.lock diff --git a/lib/declarative_authorization/maintenance.rb b/lib/declarative_authorization/maintenance.rb index 6b8e9d2b..d22ce324 100644 --- a/lib/declarative_authorization/maintenance.rb +++ b/lib/declarative_authorization/maintenance.rb @@ -181,9 +181,9 @@ def request_with(user, method, xhr, action, params = {}, session = session.merge(user: user, user_id: user && user.id) with_user(user) do if xhr - xhr method, action, params, session, flash + xhr method, action, params: params, session: session, flash: flash else - send method, action, params, session, flash + send method, action, params: params, session: session, flash: flash end end end diff --git a/test/maintenance_test.rb b/test/maintenance_test.rb index 55ea47ea..00530c53 100644 --- a/test/maintenance_test.rb +++ b/test/maintenance_test.rb @@ -43,3 +43,28 @@ def test_without_access_control end end end + +class MaintenanceMocksController < MocksController + filter_access_to :test_action, require: :test, context: :permissions + define_action_methods :test_action +end + +class MaintenanceControllerTest < ActionController::TestCase + tests MaintenanceMocksController + + def test_request_with + reader = Authorization::Reader::DSLReader.new + reader.parse %( + authorization do + role :test_role do + has_permission_on :permissions, :to => :test + has_permission_on :specific_mocks, :to => :show + end + end + ) + Authorization::Engine.instance(reader) + + get_with(MockUser.new(:test_role), 'test_action') + assert @controller.authorized? + end +end \ No newline at end of file diff --git a/test/test_helper.rb b/test/test_helper.rb index 833d3462..3a74082f 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -54,6 +54,7 @@ def self.find_or_initialize_by(args) end class MockUser < MockDataObject + attr_accessor :id def initialize(*roles) options = roles.last.is_a?(::Hash) ? roles.pop : {} super({ role_symbols: roles, login: hash }.merge(options))