diff --git a/lemur/common/schema.py b/lemur/common/schema.py index 1e081f8c..14086dc9 100644 --- a/lemur/common/schema.py +++ b/lemur/common/schema.py @@ -135,7 +135,6 @@ def unwrap_pagination(data, output_schema): marshaled_data = {'total': len(data)} marshaled_data['items'] = output_schema.dump(data, many=True).data return marshaled_data - return output_schema.dump(data).data diff --git a/lemur/dns_providers/service.py b/lemur/dns_providers/service.py index b2eef9e1..64cd6782 100644 --- a/lemur/dns_providers/service.py +++ b/lemur/dns_providers/service.py @@ -1,3 +1,6 @@ +import json + +from flask import current_app from lemur import database from lemur.dns_providers.models import DnsProviders @@ -31,3 +34,10 @@ def delete(dns_provider_id): :param dns_provider_id: Lemur assigned ID """ database.delete(get(dns_provider_id)) + + +def get_types(): + provider_config = current_app.config.get('ACME_DNS_PROVIDER_TYPES') + if not provider_config: + raise Exception("No DNS Provider configuration specified.") + return provider_config diff --git a/lemur/dns_providers/views.py b/lemur/dns_providers/views.py index 0f324bdf..4eff0ece 100644 --- a/lemur/dns_providers/views.py +++ b/lemur/dns_providers/views.py @@ -78,10 +78,24 @@ class DnsProvidersList(AuthenticatedResource): args['user'] = g.user return service.render(args) + @admin_permission.require(http_exception=403) def delete(self, dns_provider_id): service.delete(dns_provider_id) return {'result': True} +class DnsProviderTypes(AuthenticatedResource): + """ Defines the 'dns_provider_types' endpoint """ + + def __init__(self): + self.reqparse = reqparse.RequestParser() + super(DnsProviderTypes, self).__init__() + + def get(self): + return service.get_types() + + api.add_resource(DnsProvidersList, '/dns_providers', endpoint='dns_providers') +api.add_resource(DnsProvidersList, '/dns_providers/', endpoint='dns_provider') +api.add_resource(DnsProviderTypes, '/dns_provider_types', endpoint='dns_provider_types') diff --git a/lemur/plugins/lemur_acme/plugin.py b/lemur/plugins/lemur_acme/plugin.py index e7e6d8c3..a6901c5c 100644 --- a/lemur/plugins/lemur_acme/plugin.py +++ b/lemur/plugins/lemur_acme/plugin.py @@ -113,13 +113,11 @@ def setup_acme_client(authority): if not authority.options: raise Exception("Invalid authority. Options not set") options = {} - for o in json.loads(authority.options): - print(o) - options[o.get("name")] = o.get("value") - email = options.get('email', current_app.config.get('ACME_EMAIL')) - tel = options.get('telephone', current_app.config.get('ACME_TEL')) - directory_url = options.get('acme_url', current_app.config.get('ACME_DIRECTORY_URL')) - contact = ('mailto:{}'.format(email), 'tel:{}'.format(tel)) + authority_options = json.loads(authority.options) + options[authority_options.get("name")] = authority_options.get("value") + email = authority_options.get('email', current_app.config.get('ACME_EMAIL')) + tel = authority_options.get('telephone', current_app.config.get('ACME_TEL')) + directory_url = authority_options.get('acme_url', current_app.config.get('ACME_DIRECTORY_URL')) key = jose.JWKRSA(key=generate_private_key('RSA2048')) diff --git a/lemur/plugins/lemur_acme/tests/test_acme.py b/lemur/plugins/lemur_acme/tests/test_acme.py index 39d78bbe..7aeef238 100644 --- a/lemur/plugins/lemur_acme/tests/test_acme.py +++ b/lemur/plugins/lemur_acme/tests/test_acme.py @@ -1,4 +1,119 @@ +import unittest + +from acme import challenges + +from lemur.plugins.lemur_acme import plugin, route53, cloudflare +from lemur.plugins.base import plugins +from mock import MagicMock, Mock, patch + + +class TestAcme(unittest.TestCase): + + @patch('lemur.plugins.lemur_acme.plugin.len', return_value=1) + def test_find_dns_challenge(self, mock_len): + assert mock_len + + from acme import challenges + c = challenges.DNS01() + + mock_authz = Mock() + mock_authz.body.resolved_combinations = [] + mock_entry = Mock() + mock_entry.chall = c + mock_authz.body.resolved_combinations.append(mock_entry) + result = yield plugin.find_dns_challenge(mock_authz) + self.assertEqual(result, mock_entry) + + def test_authz_record(self): + a = plugin.AuthorizationRecord("host", "authz", "challenge", "id") + self.assertEqual(type(a), plugin.AuthorizationRecord) + + @patch('acme.client.Client') + @patch('lemur.plugins.lemur_acme.plugin.current_app') + @patch('lemur.plugins.lemur_acme.plugin.len', return_value=1) + @patch('lemur.plugins.lemur_acme.plugin.find_dns_challenge') + def test_start_dns_challenge(self, mock_find_dns_challenge, mock_len, mock_app, mock_acme): + assert mock_len + mock_app.logger.debug = Mock() + mock_authz = Mock() + mock_authz.body.resolved_combinations = [] + mock_entry = MagicMock() + from acme import challenges + c = challenges.DNS01() + mock_entry.chall = c + mock_authz.body.resolved_combinations.append(mock_entry) + mock_acme.request_domain_challenges = Mock(return_value=mock_authz) + mock_dns_provider = Mock() + mock_dns_provider.create_txt_record = Mock(return_value=1) + + values = [mock_entry] + iterable = mock_find_dns_challenge.return_value + iterator = iter(values) + iterable.__iter__.return_value = iterator + result = plugin.start_dns_challenge(mock_acme, "accountid", "host", mock_dns_provider) + self.assertEqual(type(result), plugin.AuthorizationRecord) + + @patch('acme.client.Client') + def test_complete_dns_challenge_success(self, mock_acme): + mock_dns_provider = Mock() + mock_dns_provider.wait_for_dns_change = Mock(return_value=True) + + mock_authz = Mock() + mock_authz.dns_challenge.response = Mock() + mock_authz.dns_challenge.response.simple_verify = Mock(return_value=True) + + plugin.complete_dns_challenge(mock_acme, "accountid", mock_authz, mock_dns_provider) + + @patch('acme.client.Client') + def test_complete_dns_challenge_fail(self, mock_acme): + mock_dns_provider = Mock() + mock_dns_provider.wait_for_dns_change = Mock(return_value=True) + + mock_authz = Mock() + mock_authz.dns_challenge.response = Mock() + mock_authz.dns_challenge.response.simple_verify = Mock(return_value=False) + self.assertRaises( + ValueError, + plugin.complete_dns_challenge(mock_acme, "accountid", mock_authz, mock_dns_provider) + ) + + @patch('acme.client.Client') + @patch('OpenSSL.crypto', return_value="mock_cert") + @patch('josepy.util.ComparableX509') + @patch('lemur.plugins.lemur_acme.plugin.find_dns_challenge') + @patch('lemur.plugins.lemur_acme.plugin.current_app') + def test_request_certificate(self, mock_current_app, mock_find_dns_challenge, mock_jose, mock_crypto, mock_acme): + mock_cert_response = Mock() + mock_cert_response.body = "123" + mock_cert_response_full = [mock_cert_response, True] + mock_acme.poll_and_request_issuance = Mock(return_value=mock_cert_response_full) + mock_authz = [] + mock_authz_record = MagicMock() + mock_authz_record.authz = Mock() + mock_authz.append(mock_authz_record) + mock_acme.fetch_chain = Mock(return_value="mock_chain") + mock_crypto.dump_certificate = Mock(return_value=b'chain') + + plugin.request_certificate(mock_acme, [], "mock_csr") + + def test_setup_acme_client_fail(self): + mock_authority = Mock() + mock_authority.options = [] + with self.assertRaises(Exception): + plugin.setup_acme_client(mock_authority) + + @patch('lemur.plugins.lemur_acme.plugin.Client') + @patch('lemur.plugins.lemur_acme.plugin.current_app') + def test_setup_acme_client_success(self, mock_current_app, mock_acme): + mock_authority = Mock() + mock_authority.options = '{"o": "mock_name", "v": "mock_value"}' + mock_client = Mock() + mock_registration = Mock() + mock_registration.uri = "http://test.com" + mock_client.register = mock_registration + mock_client.agree_to_tos = Mock(return_value=True) + mock_acme.return_value = mock_client + result_client, result_registration = plugin.setup_acme_client(mock_authority) + assert result_client + assert result_registration -def test_get_certificates(app): - from lemur.plugins.base import plugins - p = plugins.get('acme-issuer') diff --git a/lemur/static/app/angular/dns_providers/dns_provider/dns_provider.js b/lemur/static/app/angular/dns_providers/dns_provider/dns_provider.js index b9417634..62506101 100644 --- a/lemur/static/app/angular/dns_providers/dns_provider/dns_provider.js +++ b/lemur/static/app/angular/dns_providers/dns_provider/dns_provider.js @@ -5,6 +5,10 @@ angular.module('lemur') .controller('DnsProviderCreateController', function ($scope, $uibModalInstance, PluginService, DnsProviderService, LemurRestangular, toaster) { $scope.dns_provider = LemurRestangular.restangularizeElement(null, {}, 'dns_providers'); + PluginService.getByName('acme-issuer').then(function (acme) { + $scope.acme = acme; + }); + PluginService.getByType('dns_provider').then(function (plugins) { $scope.plugins = plugins; }); @@ -45,30 +49,13 @@ angular.module('lemur') DnsProviderApi.get(editId).then(function (dns_provider) { $scope.dns_provider = dns_provider; - PluginService.getByType('dns_provider').then(function (plugins) { - $scope.plugins = plugins; + PluginService.getByName('acme-issuer').then(function (acme) { + $scope.acme = acme; - _.each($scope.plugins, function (plugin) { - if (plugin.slug === $scope.dns_provider.plugin.slug) { - plugin.pluginOptions = $scope.dns_provider.plugin.pluginOptions; - $scope.dns_provider.plugin = plugin; - _.each($scope.dns_provider.plugin.pluginOptions, function (option) { - if (option.type === 'export-plugin') { - PluginService.getByType('export').then(function (plugins) { - $scope.exportPlugins = plugins; - - _.each($scope.exportPlugins, function (plugin) { - if (plugin.slug === option.value.slug) { - plugin.pluginOptions = option.value.pluginOptions; - option.value = plugin; - } - }); - }); - } - }); - } + _.each($scope.acme, function (opts) { + console.log(opts); + }); }); - }); }); $scope.save = function (dns_provider) { diff --git a/lemur/static/app/angular/dns_providers/dns_provider/dns_provider.tpl.html b/lemur/static/app/angular/dns_providers/dns_provider/dns_provider.tpl.html index 1a7beb7c..faeb46bd 100644 --- a/lemur/static/app/angular/dns_providers/dns_provider/dns_provider.tpl.html +++ b/lemur/static/app/angular/dns_providers/dns_provider/dns_provider.tpl.html @@ -2,19 +2,19 @@

CreateEdit - DnsProvider oh the places you will go!

+ Dns Provider route all the things