Ensuring that destinations require private keys by default. (#390)

* Ensuring that destinations require private keys by default.
This commit is contained in:
kevgliss 2016-07-04 15:30:20 -07:00 committed by GitHub
parent 4ee1c21144
commit 4077893d08
9 changed files with 35 additions and 24 deletions

View File

@ -137,6 +137,12 @@ Destination
Destination plugins allow you to propagate certificates managed by Lemur to additional third parties. This provides flexibility when
different orchestration systems have their own way of manage certificates or there is an existing system you wish to integrate with Lemur.
By default destination plugins have a private key requirement. If your plugin does not require a certificates private key mark `requires_key = False`
in the plugins base class like so::
class MyDestinationPlugin(DestinationPlugin):
requires_key = False
The DestinationPlugin requires only one function to be implemented::
def upload(self, cert, private_key, cert_chain, options, **kwargs):

View File

@ -11,6 +11,7 @@ from sqlalchemy import Column, Integer, String, Text, func, ForeignKey, DateTime
from sqlalchemy.dialects.postgresql import JSON
from lemur.database import db
from lemur.plugins.base import plugins
from lemur.models import roles_authorities
@ -38,3 +39,7 @@ class Authority(db.Model):
self.description = kwargs.get('description')
self.authority_certificate = kwargs['authority_certificate']
self.plugin_name = kwargs['plugin']['slug']
@property
def plugin(self):
return plugins.get(self.plugin_name)

View File

@ -158,6 +158,7 @@ def update_destinations(target, value, initiator):
:return:
"""
destination_plugin = plugins.get(value.plugin_name)
try:
destination_plugin.upload(target.name, target.body, target.private_key, target.chain, value.options)
except Exception as e:

View File

@ -584,6 +584,11 @@ class Certificates(AuthenticatedResource):
permission = CertificatePermission(cert.id, owner_role, [x.name for x in cert.roles])
if permission.can():
for destination in data['destinations']:
if destination.plugin.requires_key:
if not cert.private_key:
return dict('Unable to add destination: {0}. Certificate does not have required private key.'.format(destination.label))
return service.update(
certificate_id,
data['owner'],
@ -871,10 +876,13 @@ class CertificateExport(AuthenticatedResource):
plugin = data['plugin']['plugin_object']
if plugin.requires_key:
if permission.can():
extension, passphrase, data = plugin.export(cert.body, cert.chain, cert.private_key, options)
if cert.private_key:
if permission.can():
extension, passphrase, data = plugin.export(cert.body, cert.chain, cert.private_key, options)
else:
return dict(message='You are not authorized to export this certificate'), 403
else:
return dict(message='You are not authorized to export this certificate'), 403
return dict(message='Unable to export certificate, plugin: {0} requires a private key but no key was found.'.format(plugin.slug))
else:
extension, passphrase, data = plugin.export(cert.body, cert.chain, cert.private_key, options)

View File

@ -5,7 +5,6 @@
:license: Apache, see LICENSE for more details.
.. moduleauthor:: Kevin Glisson <kglisson@netflix.com>
"""
import copy
from sqlalchemy import Column, Integer, String, Text
from sqlalchemy_utils import JSONType
from lemur.database import db
@ -23,7 +22,4 @@ class Destination(db.Model):
@property
def plugin(self):
p = plugins.get(self.plugin_name)
c = copy.deepcopy(p)
c.options = self.options
return c
return plugins.get(self.plugin_name)

View File

@ -11,6 +11,7 @@ from lemur.plugins.base import Plugin
class DestinationPlugin(Plugin):
type = 'destination'
requires_key = True
def upload(self):
raise NotImplemented

View File

@ -68,19 +68,16 @@ class AWSDestinationPlugin(DestinationPlugin):
# }
def upload(self, name, body, private_key, cert_chain, options, **kwargs):
if private_key:
try:
iam.upload_cert(self.get_option('accountNumber', options), name, body, private_key,
cert_chain=cert_chain)
except BotoServerError as e:
if e.error_code != 'EntityAlreadyExists':
raise Exception(e)
try:
iam.upload_cert(self.get_option('accountNumber', options), name, body, private_key,
cert_chain=cert_chain)
except BotoServerError as e:
if e.error_code != 'EntityAlreadyExists':
raise Exception(e)
e = self.get_option('elb', options)
if e:
attach_certificate(kwargs['accountNumber'], ['region'], e['name'], e['port'], e['certificateId'])
else:
raise Exception("Unable to upload to AWS, private key is required")
e = self.get_option('elb', options)
if e:
attach_certificate(kwargs['accountNumber'], ['region'], e['name'], e['port'], e['certificateId'])
class AWSSourcePlugin(SourcePlugin):

View File

@ -236,9 +236,6 @@ class JavaKeystoreExportPlugin(ExportPlugin):
alias = "blah"
with mktemppath() as jks_tmp:
if not key:
raise Exception("Unable to export, no private key found.")
create_keystore(body, chain, jks_tmp, key, alias, passphrase)
with open(jks_tmp, 'rb') as f:

View File

@ -25,7 +25,7 @@ def test_authority_input_schema(client, role):
assert not errors
def test_user_authority(session, client, authority, role, user):
def test_user_authority(session, client, authority, role, user, issuer_plugin):
assert client.get(api.url_for(AuthoritiesList), headers=user['token']).json['total'] == 0
u = user['user']
u.roles.append(role)