summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lib/puppet/network/authconfig.rb82
-rwxr-xr-xlib/puppet/network/rights.rb202
-rwxr-xr-xspec/unit/network/authconfig.rb82
-rwxr-xr-xspec/unit/network/rights.rb392
4 files changed, 673 insertions, 85 deletions
diff --git a/lib/puppet/network/authconfig.rb b/lib/puppet/network/authconfig.rb
index dc67723c4..f78cdc621 100644
--- a/lib/puppet/network/authconfig.rb
+++ b/lib/puppet/network/authconfig.rb
@@ -44,7 +44,7 @@ module Puppet
end
def initialize(file = nil, parsenow = true)
- @file ||= Puppet[:authconfig]
+ @file = file || Puppet[:authconfig]
unless @file
raise Puppet::DevError, "No authconfig file defined"
@@ -99,44 +99,21 @@ module Puppet
count = 1
f.each { |line|
case line
- when /^\s*#/; next # skip comments
- when /^\s*$/; next # skip blank lines
- when /\[([\w.]+)\]/ # "namespace" or "namespace.method"
- name = $1
- if newrights.include?(name)
- raise FileServerError, "%s is already set at %s" %
- [newrights[name], name]
- end
- newrights.newright(name)
- right = newrights[name]
- when /^\s*(\w+)\s+(.+)$/
- var = $1
- value = $2
- case var
- when "allow"
- value.split(/\s*,\s*/).each { |val|
- begin
- right.info "allowing %s access" % val
- right.allow(val)
- rescue AuthStoreError => detail
- raise ConfigurationError, "%s at line %s of %s" %
- [detail.to_s, count, @config]
- end
- }
- when "deny"
- value.split(/\s*,\s*/).each { |val|
- begin
- right.info "denying %s access" % val
- right.deny(val)
- rescue AuthStoreError => detail
- raise ConfigurationError, "%s at line %s of %s" %
- [detail.to_s, count, @config]
- end
- }
- else
- raise ConfigurationError,
- "Invalid argument '%s' at line %s" % [var, count]
+ when /^\s*#/ # skip comments
+ count += 1
+ next
+ when /^\s*$/ # skip blank lines
+ count += 1
+ next
+ when /^(?:(\[[\w.]+\])|(path)\s+((?:~\s+)?[^ ]+))\s*$/ # "namespace" or "namespace.method" or "path /path" or "path ~ regex"
+ name = $1
+ if $2 == "path"
+ name = $3
end
+ name.chomp!
+ right = newrights.newright(name, count)
+ when /^\s*(allow|deny|method)\s+(.+)$/
+ parse_right_directive(right, $1, $2, count)
else
raise ConfigurationError, "Invalid line %s: %s" % [count, line]
end
@@ -162,6 +139,35 @@ module Puppet
}
@rights = newrights
end
+
+ def parse_right_directive(right, var, value, count)
+ case var
+ when "allow"
+ modify_right(right, :allow, value, "allowing %s access", count)
+ when "deny"
+ modify_right(right, :deny, value, "denying %s access", count)
+ when "method"
+ unless right.acl_type == :regex
+ raise ConfigurationError, "'method' directive not allowed in namespace ACL at line %s of %s" % [count, @config]
+ end
+ modify_right(right, :restrict_method, value, "allowing method %s access", count)
+ else
+ raise ConfigurationError,
+ "Invalid argument '%s' at line %s" % [var, count]
+ end
+ end
+
+ def modify_right(right, method, value, msg, count)
+ value.split(/\s*,\s*/).each do |val|
+ begin
+ right.info msg % val
+ right.send(method, val)
+ rescue AuthStoreError => detail
+ raise ConfigurationError, "%s at line %s of %s" % [detail.to_s, count, @file]
+ end
+ end
+ end
+
end
end
diff --git a/lib/puppet/network/rights.rb b/lib/puppet/network/rights.rb
index a4133f22c..6b2082cdb 100755
--- a/lib/puppet/network/rights.rb
+++ b/lib/puppet/network/rights.rb
@@ -1,15 +1,16 @@
-require 'ipaddr'
require 'puppet/network/authstore'
# Define a set of rights and who has access to them.
-class Puppet::Network::Rights < Hash
+# There are two types of rights:
+# * named rights (ie a common string)
+# * path based rights (which are matched on a longest prefix basis)
+class Puppet::Network::Rights
+
# We basically just proxy directly to our rights. Each Right stores
# its own auth abilities.
- [:allow, :allowed?, :deny].each do |method|
+ [:allow, :deny].each do |method|
define_method(method) do |name, *args|
- name = name.intern if name.is_a? String
-
- if obj = right(name)
+ if obj = self[name]
obj.send(method, *args)
else
raise ArgumentError, "Unknown right '%s'" % name
@@ -17,45 +18,115 @@ class Puppet::Network::Rights < Hash
end
end
+ # this method is used to add a new allowed +method+ to +name+
+ # method applies only to path rights
+ def restrict_method(name, *args)
+ if right = self[name]
+ right.restrict_method(*args)
+ else
+ raise ArgumentError, "'%s' right is not allowing method specification" % name
+ end
+ end
+
+ def allowed?(name, *args)
+ res = :nomatch
+ right = @rights.find do |acl|
+ # an acl can return :dunno, which means "I'm not qualified to answer your question,
+ # please ask someone else". This is used when for instance an acl matches, but not for the
+ # current rest method, where we might think some other acl might be more specific.
+ if match = acl.match?(name)
+ args << match
+ if (res = acl.allowed?(*args)) != :dunno
+ return res
+ end
+ end
+ false
+ end
+
+ # if allowed or denied, tell it to the world
+ return res unless res == :nomatch
+
+ # there were no rights allowing/denying name
+ # if name is not a path, let's throw
+ raise ArgumentError, "Unknown namespace right '%s'" % name unless name =~ /^\//
+
+ # but if this was a path, we implement a deny all policy by default
+ # on unknown rights.
+ return false
+ end
+
+ def initialize()
+ @rights = []
+ end
+
def [](name)
- name = name.intern if name.is_a? String
- super(name)
+ @rights.find { |acl| acl == name }
+ end
+
+ def include?(name)
+ @rights.include?(name)
+ end
+
+ def each
+ @rights.each { |r| yield r.name,r }
end
# Define a new right to which access can be provided.
- def newright(name)
- name = name.intern if name.is_a? String
- shortname = Right.shortname(name)
- if self.include? name
- raise ArgumentError, "Right '%s' is already defined" % name
- else
- self[name] = Right.new(name, shortname)
- end
+ def newright(name, line=nil)
+ add_right( Right.new(name, line) )
end
private
+ def add_right(right)
+ if right.acl_type == :name and include?(right.key)
+ raise ArgumentError, "Right '%s' already exists"
+ end
+ @rights << right
+ sort_rights
+ right
+ end
+
+ def sort_rights
+ @rights.sort!
+ end
+
# Retrieve a right by name.
def right(name)
- name = name.intern if name.is_a? String
self[name]
end
# A right.
class Right < Puppet::Network::AuthStore
- attr_accessor :name, :shortname
+ attr_accessor :name, :key, :acl_type, :line
+ attr_accessor :methods, :length
- Puppet::Util.logmethods(self, true)
+ ALL = [:save, :destroy, :find, :search]
- def self.shortname(name)
- name.to_s[0..0]
- end
+ Puppet::Util.logmethods(self, true)
- def initialize(name, shortname = nil)
+ def initialize(name, line)
+ @methods = []
@name = name
- @shortname = shortname
- unless @shortname
- @shortname = Right.shortname(name)
+ @line = line || 0
+ case name
+ when Symbol
+ @acl_type = :name
+ @key = name
+ when /^\[(.+)\]$/
+ @acl_type = :name
+ @key = $1.intern if name.is_a?(String)
+ when /^\//
+ @acl_type = :regex
+ @key = Regexp.new("^" + Regexp.escape(name))
+ @methods = ALL
+ when /^~/ # this is a regex
+ @acl_type = :regex
+ @name = name.gsub(/^~\s+/,'')
+ @key = Regexp.new(@name)
+ @methods = ALL
+ else
+ raise ArgumentError, "Unknown right type '%s'" % name
end
super()
end
@@ -68,6 +139,85 @@ class Puppet::Network::Rights < Hash
def valid?
true
end
+
+ def regex?
+ acl_type == :regex
+ end
+
+ # does this right is allowed for this triplet?
+ # if this right is too restrictive (ie we don't match this access method)
+ # then return :dunno so that upper layers have a chance to try another right
+ # tailored to the given method
+ def allowed?(name, ip, method = nil, match = nil)
+ return :dunno if acl_type == :regex and not @methods.include?(method)
+
+ if acl_type == :regex and match # make sure any capture are replaced
+ interpolate(match)
+ end
+
+ res = super(name,ip)
+
+ if acl_type == :regex
+ reset_interpolation
+ end
+ res
+ end
+
+ # restrict this right to some method only
+ def restrict_method(m)
+ m = m.intern if m.is_a?(String)
+
+ unless ALL.include?(m)
+ raise ArgumentError, "'%s' is not an allowed value for method directive" % m
+ end
+
+ # if we were allowing all methods, then starts from scratch
+ if @methods === ALL
+ @methods = []
+ end
+
+ if @methods.include?(m)
+ raise ArgumentError, "'%s' is already in the '%s' ACL" % [m, name]
+ end
+
+ @methods << m
+ end
+
+ def match?(key)
+ # if we are a namespace compare directly
+ return self.key == namespace_to_key(key) if acl_type == :name
+
+ # otherwise match with the regex
+ return self.key.match(key)
+ end
+
+ def namespace_to_key(key)
+ key = key.intern if key.is_a?(String)
+ key
+ end
+
+ # this is where all the magic happens.
+ # we're sorting the rights array with this scheme:
+ # * namespace rights are all in front
+ # * regex path rights are then all queued in file order
+ def <=>(rhs)
+ # move namespace rights at front
+ if self.acl_type != rhs.acl_type
+ return self.acl_type == :name ? -1 : 1
+ end
+
+ # sort by creation order (ie first match appearing in the file will win)
+ # that is don't sort, in which case the sort algorithm will order in the
+ # natural array order (ie the creation order)
+ return 0
+ end
+
+ def ==(name)
+ return self.key == namespace_to_key(name) if acl_type == :name
+ return self.name == name
+ end
+
end
+
end
diff --git a/spec/unit/network/authconfig.rb b/spec/unit/network/authconfig.rb
index 9d5f6154d..d891fe45a 100755
--- a/spec/unit/network/authconfig.rb
+++ b/spec/unit/network/authconfig.rb
@@ -28,7 +28,7 @@ describe Puppet::Network::AuthConfig do
Puppet::Network::AuthConfig.new
end
- it "should raise an error if no file is defined in fine" do
+ it "should raise an error if no file is defined finally" do
Puppet.stubs(:[]).with(:authconfig).returns(nil)
lambda { Puppet::Network::AuthConfig.new }.should raise_error(Puppet::DevError)
@@ -111,6 +111,14 @@ describe Puppet::Network::AuthConfig do
@authconfig.read
end
+ it "should increment line number even on commented lines" do
+ @fd.stubs(:each).multiple_yields(' # comment','[puppetca]')
+
+ @rights.expects(:newright).with('[puppetca]', 2)
+
+ @authconfig.read
+ end
+
it "should skip blank lines" do
@fd.stubs(:each).yields(' ')
@@ -119,7 +127,15 @@ describe Puppet::Network::AuthConfig do
@authconfig.read
end
- it "should throw an error if read rights already exist" do
+ it "should increment line number even on blank lines" do
+ @fd.stubs(:each).multiple_yields(' ','[puppetca]')
+
+ @rights.expects(:newright).with('[puppetca]', 2)
+
+ @authconfig.read
+ end
+
+ it "should throw an error if the current namespace right already exist" do
@fd.stubs(:each).yields('[puppetca]')
@rights.stubs(:include?).with("puppetca").returns(true)
@@ -127,10 +143,19 @@ describe Puppet::Network::AuthConfig do
lambda { @authconfig.read }.should raise_error
end
+ it "should not throw an error if the current path right already exist" do
+ @fd.stubs(:each).yields('path /hello')
+
+ @rights.stubs(:newright).with("/hello",1)
+ @rights.stubs(:include?).with("/hello").returns(true)
+
+ lambda { @authconfig.read }.should_not raise_error
+ end
+
it "should create a new right for found namespaces" do
@fd.stubs(:each).yields('[puppetca]')
- @rights.expects(:newright).with("puppetca")
+ @rights.expects(:newright).with("[puppetca]", 1)
@authconfig.read
end
@@ -138,8 +163,24 @@ describe Puppet::Network::AuthConfig do
it "should create a new right for each found namespace line" do
@fd.stubs(:each).multiple_yields('[puppetca]', '[fileserver]')
- @rights.expects(:newright).with("puppetca")
- @rights.expects(:newright).with("fileserver")
+ @rights.expects(:newright).with("[puppetca]", 1)
+ @rights.expects(:newright).with("[fileserver]", 2)
+
+ @authconfig.read
+ end
+
+ it "should create a new right for each found path line" do
+ @fd.stubs(:each).multiple_yields('path /certificates')
+
+ @rights.expects(:newright).with("/certificates", 1)
+
+ @authconfig.read
+ end
+
+ it "should create a new right for each found regex line" do
+ @fd.stubs(:each).multiple_yields('path ~ .rb$')
+
+ @rights.expects(:newright).with("~ .rb$", 1)
@authconfig.read
end
@@ -148,26 +189,47 @@ describe Puppet::Network::AuthConfig do
acl = stub 'acl', :info
@fd.stubs(:each).multiple_yields('[puppetca]', 'allow 127.0.0.1')
- @rights.stubs(:newright).with("puppetca")
- @rights.stubs(:[]).returns(acl)
+ @rights.stubs(:newright).with("[puppetca]", 1).returns(acl)
acl.expects(:allow).with('127.0.0.1')
@authconfig.read
end
- it "should create a deny ACE on each subsequent allow" do
+ it "should create a deny ACE on each subsequent deny" do
acl = stub 'acl', :info
@fd.stubs(:each).multiple_yields('[puppetca]', 'deny 127.0.0.1')
- @rights.stubs(:newright).with("puppetca")
- @rights.stubs(:[]).returns(acl)
+ @rights.stubs(:newright).with("[puppetca]", 1).returns(acl)
acl.expects(:deny).with('127.0.0.1')
@authconfig.read
end
+ it "should inform the current ACL if we get the 'method' directive" do
+ acl = stub 'acl', :info
+ acl.stubs(:acl_type).returns(:regex)
+
+ @fd.stubs(:each).multiple_yields('path /certificates', 'method search,find')
+ @rights.stubs(:newright).with("/certificates", 1).returns(acl)
+
+ acl.expects(:restrict_method).with('search')
+ acl.expects(:restrict_method).with('find')
+
+ @authconfig.read
+ end
+
+ it "should raise an error if the 'method' directive is used in a right different than a path/regex one" do
+ acl = stub 'acl', :info
+ acl.stubs(:acl_type).returns(:regex)
+
+ @fd.stubs(:each).multiple_yields('[puppetca]', 'method search,find')
+ @rights.stubs(:newright).with("puppetca", 1).returns(acl)
+
+ lambda { @authconfig.read }.should raise_error
+ end
+
end
end
diff --git a/spec/unit/network/rights.rb b/spec/unit/network/rights.rb
index 5fe8e51f4..6e918124f 100755
--- a/spec/unit/network/rights.rb
+++ b/spec/unit/network/rights.rb
@@ -9,7 +9,7 @@ describe Puppet::Network::Rights do
@right = Puppet::Network::Rights.new
end
- [:allow, :allowed?, :deny].each do |m|
+ [:allow, :deny].each do |m|
it "should have a #{m} method" do
@right.should respond_to(m)
end
@@ -17,7 +17,7 @@ describe Puppet::Network::Rights do
describe "when using #{m}" do
it "should delegate to the correct acl" do
acl = stub 'acl'
- @right.stubs(:right).returns(acl)
+ @right.stubs(:[]).returns(acl)
acl.expects(m).with("me")
@@ -26,29 +26,399 @@ describe Puppet::Network::Rights do
end
end
- describe "when creating new ACLs" do
+ it "should throw an error if type can't be determined" do
+ lambda { @right.newright("name") }.should raise_error
+ end
+
+ describe "when creating new namespace ACLs" do
+
it "should throw an error if the ACL already exists" do
- @right.newright("name")
+ @right.newright("[name]")
- lambda { @right.newright("name")}.should raise_error
+ lambda { @right.newright("[name]") }.should raise_error
end
it "should create a new ACL with the correct name" do
- @right.newright("name")
+ @right.newright("[name]")
- @right["name"].name.should == :name
+ @right["name"].key.should == :name
end
it "should create an ACL of type Puppet::Network::AuthStore" do
- @right.newright("name")
+ @right.newright("[name]")
@right["name"].should be_a_kind_of(Puppet::Network::AuthStore)
end
+ end
+
+ describe "when creating new path ACLs" do
+ it "should not throw an error if the ACL already exists" do
+ @right.newright("/name")
+
+ lambda { @right.newright("/name")}.should_not raise_error
+ end
+
+ it "should throw an error if the acl uri path is not absolute" do
+ lambda { @right.newright("name")}.should raise_error
+ end
+
+ it "should create a new ACL with the correct path" do
+ @right.newright("/name")
+
+ @right["/name"].should_not be_nil
+ end
+
+ it "should create an ACL of type Puppet::Network::AuthStore" do
+ @right.newright("/name")
+
+ @right["/name"].should be_a_kind_of(Puppet::Network::AuthStore)
+ end
+ end
+
+ describe "when creating new regex ACLs" do
+ it "should not throw an error if the ACL already exists" do
+ @right.newright("~ .rb$")
+
+ lambda { @right.newright("~ .rb$")}.should_not raise_error
+ end
+
+ it "should create a new ACL with the correct regex" do
+ @right.newright("~ .rb$")
+
+ @right.include?(".rb$").should_not be_nil
+ end
+
+ it "should be able to lookup the regex" do
+ @right.newright("~ .rb$")
+
+ @right[".rb$"].should_not be_nil
+ end
+
+ it "should create an ACL of type Puppet::Network::AuthStore" do
+ @right.newright("~ .rb$").should be_a_kind_of(Puppet::Network::AuthStore)
+ end
+ end
+
+ describe "when checking ACLs existence" do
+ it "should return false if there are no matching rights" do
+ @right.include?("name").should be_false
+ end
+
+ it "should return true if a namespace rights exist" do
+ @right.newright("[name]")
+
+ @right.include?("name").should be_true
+ end
+
+ it "should return false if no matching namespace rights exist" do
+ @right.newright("[name]")
+
+ @right.include?("notname").should be_false
+ end
+
+ it "should return true if a path right exists" do
+ @right.newright("/name")
+
+ @right.include?("/name").should be_true
+ end
+
+ it "should return false if no matching path rights exist" do
+ @right.newright("/name")
+
+ @right.include?("/differentname").should be_false
+ end
+
+ it "should return true if a regex right exists" do
+ @right.newright("~ .rb$")
+
+ @right.include?(".rb$").should be_true
+ end
+
+ it "should return false if no matching path rights exist" do
+ @right.newright("~ .rb$")
+
+ @right.include?(".pp$").should be_false
+ end
+ end
+
+ describe "when checking if right is allowed" do
+ before :each do
+ @right.stubs(:right).returns(nil)
+
+ @pathacl = stub 'pathacl', :acl_type => :path
+ Puppet::Network::Rights::Right.stubs(:new).returns(@pathacl)
+ end
+
+ it "should first check namespace rights" do
+ acl = stub 'acl', :acl_type => :name, :key => :namespace
+ Puppet::Network::Rights::Right.stubs(:new).returns(acl)
+
+ @right.newright("[namespace]")
+ acl.expects(:match?).returns(true)
+ acl.expects(:allowed?).with(:args, true).returns(true)
+
+ @right.allowed?("namespace", :args)
+ end
+
+ it "should then check for path rights if no namespace match" do
+ acl = stub 'acl', :acl_type => :name, :match? => false
+
+ acl.expects(:allowed?).with(:args).never
+ @right.newright("/path/to/there")
+
+ @pathacl.stubs(:match?).returns(true)
+ @pathacl.expects(:allowed?)
+
+ @right.allowed?("/path/to/there", :args)
+ end
+
+ it "should pass the match? return to allowed?" do
+ @right.newright("/path/to/there")
+
+ @pathacl.expects(:match?).returns(:match)
+ @pathacl.expects(:allowed?).with(:args, :match)
+
+ @right.allowed?("/path/to/there", :args)
+ end
+
+ describe "with namespace acls" do
+ it "should raise an error if this namespace right doesn't exist" do
+ lambda{ @right.allowed?("namespace") }.should raise_error
+ end
+ end
+
+ describe "with path acls" do
+ before :each do
+ @long_acl = stub 'longpathacl', :name => "/path/to/there", :acl_type => :regex
+ Puppet::Network::Rights::Right.stubs(:new).with("/path/to/there", 0).returns(@long_acl)
+
+ @short_acl = stub 'shortpathacl', :name => "/path/to", :acl_type => :regex
+ Puppet::Network::Rights::Right.stubs(:new).with("/path/to", 0).returns(@short_acl)
+
+ @long_acl.stubs(:"<=>").with(@short_acl).returns(0)
+ @short_acl.stubs(:"<=>").with(@long_acl).returns(0)
+ end
+
+ it "should select the first match" do
+ @right.newright("/path/to/there", 0)
+ @right.newright("/path/to", 0)
+
+ @long_acl.stubs(:match?).returns(true)
+ @short_acl.stubs(:match?).returns(true)
+
+ @long_acl.expects(:allowed?).returns(true)
+ @short_acl.expects(:allowed?).never
+
+ @right.allowed?("/path/to/there/and/there", :args)
+ end
+
+ it "should select the first match that doesn't return :dunno" do
+ @right.newright("/path/to/there", 0)
+ @right.newright("/path/to", 0)
+
+ @long_acl.stubs(:match?).returns(true)
+ @short_acl.stubs(:match?).returns(true)
+
+ @long_acl.expects(:allowed?).returns(:dunno)
+ @short_acl.expects(:allowed?)
+
+ @right.allowed?("/path/to/there/and/there", :args)
+ end
+
+ it "should not select an ACL that doesn't match" do
+ @right.newright("/path/to/there", 0)
+ @right.newright("/path/to", 0)
+
+ @long_acl.stubs(:match?).returns(false)
+ @short_acl.stubs(:match?).returns(true)
+
+ @long_acl.expects(:allowed?).never
+ @short_acl.expects(:allowed?)
+
+ @right.allowed?("/path/to/there/and/there", :args)
+ end
+
+ it "should return the result of the acl" do
+ @right.newright("/path/to/there", 0)
+
+ @long_acl.stubs(:match?).returns(true)
+ @long_acl.stubs(:allowed?).returns(:returned)
+
+ @right.allowed?("/path/to/there/and/there", :args).should == :returned
+ end
+
+ it "should not raise an error if this path acl doesn't exist" do
+ lambda{ @right.allowed?("/path", :args) }.should_not raise_error
+ end
+
+ it "should return false if no path match" do
+ @right.allowed?("/path", :args).should be_false
+ end
+ end
+
+ describe "with regex acls" do
+ before :each do
+ @regex_acl1 = stub 'regex_acl1', :name => "/files/(.*)/myfile", :acl_type => :regex
+ Puppet::Network::Rights::Right.stubs(:new).with("~ /files/(.*)/myfile", 0).returns(@regex_acl1)
- it "should create an ACL with a shortname" do
- @right.newright("name")
+ @regex_acl2 = stub 'regex_acl2', :name => "/files/(.*)/myfile/", :acl_type => :regex
+ Puppet::Network::Rights::Right.stubs(:new).with("~ /files/(.*)/myfile/", 0).returns(@regex_acl2)
+
+ @regex_acl1.stubs(:"<=>").with(@regex_acl2).returns(0)
+ @regex_acl2.stubs(:"<=>").with(@regex_acl1).returns(0)
+ end
+
+ it "should select the first match" do
+ @right.newright("~ /files/(.*)/myfile", 0)
+ @right.newright("~ /files/(.*)/myfile/", 0)
+
+ @regex_acl1.stubs(:match?).returns(true)
+ @regex_acl2.stubs(:match?).returns(true)
+
+ @regex_acl1.expects(:allowed?).returns(true)
+ @regex_acl2.expects(:allowed?).never
+
+ @right.allowed?("/files/repository/myfile/other", :args)
+ end
+
+ it "should select the first match that doesn't return :dunno" do
+ @right.newright("~ /files/(.*)/myfile", 0)
+ @right.newright("~ /files/(.*)/myfile/", 0)
+
+ @regex_acl1.stubs(:match?).returns(true)
+ @regex_acl2.stubs(:match?).returns(true)
+
+ @regex_acl1.expects(:allowed?).returns(:dunno)
+ @regex_acl2.expects(:allowed?)
+
+ @right.allowed?("/files/repository/myfile/other", :args)
+ end
+
+ it "should not select an ACL that doesn't match" do
+ @right.newright("~ /files/(.*)/myfile", 0)
+ @right.newright("~ /files/(.*)/myfile/", 0)
+
+ @regex_acl1.stubs(:match?).returns(false)
+ @regex_acl2.stubs(:match?).returns(true)
+
+ @regex_acl1.expects(:allowed?).never
+ @regex_acl2.expects(:allowed?)
+
+ @right.allowed?("/files/repository/myfile/other", :args)
+ end
+
+ it "should return the result of the acl" do
+ @right.newright("~ /files/(.*)/myfile", 0)
+
+ @regex_acl1.stubs(:match?).returns(true)
+ @regex_acl1.stubs(:allowed?).returns(:returned)
+
+ @right.allowed?("/files/repository/myfile/other", :args).should == :returned
+ end
+
+ it "should not raise an error if no regex acl match" do
+ lambda{ @right.allowed?("/path", :args) }.should_not raise_error
+ end
+
+ it "should return false if no regex match" do
+ @right.allowed?("/path", :args).should be_false
+ end
- @right["name"].shortname.should == "n"
end
end
+
+ describe Puppet::Network::Rights::Right do
+ before :each do
+ @acl = Puppet::Network::Rights::Right.new("/path",0)
+ end
+
+ describe "with path" do
+ it "should say it's a regex ACL" do
+ @acl.acl_type.should == :regex
+ end
+
+ it "should match up to its path length" do
+ @acl.match?("/path/that/works").should_not be_nil
+ end
+
+ it "should match up to its path length" do
+ @acl.match?("/paththatalsoworks").should_not be_nil
+ end
+
+ it "should return nil if no match" do
+ @acl.match?("/notpath").should be_nil
+ end
+ end
+
+ describe "with regex" do
+ before :each do
+ @acl = Puppet::Network::Rights::Right.new("~ .rb$",0)
+ end
+
+ it "should say it's a regex ACL" do
+ @acl.acl_type.should == :regex
+ end
+
+ it "should match as a regex" do
+ @acl.match?("this shoud work.rb").should_not be_nil
+ end
+
+ it "should return nil if no match" do
+ @acl.match?("do not match").should be_nil
+ end
+ end
+
+ it "should allow all rest methods by default" do
+ @acl.methods.should == Puppet::Network::Rights::Right::ALL
+ end
+
+ it "should allow modification of the methods filters" do
+ @acl.restrict_method(:save)
+
+ @acl.methods.should == [:save]
+ end
+
+ it "should stack methods filters" do
+ @acl.restrict_method(:save)
+ @acl.restrict_method(:destroy)
+
+ @acl.methods.should == [:save, :destroy]
+ end
+
+ it "should raise an error if the method is already filtered" do
+ @acl.restrict_method(:save)
+
+ lambda { @acl.restrict_method(:save) }.should raise_error
+ end
+
+ describe "when checking right authorization" do
+ it "should return :dunno if this right doesn't apply" do
+ @acl.restrict_method(:destroy)
+
+ @acl.allowed?("me","127.0.0.1", :save).should == :dunno
+ end
+
+ it "should interpolate allow/deny patterns with the given match" do
+ @acl.expects(:interpolate).with(:match)
+
+ @acl.allowed?("me","127.0.0.1", :save, :match)
+ end
+
+ it "should reset interpolation after the match" do
+ @acl.expects(:reset_interpolation)
+
+ @acl.allowed?("me","127.0.0.1", :save, :match)
+ end
+
+ # mocha doesn't allow testing super...
+ # it "should delegate to the AuthStore for the result" do
+ # @acl.method(:save)
+ #
+ # @acl.expects(:allowed?).with("me","127.0.0.1")
+ #
+ # @acl.allowed?("me","127.0.0.1", :save)
+ # end
+ end
+ end
+
end