rails-doorman 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (79) hide show
  1. data/LICENSE +21 -0
  2. data/README.rdoc +94 -0
  3. data/Rakefile +89 -0
  4. data/features/doorman.feature +99 -0
  5. data/features/step_definitions/common_steps.rb +25 -0
  6. data/features/step_definitions/webrat_steps.rb +115 -0
  7. data/features/support/authorized_matcher.rb +29 -0
  8. data/features/support/env.rb +16 -0
  9. data/features/support/paths.rb +19 -0
  10. data/features/support/unauthorized_matcher.rb +29 -0
  11. data/lib/doorman.rb +111 -0
  12. data/lib/doorman/helpers.rb +17 -0
  13. data/lib/doorman/rule.rb +59 -0
  14. data/rails/init.rb +1 -0
  15. data/spec/fixtures/app/README +243 -0
  16. data/spec/fixtures/app/Rakefile +10 -0
  17. data/spec/fixtures/app/app/controllers/access_control_by_host_controller.rb +5 -0
  18. data/spec/fixtures/app/app/controllers/access_control_by_user_agent_controller.rb +4 -0
  19. data/spec/fixtures/app/app/controllers/allow_all_by_default_controller.rb +2 -0
  20. data/spec/fixtures/app/app/controllers/allowed_and_denied_roles_controller.rb +4 -0
  21. data/spec/fixtures/app/app/controllers/allowed_and_denied_users_controller.rb +4 -0
  22. data/spec/fixtures/app/app/controllers/allowed_role_controller.rb +3 -0
  23. data/spec/fixtures/app/app/controllers/allowed_role_with_only_controller.rb +3 -0
  24. data/spec/fixtures/app/app/controllers/allowed_user_controller.rb +3 -0
  25. data/spec/fixtures/app/app/controllers/application_controller.rb +37 -0
  26. data/spec/fixtures/app/app/controllers/denied_role_controller.rb +3 -0
  27. data/spec/fixtures/app/app/controllers/denied_user_controller.rb +4 -0
  28. data/spec/fixtures/app/app/controllers/deny_all_controller.rb +3 -0
  29. data/spec/fixtures/app/app/controllers/explicitly_allow_all_controller.rb +3 -0
  30. data/spec/fixtures/app/app/controllers/test_controller.rb +4 -0
  31. data/spec/fixtures/app/app/controllers/view_helpers_controller.rb +4 -0
  32. data/spec/fixtures/app/app/helpers/application_helper.rb +3 -0
  33. data/spec/fixtures/app/app/models/user.rb +7 -0
  34. data/spec/fixtures/app/app/views/layouts/application.html.erb +8 -0
  35. data/spec/fixtures/app/app/views/view_helpers/allow_via_role.html.erb +3 -0
  36. data/spec/fixtures/app/app/views/view_helpers/deny_via_role.html.erb +3 -0
  37. data/spec/fixtures/app/config/boot.rb +110 -0
  38. data/spec/fixtures/app/config/environment.rb +41 -0
  39. data/spec/fixtures/app/config/environments/development.rb +0 -0
  40. data/spec/fixtures/app/config/environments/production.rb +0 -0
  41. data/spec/fixtures/app/config/environments/test.rb +31 -0
  42. data/spec/fixtures/app/config/initializers/backtrace_silencers.rb +7 -0
  43. data/spec/fixtures/app/config/initializers/inflections.rb +10 -0
  44. data/spec/fixtures/app/config/initializers/mime_types.rb +5 -0
  45. data/spec/fixtures/app/config/initializers/new_rails_defaults.rb +19 -0
  46. data/spec/fixtures/app/config/initializers/session_store.rb +15 -0
  47. data/spec/fixtures/app/config/locales/en.yml +5 -0
  48. data/spec/fixtures/app/config/routes.rb +43 -0
  49. data/spec/fixtures/app/db/foo.txt +0 -0
  50. data/spec/fixtures/app/doc/README_FOR_APP +2 -0
  51. data/spec/fixtures/app/log/test.log +11988 -0
  52. data/spec/fixtures/app/public/404.html +30 -0
  53. data/spec/fixtures/app/public/422.html +30 -0
  54. data/spec/fixtures/app/public/500.html +30 -0
  55. data/spec/fixtures/app/public/favicon.ico +0 -0
  56. data/spec/fixtures/app/public/images/rails.png +0 -0
  57. data/spec/fixtures/app/public/javascripts/application.js +2 -0
  58. data/spec/fixtures/app/public/javascripts/controls.js +963 -0
  59. data/spec/fixtures/app/public/javascripts/dragdrop.js +973 -0
  60. data/spec/fixtures/app/public/javascripts/effects.js +1128 -0
  61. data/spec/fixtures/app/public/javascripts/prototype.js +4320 -0
  62. data/spec/fixtures/app/public/robots.txt +5 -0
  63. data/spec/fixtures/app/script/about +4 -0
  64. data/spec/fixtures/app/script/console +3 -0
  65. data/spec/fixtures/app/script/dbconsole +3 -0
  66. data/spec/fixtures/app/script/destroy +3 -0
  67. data/spec/fixtures/app/script/generate +3 -0
  68. data/spec/fixtures/app/script/performance/benchmarker +3 -0
  69. data/spec/fixtures/app/script/performance/profiler +3 -0
  70. data/spec/fixtures/app/script/plugin +3 -0
  71. data/spec/fixtures/app/script/runner +3 -0
  72. data/spec/fixtures/app/script/server +3 -0
  73. data/spec/fixtures/app/test/performance/browsing_test.rb +9 -0
  74. data/spec/fixtures/app/test/test_helper.rb +38 -0
  75. data/spec/fixtures/app/vendor/plugins/doorman/init.rb +1 -0
  76. data/spec/rails_doorman/class_methods_spec.rb +49 -0
  77. data/spec/rails_doorman/rule_spec.rb +120 -0
  78. data/spec/spec_helper.rb +15 -0
  79. metadata +225 -0
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ Copyright (c) 2008 Michael D. Ivey <ivey@gweezlebur.com>
2
+ Copyright (c) 2009 Jeremy Burks <jeremy.burks@gmail.com>
3
+
4
+ Permission is hereby granted, free of charge, to any person obtaining
5
+ a copy of this software and associated documentation files (the
6
+ "Software"), to deal in the Software without restriction, including
7
+ without limitation the rights to use, copy, modify, merge, publish,
8
+ distribute, sublicense, and/or sell copies of the Software, and to
9
+ permit persons to whom the Software is furnished to do so, subject to
10
+ the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be
13
+ included in all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,94 @@
1
+ = rails-doorman
2
+
3
+ +rails-doorman+ is an authorization plugin for Ruby on Rails applications. This code was orignally written by Michael D. Ivey for Merb.
4
+
5
+ == Configuration
6
+
7
+ Doorman expects the controller to respond to +current_user+
8
+
9
+ The +:role+ option expects +current_user+ to respond to +has_role?(role_name)+. To change the default assign the option a new value:
10
+
11
+ Doorman.options[:has_role_method]
12
+
13
+ The +:user+ option expects +current_user+ to respond to +login+. To change the default assign the option a new value:
14
+
15
+ Doorman.options[:user_identifier_method]
16
+
17
+ == Usage
18
+
19
+ === Controllers
20
+
21
+ class Admin::ArticlesController < AdminController
22
+ allow :role => :admin
23
+ end
24
+
25
+ allow :role => :admin # current_user.has_role?(:admin)
26
+ deny :role => :troll
27
+ allow :role => :admin, :exclude => :show
28
+ allow :role => :troll, :only => :index
29
+
30
+ +rails-doorman+ supports more than roles.
31
+
32
+ allow :user => :nancy # current_user.login.to_sym == 'nancy'.to_sym
33
+ allow :host => 'allowed.example.org' # request.host =~ Regexp.new('allowed.example.org')
34
+ deny :host => 'denied.example.org'
35
+ deny :user_agent => /MSIE/ # request.user_agent =~ Regexp.new(/MSIE/)
36
+
37
+ === Views
38
+
39
+ All rules can be used in views.
40
+
41
+ <% allow(:role => :admin) do %>
42
+ <h1>Allowed</h1>
43
+ <% end %>
44
+
45
+ <% deny(:role => :troll) do %>
46
+ <h1>Allowed</h1>
47
+ <% end %>
48
+
49
+ === Unauthorized
50
+
51
+ When a rule fails a Doorman::Unauthorized error is raised. The error
52
+ can be caught in ApplicationController#rescue_action_in_public.
53
+
54
+ class ApplicationController < ActionController::Base
55
+ private
56
+ def rescue_action_in_public(exception)
57
+ case exception
58
+ when Doorman::InvalidRule
59
+ render :text => 'Invalid Rule', :status => '500 Internal Server Error'
60
+ when Doorman::Unauthorized
61
+ render :text => 'Unauthorized', :status => '401 Unauthorized'
62
+ else
63
+ super(exception)
64
+ end
65
+ end
66
+ end
67
+
68
+ == Resources
69
+
70
+ Development
71
+
72
+ * http://github.com/jrun/rails-doorman
73
+
74
+ Source
75
+
76
+ * git://github.com/jrun/rails-doorman.git
77
+
78
+ Bugs
79
+
80
+ * http://github.com/jrun/rails-doorman/issues
81
+
82
+
83
+ == TODO
84
+
85
+ === Rule inheritance
86
+
87
+ Controller subclasses do not inherit its parents rules. This is more
88
+ like a bug than a todo.
89
+
90
+ === More configurable
91
+
92
+ +rails-doorman+ should be configurable but in what ways?
93
+
94
+
@@ -0,0 +1,89 @@
1
+ require 'rubygems'
2
+ require 'spec/rake/spectask'
3
+
4
+ begin
5
+ require 'jeweler'
6
+ Jeweler::Tasks.new do |gem|
7
+ gem.name = 'rails-doorman'
8
+ gem.summary = 'Ruby on Rails authorization plugin'
9
+ gem.description = 'Ruby on Rails authorization plugin'
10
+ gem.has_rdoc = false
11
+ gem.email = 'jeremy.burks@gmail.com'
12
+ gem.homepage = "http://jrun.github.com/rails-doorman"
13
+ gem.authors = ["Jeremy Burks"]
14
+ gem.files = %w(LICENSE README.rdoc Rakefile) + Dir.glob("{rails,lib,spec,features}/**/*")
15
+ gem.add_dependency('rails', '>= 2.3.2')
16
+ gem.add_development_dependency "rspec", ">= 1.2.9"
17
+ gem.add_development_dependency "rspec-rails", ">= 1.2.9"
18
+ gem.add_development_dependency "cucumber", ">= 0"
19
+ gem.add_development_dependency 'yard', '~> 0.4.0'
20
+ gem.add_development_dependency 'grancher', '> 0'
21
+
22
+ desc "Install development dependencies."
23
+ task :setup do
24
+ gems = ::Gem::SourceIndex.from_installed_gems
25
+ gem.dependencies.each do |dep|
26
+ if gems.find_name(dep.name, dep.version_requirements).empty?
27
+ puts "Installing dependency: #{dep}"
28
+ system %Q|gem install #{dep.name} -v "#{dep.version_requirements}" --development|
29
+ end
30
+ end
31
+ end
32
+
33
+ desc "Build and reinstall the gem locally."
34
+ task :reinstall => :build do
35
+ version = File.read('VERSION')
36
+ if (system("gem list #{gem.name} -l") || "") =~ /#{gem.name}-#{version}/
37
+ system "gem uninstall #{gem.name}"
38
+ end
39
+ system "gem install --no-rdoc --no-ri -l pkg/#{gem.name}-#{version}"
40
+ end
41
+ end
42
+
43
+ Jeweler::GemcutterTasks.new
44
+ rescue LoadError
45
+ puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler"
46
+ end
47
+
48
+ desc "Run the examples"
49
+ Spec::Rake::SpecTask.new do |t|
50
+ t.spec_files = ["spec/**/*_spec.rb"]
51
+ t.spec_opts = %w[--color --format specdoc --diff]
52
+ end
53
+
54
+ Spec::Rake::SpecTask.new(:rcov) do |spec|
55
+ spec.libs << 'lib' << 'spec'
56
+ spec.pattern = 'spec/**/*_spec.rb'
57
+ spec.rcov = true
58
+ end
59
+
60
+ require 'cucumber/rake/task'
61
+ Cucumber::Rake::Task.new(:features) do |t|
62
+ t.cucumber_opts = "--format pretty"
63
+ end
64
+
65
+ task :spec => :check_dependencies
66
+ task :default => [:spec, :features]
67
+ task :build => [:spec, :features, :yard]
68
+
69
+ begin
70
+ require 'yard'
71
+ YARD::Rake::YardocTask.new
72
+ rescue LoadError
73
+ task :yard do
74
+ abort "YARD is not available. Run 'rake setup' to install all development dependencies."
75
+ end
76
+ end
77
+
78
+ begin
79
+ require 'grancher/task'
80
+ Grancher::Task.new do |g|
81
+ g.branch = 'gh-pages'
82
+ g.push_to = 'origin'
83
+ g.directory 'doc'
84
+ end
85
+ rescue LoadError
86
+ task :publish do
87
+ abort "grancher is not available. Run 'rake setup' to install all development dependencies."
88
+ end
89
+ end
@@ -0,0 +1,99 @@
1
+ Feature: Manage Access
2
+ In order to
3
+ As a
4
+ I want to
5
+
6
+ Scenario: Allow all by default
7
+ When I go to /allow_all_by_default
8
+ Then I should be authorized
9
+
10
+ Scenario: Explicitly allow all
11
+ When I go to /explicitly_allow_all
12
+ Then I should be authorized
13
+
14
+ Scenario: Unauthorized when explicitly denying all
15
+ When I go to /deny_all
16
+ Then I should not be authorized
17
+
18
+ Scenario: Authorized when the user is allowed
19
+ Given I am Nancy
20
+ When I go to /allowed_user
21
+ Then I should be authorized
22
+
23
+ Scenario: Unauthorized when the user is not allowed
24
+ Given I am Jackie Boy
25
+ When I go to /allowed_user
26
+ Then I should not be authorized
27
+
28
+ Scenario: Authorized when the user belongs to the allowed rule
29
+ Given I have the role admin
30
+ When I go to /allowed_role
31
+ Then I should be authorized
32
+
33
+ Scenario: Unauthorized when the user does not belong to the rule
34
+ Given I have the role not_admin
35
+ When I go to /allowed_role
36
+ Then I should not be authorized
37
+
38
+ Scenario: Authorized when the user does not belong to the denied role
39
+ When I go to /denied_role
40
+ Then I should be authorized
41
+
42
+ Scenario: Unauthorized when the user belongs to the denied role
43
+ Given I have the role troll
44
+ When I go to /denied_role
45
+ Then I should not be authorized
46
+
47
+ Scenario: Authorized when the user belongs to an allowed role
48
+ Given I have the role admin
49
+ When I go to /allowed_and_denied_roles
50
+ Then I should be authorized
51
+
52
+ Scenario: Unauthorized when the user belongs to the denied role
53
+ Given I have the role troll
54
+ When I go to /allowed_and_denied_roles
55
+ Then I should not be authorized
56
+
57
+ Scenario: Unauthorized when the user does not belong to the role
58
+ Given I have no roles
59
+ When I go to /allowed_role_with_only/show
60
+ Then I should not be authorized
61
+
62
+ Scenario: Authorized when he user belongs to the role
63
+ Given I have the role admin
64
+ When I go to /allowed_role_with_only/show
65
+ Then I should be authorized
66
+ Given I have no roles
67
+ When I go to /allowed_role_with_only
68
+ Then I should be authorized
69
+
70
+ Scenario: Authorized when the rule does not apply to the action
71
+ Given I have the role admin
72
+ When I go to /allowed_role_with_only
73
+ Then I should be authorized
74
+
75
+ Scenario: Unauthorized when the host is not explicitly allowed
76
+ When I go to /access_control_by_host
77
+ Then I should not be authorized
78
+
79
+ Scenario: Unauthorized when authorizing via role and there is not a current user
80
+ When There is no current user
81
+ And I go to /allowed_role
82
+ Then I should not be authorized
83
+
84
+
85
+ Scenario: View Helpers - Allow
86
+ Given I have the role admin
87
+ When I go to /view_helpers/allow_via_role
88
+ Then I should see "Allowed"
89
+ Given I have no roles
90
+ When I go to /view_helpers/allow_via_role
91
+ Then I should not see "Allowed"
92
+
93
+ Scenario: View Helpers - Deny
94
+ Given I have no roles
95
+ When I go to /view_helpers/deny_via_role
96
+ Then I should see "Allowed"
97
+ Given I have the role troll
98
+ When I go to /view_helpers/deny_via_role
99
+ Then I should not see "Allowed"
@@ -0,0 +1,25 @@
1
+ Given /^I am (.*)$/ do |name|
2
+ ApplicationController.reset_current_user
3
+ ApplicationController.current_user.login = name.downcase
4
+ end
5
+
6
+ Given /^I have no roles$/ do
7
+ ApplicationController.reset_current_user
8
+ end
9
+
10
+ Given /^I have the role (.*)$/ do |role|
11
+ Given "I have no roles"
12
+ ApplicationController.current_user.roles << role.to_sym
13
+ end
14
+
15
+ Then /^I should be authorized$/ do
16
+ response.should be_authorized
17
+ end
18
+
19
+ Then /^I should not be authorized$/ do
20
+ response.should be_unauthorized
21
+ end
22
+
23
+ When /^There is no current user$/ do
24
+ ApplicationController.nil_current_user
25
+ end
@@ -0,0 +1,115 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), "..", "support", "paths"))
2
+
3
+ # Commonly used webrat steps
4
+ # http://github.com/brynary/webrat
5
+
6
+ Given /^I am on (.+)$/ do |page_name|
7
+ visit path_to(page_name)
8
+ end
9
+
10
+ When /^I go to (.+)$/ do |page_name|
11
+ visit path_to(page_name)
12
+ end
13
+
14
+ When /^I press "([^\"]*)"$/ do |button|
15
+ click_button(button)
16
+ end
17
+
18
+ When /^I follow "([^\"]*)"$/ do |link|
19
+ click_link(link)
20
+ end
21
+
22
+ When /^I fill in "([^\"]*)" with "([^\"]*)"$/ do |field, value|
23
+ fill_in(field, :with => value)
24
+ end
25
+
26
+ When /^I select "([^\"]*)" from "([^\"]*)"$/ do |value, field|
27
+ select(value, :from => field)
28
+ end
29
+
30
+ # Use this step in conjunction with Rail's datetime_select helper. For example:
31
+ # When I select "December 25, 2008 10:00" as the date and time
32
+ When /^I select "([^\"]*)" as the date and time$/ do |time|
33
+ select_datetime(time)
34
+ end
35
+
36
+ # Use this step when using multiple datetime_select helpers on a page or
37
+ # you want to specify which datetime to select. Given the following view:
38
+ # <%= f.label :preferred %><br />
39
+ # <%= f.datetime_select :preferred %>
40
+ # <%= f.label :alternative %><br />
41
+ # <%= f.datetime_select :alternative %>
42
+ # The following steps would fill out the form:
43
+ # When I select "November 23, 2004 11:20" as the "Preferred" data and time
44
+ # And I select "November 25, 2004 10:30" as the "Alternative" data and time
45
+ When /^I select "([^\"]*)" as the "([^\"]*)" date and time$/ do |datetime, datetime_label|
46
+ select_datetime(datetime, :from => datetime_label)
47
+ end
48
+
49
+ # Use this step in conjunction with Rail's time_select helper. For example:
50
+ # When I select "2:20PM" as the time
51
+ # Note: Rail's default time helper provides 24-hour time-- not 12 hour time. Webrat
52
+ # will convert the 2:20PM to 14:20 and then select it.
53
+ When /^I select "([^\"]*)" as the time$/ do |time|
54
+ select_time(time)
55
+ end
56
+
57
+ # Use this step when using multiple time_select helpers on a page or you want to
58
+ # specify the name of the time on the form. For example:
59
+ # When I select "7:30AM" as the "Gym" time
60
+ When /^I select "([^\"]*)" as the "([^\"]*)" time$/ do |time, time_label|
61
+ select_time(time, :from => time_label)
62
+ end
63
+
64
+ # Use this step in conjunction with Rail's date_select helper. For example:
65
+ # When I select "February 20, 1981" as the date
66
+ When /^I select "([^\"]*)" as the date$/ do |date|
67
+ select_date(date)
68
+ end
69
+
70
+ # Use this step when using multiple date_select helpers on one page or
71
+ # you want to specify the name of the date on the form. For example:
72
+ # When I select "April 26, 1982" as the "Date of Birth" date
73
+ When /^I select "([^\"]*)" as the "([^\"]*)" date$/ do |date, date_label|
74
+ select_date(date, :from => date_label)
75
+ end
76
+
77
+ When /^I check "([^\"]*)"$/ do |field|
78
+ check(field)
79
+ end
80
+
81
+ When /^I uncheck "([^\"]*)"$/ do |field|
82
+ uncheck(field)
83
+ end
84
+
85
+ When /^I choose "([^\"]*)"$/ do |field|
86
+ choose(field)
87
+ end
88
+
89
+ When /^I attach the file at "([^\"]*)" to "([^\"]*)"$/ do |path, field|
90
+ attach_file(field, path)
91
+ end
92
+
93
+ Then /^I should see "([^\"]*)"$/ do |text|
94
+ response.should contain(text)
95
+ end
96
+
97
+ Then /^I should not see "([^\"]*)"$/ do |text|
98
+ response.should_not contain(text)
99
+ end
100
+
101
+ Then /^the "([^\"]*)" field should contain "([^\"]*)"$/ do |field, value|
102
+ field_labeled(field).value.should =~ /#{value}/
103
+ end
104
+
105
+ Then /^the "([^\"]*)" field should not contain "([^\"]*)"$/ do |field, value|
106
+ field_labeled(field).value.should_not =~ /#{value}/
107
+ end
108
+
109
+ Then /^the "([^\"]*)" checkbox should be checked$/ do |label|
110
+ field_labeled(label).should be_checked
111
+ end
112
+
113
+ Then /^I should be on (.+)$/ do |page_name|
114
+ URI.parse(current_url).path.should == path_to(page_name)
115
+ end