Introduces a new auth.conf directive (auth or authenticated) which takes an argument (on,yes/off,no). This can be used to restrict an ACL to only some state of authentication of a REST request. If no auth directive is given, both type of requests are used.
Signed-off-by: Brice Figureau <[email protected]> --- lib/puppet/network/authconfig.rb | 7 +++++- lib/puppet/network/rights.rb | 26 ++++++++++++++++++++---- spec/unit/network/authconfig.rb | 34 +++++++++++++++++++++++++++++++++ spec/unit/network/rights.rb | 39 +++++++++++++++++++++++++++++++++++-- 4 files changed, 97 insertions(+), 9 deletions(-) diff --git a/lib/puppet/network/authconfig.rb b/lib/puppet/network/authconfig.rb index 3e40c9d..41f8f1c 100644 --- a/lib/puppet/network/authconfig.rb +++ b/lib/puppet/network/authconfig.rb @@ -111,7 +111,7 @@ module Puppet end name.chomp! right = newrights.newright(name, count, @file) - when /^\s*(allow|deny|method|environment)\s+(.+)$/ + when /^\s*(allow|deny|method|environment|auth(?:enticated)?)\s+(.+)$/ parse_right_directive(right, $1, $2, count) else raise ConfigurationError, "Invalid line %s: %s" % [count, line] @@ -155,6 +155,11 @@ module Puppet 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) + when /auth(?:enticated)?/ + unless right.acl_type == :regex + raise ConfigurationError, "'authenticated' directive not allowed in namespace ACL at line %s of %s" % [count, @config] + end + modify_right(right, :restrict_authenticated, value, "adding authentication %s", count) else raise ConfigurationError, "Invalid argument '%s' at line %s" % [var, count] diff --git a/lib/puppet/network/rights.rb b/lib/puppet/network/rights.rb index 75005d8..fc2d685 100755 --- a/lib/puppet/network/rights.rb +++ b/lib/puppet/network/rights.rb @@ -14,7 +14,7 @@ class Rights # We basically just proxy directly to our rights. Each Right stores # its own auth abilities. - [:allow, :deny, :restrict_method, :restrict_environment].each do |method| + [:allow, :deny, :restrict_method, :restrict_environment, :restrict_authenticated].each do |method| define_method(method) do |name, *args| if obj = self[name] obj.send(method, *args) @@ -27,7 +27,7 @@ class Rights # Check that name is allowed or not def allowed?(name, *args) begin - fail_on_deny(name, *args) + fail_on_deny(name, :node => args[0], :ip => args[1]) rescue AuthorizationError return false rescue ArgumentError @@ -59,10 +59,12 @@ class Rights # if we end here, then that means we either didn't match # or failed, in any case will throw an error to the outside world - if name =~ /^\// + if name =~ /^\// or right # we're a patch ACL, let's fail msg = "%s access to %s [%s]" % [ (args[:node].nil? ? args[:ip] : "#{args[:node]}(#{args[:ip]})"), name, args[:method] ] + msg += " authenticated " if args[:authenticated] + error = AuthorizationError.new("Forbidden request: " + msg) if right error.file = right.file @@ -121,7 +123,7 @@ class Rights # A right. class Right < Puppet::Network::AuthStore attr_accessor :name, :key, :acl_type, :line, :file - attr_accessor :methods, :environment + attr_accessor :methods, :environment, :authentication ALL = [:save, :destroy, :find, :search] @@ -130,6 +132,7 @@ class Rights def initialize(name, line, file) @methods = [] @environment = [] + @authentication = nil @name = name @line = line || 0 @file = file @@ -173,9 +176,10 @@ class 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, args) + def allowed?(name, ip, args = {}) return :dunno if acl_type == :regex and not @methods.include?(args[:method]) return :dunno if acl_type == :regex and @environment.size > 0 and not @environment.include?(args[:environment]) + return :dunno if acl_type == :regex and not @authentication.nil? and args[:authenticated] != @authentication begin # make sure any capture are replaced if needed @@ -216,6 +220,18 @@ class Rights @environment << env end + def restrict_authenticated(authentication) + case authentication + when "yes", "on", "true", true + authentication = true + when "no", "off", "false", false + authentication = false + else + raise ArgumentError, "'%s' incorrect authenticated value: %s" % [name, authentication] + end + @authentication = authentication + 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 21af89b..f666523 100644 --- a/spec/unit/network/authconfig.rb +++ b/spec/unit/network/authconfig.rb @@ -253,6 +253,40 @@ describe Puppet::Network::AuthConfig do lambda { @authconfig.read }.should raise_error end + it "should inform the current ACL if we get the 'auth' directive" do + acl = stub 'acl', :info + acl.stubs(:acl_type).returns(:regex) + + @fd.stubs(:each).multiple_yields('path /certificates', 'auth yes') + @rights.stubs(:newright).with("/certificates", 1, 'dummy').returns(acl) + + acl.expects(:restrict_authenticated).with('yes') + + @authconfig.read + end + + it "should also allow the longest 'authenticated' directive" do + acl = stub 'acl', :info + acl.stubs(:acl_type).returns(:regex) + + @fd.stubs(:each).multiple_yields('path /certificates', 'authenticated yes') + @rights.stubs(:newright).with("/certificates", 1, 'dummy').returns(acl) + + acl.expects(:restrict_authenticated).with('yes') + + @authconfig.read + end + + it "should raise an error if the 'auth' 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]', 'auth yes') + @rights.stubs(:newright).with("puppetca", 1, 'dummy').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 be1db72..f98249a 100644 --- 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, :restrict_method, :restrict_environment].each do |m| + [:allow, :deny, :restrict_method, :restrict_environment, :restrict_authenticated].each do |m| it "should have a #{m} method" do @right.should respond_to(m) end @@ -150,9 +150,9 @@ describe Puppet::Network::Rights do end it "should delegate to fail_on_deny" do - @right.expects(:fail_on_deny).with("namespace", :args) + @right.expects(:fail_on_deny).with("namespace", :node => "host.domain.com", :ip => "127.0.0.1") - @right.allowed?("namespace", :args) + @right.allowed?("namespace", "host.domain.com", "127.0.0.1") end it "should return true if fail_on_deny doesn't fail" do @@ -397,6 +397,10 @@ describe Puppet::Network::Rights do @acl.methods.should == Puppet::Network::Rights::Right::ALL end + it "should allow all request authentication state by default" do + @acl.authentication.should be_nil + end + it "should allow modification of the methods filters" do @acl.restrict_method(:save) @@ -424,6 +428,22 @@ describe Puppet::Network::Rights do @acl.environment.should == [:env] end + ["on", "yes", "true", true].each do |auth| + it "should allow filtering on authenticated requests with '#{auth}'" do + @acl.restrict_authenticated(auth) + + @acl.authentication.should be_true + end + end + + ["off", "no", "false", false].each do |auth| + it "should allow filtering on unauthenticated requests with '#{auth}'" do + @acl.restrict_authenticated(auth) + + @acl.authentication.should be_false + end + end + describe "when checking right authorization" do it "should return :dunno if this right is not restricted to the given method" do @acl.restrict_method(:destroy) @@ -446,6 +466,19 @@ describe Puppet::Network::Rights do @acl.allowed?("me","127.0.0.1", { :method => :save, :environment => :development }).should == :dunno end + it "should return :dunno if this right is not restricted to the given request authentication state" do + @acl.restrict_authenticated(true) + + @acl.allowed?("me","127.0.0.1", { :method => :save, :authenticated => false }).should == :dunno + end + + it "should return allow/deny if this right is restricted to the given request authentication state" do + @acl.restrict_authenticated(false) + @acl.allow("127.0.0.1") + + @acl.allowed?("me","127.0.0.1", { :authenticated => false }).should be_true + end + it "should interpolate allow/deny patterns with the given match" do @acl.expects(:interpolate).with(:match) -- 1.6.0.2 --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Puppet Developers" group. To post to this group, send email to [email protected] To unsubscribe from this group, send email to [email protected] For more options, visit this group at http://groups.google.com/group/puppet-dev?hl=en -~----------~----~----~----~------~----~------~--~---
