From 6fd47edbe300e7a30852aec0b1737b5975efde31 Mon Sep 17 00:00:00 2001 From: kevgliss Date: Thu, 17 Nov 2016 16:19:52 -0800 Subject: [PATCH] Adds the ability to clone existing certificates. (#513) --- lemur/certificates/models.py | 13 ++ lemur/certificates/schemas.py | 26 +++- .../certificates/certificate/certificate.js | 127 ++++++++++++++++++ .../certificate/certificateWizard.tpl.html | 2 +- .../certificates/certificate/edit.tpl.html | 2 +- .../certificates/certificate/export.tpl.html | 74 +++++----- .../app/angular/certificates/services.js | 24 +++- .../app/angular/certificates/view/view.js | 21 ++- .../angular/certificates/view/view.tpl.html | 29 ++-- 9 files changed, 264 insertions(+), 54 deletions(-) diff --git a/lemur/certificates/models.py b/lemur/certificates/models.py index 39eafd56..4729afa9 100644 --- a/lemur/certificates/models.py +++ b/lemur/certificates/models.py @@ -148,6 +148,19 @@ class Certificate(db.Model): else_=False ) + @property + def extensions(self): + # TODO pull the OU, O, CN, etc + other extensions. + names = [{'name_type': 'DNSName', 'value': x.name} for x in self.domains] + + extensions = { + 'sub_alt_names': { + 'names': names + } + } + + return extensions + def get_arn(self, account_number): """ Generate a valid AWS IAM arn diff --git a/lemur/certificates/schemas.py b/lemur/certificates/schemas.py index 036def3b..523400de 100644 --- a/lemur/certificates/schemas.py +++ b/lemur/certificates/schemas.py @@ -110,9 +110,17 @@ class CertificateNestedOutputSchema(LemurOutputSchema): chain = fields.String() description = fields.String() name = fields.String() + + # Note aliasing is the first step in deprecating these fields. cn = fields.String() + common_name = fields.String(attribute='cn') + not_after = fields.DateTime() + validity_end = ArrowDateTime(attribute='not_after') + not_before = fields.DateTime() + validity_start = ArrowDateTime(attribute='not_before') + owner = fields.Email() status = fields.Boolean() creator = fields.Nested(UserNestedOutputSchema) @@ -127,8 +135,6 @@ class CertificateCloneSchema(LemurOutputSchema): class CertificateOutputSchema(LemurOutputSchema): id = fields.Integer() - active = fields.Boolean() - notify = fields.Boolean() bits = fields.Integer() body = fields.String() chain = fields.String() @@ -136,15 +142,31 @@ class CertificateOutputSchema(LemurOutputSchema): description = fields.String() issuer = fields.String() name = fields.String() + + # Note aliasing is the first step in deprecating these fields. + notify = fields.Boolean() + active = fields.Boolean(attribute='notify') + cn = fields.String() + common_name = fields.String(attribute='cn') + not_after = fields.DateTime() + validity_end = ArrowDateTime(attribute='not_after') + not_before = fields.DateTime() + validity_start = ArrowDateTime(attribute='not_before') + owner = fields.Email() san = fields.Boolean() serial = fields.String() signing_algorithm = fields.String() + status = fields.Boolean() user = fields.Nested(UserNestedOutputSchema) + + extensions = fields.Nested(ExtensionSchema) + + # associated objects domains = fields.Nested(DomainNestedOutputSchema, many=True) destinations = fields.Nested(DestinationNestedOutputSchema, many=True) notifications = fields.Nested(NotificationNestedOutputSchema, many=True) diff --git a/lemur/static/app/angular/certificates/certificate/certificate.js b/lemur/static/app/angular/certificates/certificate/certificate.js index d7832115..104259a0 100644 --- a/lemur/static/app/angular/certificates/certificate/certificate.js +++ b/lemur/static/app/angular/certificates/certificate/certificate.js @@ -208,4 +208,131 @@ angular.module('lemur') $scope.authorityService = AuthorityService; $scope.destinationService = DestinationService; $scope.notificationService = NotificationService; + }) + +.controller('CertificateCloneController', function ($scope, $uibModalInstance, CertificateApi, CertificateService, DestinationService, AuthorityService, AuthorityApi, PluginService, MomentService, WizardHandler, LemurRestangular, NotificationService, toaster, editId) { + CertificateApi.get(editId).then(function (certificate) { + $scope.certificate = certificate; + $scope.certificate.name = ''; // we should prefer the generated name. + CertificateService.getDefaults($scope.certificate); }); + + $scope.cancel = function () { + $uibModalInstance.dismiss('cancel'); + }; + + $scope.getAuthoritiesByName = function (value) { + return AuthorityService.findAuthorityByName(value).then(function (authorities) { + $scope.authorities = authorities; + }); + }; + + $scope.dateOptions = { + formatYear: 'yy', + maxDate: new Date(2020, 5, 22), + minDate: new Date(), + startingDay: 1 + }; + + + $scope.open1 = function() { + $scope.popup1.opened = true; + }; + + $scope.open2 = function() { + $scope.popup2.opened = true; + }; + + $scope.formats = ['dd-MMMM-yyyy', 'yyyy/MM/dd', 'dd.MM.yyyy', 'shortDate']; + $scope.format = $scope.formats[0]; + $scope.altInputFormats = ['M!/d!/yyyy']; + + $scope.popup1 = { + opened: false + }; + + $scope.popup2 = { + opened: false + }; + + $scope.clearDates = function () { + $scope.certificate.validityStart = null; + $scope.certificate.validityEnd = null; + $scope.certificate.validityYears = null; + }; + + $scope.create = function (certificate) { + WizardHandler.wizard().context.loading = true; + CertificateService.create(certificate).then( + function () { + toaster.pop({ + type: 'success', + title: certificate.name, + body: 'Successfully created!' + }); + $uibModalInstance.close(); + }, + function (response) { + toaster.pop({ + type: 'error', + title: certificate.name, + body: 'lemur-bad-request', + bodyOutputType: 'directive', + directiveData: response.data, + timeout: 100000 + }); + + WizardHandler.wizard().context.loading = false; + }); + }; + + $scope.templates = [ + { + 'name': 'Client Certificate', + 'description': '', + 'extensions': { + 'basicConstraints': {}, + 'keyUsage': { + 'isCritical': true, + 'useDigitalSignature': true + }, + 'extendedKeyUsage': { + 'isCritical': true, + 'useClientAuthentication': true + }, + 'subjectKeyIdentifier': { + 'includeSKI': true + } + } + }, + { + 'name': 'Server Certificate', + 'description': '', + 'extensions' : { + 'basicConstraints': {}, + 'keyUsage': { + 'isCritical': true, + 'useKeyEncipherment': true, + 'useDigitalSignature': true + }, + 'extendedKeyUsage': { + 'isCritical': true, + 'useServerAuthentication': true + }, + 'subjectKeyIdentifier': { + 'includeSKI': true + } + } + } + ]; + + + PluginService.getByType('destination').then(function (plugins) { + $scope.plugins = plugins; + }); + + $scope.certificateService = CertificateService; + $scope.authorityService = AuthorityService; + $scope.destinationService = DestinationService; + $scope.notificationService = NotificationService; +}); diff --git a/lemur/static/app/angular/certificates/certificate/certificateWizard.tpl.html b/lemur/static/app/angular/certificates/certificate/certificateWizard.tpl.html index db69afd4..89bfa137 100644 --- a/lemur/static/app/angular/certificates/certificate/certificateWizard.tpl.html +++ b/lemur/static/app/angular/certificates/certificate/certificateWizard.tpl.html @@ -1,6 +1,6 @@