diff options
author | Brice Figureau <brice-puppet@daysofwonder.com> | 2009-03-30 20:24:53 +0200 |
---|---|---|
committer | Brice Figureau <brice-puppet@daysofwonder.com> | 2009-04-23 20:52:03 +0200 |
commit | aac996ed17e0ec72c5098b1225eb159aae4901fc (patch) | |
tree | 7cd8ae0baaad9a486581d6ec67f6d63a2fb5bfa6 | |
parent | 72e28aeccc36092e7edf9dc25e44acdb08fa5e79 (diff) | |
download | puppet-aac996ed17e0ec72c5098b1225eb159aae4901fc.tar.gz puppet-aac996ed17e0ec72c5098b1225eb159aae4901fc.tar.xz puppet-aac996ed17e0ec72c5098b1225eb159aae4901fc.zip |
Add environment support in the REST authorization layer
With the help of the new auth.conf directive 'environment',
any ACL can now be restricted to a specific environment.
Omission of the directive means that the ACL will apply
to all the defined environment.
Signed-off-by: Brice Figureau <brice-puppet@daysofwonder.com>
-rw-r--r-- | conf/auth.conf | 2 | ||||
-rw-r--r-- | lib/puppet/network/authconfig.rb | 9 | ||||
-rw-r--r-- | lib/puppet/network/rest_authconfig.rb | 2 | ||||
-rwxr-xr-x | lib/puppet/network/rights.rb | 28 | ||||
-rwxr-xr-x | spec/unit/network/authconfig.rb | 23 | ||||
-rwxr-xr-x | spec/unit/network/rest_authconfig.rb | 5 | ||||
-rwxr-xr-x | spec/unit/network/rights.rb | 31 |
7 files changed, 78 insertions, 22 deletions
diff --git a/conf/auth.conf b/conf/auth.conf index 1c037901d..784acc980 100644 --- a/conf/auth.conf +++ b/conf/auth.conf @@ -9,6 +9,7 @@ # Path syntax (the one used below): # --------------------------------- # path /path/to/resource +# [environment envlist] # [method methodlist] # allow [host|ip|*] # deny [host|ip] @@ -21,6 +22,7 @@ # This one is differenciated from the path one by a '~' # # path ~ regex +# [environment envlist] # [method methodlist] # allow [host|ip|*] # deny [host|ip] diff --git a/lib/puppet/network/authconfig.rb b/lib/puppet/network/authconfig.rb index f78cdc621..3e0807ad1 100644 --- a/lib/puppet/network/authconfig.rb +++ b/lib/puppet/network/authconfig.rb @@ -112,7 +112,7 @@ module Puppet end name.chomp! right = newrights.newright(name, count) - when /^\s*(allow|deny|method)\s+(.+)$/ + when /^\s*(allow|deny|method|environment)\s+(.+)$/ parse_right_directive(right, $1, $2, count) else raise ConfigurationError, "Invalid line %s: %s" % [count, line] @@ -150,7 +150,12 @@ module Puppet 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) + modify_right(right, :restrict_method, value, "allowing 'method' %s", count) + when "environment" + unless right.acl_type == :regex + raise ConfigurationError, "'environment' directive not allowed in namespace ACL at line %s of %s" % [count, @config] + end + modify_right(right, :restrict_environment, value, "adding environment %s", count) else raise ConfigurationError, "Invalid argument '%s' at line %s" % [var, count] diff --git a/lib/puppet/network/rest_authconfig.rb b/lib/puppet/network/rest_authconfig.rb index 58708e120..e3fd51753 100644 --- a/lib/puppet/network/rest_authconfig.rb +++ b/lib/puppet/network/rest_authconfig.rb @@ -25,7 +25,7 @@ module Puppet # check wether this request is allowed in our ACL def allowed?(request) read() - return @rights.allowed?(build_uri(request), request.node, request.ip, request.method) + return @rights.allowed?(build_uri(request), request.node, request.ip, request.method, request.environment) end def initialize(file = nil, parsenow = true) diff --git a/lib/puppet/network/rights.rb b/lib/puppet/network/rights.rb index 6b2082cdb..7f4bed7f6 100755 --- a/lib/puppet/network/rights.rb +++ b/lib/puppet/network/rights.rb @@ -8,7 +8,7 @@ class Puppet::Network::Rights # We basically just proxy directly to our rights. Each Right stores # its own auth abilities. - [:allow, :deny].each do |method| + [:allow, :deny, :restrict_method, :restrict_environment].each do |method| define_method(method) do |name, *args| if obj = self[name] obj.send(method, *args) @@ -18,16 +18,6 @@ class Puppet::Network::Rights 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| @@ -99,7 +89,7 @@ class Puppet::Network::Rights # A right. class Right < Puppet::Network::AuthStore attr_accessor :name, :key, :acl_type, :line - attr_accessor :methods, :length + attr_accessor :methods, :environment ALL = [:save, :destroy, :find, :search] @@ -107,8 +97,10 @@ class Puppet::Network::Rights def initialize(name, line) @methods = [] + @environment = [] @name = name @line = line || 0 + case name when Symbol @acl_type = :name @@ -148,8 +140,9 @@ class Puppet::Network::Rights # 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) + def allowed?(name, ip, method = nil, environment = nil, match = nil) return :dunno if acl_type == :regex and not @methods.include?(method) + return :dunno if acl_type == :regex and @environment.size > 0 and not @environment.include?(environment) if acl_type == :regex and match # make sure any capture are replaced interpolate(match) @@ -183,6 +176,15 @@ class Puppet::Network::Rights @methods << m end + def restrict_environment(env) + env = Puppet::Node::Environment.new(env) + if @environment.include?(env) + raise ArgumentError, "'%s' is already in the '%s' ACL" % [env, name] + end + + @environment << env + end + def match?(key) # if we are a namespace compare directly return self.key == namespace_to_key(key) if acl_type == :name diff --git a/spec/unit/network/authconfig.rb b/spec/unit/network/authconfig.rb index d891fe45a..186d30ce3 100755 --- a/spec/unit/network/authconfig.rb +++ b/spec/unit/network/authconfig.rb @@ -230,6 +230,29 @@ describe Puppet::Network::AuthConfig do lambda { @authconfig.read }.should raise_error end + it "should inform the current ACL if we get the 'environment' directive" do + acl = stub 'acl', :info + acl.stubs(:acl_type).returns(:regex) + + @fd.stubs(:each).multiple_yields('path /certificates', 'environment production,development') + @rights.stubs(:newright).with("/certificates", 1).returns(acl) + + acl.expects(:restrict_environment).with('production') + acl.expects(:restrict_environment).with('development') + + @authconfig.read + end + + it "should raise an error if the 'environment' 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]', 'environment env') + @rights.stubs(:newright).with("puppetca", 1).returns(acl) + + lambda { @authconfig.read }.should raise_error + end + end end diff --git a/spec/unit/network/rest_authconfig.rb b/spec/unit/network/rest_authconfig.rb index 1f98f4082..ea5a82cce 100755 --- a/spec/unit/network/rest_authconfig.rb +++ b/spec/unit/network/rest_authconfig.rb @@ -16,7 +16,8 @@ describe Puppet::Network::RestAuthConfig do @acl = stub_everything 'rights' @authconfig.rights = @acl - @request = stub 'request', :indirection_name => "path", :key => "to/resource", :ip => "127.0.0.1", :node => "me", :method => :save + @request = stub 'request', :indirection_name => "path", :key => "to/resource", :ip => "127.0.0.1", + :node => "me", :method => :save, :environment => :env end it "should use the puppet default rest authorization file" do @@ -32,7 +33,7 @@ describe Puppet::Network::RestAuthConfig do end it "should ask for authorization to the ACL subsystem" do - @acl.expects(:allowed?).with("/path/to/resource", "me", "127.0.0.1", :save) + @acl.expects(:allowed?).with("/path/to/resource", "me", "127.0.0.1", :save, :env) @authconfig.allowed?(@request) end diff --git a/spec/unit/network/rights.rb b/spec/unit/network/rights.rb index 6e918124f..97094f8e5 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, :deny].each do |m| + [:allow, :deny, :restrict_method, :restrict_environment].each do |m| it "should have a #{m} method" do @right.should respond_to(m) end @@ -391,23 +391,46 @@ describe Puppet::Network::Rights do lambda { @acl.restrict_method(:save) }.should raise_error end + it "should allow setting an environment filters" do + Puppet::Node::Environment.stubs(:new).with(:environment).returns(:env) + + @acl.restrict_environment(:environment) + + @acl.environment.should == [:env] + end + describe "when checking right authorization" do - it "should return :dunno if this right doesn't apply" do + it "should return :dunno if this right is not restricted to the given method" do @acl.restrict_method(:destroy) @acl.allowed?("me","127.0.0.1", :save).should == :dunno end + it "should return allow/deny if this right is restricted to the given method" do + @acl.restrict_method(:save) + @acl.allow("127.0.0.1") + + @acl.allowed?("me","127.0.0.1", :save).should be_true + end + + it "should return :dunno if this right is not restricted to the given environment" do + Puppet::Node::Environment.stubs(:new).returns(:production) + + @acl.restrict_environment(:production) + + @acl.allowed?("me","127.0.0.1", :save, :development).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) + @acl.allowed?("me","127.0.0.1", :save, nil, :match) end it "should reset interpolation after the match" do @acl.expects(:reset_interpolation) - @acl.allowed?("me","127.0.0.1", :save, :match) + @acl.allowed?("me","127.0.0.1", :save, nil, :match) end # mocha doesn't allow testing super... |