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/.travis.yml b/.travis.yml index 2cd0bb7b..01101563 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,20 +1,12 @@ language: ruby script: bundle exec rake test +cache: bundler rvm: - - 1.8.7 - - 1.9.3 + - 2.2 + - 2.4 + - 2.5 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 - gemfile: gemfiles/4.1.gemfile - - rvm: 1.9.3 - gemfile: gemfiles/2.3.gemfile + - gemfiles/4.2.gemfile + - gemfiles/5.0.gemfile + - gemfiles/5.2.gemfile + diff --git a/README.rdoc b/README.rdoc index e6118710..12edfcab 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 @@ -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. @@ -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 @@ -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 %> @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -454,14 +454,12 @@ 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 - + Or, with RSpec, it would work like this: describe Employee do @@ -484,29 +482,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,18 +504,18 @@ 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 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 +534,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 +576,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 +586,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/Rakefile b/Rakefile index 635ba70f..223a7d11 100644 --- a/Rakefile +++ b/Rakefile @@ -3,9 +3,9 @@ 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 +def run_for_bundles(cmd) Dir['gemfiles/*.gemfile'].each do |gemfile| puts "\n#{gemfile}: #{cmd}" ENV['BUNDLE_GEMFILE'] = 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/Readme.md b/Readme.md new file mode 100644 index 00000000..24647212 --- /dev/null +++ b/Readme.md @@ -0,0 +1,16 @@ +Original docs: [https://github.com/stffn/declarative_authorization/blob/master/README.rdoc](https://github.com/stffn/declarative_authorization/blob/master/README.rdoc) + +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/{RAILS_VERSION}.gemfile Gemfile +bundle + +bundle exec rake test +``` + + diff --git a/app/controllers/authorization_rules_controller.rb b/app/controllers/authorization_rules_controller.rb index 9c454378..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 - @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]} + 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 - 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! + @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 - @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[: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 - if options[:only_relevant_contexts] - @contexts.delete_if do |context| - @roles.all? {|role| !@role_privs[role] || !@role_privs[role].any? {|info| info[0] == context}} + @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 - 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[:only_relevant_contexts] + @contexts.delete_if do |context| + @roles.all? { |role| !@role_privs[role] || @role_privs[role].none? { |info| info[0] == context } } 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? || (c == context) } + .collect { |p, _c| p } + privs.concat(context_lower_privs).uniq! + 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 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 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 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 effa802d..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 - - helper :authorization_rules - filter_access_to :all, :require => :read - # TODO set context? + class AuthorizationUsagesController < ApplicationController + 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 dba93924..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) + 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] } @@ -15,45 +15,45 @@ 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), - "\\1\\2") + (re.is_a?(Symbol) ? Regexp.new("()(:#{Regexp.escape(re.to_s)})\\b") : re), + "\\1\\2" + ) end end 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") - 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 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}'" + 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') - end - - def role_color (role, fill = false) + 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) if @has_changes if has_changed(:add_role, role) fill ? '#ddffdd' : '#000000' @@ -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 @@ -73,88 +73,84 @@ def role_color (role, fill = false) @@role_colors[role][fill ? 1 : 0] 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) - begin - I18n.t(privilege, :scope => [:declarative_authorization, :privilege], :raise => true) - rescue - privilege.to_s - end + def human_privilege(privilege) + 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 + def human_context(context) + context.to_s.classify.constantize.human_name + rescue StandardError + context.to_s 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) + 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 + def human_role(role) + Authorization::Engine.instance.title_for(role) || role.to_s end - def describe_step (step, options = {}) - options = {:with_removal => false}.merge(options) + def describe_step(step, 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) + 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 - - def readable_step_info (info) + + def readable_step_info(info) case info when Symbol then info.inspect when User then info.login @@ -162,57 +158,57 @@ def readable_step_info (info) end 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 * ';' + 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) - step.collect {|info| readable_step_info(info) } * ',' + 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). - map(&:to_sym) + [:new_role_for_change_analyzer]).uniq}.to_param + 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] - 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) + 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 78326f7e..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/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/config/routes.rb b/config/routes.rb index f5c49d31..25a92117 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -1,20 +1,12 @@ -if Authorization::activate_authorization_rules_browser? - if Rails.respond_to?(:application) - 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 - 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 + resources :authorization_usages, only: :index end end diff --git a/declarative_authorization.gemspec b/declarative_authorization.gemspec index c36e1cb7..d8e4c2b1 100644 --- a/declarative_authorization.gemspec +++ b/declarative_authorization.gemspec @@ -1,17 +1,14 @@ -# -*- encoding: utf-8 -*- - Gem::Specification.new do |s| - s.name = "declarative_authorization" - s.version = "1.0.0.pre" - - s.required_ruby_version = ">= 1.8.6" - 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.name = 'declarative_authorization' + s.version = '1.1.0.pre' - #s.add_dependency('rails', '>= 2.1.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' + 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', '< 6') + 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/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 deleted file mode 100644 index cdff0429..00000000 --- a/gemfiles/3.2.gemfile +++ /dev/null @@ -1,8 +0,0 @@ -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 deleted file mode 100644 index 2096153a..00000000 --- a/gemfiles/4.0.gemfile +++ /dev/null @@ -1,8 +0,0 @@ -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 deleted file mode 100644 index a54f675c..00000000 --- a/gemfiles/4.1.gemfile +++ /dev/null @@ -1,7 +0,0 @@ -source 'https://rubygems.org' - -gem 'rails', '~> 4.1.0' -gem 'sqlite3' -gem 'ruby_parser' -gem 'rdoc' -gemspec :path => '..' \ No newline at end of file diff --git a/gemfiles/4.2.gemfile b/gemfiles/4.2.gemfile new file mode 100644 index 00000000..9470b331 --- /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: '..' diff --git a/gemfiles/5.0.gemfile b/gemfiles/5.0.gemfile new file mode 100644 index 00000000..9133e2fd --- /dev/null +++ b/gemfiles/5.0.gemfile @@ -0,0 +1,8 @@ +source 'https://rubygems.org' + +gem 'rails', '~> 5.0.0' +gem 'sqlite3' +gem 'rdoc' +gem 'rails-controller-testing' +gem 'minitest', '5.10.3' +gemspec path: '..' diff --git a/gemfiles/2.3.gemfile b/gemfiles/5.2.gemfile similarity index 59% rename from gemfiles/2.3.gemfile rename to gemfiles/5.2.gemfile index fa5f3b14..32956ace 100644 --- a/gemfiles/2.3.gemfile +++ b/gemfiles/5.2.gemfile @@ -1,8 +1,7 @@ source 'https://rubygems.org' -gem 'rails', '~> 2.3.0' +gem 'rails', '~> 5.2' gem 'sqlite3' -gem 'ruby_parser' gem 'rdoc' +gem 'rails-controller-testing' gemspec :path => '..' - diff --git a/lib/declarative_authorization.rb b/lib/declarative_authorization.rb index 81d1f02e..bce517da 100644 --- a/lib/declarative_authorization.rb +++ b/lib/declarative_authorization.rb @@ -1,17 +1,11 @@ -require File.join(%w{declarative_authorization rails_legacy}) -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 -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) +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/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 b8fc761a..429e4bab 100644 --- a/lib/declarative_authorization/authorization.rb +++ b/lib/declarative_authorization/authorization.rb @@ -1,74 +1,70 @@ # 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 + def self.ignore_access_control(state = nil) # :nodoc: + 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 - def self.dot_path= (path) + def self.dot_path=(path) @@dot_path = path end - + @@default_role = :guest 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) - if Rails.version < "3.2" - object.respond_to?(:proxy_reflection) - else - object.respond_to?(:proxy_association) - end + def self.is_a_association_proxy?(object) + object.respond_to?(:proxy_association) 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,25 +76,27 @@ 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. - def initialize (reader = nil) - #@auth_rules = AuthorizationRuleSet.new reader.auth_rules_reader.auth_rules + 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: + def initialize_copy(from) # :nodoc: @reader = from.reader.clone end # {[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| + value.each do |val| @rev_priv_hierarchy[val] ||= [] @rev_priv_hierarchy[val] << key end @@ -106,10 +104,10 @@ def rev_priv_hierarchy end @rev_priv_hierarchy end - + # {[priv, ctx] => [priv, ...]} - def rev_role_hierarchy - if @rev_role_hierarchy.nil? + def rev_role_hierarchy + if @rev_role_hierarchy.blank? @rev_role_hierarchy = {} role_hierarchy.each do |higher_role, lower_roles| lower_roles.each do |role| @@ -119,43 +117,43 @@ 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+] # 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, - :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 - + # # If the object responds to :proxy_reflection, we're probably working with # an association proxy. Use 'new' to leverage ActiveRecord's builder @@ -164,24 +162,28 @@ 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 + + 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 - - 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? + 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 + # 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,90 +191,93 @@ def permit! (privilege, options = {}) if options[:bang] if rules.empty? - raise NotAuthorized, "No matching rules found for #{privilege} for #{user.inspect} " + - "(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.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: - if permit!(privilege, options.merge(:bang=> false)) + def permit?(privilege, options = {}) # :yields: + if permit!(privilege, options.merge(bang: false)) yield if block_given? true else 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! - # - def obligations (privilege, options = {}) - options = {:context => nil}.merge(options) + # + def obligations(privilege, 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]) - - return [] if roles.is_a?(Array) and not (roles & omnipotent_roles).empty? - + permit!(privilege, skip_attribute_test: true, user: user, context: options[:context]) + + 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| 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) + 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) + raise AuthorizationUsageError, "User object doesn't respond to roles (#{user.try(:id)})" \ + 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 - + # Returns the role symbols and inherritted role symbols for the given user def roles_with_hierarchy_for(user) flatten_roles(roles_for(user)) @@ -280,7 +285,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 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 @@ -290,89 +301,91 @@ 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? + def self.instance(dsl_file = nil) + if dsl_file || development_reload? @@instance = new(dsl_file) else @@instance ||= new end end - + 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 @privilege = privilege @context = context end - - def evaluate (value_block) - # TODO cache? + + def evaluate(value_block) + # 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 (#{user.inspect}) 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] [user, roles, privileges] end - - def flatten_roles (roles, flattened_roles = Set.new) - # TODO caching? - roles.reject {|role| flattened_roles.include?(role)}.each do |role| + + def flatten_roles(roles, flattened_roles = Set.new) + # 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 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? - raise AuthorizationUsageError, "No context given or inferable from object" unless context - privileges.reject {|priv| flattened_privileges.include?(priv)}.each do |priv| + 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| 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]] end 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 - class AuthorizationRuleSet include Enumerable extend Forwardable def_delegators :@rules, :each, :length, :[] - def initialize (rules = []) + def initialize(rules = []) @rules = rules.clone reset! end - def initialize_copy (source) - @rules = @rules.collect {|rule| rule.clone} + def initialize_copy(_source) + @rules = @rules.collect(&:clone) reset! end @@ -383,22 +396,27 @@ 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 - @rules.each &block + + def each(&block) + @rules.each(&block) end private + def reset! - @cached_auth_rules =nil + @cached_auth_rules = nil end + def cached_auth_rules return @cached_auth_rules if @cached_auth_rules @cached_auth_rules = {} @@ -411,12 +429,13 @@ 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, - options = {}) + :source_file, :source_line + + def initialize(role, privileges = [], contexts = nil, join_operator = :or, + options = {}) @role = role @privileges = Set.new(privileges) @contexts = Set.new((contexts && !contexts.is_a?(Array) ? [contexts] : contexts)) @@ -426,38 +445,38 @@ 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) + + 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? + @contexts.include?(context) && roles.include?(@role) && + !(@privileges & privs).empty? end - def validate? (attr_validator, skip_attribute = false) - skip_attribute or @attributes.empty? or + def validate?(attr_validator, skip_attribute = false) + 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 end - def obligations (attr_validator) + def obligations(attr_validator) exceptions = [] obligations = @attributes.collect do |attr| begin @@ -468,13 +487,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 @@ -492,35 +511,35 @@ def obligations (attr_validator) end def to_long_s - attributes.collect {|attr| attr.to_long_s } * "; " + attributes.collect(&:to_long_s) * '; ' end end - + 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 - - 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) end return false end - + (hash || @conditions_hash).all? do |attr, value| attr_value = object_attribute_value(object, attr) if value.is_a?(Hash) @@ -528,12 +547,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 @@ -548,41 +567,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 @@ -596,35 +615,34 @@ 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 - + # 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) 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 end - def to_long_s (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}" @@ -632,18 +650,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 + + def object_attribute_value(object, attr) + 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)| + def deep_hash_clone(hash) + hash.each_with_object({}) do |(key, val), memo| memo[key] = case val when Hash deep_hash_clone(val) @@ -652,7 +669,6 @@ def deep_hash_clone (hash) else val.clone end - memo end end end @@ -662,17 +678,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 @@ -685,15 +701,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| @@ -704,14 +720,14 @@ 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 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 @@ -723,28 +739,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 @@ -759,8 +774,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 @@ -771,28 +786,28 @@ 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) + 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? reflection end end - + # 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 end - diff --git a/lib/declarative_authorization/development_support/analyzer.rb b/lib/declarative_authorization/development_support/analyzer.rb index a49f2c7a..3cdc28ea 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 @@ -21,9 +19,9 @@ 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) + # 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,28 +64,33 @@ 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 + + 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)) + 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) } + def analyze_rule(rule) + 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 - def analyze_privilege (privilege) + # 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) + 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 @@ -148,7 +153,7 @@ def initialize(analyzer) @analyzer = analyzer end - def analyze (sexp_array) + def analyze(sexp_array) process(sexp_array) analyze_rules end @@ -157,48 +162,47 @@ def analyze_rules # to be implemented by specific processor end - def process_iter (exp) + def process_iter(exp) + exp.delete_if { |x| x.is_a? Integer } s(:iter, process(exp.shift), process(exp.shift), process(exp.shift)) end - def process_arglist (exp) - s(exp.collect {|inner_exp| process(inner_exp).shift}) + def process_arglist(exp) + s(exp.collect { |inner_exp| process(inner_exp).shift }) end - def process_hash (exp) - s(Hash[*exp.collect {|inner_exp| process(inner_exp).shift}]) + 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 class MergeableRulesProcessor < GeneralAuthorizationProcessor def analyze_rules + @has_permission ||= false if @has_permission - #p @has_permission - permissions_by_context_and_rules = @has_permission.inject({}) do |memo, 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 end - def process_call (exp) + def process_call(exp) klass = exp.shift name = exp.shift case name @@ -213,11 +217,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 +241,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 @@ -249,7 +253,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..85e22f44 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] + def find_approaches_for(change_action, type, options, &tests) + 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] - [: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] + when %i[remove permission] + %i[remove_role_from_user remove_privilege add_privilege +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 - next_step(viable_approaches, candidates, approach_checker, options[:to], - options[:on], strategy) + while !candidates.empty? && (step_count < 100) + next_step(viable_approaches, candidates, approach_checker, options[:to], + options[:on], strategy) step_count += 1 end @@ -69,11 +66,12 @@ def find_approaches_for (change_action, type, options, &tests) class ApproachChecker attr_reader :failed_test_count, :users - def initialize (analyzer, tests) - @analyzer, @tests = analyzer, tests + def initialize(analyzer, tests) + @analyzer = analyzer + @tests = tests end - def check (engine, users) + def check(engine, users) @current_engine = engine @failed_test_count = 0 @users = users @@ -82,50 +80,52 @@ 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) - @engine, @users, @steps = engine, users, steps + def initialize(engine, users, steps) + @engine = engine + @users = users + @steps = 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})" + # 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 def changes - @steps.select {|step| step.length > 1} + @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)} } + 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,42 +133,45 @@ def sort_value end def inspect - "Approach (#{state_hash}): Steps: #{changes.map(&:inspect) * ', '}"# + - # "\n Roles: #{AnalyzerEngine.roles(@engine).map(&:to_sym).inspect}; " + - # "\n Users: #{@users.map(&:role_symbols).inspect}" + "Approach (#{state_hash}): Steps: #{changes.map(&:inspect) * ', '}" # + + # "\n Roles: #{AnalyzerEngine.roles(@engine).map(&:to_sym).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) - # TODO use approach.users.index(self[idx]) == + def eql?(other) + # 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? do |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 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) + + def next_step(viable_approaches, candidates, approach_checker, + 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 +179,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 +232,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 @@ -242,8 +245,8 @@ def next_step (viable_approaches, candidates, approach_checker, candidates.sort! end - def relevant_roles (approach) - #return AnalyzerEngine.roles(approach.engine) + 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) ? [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 8e476057..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,13 +38,12 @@ 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 # 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 = {} @@ -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 @@ -72,9 +70,9 @@ 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) + if grouped.last && grouped.last.approach.similar_to(approach) grouped.last.similar_approaches << approach else grouped << GroupedApproach.new(approach) @@ -84,7 +82,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 +91,12 @@ def initialize (approach) class ApproachChecker attr_reader :users, :failed_tests - def initialize (analyzer, tests) - @analyzer, @tests = analyzer, tests + def initialize(analyzer, tests) + @analyzer = analyzer + @tests = tests end - def check (engine, users) + def check(engine, users) @current_engine = engine @failed_tests = [] @current_test_args = nil @@ -108,22 +107,24 @@ 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)])) + *(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 + def initialize(positive, privilege, options = {}) + @positive = positive + @privilege = privilege @context = options[:context] @user = options[:user] end @@ -131,27 +132,29 @@ 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 + def initialize(engine, users, steps) + @engine = engine + @users = users + @steps = 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})" + # 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]} + def affected_users(original_engine, original_users, privilege, context) + (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 @@ -177,29 +180,29 @@ def abstract_actions end end - def reverse_of_previous? (specific_action) - changes.any? {|step| step.reverse?(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)} } + 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 @@ -210,19 +213,19 @@ def weight changes.sum(&: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 + def similar_to(other) + (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) + def <=>(other) sort_value <=> other.sort_value end end @@ -233,45 +236,45 @@ 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 + def eql?(other) + (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 [: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] + to_a[0, min_length] == spec[0, min_length] end - def resembles_any? (specs) - specs.any? {|spec| resembles?(spec) } + 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,40 +288,41 @@ def weight @actions.sum(&:weight) + 1 end - def apply (candidate) - @actions.all? {|action| action.apply(candidate)} + def apply(candidate) + @actions.all? { |action| action.apply(candidate) } end - def reverse? (other) - @actions.any? {|action| action.reverse?(other)} + def 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 + def resembles?(spec) + @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 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) + 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 @@ -326,19 +330,21 @@ def self.specific_actions (candidate) end attr_reader :privilege, :context, :role - def initialize (privilege_sym, context, role_sym) - @privilege, @context, @role = privilege_sym, context, role_sym + def initialize(privilege_sym, context, role_sym) + @privilege = privilege_sym + @context = context + @role = role_sym end - def apply (candidate) + def apply(candidate) AnalyzerEngine.apply_change(candidate.engine, to_a) end - def reverse? (other) - other.is_a?(RemovePrivilegeFromRoleAction) and - other.privilege == @privilege and - other.context == @context and - other.role == @role + def reverse?(other) + other.is_a?(RemovePrivilegeFromRoleAction) && + (other.privilege == @privilege) && + (other.context == @context) && + (other.role == @role) end def to_a @@ -347,7 +353,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 +363,12 @@ def self.specific_actions (candidate) end attr_reader :user, :role - def initialize (user, role_sym) - @user, @role = user, role_sym + def initialize(user, role_sym) + @user = user + @role = role_sym end - def apply (candidate) + def apply(candidate) if candidate.engine.roles_with_hierarchy_for(@user).include?(@role) false else @@ -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 + def reverse?(other) + 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) + def resembles?(spec) + super(spec[0, 2]) && ((spec.length == 2) || (spec[2] == @user.login)) end def to_a @@ -397,9 +404,10 @@ 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) + 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) @@ -409,12 +417,15 @@ def self.specific_actions (candidate) end 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 + def initialize(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 - def apply (candidate) + def apply(candidate) if AnalyzerEngine.apply_change(candidate.engine, [:add_role, @role]) super(candidate) else @@ -432,9 +443,10 @@ 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) + 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| @@ -445,8 +457,11 @@ def self.specific_actions (candidate) end attr_reader :user, :privilege, :context, :role - def initialize (user, privilege_sym, context, role_sym) - @user, @privilege, @context, @role = user, privilege_sym, context, role_sym + def initialize(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) @@ -455,32 +470,35 @@ 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) + 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 end attr_reader :privilege, :context, :role - def initialize (privilege_sym, context, role_sym) - @privilege, @context, @role = privilege_sym, context, role_sym + def initialize(privilege_sym, context, role_sym) + @privilege = privilege_sym + @context = context + @role = role_sym end - def apply (candidate) + def apply(candidate) AnalyzerEngine.apply_change(candidate.engine, to_a) end - - def reverse? (other) - (other.is_a?(AssignPrivilegeToRoleAction) or - other.is_a?(AbstractCompoundAction)) and - other.reverse?(self) + + def reverse?(other) + (other.is_a?(AssignPrivilegeToRoleAction) || + other.is_a?(AbstractCompoundAction)) && + other.reverse?(self) end def to_a @@ -489,46 +507,47 @@ 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 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 + def initialize(user, role_sym) + @user = user + @role = role_sym end - def apply (candidate) + def apply(candidate) # beware of shallow copies! cloned_user = @user.clone user_index = candidate.users.index(@user) 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) + def reverse?(other) + (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) + def resembles?(spec) + super(spec[0, 2]) && ((spec.length == 2) || (spec[2] == @user.login)) end def to_a @@ -537,7 +556,8 @@ 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,15 +567,15 @@ 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| 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 @@ -563,7 +583,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 +598,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)} + (@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 +615,23 @@ 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..9963e0c3 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 @@ -13,31 +13,30 @@ 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) + 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 + 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) - 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) + def self.apply_change(engine, change) case change[0] when :add_role role_symbol = change[1] @@ -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) @@ -78,7 +77,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 @@ -87,29 +86,32 @@ 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 # 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 + + (@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 + + (@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) + + def rules_for_permission(privilege, context) rules.select do |rule| rule.matches?([@role], [privilege.to_sym], context) end @@ -118,75 +120,81 @@ 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) - rules_by_role = engine.auth_rules.inject({}) do |memo, rule| + def self.all(engine) + 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) + + 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) + 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) + + 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 + + (@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] || []). - 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,33 +202,37 @@ 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 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 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 +241,16 @@ def delete (privilege) end end - def intersects? (privileges) - intersection(privileges).length > 0 + def intersects?(privileges) + !intersection(privileges).empty? 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..3b3ba213 100644 --- a/lib/declarative_authorization/helper.rb +++ b/lib/declarative_authorization/helper.rb @@ -3,12 +3,11 @@ 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 +26,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) + # + 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,22 +46,22 @@ def permitted_to? (privilege, object_or_sym = nil, options = {}, &block) # <% else %> # ... # <% end %> - # - def has_role? (*roles, &block) + # + 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) + + 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 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..3b6e75dc 100644 --- a/lib/declarative_authorization/in_controller.rb +++ b/lib/declarative_authorization/in_controller.rb @@ -3,15 +3,12 @@ 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 @@ -23,7 +20,8 @@ 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 @@ -31,18 +29,18 @@ 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 # 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 @@ -50,69 +48,70 @@ 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 = {}) + def permitted_to!(privilege, object_or_sym = nil, options = {}) authorization_engine.permit!(privilege, options_for_permit(object_or_sym, options, true)) end # 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) + 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 + + # 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 @@ -121,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 @@ -131,34 +130,34 @@ 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, plain: 'You are not allowed to access this action.', + status: :forbidden) end 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 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 @@ -168,10 +167,10 @@ def new_blank_controller_object (context_without_namespace, parent_context_witho 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 @@ -179,20 +178,20 @@ 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 - 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 @@ -210,16 +209,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 +227,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+ @@ -238,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 # @@ -250,12 +249,12 @@ 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 # 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 +262,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,41 +282,41 @@ 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) + # + + 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] actions = args.flatten # prevent setting filter_access_filter multiple times - skip_before_filter :filter_access_filter - 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) end - filter_access_permissions << + filter_access_permissions << ControllerPermission.new(actions, privilege, context, options[:strong_parameters], options[:attribute_check], @@ -325,16 +324,16 @@ 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| - p1.clone.remove_actions(perms.inject(Set.new) {|actions, p2| actions + p2.actions}) + perms + + mod.filter_access_permissions.collect do |p1| + p1.clone.remove_actions(perms.inject(Set.new) { |actions, p2| actions + p2.actions }) end else perms @@ -344,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. @@ -393,12 +392,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 +408,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: @@ -457,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 @@ -482,30 +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 Rails.version >= '4' && options[:strong_parameters] == nil - options.merge!({ :strong_parameters => false }) if Rails.version < '4' && 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 @@ -513,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 @@ -523,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 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) @@ -567,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 @@ -595,28 +595,29 @@ 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? - 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 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: class_variable_defined?(:@@declarative_authorization_permissions) end - def actions_from_option (option) # :nodoc: + def actions_from_option(option) # :nodoc: case option when nil {} when Symbol, String - {option.to_sym => option.to_sym} + { option.to_sym => option.to_sym } when Hash option when Enumerable @@ -632,12 +633,12 @@ 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, - load_object_model = nil, load_object_method = nil, - filter_block = nil) + 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 @privilege = privilege @context = context @@ -647,51 +648,53 @@ def initialize (actions, privilege, context, strong_params, attribute_check = fa @attribute_check = attribute_check @strong_params = strong_params end - - def matches? (action_name) + + def matches?(action_name) @actions.include?(action_name.to_sym) end - - def permit! (contr) - if @filter_block - return contr.instance_eval(&@filter_block) - end + + def permit!(contr) + 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) + 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) + + def remove_actions(actions) @actions -= actions self end - + 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) + object = if contr.instance_variable_defined?(instance_var) + contr.instance_variable_get(instance_var) + else + nil + end 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) @@ -701,4 +704,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 11edee60..97ea5e53 100644 --- a/lib/declarative_authorization/in_model.rb +++ b/lib/declarative_authorization/in_model.rb @@ -3,77 +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) + 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 - 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 = {} ) + 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 @@ -81,14 +52,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 @@ -97,78 +68,70 @@ 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) - 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 + def self.with_permissions_to(*args) + 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 + user = options[:user] || Authorization.current_user - engine = options[:engine] || Authorization::Engine.instance - engine.permit!(privileges, :user => user, :skip_attribute_test => true, - :context => context) + 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 + 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 # 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. # - def self.using_access_control (options = {}) + 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]) - end - - if Rails.version < "3" - def after_find; end + 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 cc63b9d8..d22ce324 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 @@ -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 @@ -66,63 +66,60 @@ 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| + actions = controller.public_instance_methods(false) - controller.private_methods + 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 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,11 +134,11 @@ 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 + + # 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 + def assert_raise_with_user(user, *args, &block) + assert_raises(*args) do with_user(user, &block) end end @@ -158,49 +155,47 @@ 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) + if args.first.class == Hash options = args.extract_options! 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 - def should_not_be_allowed_to (privilege, *args) + 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] end assert !Authorization::Engine.instance.permit?(privilege, options) end - - def request_with (user, method, xhr, action, params = {}, - session = {}, flash = {}) - session = session.merge({:user => user, :user_id => user && user.id}) + + def request_with(user, method, xhr, action, params = {}, + session = {}, flash = {}) + 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 - - def self.included (base) - [:get, :post, :put, :delete].each do |method| + + def self.included(base) + %i[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..73ac5c9a 100644 --- a/lib/declarative_authorization/obligation_scope.rb +++ b/lib/declarative_authorization/obligation_scope.rb @@ -42,59 +42,61 @@ 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) - def initialize (model, options) + class ObligationScope < ActiveRecord::Relation + def initialize(model, _options) @finder_options = {} - if Rails.version < "3" - super(model, options) + if Rails.version >= '5.2' + super(model, table: model.table_name) + elsif Rails.version >= '5' + super(model, model.table_name, nil) # , model.predicate_builder ? else - super(model, model.table_name) + super(model, model.table_name) end 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]) - end + # 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! 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 ) + 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 + reflection = begin + reflection_for(path_to_this_point) + rescue StandardError + nil + end if reflection - follow_path( next_steps, path_to_this_point ) + follow_path(next_steps, path_to_this_point) else - follow_comparison( next_steps, past_steps, step ) + follow_comparison(next_steps, past_steps, step) end 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 + 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}" @@ -102,121 +104,113 @@ def follow_path( steps, past_steps = [] ) end def top_level_model - if Rails.version < "3" - @proxy_scope - else - self.klass - end + klass end - def finder_options - Rails.version < "3" ? @proxy_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 ]+. # # 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 ) - 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. - def model_for (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 - else - reflection.proxy_association.reflection.klass - end + reflection.proxy_association.reflection.klass elsif reflection.respond_to?(:klass) reflection.klass else 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 ) + @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. - def map_reflection_for( path ) + def map_reflection_for(path) raise "reflection for #{path.inspect} already exists" unless reflections[path].nil? 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 ) + parent = reflection_for(path[0..-2]) + if !Authorization.is_a_association_proxy?(parent) && parent.respond_to?(:klass) + parent.klass.reflect_on_association(path.last) else - parent.reflect_on_association( path.last ) + parent.reflect_on_association(path.last) end - rescue - parent.reflect_on_association( path.last ) + rescue StandardError + parent.reflect_on_association(path.last) end raise "invalid path #{path.inspect}" if reflection.nil? 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) + if !Authorization.is_a_association_proxy?(reflection) && !reflection.respond_to?(:proxy_scope) && reflection.is_a?(ActiveRecord::Reflection::ThroughReflection) 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 ) + 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.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 ) + table_alias = "#{reflection.name.to_s.pluralize}_#{reflection.active_record.table_name}".to(max_length - 1) + 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}" + 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 - 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 +223,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 = [] @@ -242,16 +236,16 @@ 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 ) + 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"] + if (attribute == :id) && (operator == :is) && 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] @@ -265,10 +259,10 @@ def rebuild_condition_options! 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" + sql_attribute = "#{parent_model.connection.quote_table_name(attribute_table_alias)}." \ + "#{parent_model.connection.quote_table_name(attribute_name)}" + if value.nil? && %i[is is_not].include?(operator) + obligation_conds << "#{sql_attribute} IS #{%i[contains is].include?(operator) ? '' : 'NOT '}NULL" else attribute_operator = case operator when :contains, :is then "= :#{bindvar}" @@ -286,27 +280,36 @@ def rebuild_condition_options! end end end - 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)} + (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) + 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 - + # 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| - next if path.empty? or @join_table_joins.include?(path) + polymorphic_paths = {} + reflections.each do |path, refs| + next if path.empty? || @join_table_joins.include?(path) + + first_ref = refs + if polymorphic?(first_ref) + # sanity check + 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 existing_join = joins.find do |join| existing_path = join_to_path(join) @@ -323,19 +326,45 @@ 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| + 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 ) + finder_options.delete(:include) else - finder_options.delete( :joins ) + # 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 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 +377,7 @@ def path_to_join (path) end end - def join_to_path (join) + def join_to_path(join) case join when Symbol [join] @@ -356,6 +385,14 @@ 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 - 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/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 cc04a303..aed9401d 100644 --- a/lib/declarative_authorization/reader.rb +++ b/lib/declarative_authorization/reader.rb @@ -1,12 +1,9 @@ # 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. - # - # 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 @@ -40,12 +37,12 @@ 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 - + # 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 @@ -54,12 +51,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 +76,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,20 +87,20 @@ 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) - # TODO cache reader in production mode? + def self.load(dsl_files) + # TODO: cache reader in production mode? reader = new dsl_files = [dsl_files].flatten dsl_files.each do |file| @@ -114,19 +111,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 @@ -135,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: @@ -146,12 +143,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 +157,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,8 +174,8 @@ 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? + def includes(*privileges) + raise DSLError, 'includes only in privilege block' if @current_priv.nil? privileges.each do |priv| append_privilege priv @privilege_hierarchy[@current_priv] ||= [] @@ -189,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 @@ -203,14 +200,14 @@ def initialize # :nodoc: @auth_rules = AuthorizationRuleSet.new end - def initialize_copy (from) # :nodoc: - [:roles, :role_hierarchy, :auth_rules, - :role_descriptions, :role_titles, :omnipotent_roles].each do |attribute| + def initialize_copy(from) # :nodoc: + %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 - 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 +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 @@ -240,12 +237,12 @@ def role (role, options = {}, &block) # has_permission_on :employees, :to => :read # end # - def includes (*roles) - raise DSLError, "includes only in role blocks" if @current_role.nil? + def includes(*roles) + raise DSLError, 'includes only in role blocks' if @current_role.nil? @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 +262,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 @@ -274,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) - - privs = options[:to] + + 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 @@ -303,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 @@ -312,21 +309,21 @@ def has_omnipotence # description "To be assigned to administrative personnel" # has_permission_on ... # end - def description (text) - raise DSLError, "description only allowed in role blocks" if @current_role.nil? + 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" # has_permission_on ... # end - def title (text) - raise DSLError, "title only allowed in role blocks" if @current_role.nil? + 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. @@ -335,15 +332,15 @@ def title (text) # to :create, :read, :update, :delete # end # end - def to (*privs) - raise DSLError, "to only allowed in has_permission_on blocks" if @current_rule.nil? + def to(*privs) + raise DSLError, 'to only allowed in has_permission_on blocks' if @current_rule.nil? @current_rule.append_privileges(privs.flatten) end # 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 +352,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 +372,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 @@ -394,8 +391,8 @@ def to (*privs) # if_attribute :type => "special" # if_attribute :id => [1,2] # - def if_attribute (attr_conditions_hash) - raise DSLError, "if_attribute only in has_permission blocks" if @current_rule.nil? + 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) end @@ -446,37 +443,37 @@ 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 = {}) - raise DSLError, "if_permitted_to only in has_permission blocks" if @current_rule.nil? + 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: - 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 # 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,63 +481,63 @@ 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) 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 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], - 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 f96eea9b..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 + 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 \ No newline at end of file +end diff --git a/lib/generators/authorization/rules/rules_generator.rb b/lib/generators/authorization/rules/rules_generator.rb index db090955..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 bdaa9c71..a05054b9 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 @@ -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 ea466fda..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,32 +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_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 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 @@ -114,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 @@ -134,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 @@ -152,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 @@ -170,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 @@ -187,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 @@ -205,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 @@ -232,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 @@ -265,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 @@ -292,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 @@ -314,68 +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) - 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) - 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_raise(Authorization::AuthorizationUsageError) do - engine.permit?(:test, :context => :permissions, :user => MockUser.new(1, 2)) + assert_raises(Authorization::AuthorizationUsageError) do + engine.permit?(:test, context: :permissions, user: MockUser.new(1, 2)) end - assert_raise(Authorization::AuthorizationUsageError) do - engine.permit?(:test, :context => :permissions, :user => MockDataObject.new) + assert_raises(Authorization::AuthorizationUsageError) do + 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_raise Authorization::AuthorizationUsageError do - engine.permit?(:test, :context => :permissions, - :user => MockUser.new(:test_role), - :object => MockDataObject.new(:test_attrs => 1 )) + 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 - engine.permit?(:test, :context => :permissions, - :user => MockUser.new(:test_role_2), - :object => MockDataObject.new(:test_attrs => [1, 2] )) + assert_raises Authorization::AuthorizationUsageError do + 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,23 +915,21 @@ def test_attribute_with_permissions_nil end end end - } + ) 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 - - assert !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)) 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 @@ -949,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 @@ -975,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 @@ -1002,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 @@ -1029,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 @@ -1050,58 +1041,58 @@ def test_raise_on_if_attribute_hash_on_collection end end end - } + ) engine = Authorization::Engine.new(reader) - assert_raise Authorization::AuthorizationUsageError do - engine.permit?(:test, :context => :permissions, - :user => MockUser.new(:test_role), - :object => MockDataObject.new(:test_attrs => [1, 2, 3])) + assert_raises Authorization::AuthorizationUsageError do + 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 @@ -1111,14 +1102,13 @@ def test_clone end end end - } + ) engine = Authorization::Engine.new(reader) cloned_engine = engine.clone - assert_not_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, - cloned_engine.auth_rules.first.attributes.first.send(:instance_variable_get, :@conditions_hash)[:attr].object_id + refute_equal 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 end end - diff --git a/test/controller_filter_resource_access_test.rb b/test/controller_filter_resource_access_test.rb index f7becfa4..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,66 +58,69 @@ 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 = {}) + 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 = {}) + 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 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 = {}) - NestedResource.new(attributes.merge(:parent_mock => @parent_mock)) + + def new(attributes = {}) + 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) + 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,76 +499,74 @@ 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 -if Rails.version >= '4' +class StrongResource < MockDataObject + def self.name + 'StrongResource' + end +end - class StrongResource < MockDataObject - def self.name - "StrongResource" - 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 - private - def strong_resource_params - params.require(:strong_resource).permit(:test_param1, :test_param2) - end + 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 \ No newline at end of file +end diff --git a/test/controller_test.rb b/test/controller_test.rb index 3cbe678c..5637ed00 100644 --- a/test/controller_test.rb +++ b/test/controller_test.rb @@ -1,104 +1,114 @@ require 'test_helper' - class LoadMockObject < MockDataObject def self.name - "LoadMockObject" + 'LoadMockObject' end end ################## + +class ActionController::Base + class << self + def before_actions + filters = _process_action_callbacks.select { |c| c.kind == :before } + filters.map!(&:raw_filter) + end + 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 [:action_group_action_1, :action_group_action_2] + 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 %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 tests SpecificMocksController - + 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 @@ -109,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 @@ -124,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 @@ -139,77 +149,79 @@ 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) - assert_equal mock_object, - @controller.send(:instance_variable_get, :"@load_mock_object") + mock_object) + request!(MockUser.new(:test_role), 'edit_2', reader) + assert_equal 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) end -end + def teardown + @controller.current_user = nil + 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 @@ -217,16 +229,17 @@ 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 end class LoadObjectControllerTest < ActionController::TestCase tests LoadMockObjectsController - + 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 @@ -235,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 @@ -260,23 +273,22 @@ def test_filter_access_object_load_without_param end end end - } + ) - assert_raise 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 - 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 - + 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 @@ -290,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 @@ -318,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 + 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 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 @@ -362,29 +372,28 @@ class PeopleController < MocksController end class PluralizationControllerTest < ActionController::TestCase tests PeopleController - + 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 @@ -394,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 @@ -412,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 @@ -420,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 @@ -431,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 @@ -447,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 @@ -456,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 @@ -467,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 f2535af6..9730d6e1 100644 --- a/test/development_support/analyzer_test.rb +++ b/test/development_support/analyzer_test.rb @@ -2,95 +2,87 @@ 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 - assert_nothing_raised do - engine, analyzer = engine_analyzer_for %{ + 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 + has_permission_on :conferences, to: :read do if_attribute :published => true end - has_permission_on :talks, :to => :read do + 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 + has_permission_on :users, to: :create + has_permission_on :authorization_rules, to: :read + has_permission_on :authorization_usages, to: :read end - - role :user do + role :user do includes :guest - has_permission_on :conference_attendees, :to => :create do + 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 + 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 + has_permission_on :talk_attendees, to: :create do if_attribute :talk => { :conference => { :attendees => contains {user} }} end - has_permission_on :talk_attendees, :to => :delete do + has_permission_on :talk_attendees, to: :delete do if_attribute :user => is {user}, :talk => { :conference => { :attendees => contains {user} }} end end - - role :conference_organizer do + role :conference_organizer do has_permission_on :conferences do to :manage # if... end - has_permission_on [:conference_attendees, :talks, :talk_attendees], :to => :manage + 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 + 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 - - privileges do + 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 - 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 - assert_nothing_raised do - engine, analyzer = engine_analyzer_for %{ + def test_mergeable_rules_with_in_block_to + _engine, _analyzer = engine_analyzer_for %( authorization do role :test_role do has_permission_on :permissions do @@ -98,184 +90,184 @@ def test_mergeable_rules_with_in_block_to 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 46471af5..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 - assert_not_equal 0, approaches.length - #assert_equal :role, approaches.first.target_type - #assert_equal :test_role_2, approaches.first.target.to_sym + refute_equal 0, approaches.length + # 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 - assert_not_equal 0, approaches.length - #assert_equal :role, approaches.first.target_type - #assert_equal :test_role_2, approaches.first.target.to_sym + refute_equal 0, approaches.length + # 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 - assert_not_equal 0, approaches.length - #assert_equal :role, approaches.first.target_type - #assert_equal :test_role_2, approaches.first.target.to_sym + refute_equal 0, approaches.length + # 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 - assert_not_equal 0, approaches.length - assert approaches.any? {|approach| approach.users.first.role_symbols.include?(:test_role) } + refute_equal 0, approaches.length + 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 - assert_not_equal 0, approaches.length - assert approaches.any? {|approach| approach.users.first.role_symbols.empty? } + 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 1b694b9a..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 - assert_not_equal 0, approaches.length - assert approaches.any? {|approach| approach.changes.first.class == Authorization::DevelopmentSupport::ChangeSupporter::AddPrivilegeAndAssignRoleToUserAction} + refute_equal 0, approaches.length + 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 - assert_not_equal 0, approaches.length - assert !approaches.any? {|approach| approach.steps.any? {|step| step.class == Authorization::DevelopmentSupport::ChangeSupporter::AssignRoleToUserAction}} + refute_equal 0, approaches.length + 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 - assert_not_equal 0, approaches.length - assert !approaches.any? {|approach| approach.steps.any? {|step| step.class == Authorization::DevelopmentSupport::ChangeSupporter::AssignRoleToUserAction and step.role == :test_role }} + refute_equal 0, approaches.length + 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 - assert_not_equal 0, approaches.length - assert !approaches.any? {|approach| approach.steps.any? {|step| step.class == Authorization::DevelopmentSupport::ChangeSupporter::AssignPrivilegeToRoleAction}} + refute_equal 0, approaches.length + 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 - assert_not_equal 0, approaches.length - assert !approaches.any? {|approach| approach.steps.any? {|step| step.class == Authorization::DevelopmentSupport::ChangeSupporter::RemoveRoleFromUserAction}} + refute_equal 0, approaches.length + 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 2c11ba5d..cae6e3d5 100644 --- a/test/dsl_reader_test.rb +++ b/test/dsl_reader_test.rb @@ -3,66 +3,66 @@ 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] + 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 %{ + 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 [[:lower_priv, nil]], - reader.privileges_reader.privilege_hierarchy[:test_priv_3] + ) + 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] 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 end - + 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,16 +71,16 @@ 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) 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 %| + reader.parse %( authorization do role :test_role do has_permission_on :perms, :to => :test do @@ -97,65 +97,65 @@ 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) end - + 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) end - + 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_raise(Authorization::Reader::DSLError) do - reader.parse %{ + assert_raises(Authorization::Reader::DSLError) do + reader.parse %( authorization do includes :lesser_role end - } + ) end end - + def test_syntax_error reader = Authorization::Reader::DSLReader.new - assert_raise(Authorization::Reader::DSLSyntaxError) do - reader.parse %{ + assert_raises(Authorization::Reader::DSLSyntaxError) do + reader.parse %( authorizations do end - } + ) end end - + def test_syntax_error_2 reader = Authorization::Reader::DSLReader.new - assert_raise(Authorization::Reader::DSLSyntaxError) do - reader.parse %{ + assert_raises(Authorization::Reader::DSLSyntaxError) do + 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_raise(Authorization::Reader::DSLFileNotFoundError) do - Authorization::Reader::DSLReader.new.load!("nonexistent_file.rb") + assert_raises(Authorization::Reader::DSLFileNotFoundError) do + Authorization::Reader::DSLReader.new.load!('nonexistent_file.rb') end end end - diff --git a/test/helper_test.rb b/test/helper_test.rb index d0f1c674..ced85293 100644 --- a/test/helper_test.rb +++ b/test/helper_test.rb @@ -1,19 +1,18 @@ 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 tests HelperMocksController include Authorization::AuthorizationHelper attr_reader :controller - + 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,19 +21,19 @@ def test_permit has_permission_on :mocks, :to => :update end end - } + ) 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 @@ -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,12 +52,12 @@ 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) assert permitted_to?(:show, :mocks) assert !permitted_to?(:show, mock_2) @@ -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,88 +74,88 @@ 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) - + 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 %{ + 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) - + 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 + 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 %{ + reader.parse %( authorization do end - } + ) request!(nil, :action, reader) - + # test intermittently fails assert !has_role?(:test_role) block_evaled = false @@ -165,10 +164,10 @@ 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 %{ + reader.parse %( authorization do role :test_role do has_permission_on :mocks, :to => :show @@ -176,16 +175,15 @@ 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) - + assert has_role_with_hierarchy?(:test_role) assert !has_role_with_hierarchy?(:other_role) @@ -194,17 +192,17 @@ 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 %{ + reader.parse %( authorization do role :test_role do has_permission_on :mocks, :to => :show @@ -212,34 +210,33 @@ 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 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 + 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..00530c53 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,62 @@ 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 +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/model_test.rb b/test/model_test.rb index 2fc2b763..ef94df46 100644 --- a/test/model_test.rb +++ b/test/model_test.rb @@ -1,71 +1,47 @@ 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) -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 + 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 - # :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_one :test_attr_throughs_with_attr_and_has_one, + -> { 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, :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, -> { 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 @@ -78,13 +54,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 @@ -93,13 +69,7 @@ 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) + def initialize(*args) @role_symbols = [] super(*args) end @@ -112,44 +82,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 + using_access_control include_read: true, + context: :test_model_security_models 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,16 +110,12 @@ 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 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 @@ -177,20 +124,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) - 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 + 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 @@ -198,7 +141,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 @@ -206,18 +149,18 @@ def test_with_belongs_to_and_has_many_with_contains end end end - } + ) Authorization::Engine.instance(reader) - test_attr_1 = TestAttr.create! + 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 - assert_raise Authorization::NotAuthorized do - TestAttr.with_permissions_to( :update_test_attrs, :user => user ) + 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) end TestAttr.delete_all TestModel.delete_all @@ -225,7 +168,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 @@ -233,20 +176,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 @@ -255,7 +198,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 @@ -263,23 +206,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 @@ -288,7 +231,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 @@ -296,25 +239,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 - assert_raise Authorization::NotAuthorized do - TestModel.with_permissions_to(:update_test_models, :user => user) + 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) 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 @@ -322,7 +265,7 @@ def test_named_scope_on_proxy end end end - } + ) Authorization::Engine.instance(reader) test_model_1 = TestModel.create! @@ -330,15 +273,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 @@ -349,33 +292,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 1, TestModel.query_count if Rails.version < "3" + 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.query_count if Rails.version < "3" + assert_equal 1, TestModel.with_content.with_permissions_to(:read, user: user).length 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" + assert_equal 1, country.test_models.with_permissions_to(:read, user: user).length TestModel.delete_all Country.delete_all @@ -383,7 +319,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 @@ -391,20 +327,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 @@ -417,22 +353,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 @@ -440,21 +376,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 @@ -462,25 +398,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 - assert_raise Authorization::NotAuthorized do - TestModel.with_permissions_to(:update_test_models, :user => user) + 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) 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 @@ -488,25 +424,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 - assert_raise Authorization::NotAuthorized do - TestModel.with_permissions_to(:update_test_models, :user => user) + 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) 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 @@ -514,25 +450,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 - assert_raise Authorization::NotAuthorized do - TestModel.with_permissions_to(:update_test_models, :user => user) + 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) 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 @@ -540,46 +476,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 - assert_raise Authorization::NotAuthorized do - TestModel.with_permissions_to(:update_test_models, :user => user) + 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) 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_raise Authorization::NotAuthorized do - TestModel.with_permissions_to(:update, :user => user) + assert_equal 1, TestModel.with_permissions_to(:read, user: user).length + assert_raises Authorization::NotAuthorized do + 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 @@ -590,49 +526,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 @@ -641,20 +576,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 @@ -662,21 +597,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 @@ -685,19 +620,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 + 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 @@ -710,23 +645,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 @@ -734,16 +669,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 @@ -751,7 +686,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 @@ -759,16 +694,42 @@ 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 + end + + 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 + ) + 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 @@ -776,7 +737,7 @@ def test_with_deep_attribute 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 @@ -785,17 +746,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 @@ -803,7 +764,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 @@ -811,7 +772,7 @@ def test_with_contains end end end - } + ) Authorization::Engine.instance(reader) test_model_1 = TestModel.create! @@ -821,13 +782,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 - 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 + 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 @@ -835,7 +792,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 @@ -843,7 +800,7 @@ def test_with_does_not_contain end end end - } + ) Authorization::Engine.instance(reader) test_model_1 = TestModel.create! @@ -852,8 +809,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 @@ -861,7 +818,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 @@ -869,34 +826,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 @@ -904,23 +861,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 @@ -928,10 +885,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 @@ -939,21 +896,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 @@ -961,43 +918,40 @@ 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! + 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, - :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 %{ + reader.parse %( authorization do role :test_role do has_permission_on :test_models, :to => :read do @@ -1005,7 +959,7 @@ def test_with_intersects_with end end end - } + ) Authorization::Engine.instance(reader) test_model_1 = TestModel.create! @@ -1016,12 +970,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 @@ -1029,7 +983,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 @@ -1037,61 +991,24 @@ 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 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 %{ + reader.parse %( authorization do role :test_role do has_permission_on :test_attrs, :to => :read do @@ -1099,7 +1016,7 @@ def test_with_is_in end end end - } + ) Authorization::Engine.instance(reader) test_model_1 = TestModel.create! @@ -1107,10 +1024,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 @@ -1118,7 +1035,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 @@ -1126,7 +1043,7 @@ def test_with_not_is_in end end end - } + ) Authorization::Engine.instance(reader) TestModel.delete_all TestAttr.delete_all @@ -1136,10 +1053,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 @@ -1147,7 +1064,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 @@ -1158,21 +1075,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 @@ -1193,28 +1110,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) - 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 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 TestModel.delete_all TestAttr.delete_all @@ -1222,7 +1136,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 @@ -1241,20 +1155,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_raise Authorization::NotAuthorized do - TestAttr.with_permissions_to(:read, :user => non_allowed_user).find(:all) + 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) end TestModel.delete_all @@ -1263,7 +1177,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 @@ -1274,24 +1188,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 @@ -1302,23 +1216,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 @@ -1329,17 +1243,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 @@ -1347,7 +1261,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 @@ -1356,21 +1270,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! + 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 @@ -1381,19 +1295,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 @@ -1404,22 +1318,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! + 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 @@ -1428,27 +1342,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_attr_2 = TestAttr.create!( - :test_model => TestModel.create!(:content => 'test_2_1'), - :test_another_model => TestModel.create!(:content => 'test_2_2') - ) + TestAttr.create!( + test_model: TestModel.create!(content: 'test_1_1'), + test_another_model: TestModel.create!(content: 'test_1_2') + ) + TestAttr.create!( + 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 @@ -1461,32 +1375,28 @@ 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') - ) + 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_model => TestModel.create!(:content => 'test_2_1'), - :test_another_model => TestModel.create!(:content => 'test_2_2') - ) - test_attr_2.test_model.test_attrs.create! + test_model: TestModel.create!(content: 'test_2_1'), + test_another_model: TestModel.create!(content: 'test_2_2') + ) + + 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) - 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 TestModel.delete_all TestAttr.delete_all end 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 @@ -1499,28 +1409,25 @@ 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)) - ) - test_attr_2 = TestAttr.create!( - :company => Company.create!(:name => 'company_2', - :country => country) - ) + TestAttr.create!( + branch: Branch.create!(name: 'branch_1', + company: Company.create!(name: 'company_1', + country: country)) + ) + TestAttr.create!( + 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 - 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 TestModel.delete_all TestAttr.delete_all end @@ -1529,7 +1436,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 @@ -1537,26 +1444,24 @@ 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) - - assert_nothing_raised do - assert instance.permit?(:update, :user => user, :object => test_model.test_attr_has_one) - end - + + user = MockUser.new(:test_role, test_attr: test_attr) + + assert instance.permit?(:update, user: user, object: test_model.test_attr_has_one) + TestModel.delete_all TestAttr.delete_all end 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 @@ -1565,24 +1470,23 @@ def test_model_security_write_allowed end end end - } + ) Authorization::Engine.instance(reader) 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 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 @@ -1593,21 +1497,21 @@ 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) assert(object = TestModelSecurityModel.create) Authorization.current_user = MockUser.new(:test_role_restricted) - assert_raise Authorization::NotAuthorized do - object.update_attributes(:attr_2 => 2) + assert_raises Authorization::NotAuthorized do + 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 @@ -1621,31 +1525,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_raise Authorization::AttributeAuthorizationError do - TestModelSecurityModel.create :attr => 2 + assert_raises Authorization::AttributeAuthorizationError do + TestModelSecurityModel.create attr: 2 end object = TestModelSecurityModel.create - assert_raise Authorization::AttributeAuthorizationError do - object.update_attributes(:attr => 2) + 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 - object.update_attributes(:attr => 2) + assert_raises Authorization::AttributeAuthorizationError do + 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 @@ -1659,24 +1561,22 @@ 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) - 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 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 @@ -1685,24 +1585,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 - assert_nothing_raised do - object_with_find.class.find(object_with_find.id) - end + 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 @@ -1716,21 +1614,21 @@ 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_raise Authorization::AttributeAuthorizationError do + assert_raises Authorization::AttributeAuthorizationError do object.destroy end end 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 @@ -1744,36 +1642,36 @@ 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 + TestModelSecurityModel.create attr: 2 Authorization.current_user = MockUser.new(:test_role) - # TODO before not checked yet - #assert_raise 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) - assert_raise Authorization::NotAuthorized do + assert_raises Authorization::NotAuthorized do TestModelSecurityModel.create end end 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 @@ -1782,29 +1680,28 @@ 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])) - assert_nothing_raised do - object.update_attributes(:attr_2 => 2) - end + assert(object = TestModelSecurityModel.create(test_attrs: [test_attr])) + object.update_attributes(attr_2: 2) + 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 + assert_raises ActiveRecord::RecordNotFound do TestModelSecurityModel.find(object.id) end end 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 @@ -1812,22 +1709,20 @@ 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 - assert_nothing_raised do - test_model.update_attributes(params[:model_data]) - end + with_user MockUser.new(:test_role, branch: test_attr.branch) do + test_model.update_attributes(params[:model_data]) end without_access_control do assert_equal params[:model_data][:attr], test_model.reload.attr @@ -1845,7 +1740,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 @@ -1853,57 +1748,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_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_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 @@ -1911,7 +1806,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}, @@ -1919,25 +1813,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) - 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 + 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 TestModel.delete_all TestAttr.delete_all TestAttrThrough.delete_all @@ -1945,7 +1836,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 @@ -1953,56 +1844,58 @@ 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 - assert_nothing_raised do - allowed_read_company.permitted_to!(:read, :user => user) - end - assert_raise Authorization::NotAuthorized do - prohibited_company.permitted_to!(:update, :user => user) + 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 - prohibited_company.permitted_to!(:read, :user => user) + assert_raises Authorization::AttributeAuthorizationError do + 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 -end + def teardown + Authorization.current_user = nil + end +end diff --git a/test/test_helper.rb b/test/test_helper.rb index 2d0ffc1b..3a74082f 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -1,60 +1,35 @@ -require 'pathname' - ENV['RAILS_ENV'] = 'test' +require 'pathname' require 'bundler/setup' +require 'rails/all' +require 'minitest/autorun' begin - # rails 3 - require 'rails/all' + require 'rails-controller-testing' rescue LoadError - # rails 2.3 - %w(action_pack action_controller active_record active_support initializer).each {|f| require f} + # Not required for Rails 4.2; not present in that Gemfile 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]) - -# 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}" RAILS_ROOT = File.dirname(__FILE__) -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 +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]) class MockDataObject - def initialize (attrs = {}) + def initialize(attrs = {}) attrs.each do |key, value| instance_variable_set(:"@#{key}", value) + next if respond_to?(:"#{key}") self.class.class_eval do - attr_reader key + attr_reader key unless method_defined?(key) end end end - + def self.descends_from_active_record? true end @@ -64,27 +39,28 @@ 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) + attr_accessor :id + 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 @@ -92,16 +68,16 @@ 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) + + 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 @@ -109,11 +85,11 @@ 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 + + def logger(*_args) + Class.new do def warn(*args) - #p args + # p args end alias_method :info, :warn alias_method :debug, :warn @@ -124,132 +100,57 @@ 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' - 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! - 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 +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__) + config.paths['config/database'] = database_path + initialize! end end - -ActionController::Base.send :include, Authorization::AuthorizationInController -if Rails.version < "3" - require "action_controller/test_process" +class ApplicationController < ActionController::Base 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 +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 + +ActionController::Base.send :include, Authorization::AuthorizationInController -elsif Rails.version < '4.1' - class Test::Unit::TestCase - include Authorization::TestHelper +module Test + module Unit end +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 +class Test::Unit::TestCase < Minitest::Test + include Authorization::TestHelper +end - unless Rails.version < "3" - def setup - #@routes = Rails::Application.routes - @routes = Rails.application.routes - end - end - end -else - module Test - module Unit - end - end +class ActiveSupport::TestCase + include Authorization::TestHelper - class Test::Unit::TestCase < Minitest::Test - include Authorization::TestHelper - 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) - 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 + ((params.delete(:clear) || []) + [:@authorized]).each do |var| + @controller.instance_variable_set(var, nil) end + get action, params: 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 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