diff options
author | Vladimir Shushlin <v.shushlin@gmail.com> | 2019-04-12 18:54:44 +0300 |
---|---|---|
committer | Vladimir Shushlin <v.shushlin@gmail.com> | 2019-04-12 19:04:03 +0300 |
commit | 4c5a9cf3158939c1f645454887dda04cb0edfa8f (patch) | |
tree | 8f3241c1488a2e25188243db05eed3e5f772c1a3 | |
parent | d3bb4af50381451f623e01719e4387f14ff3912c (diff) | |
download | gitlab-ce-acme-client.tar.gz |
WIPacme-client
-rw-r--r-- | lib/gitlab/acme.rb | 69 | ||||
-rw-r--r-- | spec/lib/gitlab/acme_spec.rb | 39 | ||||
-rw-r--r-- | spec/support/helpers/acme_helpers.rb | 34 |
3 files changed, 142 insertions, 0 deletions
diff --git a/lib/gitlab/acme.rb b/lib/gitlab/acme.rb new file mode 100644 index 00000000000..b682aeaec38 --- /dev/null +++ b/lib/gitlab/acme.rb @@ -0,0 +1,69 @@ +# frozen_string_literal: true + +module Gitlab + module Acme + PRODUCTION_DIRECTORY_URL = 'https://acme-v02.api.letsencrypt.org/directory' + STAGING_DIRECTORY_URL = 'https://acme-staging-v02.api.letsencrypt.org/directory' + + class << self + def client + raise 'Acme integration is disabled' unless acme_integration_enabled? + + acme_client = ::Acme::Client.new(private_key: private_key, + directory: directory, + kid: acme_account_kid) + + # account wasn't yet registered in Let's Encrypt + # if it was calling new_account will just return the same id + # we save kid to avoid making new_account call every time + unless acme_account_kid + binding.pry + account = acme_client.new_account(contact: contact, terms_of_service_agreed: true) + ApplicationSetting.current.update(acme_account_kid: account.kid) + end + + acme_client + end + + def terms_of_service_url + ::Acme::Client.new(directory: directory).terms_of_service + end + + private + + def acme_integration_enabled? + application_settings = Gitlab::CurrentSettings.current_application_settings + + application_settings.acme_terms_of_service_accepted && + admin_email + end + + # gets acme private key from application settings + # generates and saves one if it doesn't exist + def private_key + private_key_string = ApplicationSetting.current.acme_private_key + OpenSSL::PKey::RSA.new(private_key_string) if private_key_string + end + + def acme_account_kid + ApplicationSetting.current.acme_account_kid + end + + def admin_email + ApplicationSetting.current.acme_notification_email + end + + def contact + "mailto:#{admin_email}" + end + + def directory + if Rails.env.production? + PRODUCTION_DIRECTORY_URL + else + STAGING_DIRECTORY_URL + end + end + end + end +end diff --git a/spec/lib/gitlab/acme_spec.rb b/spec/lib/gitlab/acme_spec.rb new file mode 100644 index 00000000000..560767816a9 --- /dev/null +++ b/spec/lib/gitlab/acme_spec.rb @@ -0,0 +1,39 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe Gitlab::Acme do + include AcmeHelpers + + before do + #WebMock.allow_net_connect! + stub_directory + end + + describe '#create' do + subject { described_class.client } + + context 'when admin email is set' do + let!(:application_setting) { create(:application_setting, acme_notification_email: 'info@test.example.com', acme_terms_of_service_accepted: true, acme_private_key: OpenSSL::PKey::RSA.new(4096).to_s) } + + context 'when account is not yet created' do + it 'creates new account' do + + subject + end + end + + context 'when account is already created' do + it 'returns Acme client' do + expect(subject).to be_a(Acme::Client) + end + end + end + + context 'when admin email is not set' do + it 'raises an exeption' do + expect { subject }.to raise_error('Acme integration is disabled') + end + end + end +end diff --git a/spec/support/helpers/acme_helpers.rb b/spec/support/helpers/acme_helpers.rb new file mode 100644 index 00000000000..0cccc847d4c --- /dev/null +++ b/spec/support/helpers/acme_helpers.rb @@ -0,0 +1,34 @@ +# frozen_string_literal: true + +module AcmeHelpers + NEW_NONCE_URL = 'https://acme-staging-v02.api.letsencrypt.org/acme/new-nonce' + + def stub_directory + response = <<-EOF +{ + "eQ3fEKjOSxE": "https://community.letsencrypt.org/t/adding-random-entries-to-the-directory/33417", + "keyChange": "https://acme-staging-v02.api.letsencrypt.org/acme/key-change", + "meta": { + "caaIdentities": [ + "letsencrypt.org" + ], + "termsOfService": "https://letsencrypt.org/documents/LE-SA-v1.2-November-15-2017.pdf", + "website": "https://letsencrypt.org/docs/staging-environment/" + }, + "newAccount": "https://acme-staging-v02.api.letsencrypt.org/acme/new-acct", + "newNonce": "https://acme-staging-v02.api.letsencrypt.org/acme/new-nonce", + "newOrder": "https://acme-staging-v02.api.letsencrypt.org/acme/new-order", + "revokeCert": "https://acme-staging-v02.api.letsencrypt.org/acme/revoke-cert" +} +EOF + stub_request(:get, Gitlab::Acme::STAGING_DIRECTORY_URL) + .to_return(status: 200, body: response, headers: {}) + + stub_request(:head, NEW_NONCE_URL) + .to_return(status: 200, body: "", headers: {}) + end + + def stub_new_account + stub_request(:post, "https://acme-staging-v02.api.letsencrypt.org/acme/new-acct") + end +end |