San alt name (#468)

This commit is contained in:
kevgliss 2016-10-31 11:00:15 -07:00 committed by GitHub
parent f990f92977
commit 1ac1a44e83
16 changed files with 123 additions and 11 deletions

5
.pre-commit-config.yaml Normal file
View File

@ -0,0 +1,5 @@
- repo: git://github.com/pre-commit/pre-commit-hooks
sha: 18d7035de5388cc7775be57f529c154bf541aab9
hooks:
- id: trailing-whitespace
- id: flake8

View File

@ -29,6 +29,7 @@ before_script:
- psql -c "create user lemur with password 'lemur;'" -U postgres - psql -c "create user lemur with password 'lemur;'" -U postgres
- npm config set registry https://registry.npmjs.org - npm config set registry https://registry.npmjs.org
- npm install -g bower - npm install -g bower
- pip install --upgrade setuptools
script: script:
- make test - make test

View File

@ -115,6 +115,12 @@ class CertificateNestedOutputSchema(LemurOutputSchema):
issuer = fields.Nested(AuthorityNestedOutputSchema) issuer = fields.Nested(AuthorityNestedOutputSchema)
class CertificateCloneSchema(LemurOutputSchema):
__envelope__ = False
description = fields.String()
common_name = fields.String()
class CertificateOutputSchema(LemurOutputSchema): class CertificateOutputSchema(LemurOutputSchema):
id = fields.Integer() id = fields.Integer()
active = fields.Boolean() active = fields.Boolean()

View File

@ -456,3 +456,49 @@ def get_name_from_arn(arn):
:return: name of the certificate as uploaded to AWS :return: name of the certificate as uploaded to AWS
""" """
return arn.split("/", 1)[1] return arn.split("/", 1)[1]
def calculate_reissue_range(start, end):
"""
Determine what the new validity_start and validity_end dates should be.
:param start:
:param end:
:return:
"""
span = end - start
new_start = arrow.utcnow().date()
new_end = new_start + span
return new_start, new_end
# TODO pull the OU, O, CN, etc + other extensions.
def get_certificate_primitives(certificate):
"""
Retrieve key primitive from a certificate such that the certificate
could be recreated with new expiration or be used to build upon.
:param certificate:
:return: dict of certificate primitives, should be enough to effectively re-issue
certificate via `create`.
"""
start, end = calculate_reissue_range(certificate.not_before, certificate.not_after)
names = [{'name_type': 'DNSName', 'value': x.name} for x in certificate.domains]
extensions = {
'sub_alt_names': {
'names': names
}
}
return dict(
authority=certificate.authority,
common_name=certificate.cn,
description=certificate.description,
validity_start=start,
validity_end=end,
destinations=certificate.destinations,
roles=certificate.roles,
extensions=extensions,
owner=certificate.owner
)

View File

@ -890,12 +890,24 @@ class CertificateExport(AuthenticatedResource):
return dict(extension=extension, passphrase=passphrase, data=base64.b64encode(data).decode('utf-8')) return dict(extension=extension, passphrase=passphrase, data=base64.b64encode(data).decode('utf-8'))
class CertificateClone(AuthenticatedResource):
def __init__(self):
self.reqparse = reqparse.RequestParser()
super(CertificateExport, self).__init__()
@validate_schema(None, certificate_output_schema)
def get(self, certificate_id):
pass
api.add_resource(CertificatesList, '/certificates', endpoint='certificates') api.add_resource(CertificatesList, '/certificates', endpoint='certificates')
api.add_resource(Certificates, '/certificates/<int:certificate_id>', endpoint='certificate') api.add_resource(Certificates, '/certificates/<int:certificate_id>', endpoint='certificate')
api.add_resource(CertificatesStats, '/certificates/stats', endpoint='certificateStats') api.add_resource(CertificatesStats, '/certificates/stats', endpoint='certificateStats')
api.add_resource(CertificatesUpload, '/certificates/upload', endpoint='certificateUpload') api.add_resource(CertificatesUpload, '/certificates/upload', endpoint='certificateUpload')
api.add_resource(CertificatePrivateKey, '/certificates/<int:certificate_id>/key', endpoint='privateKeyCertificates') api.add_resource(CertificatePrivateKey, '/certificates/<int:certificate_id>/key', endpoint='privateKeyCertificates')
api.add_resource(CertificateExport, '/certificates/<int:certificate_id>/export', endpoint='exportCertificate') api.add_resource(CertificateExport, '/certificates/<int:certificate_id>/export', endpoint='exportCertificate')
api.add_resource(CertificateClone, '/certificates/<int:certificate_id>/clone', endpoint='cloneCertificate')
api.add_resource(NotificationCertificatesList, '/notifications/<int:notification_id>/certificates', api.add_resource(NotificationCertificatesList, '/notifications/<int:notification_id>/certificates',
endpoint='notificationCertificates') endpoint='notificationCertificates')
api.add_resource(CertificatesReplacementsList, '/certificates/<int:certificate_id>/replacements', api.add_resource(CertificatesReplacementsList, '/certificates/<int:certificate_id>/replacements',

View File

@ -24,7 +24,7 @@ def test_export_truststore_default_password(app):
actual = p.export(INTERNAL_CERTIFICATE_A_STR, "", "", options) actual = p.export(INTERNAL_CERTIFICATE_A_STR, "", "", options)
assert actual[0] == 'jks' assert actual[0] == 'jks'
assert isinstance(actual[1], str) assert isinstance(actual[1], six.string_types)
assert isinstance(actual[2], bytes) assert isinstance(actual[2], bytes)

View File

@ -220,7 +220,7 @@ class SubAltNameSchema(BaseExtensionSchema):
@validates_schema @validates_schema
def check_sensitive(self, data): def check_sensitive(self, data):
if data['name_type'] == 'DNSName': if data.get('name_type') == 'DNSName':
validators.sensitive_domain(data['value']) validators.sensitive_domain(data['value'])

View File

@ -28,7 +28,7 @@ angular.module('lemur')
} }
if (!angular.isString(this.subAltType)) { if (!angular.isString(this.subAltType)) {
this.subAltType = 'CNAME'; this.subAltType = 'DNSName';
} }
if (angular.isString(this.subAltValue) && angular.isString(this.subAltType)) { if (angular.isString(this.subAltValue) && angular.isString(this.subAltType)) {

View File

@ -107,7 +107,9 @@ def notification(session):
@pytest.fixture @pytest.fixture
def certificate(session): def certificate(session):
c = CertificateFactory() u = UserFactory()
a = AuthorityFactory()
c = CertificateFactory(user=u, authority=a)
session.commit() session.commit()
return c return c

View File

@ -1,7 +1,10 @@
from __future__ import unicode_literals # at top of module from __future__ import unicode_literals # at top of module
import pytest
import json import json
import pytest
import datetime
from freezegun import freeze_time
from lemur.certificates.views import * # noqa from lemur.certificates.views import * # noqa
@ -9,6 +12,32 @@ from lemur.tests.vectors import VALID_ADMIN_HEADER_TOKEN, VALID_USER_HEADER_TOKE
INTERNAL_VALID_LONG_STR, INTERNAL_VALID_SAN_STR, PRIVATE_KEY_STR INTERNAL_VALID_LONG_STR, INTERNAL_VALID_SAN_STR, PRIVATE_KEY_STR
def test_get_certificate_primitives(certificate):
from lemur.certificates.service import get_certificate_primitives
names = [{'name_type': 'DNSName', 'value': x.name} for x in certificate.domains]
data = {
'common_name': certificate.cn,
'owner': certificate.owner,
'authority': certificate.authority,
'description': certificate.description,
'extensions': {
'sub_alt_names': {
'names': names
}
},
'destinations': [],
'roles': [],
'validity_end': datetime.date(year=2021, month=5, day=7),
'validity_start': datetime.date(year=2016, month=10, day=30)
}
with freeze_time(datetime.date(year=2016, month=10, day=30)):
primitives = get_certificate_primitives(certificate)
assert data == primitives
def test_certificate_edit_schema(session): def test_certificate_edit_schema(session):
from lemur.certificates.schemas import CertificateEditInputSchema from lemur.certificates.schemas import CertificateEditInputSchema
@ -203,7 +232,7 @@ def test_certificate_valid_dates(client, authority):
assert not errors assert not errors
def test_sub_alt_name_schema(): def test_sub_alt_name_schema(session):
from lemur.schemas import SubAltNameSchema, SubAltNamesSchema from lemur.schemas import SubAltNameSchema, SubAltNamesSchema
input_data = {'nameType': 'DNSName', 'value': 'test.example.com'} input_data = {'nameType': 'DNSName', 'value': 'test.example.com'}
@ -212,7 +241,6 @@ def test_sub_alt_name_schema():
assert data == {'name_type': 'DNSName', 'value': 'test.example.com'} assert data == {'name_type': 'DNSName', 'value': 'test.example.com'}
data, errors = SubAltNameSchema().dumps(data) data, errors = SubAltNameSchema().dumps(data)
assert data == json.dumps(input_data)
assert not errors assert not errors
input_datas = {'names': [input_data]} input_datas = {'names': [input_data]}
@ -225,6 +253,10 @@ def test_sub_alt_name_schema():
assert data == json.dumps(input_datas) assert data == json.dumps(input_datas)
assert not errors assert not errors
input_data = {'nameType': 'CNAME', 'value': 'test.example.com'}
data, errors = SubAltNameSchema().load(input_data)
assert errors
def test_key_usage_schema(): def test_key_usage_schema():
from lemur.schemas import KeyUsageSchema from lemur.schemas import KeyUsageSchema

View File

@ -14,6 +14,13 @@ def test_private_key(session):
private_key('invalid_private_key') private_key('invalid_private_key')
def test_sub_alt_type(session):
from lemur.common.validators import sub_alt_type
with pytest.raises(ValidationError):
sub_alt_type('CNAME')
def test_dates(session): def test_dates(session):
from lemur.common.validators import dates from lemur.common.validators import dates

View File

@ -84,6 +84,7 @@ docs_require = [
dev_requires = [ dev_requires = [
'flake8>=2.0,<3.0', 'flake8>=2.0,<3.0',
'pre-commit',
'invoke', 'invoke',
'twine' 'twine'
] ]