summaryrefslogtreecommitdiffstats
path: root/spec/unit/network/http/rack/xmlrpc_spec.rb
blob: abfe84ba6d751a97c52538bcb5ce1f87e8aa8381 (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
#!/usr/bin/env ruby

require File.dirname(__FILE__) + '/../../../../spec_helper'
require 'puppet/network/http/rack' if Puppet.features.rack?
require 'puppet/network/http/rack/xmlrpc' if Puppet.features.rack?

describe "Puppet::Network::HTTP::RackXMLRPC" do
    confine "Rack is not available" => Puppet.features.rack?

    describe "when initializing" do
        it "should create an Puppet::Network::XMLRPCServer" do
            Puppet::Network::XMLRPCServer.expects(:new).returns stub_everything
            Puppet::Network::HTTP::RackXMLRPC.new([])
        end

        it "should create each handler" do
            handler = stub_everything 'handler'
            Puppet::Network::XMLRPCServer.any_instance.stubs(:add_handler)
            Puppet::Network::Handler.expects(:handler).returns(handler).times(2)
            Puppet::Network::HTTP::RackXMLRPC.new([:foo, :bar])
        end

        it "should add each handler to the XMLRPCserver" do
            handler = stub_everything 'handler'
            Puppet::Network::Handler.stubs(:handler).returns(handler)
            Puppet::Network::XMLRPCServer.any_instance.expects(:add_handler).times(2)
            Puppet::Network::HTTP::RackXMLRPC.new([:foo, :bar])
        end
    end

    describe "when serving a request" do

        before :each do
            foo_handler = stub_everything 'foo_handler'
            Puppet::Network::Handler.stubs(:handler).with(:foo).returns foo_handler
            Puppet::Network::XMLRPCServer.any_instance.stubs(:add_handler)
            Puppet::Network::XMLRPCServer.any_instance.stubs(:process).returns('<xml/>')
            @handler = Puppet::Network::HTTP::RackXMLRPC.new([:foo])
        end

        before :each do
            @response = Rack::Response.new()
        end

        def mk_req(opts = {})
            opts[:method] = 'POST' if !opts[:method]
            opts['CONTENT_TYPE'] = 'text/xml; foo=bar' if !opts['CONTENT_TYPE']
            env = Rack::MockRequest.env_for('/RPC2', opts)
            Rack::Request.new(env)
        end

        it "should reject non-POST requests" do
            req = mk_req :method => 'PUT'
            @handler.process(req, @response)
            @response.status.should == 405
        end

        it "should reject non text/xml requests" do
            req = mk_req 'CONTENT_TYPE' => 'yadda/plain'
        end

        it "should create a ClientRequest" do
            cr = Puppet::Network::ClientRequest.new(nil, '127.0.0.1', false)
            Puppet::Network::ClientRequest.expects(:new).returns cr
            req = mk_req
            @handler.process(req, @response)
        end

        it "should let xmlrpcserver process the request" do
            Puppet::Network::XMLRPCServer.any_instance.expects(:process).returns('yay')
            req = mk_req
            @handler.process(req, @response)
        end

        it "should report the response as OK" do
            req = mk_req
            @handler.process(req, @response)
            @response.status.should == 200
        end

        it "should report the response with the correct content type" do
            req = mk_req
            @handler.process(req, @response)
            @response['Content-Type'].should == 'text/xml; charset=utf-8'
        end

        it "should set 'authenticated' to false if no certificate is present" do
            req = mk_req
            Puppet::Network::ClientRequest.expects(:new).with() { |node,ip,authenticated| authenticated == false }
            @handler.process(req, @response)
        end

        it "should use the client's ip address" do
            req = mk_req 'REMOTE_ADDR' => 'ipaddress'
            Puppet::Network::ClientRequest.expects(:new).with() { |node,ip,authenticated| ip == 'ipaddress' }
            @handler.process(req, @response)
        end

        describe "with pre-validated certificates" do

            it "should use the :ssl_client_header to determine the parameter when looking for the certificate" do
                Puppet.settings.stubs(:value).returns "eh"
                Puppet.settings.expects(:value).with(:ssl_client_header).returns "myheader"
                req = mk_req "myheader" => "/CN=host.domain.com"
                @handler.process(req, @response)
            end

            it "should retrieve the hostname by matching the certificate parameter" do
                Puppet.settings.stubs(:value).returns "eh"
                Puppet.settings.expects(:value).with(:ssl_client_header).returns "myheader"
                Puppet::Network::ClientRequest.expects(:new).with() { |node,ip,authenticated| node == "host.domain.com" }
                req = mk_req "myheader" => "/CN=host.domain.com"
                @handler.process(req, @response)
            end

            it "should use the :ssl_client_header to determine the parameter for checking whether the host certificate is valid" do
                Puppet.settings.stubs(:value).with(:ssl_client_header).returns "certheader"
                Puppet.settings.expects(:value).with(:ssl_client_verify_header).returns "myheader"
                req = mk_req "myheader" => "SUCCESS", "certheader" => "/CN=host.domain.com"
                @handler.process(req, @response)
            end

            it "should consider the host authenticated if the validity parameter contains 'SUCCESS'" do
                Puppet.settings.stubs(:value).with(:ssl_client_header).returns "certheader"
                Puppet.settings.stubs(:value).with(:ssl_client_verify_header).returns "myheader"
                Puppet::Network::ClientRequest.expects(:new).with() { |node,ip,authenticated| authenticated == true }
                req = mk_req "myheader" => "SUCCESS", "certheader" => "/CN=host.domain.com"
                @handler.process(req, @response)
            end

            it "should consider the host unauthenticated if the validity parameter does not contain 'SUCCESS'" do
                Puppet.settings.stubs(:value).with(:ssl_client_header).returns "certheader"
                Puppet.settings.stubs(:value).with(:ssl_client_verify_header).returns "myheader"
                Puppet::Network::ClientRequest.expects(:new).with() { |node,ip,authenticated| authenticated == false }
                req = mk_req "myheader" => "whatever", "certheader" => "/CN=host.domain.com"
                @handler.process(req, @response)
            end

            it "should consider the host unauthenticated if no certificate information is present" do
                Puppet.settings.stubs(:value).with(:ssl_client_header).returns "certheader"
                Puppet.settings.stubs(:value).with(:ssl_client_verify_header).returns "myheader"
                Puppet::Network::ClientRequest.expects(:new).with() { |node,ip,authenticated| authenticated == false }
                req = mk_req "myheader" => nil, "certheader" => "/CN=host.domain.com"
                @handler.process(req, @response)
            end

            it "should resolve the node name with an ip address look-up if no certificate is present" do
                Puppet.settings.stubs(:value).returns "eh"
                Puppet.settings.expects(:value).with(:ssl_client_header).returns "myheader"
                Resolv.any_instance.expects(:getname).returns("host.domain.com")
                Puppet::Network::ClientRequest.expects(:new).with() { |node,ip,authenticated| node == "host.domain.com" }
                req = mk_req "myheader" => nil
                @handler.process(req, @response)
            end
        end
    end
end