summaryrefslogtreecommitdiffstats
path: root/lib/puppet/network/authconfig.rb
blob: 8e377371957ab00f917cd3afb3937dcbc48d3da6 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
require 'puppet/util/loadedfile'
require 'puppet/network/rights'

module Puppet
    class ConfigurationError < Puppet::Error; end
    class Network::AuthConfig < Puppet::Util::LoadedFile

        def self.main
            unless defined? @main
                @main = self.new()
            end
            @main
        end

        # Just proxy the setting methods to our rights stuff
        [:allow, :deny].each do |method|
            define_method(method) do |*args|
                @rights.send(method, *args)
            end         
        end

        # Here we add a little bit of semantics.  They can set auth on a whole
        # namespace or on just a single method in the namespace.
        def allowed?(request)
            name        = request.call.intern
            namespace   = request.handler.intern
            method      = request.method.intern

            read()

            if @rights.include?(name)
                return @rights[name].allowed?(request.name, request.ip)
            elsif @rights.include?(namespace)
                return @rights[namespace].allowed?(request.name, request.ip)
            else
                return false
            end
        end

        # Does the file exist?  Puppetmasterd does not require it, but
        # puppetd does.
        def exists?
            FileTest.exists?(@file)
        end

        def initialize(file = nil, parsenow = true)
            @file ||= Puppet[:authconfig]

            unless @file
                raise Puppet::DevError, "No authconfig file defined"
            end
            return unless self.exists?
            super(@file)
            @rights = Puppet::Network::Rights.new
            @configstamp = @configstatted = nil
            @configtimeout = 60

            if parsenow
                read()
            end
        end

        # Read the configuration file.
        def read
            return unless FileTest.exists?(@file)

            if @configstamp
                if @configtimeout and @configstatted
                    if Time.now - @configstatted > @configtimeout
                        @configstatted = Time.now
                        tmp = File.stat(@file).ctime

                        if tmp == @configstamp
                            return
                        else
                            Puppet.notice "%s vs %s" % [tmp, @configstamp]
                        end
                    else
                        return
                    end
                else    
                    Puppet.notice "%s and %s" % [@configtimeout, @configstatted]
                end
            end

            parse()

            @configstamp = File.stat(@file).ctime
            @configstatted = Time.now
        end

        private

        def parse
            newrights = Puppet::Network::Rights.new
            begin
                File.open(@file) { |f|
                    right = nil
                    count = 1
                    f.each { |line|
                        case line
                        when /^\s*#/: next # skip comments
                        when /^\s*$/: next # skip blank lines
                        when /\[([\w.]+)\]/: # "namespace" or "namespace.method"
                            name = $1
                            if newrights.include?(name)
                                raise FileServerError, "%s is already set at %s" %
                                    [newrights[name], name]
                            end
                            newrights.newright(name)
                            right = newrights[name]
                        when /^\s*(\w+)\s+(.+)$/:
                            var = $1
                            value = $2
                            case var
                            when "allow":
                                value.split(/\s*,\s*/).each { |val|
                                    begin
                                        right.info "allowing %s access" % val
                                        right.allow(val)
                                    rescue AuthStoreError => detail
                                        raise ConfigurationError, "%s at line %s of %s" %
                                            [detail.to_s, count, @config]
                                    end
                                }
                            when "deny":
                                value.split(/\s*,\s*/).each { |val|
                                    begin
                                        right.info "denying %s access" % val
                                        right.deny(val)
                                    rescue AuthStoreError => detail
                                        raise ConfigurationError, "%s at line %s of %s" %
                                            [detail.to_s, count, @config]
                                    end
                                }
                            else
                                raise ConfigurationError,
                                    "Invalid argument '%s' at line %s" % [var, count]
                            end
                        else
                            raise ConfigurationError, "Invalid line %s: %s" % [count, line]
                        end
                        count += 1
                    }
                }
            rescue Errno::EACCES => detail
                Puppet.err "Configuration error: Cannot read %s; cannot serve" % @file
                #raise Puppet::Error, "Cannot read %s" % @config
            rescue Errno::ENOENT => detail
                Puppet.err "Configuration error: '%s' does not exit; cannot serve" %
                    @file
                #raise Puppet::Error, "%s does not exit" % @config
            #rescue FileServerError => detail
            #    Puppet.err "FileServer error: %s" % detail
            end

            # Verify each of the rights are valid.
            # We let the check raise an error, so that it can raise an error
            # pointing to the specific problem.
            newrights.each { |name, right|
                right.valid?
            }
            @rights = newrights
        end
    end
end