From 22b82abcd27834e43426f2758fba5728c146be61 Mon Sep 17 00:00:00 2001 From: Brice Figureau Date: Sat, 11 Apr 2009 18:58:56 +0200 Subject: Add dynamic authorization to authstore 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 authconfig regex support --- lib/puppet/network/authstore.rb | 41 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 40 insertions(+), 1 deletion(-) (limited to 'lib') 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. -- cgit