jrun-merb_doorman 0.0.1

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.
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2008 Michael D. Ivey <ivey@gweezlebur.com>
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README ADDED
@@ -0,0 +1,29 @@
1
+ merb_doorman
2
+ ============
3
+
4
+ *** Want to contribute? Some of the code isn't spec'd yet. ***
5
+
6
+
7
+ Merb plugin that provides an allow/deny DSL for controlling access
8
+
9
+
10
+ # mostly open:
11
+ # there is an implicit "allow :all" as the last rule
12
+ # rules continue to match until an allow is found, or we run out
13
+ # of rules
14
+
15
+ deny :host => "209.34.*"
16
+ deny :user => "bill" # calls current_user.login, but this is configurable
17
+ deny :user_agent => /MSIE/
18
+ deny {|c| c.params["arbitrary"] == "expressions"}
19
+
20
+
21
+ # mostly closed:
22
+ deny :all # removes implicit final allow :all
23
+ allow :host => "*.example.com"
24
+ allow :time => "8am-5pm" # not implemented yet
25
+
26
+ # store a block for repeated usage
27
+ Merb::Access.add_block :admin, {|c| c.current_user.admin?}
28
+
29
+ allow :admin
data/Rakefile ADDED
@@ -0,0 +1,67 @@
1
+ require 'rubygems'
2
+ require 'rake/gempackagetask'
3
+ require 'spec/rake/spectask'
4
+
5
+ require 'merb-core'
6
+ require 'merb-core/tasks/merb'
7
+
8
+ GEM_NAME = "merb_doorman"
9
+ GEM_VERSION = "0.0.1"
10
+ AUTHOR = "Michael D. Ivey"
11
+ EMAIL = "ivey@gweezlebur.com"
12
+ HOMEPAGE = "http://github.com/ivey/merb_doorman/"
13
+ SUMMARY = "Merb plugin that provides an allow/deny DSL for controlling access"
14
+
15
+ spec = Gem::Specification.new do |s|
16
+ s.rubyforge_project = 'merb'
17
+ s.name = GEM_NAME
18
+ s.version = GEM_VERSION
19
+ s.platform = Gem::Platform::RUBY
20
+ s.has_rdoc = true
21
+ s.extra_rdoc_files = ["README", "LICENSE", 'TODO']
22
+ s.summary = SUMMARY
23
+ s.description = s.summary
24
+ s.author = AUTHOR
25
+ s.email = EMAIL
26
+ s.homepage = HOMEPAGE
27
+ s.add_dependency('merb-core', '>= 1.0')
28
+ s.require_path = 'lib'
29
+ s.files = %w(LICENSE README Rakefile TODO) + Dir.glob("{lib,spec}/**/*")
30
+ end
31
+
32
+ Rake::GemPackageTask.new(spec) do |pkg|
33
+ pkg.gem_spec = spec
34
+ end
35
+
36
+ desc "install the plugin as a gem"
37
+ task :install do
38
+ Merb::RakeHelper.install(GEM_NAME, :version => GEM_VERSION)
39
+ end
40
+
41
+ desc "Uninstall the gem"
42
+ task :uninstall do
43
+ Merb::RakeHelper.uninstall(GEM_NAME, :version => GEM_VERSION)
44
+ end
45
+
46
+ namespace :gem do
47
+ desc "Repackage, uninstall and install gem"
48
+ task :refresh do
49
+ Rake::Task[:spec].invoke
50
+ Rake::Task[:repackage].invoke
51
+ Rake::Task[:uninstall].invoke
52
+ Rake::Task[:install].invoke
53
+ end
54
+ end
55
+
56
+ desc "Create a gemspec file"
57
+ task :gemspec do
58
+ File.open("#{GEM_NAME}.gemspec", "w") do |file|
59
+ file.puts spec.to_ruby
60
+ end
61
+ end
62
+
63
+ desc "Run the examples"
64
+ Spec::Rake::SpecTask.new do |t|
65
+ t.spec_files = ["spec/**/*_spec.rb"]
66
+ t.spec_opts = %w[--color --format specdoc --diff]
67
+ end
data/TODO ADDED
@@ -0,0 +1,3 @@
1
+ * Multiple roles
2
+ * :only, :exclude, :if
3
+ * Something accessible from views
@@ -0,0 +1,118 @@
1
+ require 'merb_doorman/rule'
2
+ require 'merb_doorman/helpers'
3
+
4
+ module Merb
5
+ module Plugins
6
+ module Doorman
7
+ SUPPORTED_METHODS = [:block, :host, :role, :time, :user, :user_agent]
8
+
9
+ def self.supported_method?(method)
10
+ SUPPORTED_METHODS.include?(method)
11
+ end
12
+
13
+ def self.included(base)
14
+ base.extend(ClassMethods)
15
+ base.send(:include, InstanceMethods)
16
+ base.class_eval do
17
+ before :_doorman_check_acl
18
+ end
19
+ end
20
+
21
+ module ClassMethods
22
+ def _doorman_list
23
+ @_doorman_list ||= []
24
+ end
25
+
26
+ def _doorman_default
27
+ @_doorman_default ||= :allow
28
+ end
29
+
30
+ def deny(*args, &block)
31
+ _add_acl(:deny, args, block)
32
+ end
33
+
34
+ def allow(*args, &block)
35
+ _add_acl(:allow, args, block)
36
+ end
37
+
38
+ def _clear_acl_list
39
+ @_doorman_list = nil
40
+ end
41
+
42
+ def _add_acl(type, args, block)
43
+ opts = args.is_a?(Array) ? args.first : args
44
+ if opts == :all
45
+ @_doorman_default = type
46
+ return true
47
+ end
48
+ if block
49
+ _doorman_list << Rule.from_block(type, opts, &block)
50
+ else
51
+ _doorman_list << Rule.from_hash(type, opts)
52
+ end
53
+ end
54
+
55
+ def _doorman_user_block
56
+ Merb::Plugins.config[:merb_doorman][:user_block]
57
+ end
58
+
59
+ def _doorman_role_block
60
+ Merb::Plugins.config[:merb_doorman][:role_block]
61
+ end
62
+ end
63
+
64
+ module InstanceMethods
65
+ private
66
+ def _doorman_check_acl
67
+ allowed = false
68
+ self.class._doorman_list.each do |rule|
69
+ next unless rule.evaluate?(self.action_name)
70
+ if _check_rule(rule)
71
+ allowed = true
72
+ else
73
+ raise ::Merb::ControllerExceptions::Unauthorized
74
+ end
75
+ end
76
+ if self.class._doorman_default == :deny && !allowed
77
+ raise ::Merb::ControllerExceptions::Unauthorized
78
+ end
79
+ end
80
+
81
+ def _check_rule(rule)
82
+ match = case rule.method
83
+ when :block
84
+ rule.value.call(self)
85
+ when :host
86
+ request.host =~ Regexp.new(rule.value)
87
+ when :role
88
+ self.class._doorman_role_block.call(self, rule.value)
89
+ when :time
90
+ false #not implemented
91
+ when :user
92
+ self.class._doorman_user_block.call(self, rule.value)
93
+ when :user_agent
94
+ request.user_agent =~ Regexp.new(rule.value)
95
+ else
96
+ false
97
+ end
98
+ rule.deny? ? !match : match
99
+ end
100
+ end
101
+
102
+ end
103
+ end
104
+ end
105
+
106
+ if defined?(Merb::Plugins)
107
+ Merb::Plugins.config[:merb_doorman][:user_block] = proc do |c, login|
108
+ c.respond_to?(:current_user) &&
109
+ c.current_user.login == login.to_s
110
+ end
111
+ Merb::Plugins.config[:merb_doorman][:role_block] = proc do |c, role|
112
+ c.respond_to?(:current_user) &&
113
+ c.current_user.respond_to?(:has_role?) &&
114
+ c.current_user.has_role?(role)
115
+ end
116
+ Merb::Controller.send(:include, Merb::Plugins::Doorman)
117
+ Merb::GlobalHelpers.send(:include, Merb::Plugins::Doorman::Helpers)
118
+ end
@@ -0,0 +1,22 @@
1
+ module Merb
2
+ module Plugins
3
+ module Doorman
4
+
5
+ module Helpers
6
+ def allow(*args, &blk)
7
+ _capture_within_rule_context(:allow, args, &blk)
8
+ end
9
+
10
+ def deny(*args, &blk)
11
+ _capture_within_rule_context(:deny, args, &blk)
12
+ end
13
+
14
+ def _capture_within_rule_context(type, args, &blk)
15
+ _check_rule(Doorman::Rule.from_hash(type, args.first)) ? capture(&blk) : ""
16
+ end
17
+ private :_capture_within_rule_context
18
+ end
19
+
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,6 @@
1
+ namespace :merb_doorman do
2
+ desc "Do something for merb_doorman"
3
+ task :default do
4
+ puts "merb_doorman doesn't do anything"
5
+ end
6
+ end
@@ -0,0 +1,61 @@
1
+ module Merb
2
+ module Plugins
3
+ module Doorman
4
+ class InvalidRule < StandardError
5
+ def initialize(*args)
6
+ super "merb_doorman: invalid rule #{args.inspect}"
7
+ end
8
+ end
9
+
10
+ class Rule
11
+ def self.from_hash(type, opts)
12
+ rule = new(type)
13
+
14
+ h = opts.except(:only, :exclude)
15
+ raise InvalidRule.new(type, opts) if h.size > 1
16
+
17
+ rule.method = h.keys.first.to_sym
18
+ unless Doorman.supported_method?(rule.method)
19
+ raise InvalidRule.new(type, opts)
20
+ end
21
+ rule.value = h.values.first
22
+ rule.limits = extract_limits(opts)
23
+ rule
24
+ end
25
+
26
+ def self.from_block(type, opts = nil, &block)
27
+ raise InvalidRule.new(type, opts, block) unless block.arity == 1
28
+ opts ||= {}
29
+
30
+ rule = new(type)
31
+ rule.method = :block
32
+ rule.value = block
33
+ rule.limits = extract_limits(opts)
34
+ rule
35
+ end
36
+
37
+ def self.extract_limits(h)
38
+ h.only(:only, :exclude).inject({}) do |limits, kv|
39
+ limits.merge!(kv.first => Array(kv.last))
40
+ end
41
+ end
42
+
43
+ attr_accessor :type, :method, :value, :limits
44
+
45
+ def initialize(type)
46
+ @type, @limits = type, {}
47
+ end
48
+
49
+ def deny?
50
+ type == :deny
51
+ end
52
+
53
+ def evaluate?(action_name)
54
+ (!limits.key?(:only) || limits[:only].include?(action_name)) &&
55
+ (!limits.key?(:exclude) || !limits[:exclude].include?(action_name))
56
+ end
57
+ end
58
+
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,16 @@
1
+ require File.dirname(__FILE__) + '/spec_helper'
2
+
3
+ class AllowAllByDefault < Merb::Plugins::Doorman::TestController; end
4
+
5
+ class ExplicitAllowAll < Merb::Plugins::Doorman::TestController
6
+ allow :all
7
+ end
8
+
9
+ [AllowAllByDefault, ExplicitAllowAll].each do |controller|
10
+ describe controller, 'request' do
11
+ it "should be authorized when explicitly denying all" do
12
+ response = request(url(:controller => controller.controller_name))
13
+ response.should be_authorized
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,46 @@
1
+ require File.dirname(__FILE__) + '/spec_helper'
2
+
3
+ describe Merb::Plugins::Doorman::ClassMethods do
4
+ include Merb::Plugins::Doorman::ClassMethods
5
+
6
+ before(:each) do
7
+ _clear_acl_list
8
+ end
9
+
10
+ it "should store the ACL" do
11
+ _doorman_list.should be_an_instance_of(Array)
12
+ end
13
+
14
+ it "should have a deny method" do
15
+ lambda { deny :all }.should_not raise_error
16
+ end
17
+
18
+ it "should store a deny entry on the ACL" do
19
+ s = _doorman_list.size
20
+ deny :host => "192.168.*"
21
+ _doorman_list.should have(s + 1).elements
22
+ end
23
+
24
+ it "should have an allow method" do
25
+ lambda { allow :all }.should_not raise_error
26
+ end
27
+
28
+ it "should store an allow entry on the ACL" do
29
+ s = _doorman_list.size
30
+ allow :user_agent => /MSIE/
31
+ _doorman_list.should have(s + 1).elements
32
+ end
33
+
34
+ it "should allow valid ACL entries" do
35
+ lambda { deny :host => "192.168.*" }.should_not raise_error
36
+ lambda { deny :user => "bill" }.should_not raise_error
37
+ lambda { deny :user_agent => /MSIE/ }.should_not raise_error
38
+ lambda { deny :time => "8am-5pm" }.should_not raise_error
39
+ lambda { deny {|c| c.foo } }.should_not raise_error
40
+ end
41
+
42
+ it "should reject invalid ACL entries" do
43
+ lambda { deny :foo => "3" }.should raise_error
44
+ lambda { deny { foo } }.should raise_error
45
+ end
46
+ end
@@ -0,0 +1,12 @@
1
+ require File.dirname(__FILE__) + '/spec_helper'
2
+
3
+ class DenyAll < Merb::Plugins::Doorman::TestController
4
+ deny :all
5
+ end
6
+
7
+ describe DenyAll, 'request' do
8
+ it "should be unauthorized when explicitly denying all" do
9
+ response = request(url(:controller => DenyAll))
10
+ response.should be_unauthorized
11
+ end
12
+ end
@@ -0,0 +1,5 @@
1
+ class Exceptions < Merb::Controller
2
+ def unauthorized
3
+ render 'Unauthorized'
4
+ end
5
+ end
@@ -0,0 +1,17 @@
1
+ module Merb
2
+ module Plugins
3
+ module Doorman
4
+
5
+ class TestController < Merb::Controller
6
+ self._template_root = File.dirname(__FILE__) / ".." / "views"
7
+
8
+ class_inheritable_accessor :current_user
9
+ self.current_user ||= User.new
10
+
11
+ def show; render('Allowed Access') end
12
+ def index; render('Allowed Access') end
13
+ end
14
+
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,5 @@
1
+ class TestHelpers < Merb::Plugins::Doorman::TestController
2
+ def example_setup_is_ok; render end
3
+ def allow_via_role; render end
4
+ def deny_via_role; render end
5
+ end
@@ -0,0 +1,14 @@
1
+ module Merb
2
+ module Plugins
3
+ module Doorman
4
+
5
+ class User
6
+ attr_accessor :login, :roles
7
+ def initialize; reset end
8
+ def reset; @login, @roles = '', [] end
9
+ def has_role?(role); @roles.include?(role) end
10
+ end
11
+
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,3 @@
1
+ <%= allow(:role => :admin) do %>
2
+ <h1>Allowed</h1>
3
+ <% end =%>
@@ -0,0 +1,3 @@
1
+ <%= deny(:role => :troll) do %>
2
+ <h1>Allowed</h1>
3
+ <% end =%>
@@ -0,0 +1 @@
1
+ <h1>Good to go</h1>
data/spec/host_spec.rb ADDED
@@ -0,0 +1,49 @@
1
+ require File.dirname(__FILE__) + '/spec_helper'
2
+
3
+ class AccessControllByHost < Merb::Plugins::Doorman::TestController
4
+ allow :all
5
+ allow :host => "allowed.example.org"
6
+ deny :host => "denied.example.org"
7
+ end
8
+ describe AccessControllByHost, 'request' do
9
+ it "should be unauthorized when the host is not explicitly allowed" do
10
+ response = request(url(:controller => AccessControllByHost))
11
+ response.should be_unauthorized
12
+ end
13
+
14
+ it "should be authorized when the host is allowed" do
15
+ response = request(url(:controller => AccessControllByHost), 'SERVER_NAME' => 'allowed.example.org')
16
+ response.should be_authorized
17
+ end
18
+
19
+ it "should be unauthorized when the host is denied" do
20
+ response = request(url(:controller => AccessControllByHost), 'SERVER_NAME' => 'denied.example.org')
21
+ response.should be_unauthorized
22
+ end
23
+ end
24
+
25
+ class AccessControllDenyAllExceptHost < Merb::Plugins::Doorman::TestController
26
+ deny :all
27
+ allow :host => "allowed.example.org"
28
+ end
29
+ describe AccessControllDenyAllExceptHost, 'request' do
30
+ it "should be authorized when the host is allowed" do
31
+ response = request(url(:controller => AccessControllDenyAllExceptHost))
32
+ response.should be_unauthorized
33
+ response = request(url(:controller => AccessControllDenyAllExceptHost), 'SERVER_NAME' => 'allowed.example.org')
34
+ response.should be_authorized
35
+ end
36
+ end
37
+
38
+ class AccessControllAllowAllExceptHost < Merb::Plugins::Doorman::TestController
39
+ allow :all
40
+ deny :host => "denied.example.org"
41
+ end
42
+ describe AccessControllDenyAllExceptHost, 'request' do
43
+ it "should be authorized when the host is allowed" do
44
+ response = request(url(:controller => AccessControllAllowAllExceptHost))
45
+ response.should be_authorized
46
+ response = request(url(:controller => AccessControllAllowAllExceptHost), 'SERVER_NAME' => 'denied.example.org')
47
+ response.should be_unauthorized
48
+ end
49
+ end
@@ -0,0 +1,19 @@
1
+ class BeAuthorized
2
+ def matches?(response)
3
+ @response = response
4
+ response.status == 200 && response.body == 'Allowed Access'
5
+ end
6
+
7
+ # ==== Returns
8
+ # String:: The failure message.
9
+ def failure_message
10
+ "expected the response from #{@response.url} #{$/} to have the status 200 Ok and body 'Allowed Access'" <<
11
+ "#{$/} but the status is #{@response.status} and the body is '#{@response.body}'"
12
+ end
13
+
14
+ # ==== Returns
15
+ # String:: The failure message to be displayed in negative matches.
16
+ def negative_failure_message
17
+ "expected the response from #{@response.url} #{$/} not to have the status 200 Ok and body 'Allowed Access'"
18
+ end
19
+ end
@@ -0,0 +1,19 @@
1
+ class BeUnauthorized
2
+ def matches?(response)
3
+ @response = response
4
+ response.status == 401 && response.body == 'Unauthorized'
5
+ end
6
+
7
+ # ==== Returns
8
+ # String:: The failure message.
9
+ def failure_message
10
+ "expected the response from #{@response.url} #{$/} to have the status 401 Unauthorized and body 'Unauthorized'" <<
11
+ "#{$/} but the status is #{@response.status} and the body is '#{@response.body}'"
12
+ end
13
+
14
+ # ==== Returns
15
+ # String:: The failure message to be displayed in negative matches.
16
+ def negative_failure_message
17
+ "expected the response from #{@response.url} #{$/} not to have the status 200 Ok and body 'Allowed Access'"
18
+ end
19
+ end
@@ -0,0 +1,43 @@
1
+ require File.dirname(__FILE__) + '/../spec_helper'
2
+
3
+ describe Merb::Plugins::Doorman::Helpers do
4
+ it "examples should be setup successfully" do
5
+ response = request(url(:controller => TestHelpers, :action => :example_setup_is_ok))
6
+ response.body.should == "<h1>Good to go</h1>"
7
+ end
8
+
9
+ describe "#allow" do
10
+ before(:each) do
11
+ TestHelpers.current_user.reset
12
+ end
13
+
14
+ it "should render the result of the block when allowed" do
15
+ TestHelpers.current_user.roles << :admin
16
+ response = request(url(:controller => TestHelpers, :action => :allow_via_role))
17
+ response.body.should == "\n <h1>Allowed</h1>\n"
18
+ end
19
+
20
+ it "should not return the result of the block when not allowed" do
21
+ response = request(url(:controller => TestHelpers, :action => :allow_via_role))
22
+ response.body.should == ""
23
+ end
24
+ end
25
+
26
+ describe "#deny" do
27
+ before(:each) do
28
+ TestHelpers.current_user.reset
29
+ end
30
+
31
+ it "should not return the result of the block when denied" do
32
+ TestHelpers.current_user.roles << :troll
33
+ response = request(url(:controller => TestHelpers, :action => :deny_via_role))
34
+ response.body.should == ""
35
+ end
36
+
37
+ it "should render the result of the block when not denied" do
38
+ TestHelpers.current_user.roles << :anything_but_troll
39
+ response = request(url(:controller => TestHelpers, :action => :deny_via_role))
40
+ response.body.should == "\n <h1>Allowed</h1>\n"
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,89 @@
1
+ require File.dirname(__FILE__) / '../spec_helper'
2
+
3
+ Rule = Merb::Plugins::Doorman::Rule
4
+
5
+ describe Merb::Plugins::Doorman::Rule do
6
+ describe '.from_hash' do
7
+ it "should set the method using the opts first key" do
8
+ rule = Rule.from_hash(:allow, :role => :whatever)
9
+ rule.method.should == :role
10
+ end
11
+
12
+ it "should set the value using the opts first value" do
13
+ rule = Rule.from_hash(:allow, :role => :whatever)
14
+ rule.value.should == :whatever
15
+ end
16
+
17
+ it "should move :only from options to limits" do
18
+ rule = Rule.from_hash(:allow, :role => :whatever, :only => :index)
19
+ rule.limits[:only].should_not be_nil
20
+ rule.limits[:role].should be_nil
21
+ end
22
+
23
+ it "should move :exclude from options to limits" do
24
+ rule = Rule.from_hash(:allow, :role => :whatever, :exclude => :index)
25
+ rule.limits[:exclude].should_not be_nil
26
+ rule.limits[:role].should be_nil
27
+ end
28
+
29
+ it "should convert a single :only value to an Array" do
30
+ rule = Rule.from_hash(:allow, :role => :admin, :only => :index)
31
+ rule.limits[:only].should == [:index]
32
+ end
33
+
34
+ it "should convert a single :exclude value to an Array" do
35
+ rule = Rule.from_hash(:allow, :role => :admin, :exclude => :index)
36
+ rule.limits[:exclude].should == [:index]
37
+ end
38
+
39
+ it "should raise an InvalidRule error when the options hash as too many values" do
40
+ lambda do
41
+ Rule.from_hash(:allow, :role => :admin, :user => :bob)
42
+ end.should raise_error(Merb::Plugins::Doorman::InvalidRule)
43
+ end
44
+
45
+ it "should raise an InvalidRule error when the method isn't supported" do
46
+ lambda do
47
+ Rule.from_hash(:allow, :not_suppoted => :whatever)
48
+ end.should raise_error(Merb::Plugins::Doorman::InvalidRule)
49
+ end
50
+ end
51
+
52
+ describe '.from_block' do
53
+ def block
54
+ proc {|ignored| true }
55
+ end
56
+
57
+ it "should set the method to :block" do
58
+ rule = Rule.from_block(:allow, &block)
59
+ rule.method.should == :block
60
+ end
61
+
62
+ it "should set the value to the block" do
63
+ rule = Rule.from_block(:allow, &block)
64
+ rule.value.should be_instance_of(Proc)
65
+ rule.value.call(:ignored).should be_true
66
+ end
67
+
68
+ it "should move :only from options to limits" do
69
+ rule = Rule.from_block(:allow, :only => :index, &block)
70
+ rule.limits[:only].should == [:index]
71
+ end
72
+
73
+ it "should move :exclude from options to limits" do
74
+ rule = Rule.from_block(:allow, :exclude => [:index, :show], &block)
75
+ rule.limits[:exclude].should == [:index, :show]
76
+ end
77
+
78
+ it "should convert a single :only value to an Array" do
79
+ rule = Rule.from_block(:allow, :exclude => :index, &block)
80
+ rule.limits[:exclude].should == [:index]
81
+ end
82
+
83
+ it "should raise an InvalidRule error when the blocks arity is not one" do
84
+ lambda do
85
+ Rule.from_block(:allow) {}
86
+ end.should raise_error(Merb::Plugins::Doorman::InvalidRule)
87
+ end
88
+ end
89
+ end
data/spec/role_spec.rb ADDED
@@ -0,0 +1,81 @@
1
+ require File.dirname(__FILE__) + '/spec_helper'
2
+
3
+ class AllowedRole < Merb::Plugins::Doorman::TestController
4
+ allow :role => :admin
5
+ end
6
+ describe AllowedRole, 'request' do
7
+ before(:each) do
8
+ AllowedRole.current_user.reset
9
+ end
10
+
11
+ it "should be authorized when the current user belongs to the allowed role" do
12
+ AllowedRole.current_user.roles << :admin
13
+ response = request(url(:controller => AllowedRole))
14
+ response.should be_authorized
15
+ end
16
+
17
+ it "should be unauthorized when the current user does not belong to the allowed role" do
18
+ response = request(url(:controller => AllowedRole))
19
+ response.should be_unauthorized
20
+
21
+ AllowedRole.current_user.roles << :not_admin
22
+ response = request(url(:controller => AllowedRole))
23
+ response.should be_unauthorized
24
+ end
25
+ end
26
+
27
+ class DeniedRole < Merb::Plugins::Doorman::TestController
28
+ deny :role => :troll
29
+ end
30
+ describe DeniedRole, 'request' do
31
+ before(:each) do
32
+ DeniedRole.current_user.reset
33
+ end
34
+
35
+ it "should be authorized when the current user does not belong to the denied role" do
36
+ response = request(url(:controller => DeniedRole))
37
+ response.should be_authorized
38
+ end
39
+
40
+ it "should be unauthorized when the current user belongs to the denied role" do
41
+ DeniedRole.current_user.roles << :troll
42
+ response = request(url(:controller => DeniedRole))
43
+ response.should be_unauthorized
44
+ end
45
+ end
46
+
47
+ class AllowedAndDeniedRoles < Merb::Plugins::Doorman::TestController
48
+ allow :role => :admin
49
+ deny :role => :troll
50
+ end
51
+ describe AllowedAndDeniedRoles, 'request' do
52
+ before(:each) do
53
+ AllowedAndDeniedRoles.current_user.reset
54
+ end
55
+
56
+ it "should be authorized when the current user belongs to the allowed role" do
57
+ AllowedAndDeniedRoles.current_user.roles << :admin
58
+ response = request(url(:controller => AllowedAndDeniedRoles))
59
+ response.should be_authorized
60
+ end
61
+
62
+ it "should be unauthorized when the current user belongs to the denied role" do
63
+ AllowedAndDeniedRoles.current_user.roles << :troll
64
+ response = request(url(:controller => AllowedAndDeniedRoles))
65
+ response.should be_unauthorized
66
+ end
67
+ end
68
+
69
+ class AllowedOnly < Merb::Plugins::Doorman::TestController
70
+ allow :role => :admin, :only => :show
71
+ end
72
+ describe AllowedAndDeniedRoles, 'request' do
73
+ before(:each) do
74
+ AllowedOnly.current_user.reset
75
+ end
76
+
77
+ it "should be authorized when the rule does not apply to the action" do
78
+ response = request(url(:controller => AllowedOnly, :action => :index))
79
+ response.should be_authorized
80
+ end
81
+ end
@@ -0,0 +1,42 @@
1
+ $TESTING=true
2
+ $:.push File.join(File.dirname(__FILE__), '..', 'lib')
3
+ require 'rubygems'
4
+ require 'merb-core'
5
+ require 'merb_doorman'
6
+
7
+ this_dir = File.dirname(__FILE__)
8
+
9
+ Merb.push_path(:matchers, this_dir / "matchers")
10
+ Merb.push_path(:fixture_model, this_dir / "fixtures/model")
11
+ Merb.push_path(:fixture_controller, this_dir / "fixtures/controllers")
12
+
13
+ Merb.start :environment => 'test', :adapter => 'runner'
14
+
15
+ def be_authorized
16
+ BeAuthorized.new
17
+ end
18
+
19
+ def be_unauthorized
20
+ BeUnauthorized.new
21
+ end
22
+
23
+ Spec::Runner.configure do |config|
24
+ config.include Merb::Test::RequestHelper
25
+ config.before(:all) do
26
+ Merb::Router.prepare { default_routes }
27
+ end
28
+ end
29
+
30
+ # # deny :user => "bill" # calls current_user.login, but this is configurable
31
+ # # deny {|c| c.params["arbitrary"] == "expressions"}
32
+ # #
33
+ # #
34
+ # # # mostly closed:
35
+ # # deny :all # removes implicit final allow :all
36
+ # # allow :host => "*.example.com"
37
+ # # allow :time => "8am-5pm"
38
+ # #
39
+ # # # store a block for repeated usage
40
+ # # Merb::Access.add_block :admin, {|c| c.current_user.admin?}
41
+ # #
42
+ # # allow :admin
@@ -0,0 +1,19 @@
1
+ require File.dirname(__FILE__) + '/spec_helper'
2
+
3
+ class AccessControllByUserAgent < Merb::Plugins::Doorman::TestController
4
+ deny :user_agent => /MSIE/
5
+ allow :user_agent => /iPhone/
6
+ end
7
+
8
+ describe AccessControllByUserAgent, 'request' do
9
+ it "should be authorized when the user agent is allowed" do
10
+ response = request(url(:controller => AccessControllByUserAgent.controller_name), 'HTTP_USER_AGENT' => 'Mozilla/5.0 (iPhone; U; CPU iPhone OS 2_1 like Mac OS X; en-us) AppleWebKit/525.18.1 (KHTML, like Gecko) Version/3.1.1 Mobile/5F136 Safari/525.20')
11
+ response.should be_authorized
12
+ end
13
+
14
+ it "should be unauthorized when the user agent is denied" do
15
+ response = request(url(:controller => AccessControllByUserAgent.controller_name), 'HTTP_USER_AGENT' => 'Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; Win 9x 4.90; MSIECrawler)')
16
+ response.should be_unauthorized
17
+ end
18
+ end
19
+
data/spec/user_spec.rb ADDED
@@ -0,0 +1,73 @@
1
+ require File.dirname(__FILE__) + '/spec_helper'
2
+
3
+ class AllowedUser < Merb::Plugins::Doorman::TestController
4
+ allow :user => :nancy
5
+ end
6
+ describe AllowedUser, 'request' do
7
+ before(:each) do
8
+ AllowedUser.current_user.reset
9
+ end
10
+
11
+ it "should be authorized when the current user has an allowed login" do
12
+ AllowedUser.current_user.login = 'nancy'
13
+ response = request(url(:controller => AllowedUser))
14
+ response.should be_authorized
15
+ end
16
+
17
+ it "should be unauthorized when the current user does not have an allowed login" do
18
+ response = request(url(:controller => AllowedUser))
19
+ response.should be_unauthorized
20
+
21
+ AllowedUser.current_user.login = 'jackie boy'
22
+ response = request(url(:controller => AllowedUser))
23
+ response.should be_unauthorized
24
+ end
25
+ end
26
+
27
+ class DeniedUser < Merb::Plugins::Doorman::TestController
28
+ deny :user => 'roark'
29
+ deny :user => 'kevin'
30
+ end
31
+ describe DeniedUser, 'request' do
32
+ before(:each) do
33
+ DeniedUser.current_user.reset
34
+ end
35
+
36
+ it "should be authorized when the current user does not have a denied login" do
37
+ DeniedUser.current_user.login = 'nancy'
38
+ response = request(url(:controller => DeniedUser))
39
+ response.should be_authorized
40
+ end
41
+
42
+ it "should be unauthorized when the current user has a denied login" do
43
+ DeniedUser.current_user.login = 'roark'
44
+ response = request(url(:controller => DeniedUser))
45
+ response.should be_unauthorized
46
+
47
+ DeniedUser.current_user.login = 'kevin'
48
+ response = request(url(:controller => DeniedUser))
49
+ response.should be_unauthorized
50
+ end
51
+ end
52
+
53
+ class AllowedAndDeniedUsers < Merb::Plugins::Doorman::TestController
54
+ allow :role => :admin
55
+ deny :role => :troll
56
+ end
57
+ describe AllowedAndDeniedUsers, 'request' do
58
+ before(:each) do
59
+ AllowedAndDeniedUsers.current_user.reset
60
+ end
61
+
62
+ it "should be authorized when the current user belongs to the allowed role" do
63
+ AllowedAndDeniedUsers.current_user.roles << :admin
64
+ response = request(url(:controller => AllowedAndDeniedUsers))
65
+ response.should be_authorized
66
+ end
67
+
68
+ it "should be unauthorized when the current user belongs to the denied role" do
69
+ AllowedAndDeniedUsers.current_user.roles << :troll
70
+ response = request(url(:controller => AllowedAndDeniedUsers))
71
+ response.should be_unauthorized
72
+ end
73
+ end
metadata ADDED
@@ -0,0 +1,97 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: jrun-merb_doorman
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Michael D. Ivey
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2008-11-16 00:00:00 -08:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: merb-core
17
+ version_requirement:
18
+ version_requirements: !ruby/object:Gem::Requirement
19
+ requirements:
20
+ - - ">="
21
+ - !ruby/object:Gem::Version
22
+ version: "1.0"
23
+ version:
24
+ description: Merb plugin that provides an allow/deny DSL for controlling access
25
+ email: ivey@gweezlebur.com
26
+ executables: []
27
+
28
+ extensions: []
29
+
30
+ extra_rdoc_files:
31
+ - README
32
+ - LICENSE
33
+ - TODO
34
+ files:
35
+ - LICENSE
36
+ - README
37
+ - Rakefile
38
+ - TODO
39
+ - lib/merb_doorman
40
+ - lib/merb_doorman/helpers.rb
41
+ - lib/merb_doorman/merbtasks.rb
42
+ - lib/merb_doorman/rule.rb
43
+ - lib/merb_doorman.rb
44
+ - spec/allow_all_spec.rb
45
+ - spec/class_methods_spec.rb
46
+ - spec/deny_all_spec.rb
47
+ - spec/fixtures
48
+ - spec/fixtures/controllers
49
+ - spec/fixtures/controllers/exceptions.rb
50
+ - spec/fixtures/controllers/test_controller.rb
51
+ - spec/fixtures/controllers/test_helpers.rb
52
+ - spec/fixtures/model
53
+ - spec/fixtures/model/user.rb
54
+ - spec/fixtures/views
55
+ - spec/fixtures/views/test_helpers
56
+ - spec/fixtures/views/test_helpers/allow_via_role.html.erb
57
+ - spec/fixtures/views/test_helpers/deny_via_role.html.erb
58
+ - spec/fixtures/views/test_helpers/example_setup_is_ok.html.erb
59
+ - spec/host_spec.rb
60
+ - spec/matchers
61
+ - spec/matchers/authorized_matcher.rb
62
+ - spec/matchers/unauthorized_matcher.rb
63
+ - spec/merb_doorman
64
+ - spec/merb_doorman/helpers_spec.rb
65
+ - spec/merb_doorman/rule_spec.rb
66
+ - spec/role_spec.rb
67
+ - spec/spec_helper.rb
68
+ - spec/user_agent_spec.rb
69
+ - spec/user_spec.rb
70
+ has_rdoc: true
71
+ homepage: http://github.com/ivey/merb_doorman/
72
+ post_install_message:
73
+ rdoc_options: []
74
+
75
+ require_paths:
76
+ - lib
77
+ required_ruby_version: !ruby/object:Gem::Requirement
78
+ requirements:
79
+ - - ">="
80
+ - !ruby/object:Gem::Version
81
+ version: "0"
82
+ version:
83
+ required_rubygems_version: !ruby/object:Gem::Requirement
84
+ requirements:
85
+ - - ">="
86
+ - !ruby/object:Gem::Version
87
+ version: "0"
88
+ version:
89
+ requirements: []
90
+
91
+ rubyforge_project: merb
92
+ rubygems_version: 1.2.0
93
+ signing_key:
94
+ specification_version: 2
95
+ summary: Merb plugin that provides an allow/deny DSL for controlling access
96
+ test_files: []
97
+