The idea is to have allow/deny authorization directives
that are dynamic: their evaluation is deferred until
we perform the authorization checking in allowed?.
This is done to allow replacing backreferences in allow/deny
directives by parameters of the match that selected this right.
For instance, it is possible to:
allow $1.$2
And using Right::interpolate() with the result of a regex match
using 2 captures, will evaluate $1.$2 to those captures.
For instance, if we captured [host, reductivelabs.com], then the
allow directive is replaced by:
allow host.reductivelabs.com
It is then safe to call allowed?, after which we can reset the
interpolation.
This interpolation is thread-safe.

Signed-off-by: Brice Figureau <[email protected]>

authconfig regex support
---
 lib/puppet/network/authstore.rb |   41 +++++++++++++++++++++++++++++++-
 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 7341f8a..6f7a7df 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 ad4a4f1..587f396 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.
-- 
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
-~----------~----~----~----~------~----~------~--~---

Reply via email to