diff options
-rwxr-xr-x | lib/puppet/network/authstore.rb | 41 | ||||
-rwxr-xr-x | test/network/authstore.rb | 49 |
2 files changed, 88 insertions, 2 deletions
diff --git a/lib/puppet/network/authstore.rb b/lib/puppet/network/authstore.rb index 7341f8a1e..6f7a7df25 100755 --- a/lib/puppet/network/authstore.rb +++ b/lib/puppet/network/authstore.rb @@ -45,7 +45,7 @@ module Puppet return true end - if decl = @declarations.find { |d| d.match?(name, ip) } + if decl = declarations.find { |d| d.match?(name, ip) } return decl.result end @@ -72,8 +72,29 @@ module Puppet "authstore" end + def interpolate(match) + declarations = @declarations.collect do |ace| + ace.interpolate(match) + end + declarations.sort! + Thread.current[:declarations] = declarations + end + + def reset_interpolation + Thread.current[:declarations] = nil + end + private + # returns our ACEs list, but if we have a modification of it + # in our current thread, let's return it + # this is used if we want to override the this purely immutable list + # by a modified version in a multithread safe way. + def declarations + return Thread.current[:declarations] if Thread.current[:declarations] + @declarations + end + # Store the results of a pattern into our hash. Basically just # converts the pattern and sticks it into the hash. def store(type, pattern) @@ -193,6 +214,21 @@ module Puppet @type = type end + # interpolate a pattern to replace any + # backreferences by the given match + # for instance if our pattern is $1.reductivelabs.com + # and we're called with a MatchData whose capture 1 is puppet + # we'll return a pattern of puppet.reductivelabs.com + def interpolate(match) + return self if @name == :ip + + clone = dup + clone.pattern = clone.pattern.reverse.collect do |p| + p.gsub(/\$(\d)/) { |m| match[$1.to_i] } + end.join(".") + clone + end + private # Returns nil if both values are true or both are false, returns @@ -277,6 +313,9 @@ module Puppet @pattern = munge_name(value) @pattern.pop # take off the '*' @length = @pattern.length + when /\$\d+/ # a backreference pattern ala $1.reductivelabs.com or 192.168.0.$1 or $1.$2 + @name = :dynamic + @pattern = munge_name(value) else # Else, use the IPAddr class to determine if we've got a # valid IP address. diff --git a/test/network/authstore.rb b/test/network/authstore.rb index ad4a4f1c2..587f39627 100755 --- a/test/network/authstore.rb +++ b/test/network/authstore.rb @@ -266,6 +266,51 @@ class TestAuthStore < Test::Unit::TestCase assert(@store.allowed?("host.madstop.com", "192.168.0.1"), "More specific allowal by ip failed") end + + def test_dynamic_backreferences + @store.allow("$1.madstop.com") + + assert_nothing_raised { @store.interpolate([nil, "host"]) } + assert(@store.allowed?("host.madstop.com", "192.168.0.1"), "interpolation failed") + assert_nothing_raised { @store.reset_interpolation } + end + + def test_dynamic_ip + @store.allow("192.168.0.$1") + + assert_nothing_raised { @store.interpolate([nil, "12"]) } + assert(@store.allowed?("host.madstop.com", "192.168.0.12"), "interpolation failed") + assert_nothing_raised { @store.reset_interpolation } + end + + def test_multiple_dynamic_backreferences + @store.allow("$1.$2") + + assert_nothing_raised { @store.interpolate([nil, "host", "madstop.com"]) } + assert(@store.allowed?("host.madstop.com", "192.168.0.1"), "interpolation failed") + assert_nothing_raised { @store.reset_interpolation } + end + + def test_multithreaded_allow_with_dynamic_backreferences + @store.allow("$1.madstop.com") + + threads = [] + 9.times { |a| + threads << Thread.new { + 9.times { |b| + Thread.pass + @store.interpolate([nil, "a#{b}", "madstop.com"]) + Thread.pass + assert( @store.allowed?("a#{b}.madstop.com", "192.168.0.1") ) + Thread.pass + @store.reset_interpolation + Thread.pass + } + } + } + threads.each { |th| th.join } + end + end class TestAuthStoreDeclaration < PuppetTest::TestCase @@ -292,7 +337,9 @@ class TestAuthStoreDeclaration < PuppetTest::TestCase "billy.Hostname.COM" => [:domain, %w{com hostname billy}, nil], "billy-jean.Hostname.COM" => [:domain, %w{com hostname billy-jean}, nil], "*.hostname.COM" => [:domain, %w{com hostname}, 2], - "*.hostname.COM" => [:domain, %w{com hostname}, 2] + "*.hostname.COM" => [:domain, %w{com hostname}, 2], + "$1.hostname.COM" => [:dynamic, %w{com hostname $1}, nil], + "192.168.$1.$2" => [:dynamic, %w{$2 $1 168 192}, nil] }.each do |input, output| # Create a new decl each time, so values aren't cached. |