Skip to content

Commit

Permalink
Merge pull request #196 from doximity/rails4
Browse files Browse the repository at this point in the history
Rails 4 (thanks to @divoxx, @zeiv, @gordonbisnor and @aepstein)
  • Loading branch information
stffn committed Aug 13, 2014
2 parents 549a8d3 + 963ae55 commit 45e91af
Show file tree
Hide file tree
Showing 30 changed files with 706 additions and 103 deletions.
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,7 @@ garlic
nbproject
rdoc
gemfiles/*.lock
log/*
*.sublime*


11 changes: 7 additions & 4 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,19 @@ language: ruby
script: bundle exec rake test
rvm:
- 1.8.7
- 1.9.2
- 1.9.3
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:
allow_failures:
- rvm: 1.9.2
gemfile: gemfiles/2.3.gemfile
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
103 changes: 103 additions & 0 deletions README.rdoc
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ 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


Requirements
Expand All @@ -36,6 +37,99 @@ There is a decl_auth screencast by Ryan Bates, nicely introducing the main conce
http://railscasts.com/episodes/188-declarative-authorization


= Quick Start

=== Installer

Declarative Authorization comes with an installer to make setup easy.

First, include declarative_authorization in your gemfile.

#! Gemfile
gem 'declarative_authorization'

Next, bundle and install.

$ bundle
$ rails g authorization:install [UserModel=User] [field:type field:type ...] [--create-user --commit --user-belongs-to-role]

This installer will create a Role model, an admin and a user role, and set a
has_and_belongs_to_many relationship between the User model and the Role model.
It will also add a `role_symbols` method to the user model to meet
declarative_authorization's requirements. The default User model is User. You can override this by simply typing the name of a model as above.

You can create the model with the fields provided by using the `--create-user` option.

The `--commit` option will run `rake db:migrate` and `rake db:seed`.

The `--user-belongs-to-role` option will set up a one-to-many relationship between Users and Roles.
That is, each user has a role_id column and can only have one role. Role inheritance can be used
in authorization rules.

Finally, the installer also copies default authorization rules, as below.

=== Generate Authorization Rules

To copy a default set of authorization rules which includes CRUD priveleges, run:

$ rails g authorization:rules

This command will copy the following to `config/authorization_rules.rb`. Remember
to implement the requirements of this gem as described in the Installation section
at the end of this README if you do not use the above installer.

authorization do
role :guest do
# add permissions for guests here, e.g.
# has_permission_on :conferences, :to => :read
end

# permissions on other roles, such as
# role :admin do
# has_permission_on :conferences, :to => :manage
# end
# role :user do
# has_permission_on :conferences, :to => [:read, :create]
# has_permission_on :conferences, :to => [:update, :delete] do
# if_attribute :user_id => is {user.id}
# end
# end
# See the readme or GitHub for more examples
end

privileges do
# default privilege hierarchies to facilitate RESTful Rails apps
privilege :manage, :includes => [:create, :read, :update, :delete]
privilege :create, :includes => :new
privilege :read, :includes => [:index, :show]
privilege :update, :includes => :edit
privilege :delete, :includes => :destroy
end

=== Controller Authorization

For RESTful controllers, add `filter_resource_access`:

class MyRestfulController < ApplicationController
filter_resource_access
...
end

For a non-RESTful controller, you can use `filter_access_to`:

class MyOtherController < ApplicationController
filter_access_to :all
# or a group: filter_access_to [:action1, :action2]
...
end

=== View Authorization

Declarative Authorization will use `current_user` to check authorization.

<%= link_to 'Edit Post', edit_post_path(@post) if permitted_to? :update, @post %>


= Authorization Data Model

----- App domain ----|-------- Authorization conf ---------|------- App domain ------
Expand Down Expand Up @@ -92,6 +186,15 @@ 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.

class EmployeesController < ApplicationController
filter_resource_access :strong_parameters => false
...
end

Simalarly, you can use `:strong_parameters => true` if you are using strong_parameters in Rails 3.

If you prefer less magic or your controller has no resemblance with the resource
controllers, directly calling filter_access_to may be the better option. Examples
are given in the following. E.g. the privilege index users is required for
Expand Down
2 changes: 1 addition & 1 deletion Rakefile
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
require 'rake'
require 'rake/testtask'
require 'rake/rdoctask'
require 'rdoc/task'

desc 'Default: run unit tests against all versions.'
task :default => 'bundles:test'
Expand Down
3 changes: 1 addition & 2 deletions app/controllers/authorization_rules_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
rescue LoadError; end

class AuthorizationRulesController < ApplicationController
unloadable

filter_access_to :all, :require => :read
def index
Expand Down Expand Up @@ -256,4 +255,4 @@ def find_all_users

else
class AuthorizationRulesController < ApplicationController; end
end # activate_authorization_rules_browser?
end # activate_authorization_rules_browser?
3 changes: 1 addition & 2 deletions app/controllers/authorization_usages_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
require File.join(File.dirname(__FILE__), %w{.. .. lib declarative_authorization maintenance})

class AuthorizationUsagesController < ApplicationController
unloadable

helper :authorization_rules
filter_access_to :all, :require => :read
Expand All @@ -20,4 +19,4 @@ def index

else
class AuthorizationUsagesController < ApplicationController; end
end # activate_authorization_rules_browser?
end # activate_authorization_rules_browser?
4 changes: 2 additions & 2 deletions app/views/authorization_rules/_change.erb
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
<%= select_tag :context, options_for_select(@contexts.map {|c| [human_context(c), c.to_s]}.sort, @context.to_s) %>
<br/>
<label></label>
<%= link_to_function "Show current permissions", "show_current_permissions()", :class => 'unimportant' %>
<%= link_to "Show current permissions", '#', onclick: "show_current_permissions()", :class => 'unimportant' %>
<br/><br/>
How many users should be <strong>affected</strong>?
<br/>
Expand Down Expand Up @@ -53,6 +53,6 @@
<ul id="prohibited_actions"></ul>

<p class="submit">
<%= button_to_function "Suggest Changes", "suggest_changes()" %>
<%= button_to "Suggest Changes", '#', onclick: "suggest_changes()" %>
</p>
</form>
2 changes: 1 addition & 1 deletion app/views/authorization_rules/_show_graph.erb
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,6 @@
}
<% end %>
<div id="graph-container" style="display:none">
<%= link_to_function "Hide", "$('graph-container').hide()", :class => 'important' %><br/>
<%= link_to '#', "Hide", onclick: "$('graph-container').hide()", :class => 'important' %><br/>
<object id="graph" data="" type="image/svg+xml" style="max-width:100%;margin-top: 0.5em"/>
</div>
6 changes: 3 additions & 3 deletions app/views/authorization_rules/change.html.erb
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
<h1>Suggestions on Authorization Rules Change</h1>
<p><%= navigation %></p>
<div style="display:none" id="suggest-graph-container">
<%= link_to_function "Hide", "$(this).up().hide()", :class => 'important' %>
<%= link_to_function "Toggle stacked roles", "toggle_graph_params('suggest-graph', 'stacked_roles');" %>
<%= link_to_function "Toggle only users' roles", "toggle_graph_params('suggest-graph', 'only_relevant_roles');" %><br/>
<%= link_to "Hide", '#', onclick: "$(this).up().hide()", :class => 'important' %>
<%= link_to "Toggle stacked roles", '#', onclick: "toggle_graph_params('suggest-graph', 'stacked_roles');" %>
<%= link_to "Toggle only users' roles", '#', onclick: "toggle_graph_params('suggest-graph', 'only_relevant_roles');" %><br/>
<object id="suggest-graph" data="" type="image/svg+xml" style="max-width: 98%;max-height: 95%;margin-top: 0.5em"/>
</div>
<%= render 'show_graph' %>
Expand Down
4 changes: 2 additions & 2 deletions app/views/authorization_rules/graph.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -43,5 +43,5 @@
<div style="margin: 1em;border:1px solid #ccc;max-width:95%">
<object id="graph" data="<%= url_for :format => 'svg' %>" type="image/svg+xml" style="max-width:100%"/>
</div>
<%= button_to_function "Zoom in", '$("graph").style.maxWidth = "";$(this).toggle();$(this).next().toggle()' %>
<%= button_to_function "Zoom out", '$("graph").style.maxWidth = "100%";$(this).toggle();$(this).previous().toggle()', :style => 'display:none' %>
<%= button_to "Zoom in", '#', onclick: '$("graph").style.maxWidth = "";$(this).toggle();$(this).next().toggle()' %>
<%= button_to "Zoom out", '#', onclick: '$("graph").style.maxWidth = "100%";$(this).toggle();$(this).previous().toggle()', :style => 'display:none' %>
2 changes: 1 addition & 1 deletion declarative_authorization.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

Gem::Specification.new do |s|
s.name = "declarative_authorization"
s.version = "0.5.7"
s.version = "1.0.0.pre"

s.required_ruby_version = ">= 1.8.6"
s.authors = ["Steffen Bartsch"]
Expand Down
8 changes: 8 additions & 0 deletions gemfiles/4.0.gemfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
source 'https://rubygems.org'

gem 'rails', '~> 4.0.0'
gem 'sqlite3'
gem 'ruby_parser'
gem 'rdoc'
gemspec :path => '..'

7 changes: 7 additions & 0 deletions gemfiles/4.1.gemfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
source 'https://rubygems.org'

gem 'rails', '~> 4.1.0'
gem 'sqlite3'
gem 'ruby_parser'
gem 'rdoc'
gemspec :path => '..'
13 changes: 13 additions & 0 deletions lib/declarative_authorization/adapters/active_record.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
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
end
else
raise NotImplementedError, "DeclarativeAuthorization does not support Active Record version #{ActiveRecord::VERSION::STRING}"
end
Empty file.
Empty file.
11 changes: 10 additions & 1 deletion lib/declarative_authorization/authorization.rb
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,7 @@ def permit! (privilege, options = {})
# Example: permit!( :edit, :object => user.posts )
#
if Authorization.is_a_association_proxy?(options[:object]) && options[:object].respond_to?(:new)
options[:object] = (Rails.version < "3.0" ? options[:object] : options[:object].scoped).new
options[:object] = (Rails.version < "3.0" ? options[:object] : options[:object].where(nil)).new
end

options[:context] ||= options[:object] && (
Expand Down Expand Up @@ -512,6 +512,15 @@ def validate? (attr_validator, object = nil, hash = nil)
object ||= attr_validator.object
return false unless object

if ( Authorization.is_a_association_proxy?(object) &&
object.respond_to?(:empty?) )
return false if object.empty?
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)
Expand Down
19 changes: 14 additions & 5 deletions lib/declarative_authorization/development_support/analyzer.rb
Original file line number Diff line number Diff line change
Expand Up @@ -208,9 +208,10 @@ def process_call (exp)
s(:call, klass, name)
when :has_permission_on
arglist_line = exp[0].line
arglist = process(exp.shift).shift
context = arglist.shift
args_hash = arglist.shift
# what is the purpose of arglist? Used to be process(exp.shift).shift, which broke args_hash
arglist = process(exp.shift)
context = arglist
args_hash = exp[0].nil? ? nil : process(exp.shift).shift
@has_permission << {
:context => context,
:rules => [],
Expand All @@ -223,15 +224,23 @@ def process_call (exp)
@has_permission.last[:privilege] = process(exp.shift).shift if @has_permission
s(:call, klass, name)
when :if_attribute
rules = process(exp.shift).shift
rules = process(exp.shift)
rules.unshift :if_attribute
@has_permission.last[:rules] << rules if @has_permission
s(:call, klass, name)
when :if_permitted_to
rules = process(exp.shift).shift
rules = process(exp.shift).push(process(exp.shift).shift)
rules.unshift :if_permitted_to
@has_permission.last[:rules] << rules if @has_permission
s(:call, klass, name)
when :privilege
privilege = process(exp.shift)
includes = process(exp.shift).shift
privelege_hash = {
:privilege => privilege,
:options => includes
}
s(:call, klass, name, privelege_hash)
else
s(:call, klass, name, process(exp.shift))
end
Expand Down
Loading

0 comments on commit 45e91af

Please sign in to comment.