2019-09-04 21:01:54 +05:30
|
|
|
# frozen_string_literal: true
|
|
|
|
|
|
|
|
require 'spec_helper'
|
|
|
|
|
|
|
|
describe PagesDomains::ObtainLetsEncryptCertificateService do
|
|
|
|
include LetsEncryptHelpers
|
|
|
|
|
|
|
|
let(:pages_domain) { create(:pages_domain, :without_certificate, :without_key) }
|
|
|
|
let(:service) { described_class.new(pages_domain) }
|
|
|
|
|
|
|
|
before do
|
|
|
|
stub_lets_encrypt_settings
|
|
|
|
end
|
|
|
|
|
2019-09-30 21:07:59 +05:30
|
|
|
around do |example|
|
|
|
|
Sidekiq::Testing.fake! do
|
|
|
|
example.run
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2019-09-04 21:01:54 +05:30
|
|
|
def expect_to_create_acme_challenge
|
|
|
|
expect(::PagesDomains::CreateAcmeOrderService).to receive(:new).with(pages_domain)
|
|
|
|
.and_wrap_original do |m, *args|
|
|
|
|
create_service = m.call(*args)
|
|
|
|
|
|
|
|
expect(create_service).to receive(:execute)
|
|
|
|
|
|
|
|
create_service
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
def stub_lets_encrypt_order(url, status)
|
|
|
|
order = ::Gitlab::LetsEncrypt::Order.new(acme_order_double(status: status))
|
|
|
|
|
2020-03-13 15:44:24 +05:30
|
|
|
allow_next_instance_of(::Gitlab::LetsEncrypt::Client) do |instance|
|
|
|
|
allow(instance).to receive(:load_order).with(url).and_return(order)
|
|
|
|
end
|
2019-09-04 21:01:54 +05:30
|
|
|
|
|
|
|
order
|
|
|
|
end
|
|
|
|
|
|
|
|
context 'when there is no acme order' do
|
2019-09-30 21:07:59 +05:30
|
|
|
it 'creates acme order and schedules next step' do
|
2019-09-04 21:01:54 +05:30
|
|
|
expect_to_create_acme_challenge
|
2019-09-30 21:07:59 +05:30
|
|
|
expect(PagesDomainSslRenewalWorker).to(
|
|
|
|
receive(:perform_in).with(described_class::CHALLENGE_PROCESSING_DELAY, pages_domain.id)
|
|
|
|
.and_return(nil).once
|
|
|
|
)
|
2019-09-04 21:01:54 +05:30
|
|
|
|
|
|
|
service.execute
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
context 'when there is expired acme order' do
|
|
|
|
let!(:existing_order) do
|
|
|
|
create(:pages_domain_acme_order, :expired, pages_domain: pages_domain)
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'removes acme order and creates new one' do
|
|
|
|
expect_to_create_acme_challenge
|
|
|
|
|
|
|
|
service.execute
|
|
|
|
|
|
|
|
expect(PagesDomainAcmeOrder.find_by_id(existing_order.id)).to be_nil
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
%w(pending processing).each do |status|
|
|
|
|
context "there is an order in '#{status}' status" do
|
|
|
|
let(:existing_order) do
|
|
|
|
create(:pages_domain_acme_order, pages_domain: pages_domain)
|
|
|
|
end
|
|
|
|
|
|
|
|
before do
|
|
|
|
stub_lets_encrypt_order(existing_order.url, status)
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'does not raise errors' do
|
|
|
|
expect do
|
|
|
|
service.execute
|
|
|
|
end.not_to raise_error
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
context 'when order is ready' do
|
|
|
|
let(:existing_order) do
|
|
|
|
create(:pages_domain_acme_order, pages_domain: pages_domain)
|
|
|
|
end
|
|
|
|
|
|
|
|
let!(:api_order) do
|
|
|
|
stub_lets_encrypt_order(existing_order.url, 'ready')
|
|
|
|
end
|
|
|
|
|
2019-09-30 21:07:59 +05:30
|
|
|
it 'request certificate and schedules next step' do
|
2019-09-04 21:01:54 +05:30
|
|
|
expect(api_order).to receive(:request_certificate).and_call_original
|
2019-09-30 21:07:59 +05:30
|
|
|
expect(PagesDomainSslRenewalWorker).to(
|
|
|
|
receive(:perform_in).with(described_class::CERTIFICATE_PROCESSING_DELAY, pages_domain.id)
|
|
|
|
.and_return(nil).once
|
|
|
|
)
|
2019-09-04 21:01:54 +05:30
|
|
|
|
|
|
|
service.execute
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
context 'when order is valid' do
|
|
|
|
let(:existing_order) do
|
|
|
|
create(:pages_domain_acme_order, pages_domain: pages_domain)
|
|
|
|
end
|
|
|
|
|
|
|
|
let!(:api_order) do
|
|
|
|
stub_lets_encrypt_order(existing_order.url, 'valid')
|
|
|
|
end
|
|
|
|
|
|
|
|
let(:certificate) do
|
|
|
|
key = OpenSSL::PKey.read(existing_order.private_key)
|
|
|
|
|
|
|
|
subject = "/C=BE/O=Test/OU=Test/CN=#{pages_domain.domain}"
|
|
|
|
|
|
|
|
cert = OpenSSL::X509::Certificate.new
|
|
|
|
cert.subject = cert.issuer = OpenSSL::X509::Name.parse(subject)
|
|
|
|
cert.not_before = Time.now
|
|
|
|
cert.not_after = 1.year.from_now
|
|
|
|
cert.public_key = key.public_key
|
|
|
|
cert.serial = 0x0
|
|
|
|
cert.version = 2
|
|
|
|
|
|
|
|
ef = OpenSSL::X509::ExtensionFactory.new
|
|
|
|
ef.subject_certificate = cert
|
|
|
|
ef.issuer_certificate = cert
|
|
|
|
cert.extensions = [
|
|
|
|
ef.create_extension("basicConstraints", "CA:TRUE", true),
|
|
|
|
ef.create_extension("subjectKeyIdentifier", "hash")
|
|
|
|
]
|
|
|
|
cert.add_extension ef.create_extension("authorityKeyIdentifier",
|
|
|
|
"keyid:always,issuer:always")
|
|
|
|
|
|
|
|
cert.sign key, OpenSSL::Digest::SHA1.new
|
|
|
|
|
|
|
|
cert.to_pem
|
|
|
|
end
|
|
|
|
|
|
|
|
before do
|
|
|
|
expect(api_order).to receive(:certificate) { certificate }
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'saves private_key and certificate for domain' do
|
|
|
|
service.execute
|
|
|
|
|
|
|
|
expect(pages_domain.key).to be_present
|
|
|
|
expect(pages_domain.certificate).to eq(certificate)
|
|
|
|
end
|
|
|
|
|
2019-09-30 21:07:59 +05:30
|
|
|
it 'marks certificate as gitlab_provided' do
|
|
|
|
service.execute
|
|
|
|
|
|
|
|
expect(pages_domain.certificate_source).to eq("gitlab_provided")
|
|
|
|
end
|
|
|
|
|
2019-09-04 21:01:54 +05:30
|
|
|
it 'removes order from database' do
|
|
|
|
service.execute
|
|
|
|
|
|
|
|
expect(PagesDomainAcmeOrder.find_by_id(existing_order.id)).to be_nil
|
|
|
|
end
|
|
|
|
end
|
2020-04-22 19:07:51 +05:30
|
|
|
|
|
|
|
context 'when order is invalid' do
|
|
|
|
let(:existing_order) do
|
|
|
|
create(:pages_domain_acme_order, pages_domain: pages_domain)
|
|
|
|
end
|
|
|
|
|
|
|
|
let!(:api_order) do
|
|
|
|
stub_lets_encrypt_order(existing_order.url, 'invalid')
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'saves error to domain and deletes acme order' do
|
|
|
|
expect do
|
|
|
|
service.execute
|
|
|
|
end.to change { pages_domain.reload.auto_ssl_failed }.from(false).to(true)
|
|
|
|
|
|
|
|
expect(PagesDomainAcmeOrder.find_by_id(existing_order.id)).to be_nil
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'sends notification' do
|
|
|
|
expect_next_instance_of(NotificationService) do |notification_service|
|
|
|
|
expect(notification_service).to receive(:pages_domain_auto_ssl_failed).with(pages_domain)
|
|
|
|
end
|
|
|
|
|
|
|
|
service.execute
|
|
|
|
end
|
|
|
|
end
|
2019-09-04 21:01:54 +05:30
|
|
|
end
|