diff options
author | Luke Kanies <luke@madstop.com> | 2005-08-28 00:28:04 +0000 |
---|---|---|
committer | Luke Kanies <luke@madstop.com> | 2005-08-28 00:28:04 +0000 |
commit | 28be88cc6e13c1af193fe01d56a1a446a18e01bb (patch) | |
tree | 719d57f106377a62707ccf9a9bc296ab9b076536 /lib/puppet | |
parent | 814a9b0288b74407b3ec0aa58310c9972e0ca347 (diff) | |
download | puppet-28be88cc6e13c1af193fe01d56a1a446a18e01bb.tar.gz puppet-28be88cc6e13c1af193fe01d56a1a446a18e01bb.tar.xz puppet-28be88cc6e13c1af193fe01d56a1a446a18e01bb.zip |
Adding authorization store, initially just used for file serving but eventually for all authorization, most likely
git-svn-id: https://reductivelabs.com/svn/puppet/trunk@593 980ebf18-57e1-0310-9a29-db15c13687c0
Diffstat (limited to 'lib/puppet')
-rwxr-xr-x | lib/puppet/server/authstore.rb | 224 |
1 files changed, 224 insertions, 0 deletions
diff --git a/lib/puppet/server/authstore.rb b/lib/puppet/server/authstore.rb new file mode 100755 index 000000000..966bc8372 --- /dev/null +++ b/lib/puppet/server/authstore.rb @@ -0,0 +1,224 @@ +#!/usr/bin/ruby -w + +#-------------------- +# standard module for determining whether a given hostname or IP has access to +# the requested resource +# +# $Id$ + +require 'ipaddr' + +module Puppet +class Server + class AuthStoreError < Puppet::Error; end + class AuthorizationError < Puppet::Error; end + + class AuthStore + ORDER = { + :ip => [:ip], + :name => [:hostname, :domain] + } + + def allow(pattern) + # a simple way to allow anyone at all to connect + if pattern == "*" + @globalallow = true + else + store(pattern, @allow) + end + end + + def allowed?(name, ip) + if name or ip + unless name and ip + raise Puppet::DevError, "Name and IP must be passed to 'allowed?'" + end + # else, we're networked and such + else + # we're local + return true + end + + # yay insecure overrides + if @globalallow + return true + end + + value = nil + ORDER.each { |nametype, array| + if nametype == :ip + value = IPAddr.new(ip) + else + value = name.split(".").reverse + end + + array.each { |type| + [[@deny, false], [@allow, true]].each { |ary| + hash, retval = ary + if hash.include?(type) + hash[type].each { |pattern| + if match?(nametype, value, pattern) + return retval + end + } + end + } + } + } + + # default to false + return false + end + + def deny(pattern) + store(pattern, @deny) + end + + def initialize + @globalallow = nil + @allow = Hash.new { |hash, key| + hash[key] = [] + } + @deny = Hash.new { |hash, key| + hash[key] = [] + } + end + + private + + def match?(nametype, value, pattern) + if value == pattern # simplest shortcut + return true + end + + case nametype + when :ip: matchip?(value, pattern) + when :name: matchname?(value, pattern) + else + raise Puppet::DevError, "Invalid match type %s" % nametype + end + end + + def matchip?(value, pattern) + # we're just using builtin stuff for this, thankfully + if pattern.include?(value) + return true + else + return false + end + end + + def matchname?(value, pattern) + # yay, horribly inefficient + if pattern[-1] != '*' # the pattern has no metachars and is not equal + # thus, no match + #Puppet.info "%s is not equal with no * in %s" % [value, pattern] + return false + else + # we know the last field of the pattern is '*' + # if everything up to that doesn't match, we're definitely false + if pattern[0..-2] != value[0..pattern.length-2] + #Puppet.notice "subpatterns didn't match; %s vs %s" % + # [pattern[0..-2], value[0..pattern.length-2]] + return false + end + + case value.length <=> pattern.length + when -1: # value is shorter than pattern + if pattern.length - value.length == 1 + # only ever allowed when the value is the domain of a + # splatted pattern + #Puppet.info "allowing splatted domain %s" % [value] + return true + else + return false + end + when 0: # value is the same length as pattern + if pattern[-1] == "*" + #Puppet.notice "same length with *" + return true + else + return false + end + when 1: # value is longer than pattern + # at this point we've already verified that everything up to + # the '*' in the pattern matches, so we are true + return true + end + end + end + + def store(pattern, hash) + type, value = type(pattern) + + if type and value + # this won't work once we get beyond simple stuff... + hash[type] << value + else + raise AuthStoreError, "Invalid pattern %s" % pattern + end + end + + def type(pattern) + type = value = nil + case pattern + when /^(\d+\.){3}\d+$/: + type = :ip + begin + value = IPAddr.new(pattern) + rescue ArgumentError => detail + raise AuthStoreError, "Invalid IP address pattern %s" % pattern + end + when /^(\d+\.){3}\d+\/(\d+)$/: + mask = Integer($2) + if mask < 1 or mask > 32 + raise AuthStoreError, "Invalid IP mask %s" % mask + end + type = :ip + begin + value = IPAddr.new(pattern) + rescue ArgumentError => detail + raise AuthStoreError, "Invalid IP address pattern %s" % pattern + end + when /^(\d+\.){1,3}\*$/: # an ip address with a '*' at the end + type = :ip + match = $1 + match.sub!(".", '') + ary = pattern.split(".") + + mask = case ary.index(match) + when 0: 8 + when 1: 16 + when 2: 24 + else + raise AuthStoreError, "Invalid IP pattern %s" % pattern + end + + ary.pop + while ary.length < 4 + ary.push("0") + end + + begin + value = IPAddr.new(ary.join(".") + "/" + mask.to_s) + rescue ArgumentError => detail + raise AuthStoreError, "Invalid IP address pattern %s" % pattern + end + when /^[\d.]+$/: # necessary so incomplete IP addresses can't look + # like hostnames + raise AuthStoreError, "Invalid IP address pattern %s" % pattern + when /^([a-zA-Z][-\w]*\.)+[-\w]+$/: # a full hostname + type = :hostname + value = pattern.split(".").reverse + when /^\*\.([a-zA-Z][-\w]*\.)+[-\w]+$/: # this doesn't match TLDs + type = :domain + value = pattern.split(".").reverse + else + raise AuthStoreError, "Invalid pattern %s" % pattern + end + + return [type, value] + end + end +end +end |