Skip to content

Commit 2095c8b

Browse files
authored
Merge pull request #9072 from mhashizume/PUP-11854/main/agent-renew
(PUP-11854) Add method to renew certificate
2 parents 9ab8526 + 7bf081a commit 2095c8b

File tree

2 files changed

+96
-0
lines changed

2 files changed

+96
-0
lines changed

lib/puppet/http/service/ca.rb

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,4 +104,29 @@ def put_certificate_request(name, csr, ssl_context: nil)
104104

105105
response
106106
end
107+
108+
# Submit a POST request to send a certificate renewal request to the server
109+
#
110+
# @param [Puppet::SSL::SSLContext] ssl_context
111+
#
112+
# @return [Puppet::HTTP::Response] The request response
113+
#
114+
# @api public
115+
def post_certificate_renewal(ssl_context)
116+
headers = add_puppet_headers(HEADERS)
117+
headers['Content-Type'] = 'text/plain'
118+
119+
response = @client.post(
120+
with_base_url('/certificate_renewal'),
121+
'', # Puppet::HTTP::Client.post requires a body, the API endpoint does not
122+
headers: headers,
123+
options: {ssl_context: ssl_context}
124+
)
125+
126+
raise ArgumentError.new(_('SSL context must contain a client certificate.')) unless ssl_context.client_cert
127+
128+
process_response(response)
129+
130+
[response, response.body.to_s]
131+
end
107132
end

spec/unit/http/service/ca_spec.rb

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -207,4 +207,75 @@
207207
end
208208
end
209209
end
210+
211+
context 'when getting certificates' do
212+
let(:cert) { cert_fixture('signed.pem') }
213+
let(:pem) { cert.to_pem }
214+
let(:url) { "https://www.example.com/puppet-ca/v1/certificate_renewal" }
215+
let(:cert_context) { Puppet::SSL::SSLContext.new(client_cert: pem) }
216+
let(:client) { Puppet::HTTP::Client.new(ssl_context: cert_context) }
217+
let(:session) { Puppet::HTTP::Session.new(client, []) }
218+
let(:subject) { client.create_session.route_to(:ca) }
219+
220+
it "gets a certificate from the 'certificate_renewal' endpoint" do
221+
stub_request(:post, url).to_return(body: pem)
222+
223+
_, body = subject.post_certificate_renewal(cert_context)
224+
expect(body).to eq(pem)
225+
end
226+
227+
it 'returns the request response' do
228+
stub_request(:post, url).to_return(body: 'pem')
229+
230+
resp, _ = subject.post_certificate_renewal(cert_context)
231+
expect(resp).to be_a(Puppet::HTTP::Response)
232+
end
233+
234+
it 'accepts text/plain responses' do
235+
stub_request(:post, url).with(headers: {'Accept' => 'text/plain'})
236+
237+
subject.post_certificate_renewal(cert_context)
238+
end
239+
240+
it 'raises an ArgumentError if the SSL context does not contain a client cert' do
241+
stub_request(:post, url)
242+
expect { subject.post_certificate_renewal(ssl_context) }.to raise_error(ArgumentError, 'SSL context must contain a client certificate.')
243+
end
244+
245+
it 'raises response error if unsuccessful' do
246+
stub_request(:post, url).to_return(status: [400, 'Bad Request'])
247+
248+
expect {
249+
subject.post_certificate_renewal(cert_context)
250+
}.to raise_error do |err|
251+
expect(err).to be_an_instance_of(Puppet::HTTP::ResponseError)
252+
expect(err.message).to eq('Bad Request')
253+
expect(err.response.code).to eq(400)
254+
end
255+
end
256+
257+
it 'raises a response error if unsuccessful' do
258+
stub_request(:post, url).to_return(status: [404, 'Not Found'])
259+
260+
expect {
261+
subject.post_certificate_renewal(cert_context)
262+
}.to raise_error do |err|
263+
expect(err).to be_an_instance_of(Puppet::HTTP::ResponseError)
264+
expect(err.message).to eq("Not Found")
265+
expect(err.response.code).to eq(404)
266+
end
267+
end
268+
269+
it 'raises a response error if unsuccessful' do
270+
stub_request(:post, url).to_return(status: [404, 'Forbidden'])
271+
272+
expect {
273+
subject.post_certificate_renewal(cert_context)
274+
}.to raise_error do |err|
275+
expect(err).to be_an_instance_of(Puppet::HTTP::ResponseError)
276+
expect(err.message).to eq("Forbidden")
277+
expect(err.response.code).to eq(404)
278+
end
279+
end
280+
end
210281
end

0 commit comments

Comments
 (0)