blob: 890f2990eebec76d23f4f949abc24964a0dff91e (
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
|
require 'xmlrpc/server'
require 'puppet/network/authorization'
require 'puppet/network/xmlrpc/processor'
module Puppet::Network::XMLRPC
class ServletError < RuntimeError; end
class WEBrickServlet < ::XMLRPC::WEBrickServlet
include Puppet::Network::XMLRPCProcessor
# This is a hackish way to avoid an auth message every time we have a
# normal operation
def self.log(msg)
@logs ||= {}
if @logs.include?(msg)
@logs[msg] += 1
else
Puppet.info msg
@logs[msg] = 1
end
end
# Accept a list of handlers and register them all.
def initialize(handlers)
# the servlet base class does not consume any arguments
# and its BasicServer base class only accepts a 'class_delim'
# option which won't change in Puppet at all
# thus, we don't need to pass any args to our base class,
# and we can consume them all ourselves
super()
setup_processor()
# Set up each of the passed handlers.
handlers.each do |handler|
add_handler(handler.class.interface, handler)
end
end
# Handle the actual request. We can't use the super() method, because
# we need to pass a ClientRequest object to process() so we can do
# authorization. It's the only way to stay thread-safe.
def service(request, response)
if @valid_ip
raise WEBrick::HTTPStatus::Forbidden unless @valid_ip.any? { |ip| request.peeraddr[3] =~ ip }
end
if request.request_method != "POST"
raise WEBrick::HTTPStatus::MethodNotAllowed,
"unsupported method `#{request.request_method}'."
end
raise WEBrick::HTTPStatus::BadRequest if parse_content_type(request['Content-type']).first != "text/xml"
length = (request['Content-length'] || 0).to_i
raise WEBrick::HTTPStatus::LengthRequired unless length > 0
data = request.body
raise WEBrick::HTTPStatus::BadRequest if data.nil? or data.size != length
resp = process(data, client_request(request))
raise WEBrick::HTTPStatus::InternalServerError if resp.nil? or resp.size <= 0
response.status = 200
response['Content-Length'] = resp.size
response['Content-Type'] = "text/xml; charset=utf-8"
response.body = resp
end
private
# Generate a ClientRequest object for later validation.
def client_request(request)
if peer = request.peeraddr
client = peer[2]
clientip = peer[3]
else
raise ::XMLRPC::FaultException.new(
ERR_UNCAUGHT_EXCEPTION,
"Could not retrieve client information"
)
end
# If they have a certificate (which will almost always be true)
# then we get the hostname from the cert, instead of via IP
# info
valid = false
if cert = request.client_cert
nameary = cert.subject.to_a.find { |ary|
ary[0] == "CN"
}
if nameary.nil?
Puppet.warning "Could not retrieve server name from cert"
else
unless client == nameary[1]
Puppet.debug "Overriding #{client} with cert name #{nameary[1]}"
client = nameary[1]
end
valid = true
end
end
info = Puppet::Network::ClientRequest.new(client, clientip, valid)
info
end
end
end
|