Authorities marshmallow addition (#303)

This commit is contained in:
kevgliss 2016-05-09 11:00:16 -07:00
parent 776e0fcd11
commit df0ad4d875
19 changed files with 619 additions and 529 deletions

View File

@ -0,0 +1,79 @@
"""
.. module: lemur.authorities.schemas
:platform: unix
:copyright: (c) 2015 by Netflix Inc., see AUTHORS for more
:license: Apache, see LICENSE for more details.
.. moduleauthor:: Kevin Glisson <kglisson@netflix.com>
"""
from flask import current_app
from marshmallow import fields, validates_schema
from marshmallow import validate
from marshmallow.exceptions import ValidationError
from lemur.schemas import PluginSchema, ExtensionSchema, AssociatedAuthoritySchema, AssociatedRoleSchema
from lemur.common.schema import LemurInputSchema, LemurOutputSchema
from lemur.common import validators
class AuthorityInputSchema(LemurInputSchema):
name = fields.String(required=True)
owner = fields.Email(required=True)
description = fields.String()
common_name = fields.String(required=True, validate=validators.sensitive_domain)
validity_start = fields.DateTime()
validity_end = fields.DateTime()
validity_years = fields.Integer()
# certificate body fields
organizational_unit = fields.String(missing=lambda: current_app.config.get('LEMUR_DEFAULT_ORGANIZATIONAL_UNIT'))
organization = fields.String(missing=lambda: current_app.config.get('LEMUR_DEFAULT_ORGANIZATION'))
location = fields.String(missing=lambda: current_app.config.get('LEMUR_DEFAULT_LOCATION'))
country = fields.String(missing=lambda: current_app.config.get('LEMUR_DEFAULT_COUNTRY'))
state = fields.String(missing=lambda: current_app.config.get('LEMUR_DEFAULT_STATE'))
plugin = fields.Nested(PluginSchema)
# signing related options
type = fields.String(validate=validate.OneOf(['root', 'subca']), missing='root')
authority = fields.Nested(AssociatedAuthoritySchema)
signing_algorithm = fields.String(validate=validate.OneOf(['sha256WithRSA', 'sha1WithRSA']), missing='sha256WithRSA')
key_type = fields.String(validate=validate.OneOf(['RSA2048', 'RSA4096']), missing='RSA2048')
key_name = fields.String()
sensitivity = fields.String(validate=validate.OneOf(['medium', 'high']), missing='medium')
serial_number = fields.Integer()
first_serial = fields.Integer(missing=1)
extensions = fields.Nested(ExtensionSchema)
roles = fields.Nested(AssociatedRoleSchema(many=True))
@validates_schema
def validate_dates(self, data):
validators.dates(data)
@validates_schema
def validate_subca(self, data):
if data['type'] == 'subca':
if not data.get('authority'):
raise ValidationError("If generating a subca parent 'authority' must be specified.")
class AuthorityOutputSchema(LemurOutputSchema):
id = fields.Integer()
name = fields.String()
owner = fields.Email()
not_before = fields.DateTime()
not_after = fields.DateTime()
plugin_name = fields.String()
body = fields.String()
chain = fields.String()
active = fields.Boolean()
options = fields.Dict()
roles = fields.List(fields.Nested(AssociatedRoleSchema))
authority_input_schema = AuthorityInputSchema()
authority_output_schema = AuthorityOutputSchema()
authorities_output_schema = AuthorityOutputSchema(many=True)

View File

@ -19,8 +19,6 @@ from lemur.notifications import service as notification_service
from lemur.roles.models import Role
from lemur.certificates.models import Certificate
from lemur.plugins.base import plugins
def update(authority_id, description=None, owner=None, active=None, roles=None):
"""
@ -49,20 +47,20 @@ def create(kwargs):
:return:
"""
issuer = plugins.get(kwargs.get('pluginName'))
issuer = kwargs['plugin']
kwargs['creator'] = g.current_user.email
cert_body, intermediate, issuer_roles = issuer.create_authority(kwargs)
cert = Certificate(cert_body, chain=intermediate)
cert.owner = kwargs['ownerEmail']
cert.owner = kwargs['owner']
if kwargs['caType'] == 'subca':
if kwargs['type'] == 'subca':
cert.description = "This is the ROOT certificate for the {0} sub certificate authority the parent \
authority is {1}.".format(kwargs.get('caName'), kwargs.get('caParent'))
authority is {1}.".format(kwargs.get('name'), kwargs.get('parent'))
else:
cert.description = "This is the ROOT certificate for the {0} certificate authority.".format(
kwargs.get('caName')
kwargs.get('name')
)
cert.user = g.current_user
@ -79,7 +77,7 @@ def create(kwargs):
role = role_service.create(
r['name'],
password=r['password'],
description="{0} auto generated role".format(kwargs.get('pluginName')),
description="{0} auto generated role".format(kwargs['plugin'].title),
username=r['username'])
# the user creating the authority should be able to administer it
@ -89,11 +87,11 @@ def create(kwargs):
role_objs.append(role)
authority = Authority(
kwargs.get('caName'),
kwargs['ownerEmail'],
kwargs['pluginName'],
kwargs.get('name'),
kwargs['owner'],
kwargs['plugin'].slug,
cert_body,
description=kwargs['caDescription'],
description=kwargs['description'],
chain=intermediate,
roles=role_objs
)
@ -102,10 +100,10 @@ def create(kwargs):
authority = database.create(authority)
# the owning dl or role should have this authority associated with it
owner_role = role_service.get_by_name(kwargs['ownerEmail'])
owner_role = role_service.get_by_name(kwargs['owner'])
if not owner_role:
owner_role = role_service.create(kwargs['ownerEmail'])
owner_role = role_service.create(kwargs['owner'])
owner_role.authority = authority
@ -170,10 +168,6 @@ def render(args):
:return:
"""
query = database.session_query(Authority)
sort_by = args.pop('sort_by')
sort_dir = args.pop('sort_dir')
page = args.pop('page')
count = args.pop('count')
filt = args.pop('filter')
if filt:
@ -191,9 +185,4 @@ def render(args):
authority_ids.append(role.authority.id)
query = query.filter(Authority.id.in_(authority_ids))
query = database.find_all(query, Authority, args)
if sort_by and sort_dir:
query = database.sort(query, Authority, sort_by, sort_dir)
return database.paginate(query, page, count)
return database.sort_and_page(query, Authority, args)

View File

@ -6,31 +6,19 @@
.. moduleauthor:: Kevin Glisson <kglisson@netflix.com>
"""
from flask import Blueprint, g
from flask.ext.restful import reqparse, fields, Api
from flask.ext.restful import reqparse, Api
from lemur.authorities import service
from lemur.roles import service as role_service
from lemur.certificates import service as certificate_service
from lemur.common.utils import paginated_parser
from lemur.common.schema import validate_schema
from lemur.auth.service import AuthenticatedResource
from lemur.auth.permissions import AuthorityPermission
from lemur.common.utils import paginated_parser, marshal_items
from lemur.roles import service as role_service
from lemur.certificates import service as certificate_service
from lemur.authorities import service
from lemur.authorities.schemas import authority_input_schema, authority_output_schema, authorities_output_schema
FIELDS = {
'name': fields.String,
'owner': fields.String,
'description': fields.String,
'options': fields.Raw,
'pluginName': fields.String,
'body': fields.String,
'chain': fields.String,
'active': fields.Boolean,
'notBefore': fields.DateTime(dt_format='iso8601', attribute='not_before'),
'notAfter': fields.DateTime(dt_format='iso8601', attribute='not_after'),
'id': fields.Integer,
}
mod = Blueprint('authorities', __name__)
api = Api(mod)
@ -42,7 +30,7 @@ class AuthoritiesList(AuthenticatedResource):
self.reqparse = reqparse.RequestParser()
super(AuthoritiesList, self).__init__()
@marshal_items(FIELDS)
@validate_schema(None, authorities_output_schema)
def get(self):
"""
.. http:get:: /authorities
@ -98,8 +86,8 @@ class AuthoritiesList(AuthenticatedResource):
args = parser.parse_args()
return service.render(args)
@marshal_items(FIELDS)
def post(self):
@validate_schema(authority_input_schema, authority_output_schema)
def post(self, data=None):
"""
.. http:post:: /authorities
@ -180,25 +168,7 @@ class AuthoritiesList(AuthenticatedResource):
:statuscode 403: unauthenticated
:statuscode 200: no error
"""
self.reqparse.add_argument('caName', type=str, location='json', required=True)
self.reqparse.add_argument('caDescription', type=str, location='json', required=False)
self.reqparse.add_argument('ownerEmail', type=str, location='json', required=True)
self.reqparse.add_argument('caDN', type=dict, location='json', required=False)
self.reqparse.add_argument('validityStart', type=str, location='json', required=False) # TODO validate
self.reqparse.add_argument('validityEnd', type=str, location='json', required=False) # TODO validate
self.reqparse.add_argument('extensions', type=dict, location='json', required=False)
self.reqparse.add_argument('pluginName', type=str, location='json', required=True)
self.reqparse.add_argument('caType', type=str, location='json', required=False)
self.reqparse.add_argument('caParent', type=str, location='json', required=False)
self.reqparse.add_argument('caSigningAlgo', type=str, location='json', required=False)
self.reqparse.add_argument('keyType', type=str, location='json', required=False)
self.reqparse.add_argument('caSensitivity', type=str, location='json', required=False)
self.reqparse.add_argument('caKeyName', type=str, location='json', required=False)
self.reqparse.add_argument('caSerialNumber', type=int, location='json', required=False)
self.reqparse.add_argument('caFirstSerial', type=int, location='json', required=False)
args = self.reqparse.parse_args()
return service.create(args)
return service.create(data)
class Authorities(AuthenticatedResource):
@ -206,7 +176,7 @@ class Authorities(AuthenticatedResource):
self.reqparse = reqparse.RequestParser()
super(Authorities, self).__init__()
@marshal_items(FIELDS)
@validate_schema(None, authority_output_schema)
def get(self, authority_id):
"""
.. http:get:: /authorities/1
@ -248,8 +218,8 @@ class Authorities(AuthenticatedResource):
"""
return service.get(authority_id)
@marshal_items(FIELDS)
def put(self, authority_id):
@validate_schema(authority_input_schema, authority_output_schema)
def put(self, authority_id, data=None):
"""
.. http:put:: /authorities/1
@ -295,12 +265,6 @@ class Authorities(AuthenticatedResource):
:statuscode 200: no error
:statuscode 403: unauthenticated
"""
self.reqparse.add_argument('roles', type=list, default=[], location='json')
self.reqparse.add_argument('active', type=str, location='json', required=True)
self.reqparse.add_argument('owner', type=str, location='json', required=True)
self.reqparse.add_argument('description', type=str, location='json', required=True)
args = self.reqparse.parse_args()
authority = service.get(authority_id)
role = role_service.get_by_name(authority.owner)
@ -313,7 +277,7 @@ class Authorities(AuthenticatedResource):
# we want to make sure that we cannot add roles that we are not members of
if not g.current_user.is_admin:
role_ids = set([r['id'] for r in args['roles']])
role_ids = set([r['id'] for r in data['roles']])
user_role_ids = set([r.id for r in g.current_user.roles])
if not role_ids.issubset(user_role_ids):
@ -322,10 +286,10 @@ class Authorities(AuthenticatedResource):
if permission.can():
return service.update(
authority_id,
owner=args['owner'],
description=args['description'],
active=args['active'],
roles=args['roles']
owner=data['owner'],
description=data['description'],
active=data['active'],
roles=data['roles']
)
return dict(message="You are not authorized to update this authority"), 403
@ -333,10 +297,9 @@ class Authorities(AuthenticatedResource):
class CertificateAuthority(AuthenticatedResource):
def __init__(self):
self.reqparse = reqparse.RequestParser()
super(CertificateAuthority, self).__init__()
@marshal_items(FIELDS)
@validate_schema(None, authority_output_schema)
def get(self, certificate_id):
"""
.. http:get:: /certificates/1/authority

View File

@ -7,197 +7,20 @@
"""
from flask import current_app
import arrow
from marshmallow import fields, validates_schema, pre_load, post_dump
from marshmallow import fields, validates_schema
from marshmallow.exceptions import ValidationError
from cryptography import x509
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives import serialization
from lemur.auth.permissions import SensitiveDomainPermission
from lemur.schemas import AssociatedAuthoritySchema, AssociatedDestinationSchema, AssociatedCertificateSchema, \
AssociatedNotificationSchema, PluginSchema
from lemur.common.schema import LemurInputSchema, LemurOutputSchema, LemurSchema
from lemur.domains import service as domain_service
def validate_public_certificate(body):
"""
Determines if specified string is valid public certificate.
:param body:
:return:
"""
try:
x509.load_pem_x509_certificate(bytes(body), default_backend())
except Exception:
raise ValidationError('Public certificate presented is not valid.')
def validate_private_key(key):
"""
User to validate that a given string is a RSA private key
:param key:
:return: :raise ValueError:
"""
try:
serialization.load_pem_private_key(bytes(key), None, backend=default_backend())
except Exception:
raise ValidationError('Private key presented is not valid.')
def validate_domain(domain):
"""
Determines if domain has been marked as sensitive.
:param domain:
:return:
"""
domains = domain_service.get_by_name(domain)
for domain in domains:
# we only care about non-admins
if not SensitiveDomainPermission().can():
if domain.sensitive:
raise ValidationError(
'Domain {0} has been marked as sensitive, contact and administrator \
to issue the certificate.'.format(domain))
def validate_oid_type(oid_type):
"""
Determines if the specified oid type is valid.
:param oid_type:
:return:
"""
valid_types = ['b64asn1', 'string', 'ia5string']
if oid_type.lower() not in [o_type.lower() for o_type in valid_types]:
raise ValidationError('Invalid Oid Type: {0} choose from {1}'.format(oid_type, ",".join(valid_types)))
def validate_sub_alt_type(alt_type):
"""
Determines if the specified subject alternate type is valid.
:param alt_type:
:return:
"""
valid_types = ['DNSName', 'IPAddress', 'uniFormResourceIdentifier', 'directoryName', 'rfc822Name', 'registrationID',
'otherName', 'x400Address', 'EDIPartyName']
if alt_type.lower() not in [a_type.lower() for a_type in valid_types]:
raise ValidationError('Invalid SubAltName Type: {0} choose from {1}'.format(type, ",".join(valid_types)))
def validate_csr(data):
"""
Determines if the CSR is valid.
:param data:
:return:
"""
try:
x509.load_pem_x509_csr(bytes(data), default_backend())
except Exception:
raise ValidationError('CSR presented is not valid.')
class BaseExtensionSchema(LemurSchema):
@pre_load(pass_many=True)
def preprocess(self, data, many):
return self.under(data, many=many)
@post_dump(pass_many=True)
def post_process(self, data, many):
if data:
data = self.camel(data, many=many)
return data
class BasicConstraintsSchema(BaseExtensionSchema):
pass
class AuthorityIdentifierSchema(BaseExtensionSchema):
use_authority_cert = fields.Boolean()
class AuthorityKeyIdentifierSchema(BaseExtensionSchema):
use_key_identifier = fields.Boolean()
class CertificateInfoAccessSchema(BaseExtensionSchema):
include_aia = fields.Boolean()
@post_dump
def handle_keys(self, data):
return {'includeAIA': data['include_aia']}
class KeyUsageSchema(BaseExtensionSchema):
use_crl_sign = fields.Boolean()
use_data_encipherment = fields.Boolean()
use_decipher_only = fields.Boolean()
use_encipher_only = fields.Boolean()
use_key_encipherment = fields.Boolean()
use_digital_signature = fields.Boolean()
use_non_repudiation = fields.Boolean()
class ExtendedKeyUsageSchema(BaseExtensionSchema):
use_server_authentication = fields.Boolean()
use_client_authentication = fields.Boolean()
use_eap_over_lan = fields.Boolean()
use_eap_over_ppp = fields.Boolean()
use_ocsp_signing = fields.Boolean()
use_smart_card_authentication = fields.Boolean()
use_timestamping = fields.Boolean()
class SubjectKeyIdentifierSchema(BaseExtensionSchema):
include_ski = fields.Boolean()
@post_dump
def handle_keys(self, data):
return {'includeSKI': data['include_ski']}
class SubAltNameSchema(BaseExtensionSchema):
name_type = fields.String(validate=validate_sub_alt_type)
value = fields.String()
@validates_schema
def check_sensitive(self, data):
if data['name_type'] == 'DNSName':
validate_domain(data['value'])
class SubAltNamesSchema(BaseExtensionSchema):
names = fields.Nested(SubAltNameSchema, many=True)
class CustomOIDSchema(BaseExtensionSchema):
oid = fields.String()
oid_type = fields.String(validate=validate_oid_type)
value = fields.String()
class ExtensionSchema(BaseExtensionSchema):
basic_constraints = fields.Nested(BasicConstraintsSchema)
key_usage = fields.Nested(KeyUsageSchema)
extended_key_usage = fields.Nested(ExtendedKeyUsageSchema)
subject_key_identifier = fields.Nested(SubjectKeyIdentifierSchema)
sub_alt_names = fields.Nested(SubAltNamesSchema)
authority_identifier = fields.Nested(AuthorityIdentifierSchema)
authority_key_identifier = fields.Nested(AuthorityKeyIdentifierSchema)
certificate_info_access = fields.Nested(CertificateInfoAccessSchema)
custom = fields.List(fields.Nested(CustomOIDSchema))
AssociatedNotificationSchema, PluginSchema, ExtensionSchema
from lemur.common.schema import LemurInputSchema, LemurOutputSchema
from lemur.common import validators
class CertificateInputSchema(LemurInputSchema):
name = fields.String()
owner = fields.Email(required=True)
description = fields.String()
common_name = fields.String(required=True, validate=validate_domain)
common_name = fields.String(required=True, validate=validators.sensitive_domain)
authority = fields.Nested(AssociatedAuthoritySchema, required=True)
validity_start = fields.DateTime()
@ -208,7 +31,7 @@ class CertificateInputSchema(LemurInputSchema):
notifications = fields.Nested(AssociatedNotificationSchema, missing=[], many=True)
replacements = fields.Nested(AssociatedCertificateSchema, missing=[], many=True)
csr = fields.String(validate=validate_csr)
csr = fields.String(validate=validators.csr)
# certificate body fields
organizational_unit = fields.String(missing=lambda: current_app.config.get('LEMUR_DEFAULT_ORGANIZATIONAL_UNIT'))
@ -221,34 +44,7 @@ class CertificateInputSchema(LemurInputSchema):
@validates_schema
def validate_dates(self, data):
if not data.get('validity_start') and data.get('validity_end'):
raise ValidationError('If validity start is specified so must validity end.')
if not data.get('validity_end') and data.get('validity_start'):
raise ValidationError('If validity end is specified so must validity start.')
if data.get('validity_end') and data.get('validity_years'):
raise ValidationError('Cannot specify both validity end and validity years.')
if data.get('validity_start') and data.get('validity_end'):
if not data['validity_start'] < data['validity_end']:
raise ValidationError('Validity start must be before validity end.')
if data.get('validity_start').replace(tzinfo=None) < data['authority'].not_before:
raise ValidationError('Validity start must not be before {0}'.format(data['authority'].not_before))
if data.get('validity_end').replace(tzinfo=None) > data['authority'].not_after:
raise ValidationError('Validity end must not be after {0}'.format(data['authority'].not_after))
if data.get('validity_years'):
now = arrow.utcnow()
end = now.replace(years=+data['validity_years'])
if now.naive < data['authority'].not_before:
raise ValidationError('Validity start must not be before {0}'.format(data['authority'].not_before))
if end.naive > data['authority'].not_after:
raise ValidationError('Validity end must not be after {0}'.format(data['authority'].not_after))
validators.dates(data)
class CertificateOutputSchema(LemurOutputSchema):
@ -276,9 +72,9 @@ class CertificateUploadInputSchema(LemurInputSchema):
description = fields.String()
active = fields.Boolean(missing=True)
private_key = fields.String(validate=validate_private_key)
public_cert = fields.String(required=True, validate=validate_public_certificate)
chain = fields.String(validate=validate_public_certificate)
private_key = fields.String(validate=validators.private_key)
public_cert = fields.String(required=True, validate=validators.public_certificate)
chain = fields.String(validate=validators.public_certificate) # TODO this could be multiple certificates
destinations = fields.Nested(AssociatedDestinationSchema, missing=[], many=True)
notifications = fields.Nested(AssociatedNotificationSchema, missing=[], many=True)

View File

@ -253,7 +253,7 @@ def create(**kwargs):
cert.name = kwargs['name']
database.create(cert)
cert.description = kwargs['description']
cert.description = kwargs.get('description')
g.user.certificates.append(cert)
database.update(g.user)

120
lemur/common/validators.py Normal file
View File

@ -0,0 +1,120 @@
import arrow
from marshmallow.exceptions import ValidationError
from cryptography import x509
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives import serialization
from lemur.domains import service as domain_service
from lemur.auth.permissions import SensitiveDomainPermission
def public_certificate(body):
"""
Determines if specified string is valid public certificate.
:param body:
:return:
"""
try:
x509.load_pem_x509_certificate(bytes(body), default_backend())
except Exception:
raise ValidationError('Public certificate presented is not valid.')
def private_key(key):
"""
User to validate that a given string is a RSA private key
:param key:
:return: :raise ValueError:
"""
try:
serialization.load_pem_private_key(bytes(key), None, backend=default_backend())
except Exception:
raise ValidationError('Private key presented is not valid.')
def sensitive_domain(domain):
"""
Determines if domain has been marked as sensitive.
:param domain:
:return:
"""
domains = domain_service.get_by_name(domain)
for domain in domains:
# we only care about non-admins
if not SensitiveDomainPermission().can():
if domain.sensitive:
raise ValidationError(
'Domain {0} has been marked as sensitive, contact and administrator \
to issue the certificate.'.format(domain))
def oid_type(oid_type):
"""
Determines if the specified oid type is valid.
:param oid_type:
:return:
"""
valid_types = ['b64asn1', 'string', 'ia5string']
if oid_type.lower() not in [o_type.lower() for o_type in valid_types]:
raise ValidationError('Invalid Oid Type: {0} choose from {1}'.format(oid_type, ",".join(valid_types)))
def sub_alt_type(alt_type):
"""
Determines if the specified subject alternate type is valid.
:param alt_type:
:return:
"""
valid_types = ['DNSName', 'IPAddress', 'uniFormResourceIdentifier', 'directoryName', 'rfc822Name', 'registrationID',
'otherName', 'x400Address', 'EDIPartyName']
if alt_type.lower() not in [a_type.lower() for a_type in valid_types]:
raise ValidationError('Invalid SubAltName Type: {0} choose from {1}'.format(type, ",".join(valid_types)))
def csr(data):
"""
Determines if the CSR is valid.
:param data:
:return:
"""
try:
x509.load_pem_x509_csr(bytes(data), default_backend())
except Exception:
raise ValidationError('CSR presented is not valid.')
def dates(data):
if not data.get('validity_start') and data.get('validity_end'):
raise ValidationError('If validity start is specified so must validity end.')
if not data.get('validity_end') and data.get('validity_start'):
raise ValidationError('If validity end is specified so must validity start.')
if data.get('validity_end') and data.get('validity_years'):
raise ValidationError('Cannot specify both validity end and validity years.')
if data.get('validity_start') and data.get('validity_end'):
if not data['validity_start'] < data['validity_end']:
raise ValidationError('Validity start must be before validity end.')
if data.get('authority'):
if data.get('validity_start').replace(tzinfo=None) < data['authority'].not_before:
raise ValidationError('Validity start must not be before {0}'.format(data['authority'].not_before))
if data.get('validity_end').replace(tzinfo=None) > data['authority'].not_after:
raise ValidationError('Validity end must not be after {0}'.format(data['authority'].not_after))
if data.get('validity_years'):
now = arrow.utcnow()
end = now.replace(years=+data['validity_years'])
if data.get('authority'):
if now.naive < data['authority'].not_before:
raise ValidationError('Validity start must not be before {0}'.format(data['authority'].not_before))
if end.naive > data['authority'].not_after:
raise ValidationError('Validity end must not be after {0}'.format(data['authority'].not_after))

View File

@ -289,5 +289,7 @@ def sort_and_page(query, model, args):
total = query.count()
# offset calculated at zero
page -= 1
items = query.offset(count * page).limit(count).all()
return dict(items=items, total=total)

View File

@ -7,26 +7,48 @@
.. moduleauthor:: Kevin Glisson <kglisson@netflix.com>
"""
from marshmallow import fields, post_load
from marshmallow import fields, post_load, pre_load, post_dump, validates_schema
from lemur.roles.models import Role
from lemur.authorities.models import Authority
from lemur.destinations.models import Destination
from lemur.certificates.models import Certificate
from lemur.notifications.models import Notification
from lemur.common.schema import LemurInputSchema
from lemur.common import validators
from lemur.common.schema import LemurSchema, LemurInputSchema
from lemur.plugins import plugins
class AssociatedAuthoritySchema(LemurInputSchema):
id = fields.Int(required=True)
id = fields.Int()
name = fields.String()
@post_load
def get_object(self, data, many=False):
return Authority.query.filter(Authority.id == data['id']).one()
if data.get('id'):
return Authority.query.filter(Authority.id == data['id']).one()
elif data.get('name'):
return Authority.query.filter(Authority.name == data['name']).one()
class AssociatedRoleSchema(LemurInputSchema):
id = fields.Int(required=True)
name = fields.String()
@post_load
def get_object(self, data, many=False):
if many:
ids = [d['id'] for d in data]
return Role.query.filter(Role.id.in_(ids)).all()
else:
return Role.query.filter(Role.id == data['id']).one()
class AssociatedDestinationSchema(LemurInputSchema):
id = fields.Int(required=True)
name = fields.String()
@post_load
def get_object(self, data, many=False):
@ -71,3 +93,95 @@ class PluginSchema(LemurInputSchema):
return [plugins.get(plugin['slug']) for plugin in data]
else:
return plugins.get(data['slug'])
class BaseExtensionSchema(LemurSchema):
@pre_load(pass_many=True)
def preprocess(self, data, many):
return self.under(data, many=many)
@post_dump(pass_many=True)
def post_process(self, data, many):
if data:
data = self.camel(data, many=many)
return data
class BasicConstraintsSchema(BaseExtensionSchema):
pass
class AuthorityIdentifierSchema(BaseExtensionSchema):
use_authority_cert = fields.Boolean()
class AuthorityKeyIdentifierSchema(BaseExtensionSchema):
use_key_identifier = fields.Boolean()
class CertificateInfoAccessSchema(BaseExtensionSchema):
include_aia = fields.Boolean()
@post_dump
def handle_keys(self, data):
return {'includeAIA': data['include_aia']}
class KeyUsageSchema(BaseExtensionSchema):
use_crl_sign = fields.Boolean()
use_data_encipherment = fields.Boolean()
use_decipher_only = fields.Boolean()
use_encipher_only = fields.Boolean()
use_key_encipherment = fields.Boolean()
use_digital_signature = fields.Boolean()
use_non_repudiation = fields.Boolean()
class ExtendedKeyUsageSchema(BaseExtensionSchema):
use_server_authentication = fields.Boolean()
use_client_authentication = fields.Boolean()
use_eap_over_lan = fields.Boolean()
use_eap_over_ppp = fields.Boolean()
use_ocsp_signing = fields.Boolean()
use_smart_card_authentication = fields.Boolean()
use_timestamping = fields.Boolean()
class SubjectKeyIdentifierSchema(BaseExtensionSchema):
include_ski = fields.Boolean()
@post_dump
def handle_keys(self, data):
return {'includeSKI': data['include_ski']}
class SubAltNameSchema(BaseExtensionSchema):
name_type = fields.String(validate=validators.sub_alt_type)
value = fields.String()
@validates_schema
def check_sensitive(self, data):
if data['name_type'] == 'DNSName':
validators.sensitive_domain(data['value'])
class SubAltNamesSchema(BaseExtensionSchema):
names = fields.Nested(SubAltNameSchema, many=True)
class CustomOIDSchema(BaseExtensionSchema):
oid = fields.String()
oid_type = fields.String(validate=validators.oid_type)
value = fields.String()
class ExtensionSchema(BaseExtensionSchema):
basic_constraints = fields.Nested(BasicConstraintsSchema)
key_usage = fields.Nested(KeyUsageSchema)
extended_key_usage = fields.Nested(ExtendedKeyUsageSchema)
subject_key_identifier = fields.Nested(SubjectKeyIdentifierSchema)
sub_alt_names = fields.Nested(SubAltNamesSchema)
authority_identifier = fields.Nested(AuthorityIdentifierSchema)
authority_key_identifier = fields.Nested(AuthorityKeyIdentifierSchema)
certificate_info_access = fields.Nested(CertificateInfoAccessSchema)
custom = fields.List(fields.Nested(CustomOIDSchema))

View File

@ -4,7 +4,6 @@ angular.module('lemur')
.controller('AuthorityEditController', function ($scope, $modalInstance, AuthorityApi, AuthorityService, RoleService, toaster, editId){
AuthorityApi.get(editId).then(function (authority) {
AuthorityService.getRoles(authority);
$scope.authority = authority;
});
@ -69,6 +68,7 @@ angular.module('lemur')
PluginService.getByType('issuer').then(function (plugins) {
$scope.plugins = plugins;
$scope.authority.plugin = plugins[0];
});
$scope.roleService = RoleService;

View File

@ -6,7 +6,7 @@
Country
</label>
<div class="col-sm-10">
<input name="country" ng-model="authority.caDN.country" placeholder="Country" class="form-control" ng-init="authority.caDN.country = 'US'" required/>
<input name="country" ng-model="authority.country" placeholder="Country" class="form-control" required/>
<p ng-show="dnForm.country.$invalid && !dnForm.country.$pristine" class="help-block">You must enter a country</p>
</div>
</div>
@ -16,7 +16,7 @@
State
</label>
<div class="col-sm-10">
<input name="state" ng-model="authority.caDN.state" placeholder="State" class="form-control" ng-init="authority.caDN.state = 'CA'" required/>
<input name="state" ng-model="authority.state" placeholder="State" class="form-control" required/>
<p ng-show="dnForm.state.$invalid && !dnForm.state.$pristine" class="help-block">You must enter a state</p>
</div>
</div>
@ -26,7 +26,7 @@
Location
</label>
<div class="col-sm-10">
<input name="location" ng-model="authority.caDN.location" placeholder="Location" class="form-control" ng-init="authority.caDN.location = 'Los Gatos'"required/>
<input name="location" ng-model="authority.location" placeholder="Location" class="form-control" required/>
<p ng-show="dnForm.location.$invalid && !dnForm.location.$pristine" class="help-block">You must enter a location</p>
</div>
</div>
@ -36,7 +36,7 @@
Organization
</label>
<div class="col-sm-10">
<input name="organization" ng-model="authority.caDN.organization" placeholder="Organization" class="form-control" ng-init="authority.caDN.organization = 'Netflix'" required/>
<input name="organization" ng-model="authority.organization" placeholder="Organization" class="form-control" ng-init="authority.organization = 'Netflix'" required/>
<p ng-show="dnForm.organization.$invalid && !dnForm.organization.$pristine" class="help-block">You must enter a organization</p>
</div>
</div>
@ -46,7 +46,7 @@
Organizational Unit
</label>
<div class="col-sm-10">
<input name="organizationalUnit" ng-model="authority.caDN.organizationalUnit" placeholder="Organizational Unit" class="form-control" ng-init="authority.caDN.organizationalUnit = 'Operations'"required/>
<input name="organizationalUnit" ng-model="authority.organizationalUnit" placeholder="Organizational Unit" class="form-control" required/>
<p ng-show="dnForm.organization.$invalid && !dnForm.organizationalUnit.$pristine" class="help-block">You must enter a organizational unit</p>
</div>
</div>

View File

@ -1,30 +1,10 @@
<div class="form-horizontal">
<div class="form-group">
<label class="control-label col-sm-2">
Type
</label>
<div class="col-sm-10">
<select class="form-control" ng-model="authority.caType" ng-options="option for option in ['root', 'subca']" ng-init="authority.caType = 'root'"required></select>
</div>
</div>
<div ng-show="authority.caType == 'subca'" class="form-group">
<label class="control-label col-sm-2">
Parent Authority
</label>
<div class="col-sm-10">
<input type="text" ng-model="authority.caParent" placeholder="Parent Authority Name"
typeahead="authority.name for authority in authorityService.findAuthorityByName($viewValue)" typeahead-loading="loadingAuthorities"
class="form-control input-md" typeahead-min-wait="50"
tooltip="When you specify a subordinate certificate authority you must specific the parent authority"
tooltip-trigger="focus" tooltip-placement="top">
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2">
Signing Algorithm
</label>
<div class="col-sm-10">
<select class="form-control" ng-model="authority.caSigningAlgo" ng-options="option for option in ['sha1WithRSA', 'sha256WithRSA']" ng-init="authority.caSigningAlgo = 'sha256WithRSA'"></select>
<select class="form-control" ng-model="authority.signingAlgorithm" ng-options="option for option in ['sha1WithRSA', 'sha256WithRSA']" ng-init="authority.signingAlgorithm = 'sha256WithRSA'"></select>
</div>
</div>
<div class="form-group">
@ -32,7 +12,7 @@
Sensitivity
</label>
<div class="col-sm-10">
<select class="form-control" ng-model="authority.caSensitivity" ng-options="option for option in ['medium', 'high']" ng-init="authority.caSensitivity = 'medium'"></select>
<select class="form-control" ng-model="authority.sensitivity" ng-options="option for option in ['medium', 'high']" ng-init="authority.sensitivity = 'medium'"></select>
</div>
</div>
<div class="form-group">
@ -43,7 +23,7 @@
<select class="form-control" ng-model="authority.keyType" ng-options="option for option in ['RSA2048', 'RSA4096']" ng-init="authority.keyType = 'RSA2048'"></select>
</div>
</div>
<div ng-show="authority.caSensitivity == 'high'" class="form-group">
<div ng-show="authority.sensitivity == 'high'" class="form-group">
<label class="control-label col-sm-2">
Key Name
</label>
@ -56,7 +36,7 @@
Serial Number
</label>
<div class="col-sm-10">
<input type="number" name="serialNumber" ng-model="authority.caSerialNumber" placeholder="Serial Number" class="form-control"/>
<input type="number" name="serialNumber" ng-model="authority.serialNumber" placeholder="Serial Number" class="form-control"/>
</div>
</div>
<div class="form-group">
@ -64,7 +44,7 @@
First Serial Number
</label>
<div class="col-sm-10">
<input type="number" name="firstSerialNumber" ng-model="authority.caFirstSerial" placeholder="First Serial Number" class="form-control" ng-init="1000" />
<input type="number" name="firstSerialNumber" ng-model="authority.firstSerial" placeholder="First Serial Number" class="form-control" ng-init="1000" />
</div>
</div>
<div class="form-group">
@ -72,7 +52,7 @@
Plugin
</label>
<div class="col-sm-10">
<select class="form-control" ng-model="authority.pluginName" ng-options="plugin.slug as plugin.title for plugin in plugins" ng-init="authority.pluginName = 'cloudca-issuer'" required></select>
<select class="form-control" ng-model="authority.plugin" ng-options="plugin as plugin.title for plugin in plugins" required></select>
</div>
</div>
</div>

View File

@ -1,33 +1,33 @@
<form name="trackingForm" novalidate>
<div class="form-horizontal">
<div class="form-group"
ng-class="{'has-error': trackingForm.caName.$invalid, 'has-success': !trackingForm.caName.$invalid&&trackingForm.caName.$dirty}">
ng-class="{'has-error': trackingForm.name.$invalid, 'has-success': !trackingForm.name.$invalid&&trackingForm.name.$dirty}">
<label class="control-label col-sm-2">
Name
</label>
<div class="col-sm-10">
<input name="caName" ng-model="authority.caName" placeholder="Name" tooltip="This will be the name of your authority, it is the name you will reference when creating new certificates" class="form-control" ng-pattern="/^[A-Za-z0-9_-]+$/" required/>
<p ng-show="trackingForm.caName.$invalid && !trackingForm.caName.$pristine" class="help-block">You must enter a valid authority name, spaces are not allowed</p>
<input name="name" ng-model="authority.name" placeholder="Name" tooltip="This will be the name of your authority, it is the name you will reference when creating new certificates" class="form-control" ng-pattern="/^[A-Za-z0-9_-]+$/" required/>
<p ng-show="trackingForm.name.$invalid && !trackingForm.name.$pristine" class="help-block">You must enter a valid authority name, spaces are not allowed</p>
</div>
</div>
<div class="form-group"
ng-class="{'has-error': trackingForm.ownerEmail.$invalid, 'has-success': !trackingForm.$invalid&&trackingForm.ownerEmail.$dirty}">
ng-class="{'has-error': trackingForm.owner.$invalid, 'has-success': !trackingForm.$invalid&&trackingForm.owner.$dirty}">
<label class="control-label col-sm-2">
Owner
</label>
<div class="col-sm-10">
<input type="email" name="ownerEmail" ng-model="authority.ownerEmail" placeholder="TeamDL@example.com" tooltip="This is the authorities team distribution list or the main point of contact for this authority" class="form-control" required/>
<p ng-show="trackingForm.ownerEmail.$invalid && !trackingForm.ownerEmail.$pristine" class="help-block">You must enter an Certificate Authority owner</p>
<input type="email" name="owner" ng-model="authority.owner" placeholder="TeamDL@example.com" tooltip="This is the authorities team distribution list or the main point of contact for this authority" class="form-control" required/>
<p ng-show="trackingForm.owner.$invalid && !trackingForm.owner.$pristine" class="help-block">You must enter an Certificate Authority owner</p>
</div>
</div>
<div class="form-group"
ng-class="{'has-error': trackingForm.caDescription.$invalid, 'has-success': !trackingForm.$invalid&&trackingForm.caDescription.$dirty}">
ng-class="{'has-error': trackingForm.description.$invalid, 'has-success': !trackingForm.$invalid&&trackingForm.description.$dirty}">
<label class="control-label col-sm-2">
Description
</label>
<div class="col-sm-10">
<textarea name="caDescription" ng-model="authority.caDescription" placeholder="Something elegant" class="form-control" ng-maxlength="250" required></textarea>
<p ng-show="trackingForm.caDescription.$invalid && !trackingForm.caDescription.$pristine" class="help-block">You must give a short description about this authority will be used for</p>
<textarea name="description" ng-model="authority.description" placeholder="Something elegant" class="form-control" ng-maxlength="250" required></textarea>
<p ng-show="trackingForm.description.$invalid && !trackingForm.description.$pristine" class="help-block">You must give a short description about this authority will be used for</p>
</div>
</div>
<div class="form-group"
@ -36,19 +36,51 @@
Common Name
</label>
<div class="col-sm-10">
<input name="commonName" ng-model="authority.caDN.commonName" placeholder="Common Name" class="form-control" ng-maxlength="64" required/>
<input name="commonName" ng-model="authority.commonName" placeholder="Common Name" class="form-control" ng-maxlength="64" required/>
<p ng-show="trackingForm.commonName.$invalid && !trackingForm.commonName.$pristine" class="help-block">You must enter a common name and it must be less than 64 characters in length</p>
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2">
Type
</label>
<div class="col-sm-10">
<select class="form-control" ng-model="authority.type" ng-options="option for option in ['root', 'subca']" ng-init="authority.type = 'root'"required></select>
</div>
</div>
<div ng-show="authority.type == 'subca'" class="form-group">
<label class="control-label col-sm-2">
Parent Authority
</label>
<div class="col-sm-10">
<input type="text" ng-model="authority.authority" placeholder="Parent Authority Name"
typeahead="authority as authority.name for authority in authorityService.findAuthorityByName($viewValue)" typeahead-loading="loadingAuthorities"
class="form-control input-md" typeahead-min-wait="50"
tooltip="When you specify a subordinate certificate authority you must specify the parent authority"
tooltip-trigger="focus" tooltip-placement="top">
</div>
</div>
<div class="form-group"
ng-class="{'has-error': trackingForm.validityEnd.$invalid || trackingForm.validityStart.$invalid, 'has-success': !trackingForm.$invalid&&trackingForm.validityEnd.$dirty&&trackingForm.validityStart.$dirty}">
<label class="control-label col-sm-2">
Validity Range
</label>
<div class="col-sm-4">
<div class="col-sm-2">
<select ng-model="authority.validityYears" class="form-control">
<option value="5">5 years</option>
<option value="10">10 years</option>
<option value="20">20 years</option>
<option value="30">30 years</option>
</select>
</div>
<span style="padding-top: 15px" class="text-center col-sm-1">
<strong>- or -</strong>
</span>
<div class="col-sm-3">
<div>
<div class="input-group">
<input name="validityStart" tooltip="Starting Date" class="form-control" datepicker-popup="yyyy/MM/dd" is-open="opened1" ng-model="authority.validityStart" required/>
<input name="validityStart" tooltip="Starting Date" class="form-control" datepicker-popup="yyyy/MM/dd" is-open="opened1" ng-model="authority.validityStart" min-date="authority.authority.notBefore"
max-date="authority.authority.notAfter" required/>
<p ng-show="trackingForm.validityStart.$invalid && !trackingForm.validityStart.$pristine" class="help-block">A start date is required!</p>
<span class="input-group-btn">
<button class="btn btn-default" ng-click="open($event)"><i class="glyphicon glyphicon-calendar"></i></button>
@ -56,11 +88,12 @@
</div>
</div>
</div>
<span style="padding-top: 15px" class="text-center col-sm-2"><label><span class="glyphicon glyphicon-resize-horizontal"></span></label></span>
<div class="col-sm-4">
<span style="padding-top: 15px" class="text-center col-sm-1"><label><span class="glyphicon glyphicon-resize-horizontal"></span></label></span>
<div class="col-sm-3">
<div>
<div class="input-group">
<input name="validityEnd" tooltip="Ending Date" class="form-control" datepicker-popup="yyyy/MM/dd" is-open="opened2" ng-model="authority.validityEnd" required/>
<input name="validityEnd" tooltip="Ending Date" class="form-control" datepicker-popup="yyyy/MM/dd" is-open="opened2" ng-model="authority.validityEnd" min-date="authority.authority.notBefore"
max-date="authority.authority.notAfter" required/>
<p ng-show="trackingForm.validityEnd.$invalid && !trackingForm.validityEnd.$pristine" class="help-block">A end date is required!</p>
<span class="input-group-btn">
<button class="btn btn-default" ng-click="open2($event)"><i class="glyphicon glyphicon-calendar"></i></button>

View File

@ -94,11 +94,11 @@ angular.module('lemur')
AuthorityService.getDefaults = function (authority) {
return DefaultService.get().then(function (defaults) {
authority.caDN.country = defaults.country;
authority.caDN.state = defaults.state;
authority.caDN.location = defaults.location;
authority.caDN.organization = defaults.organization;
authority.caDN.organizationalUnit = defaults.organizationalUnit;
authority.country = defaults.country;
authority.state = defaults.state;
authority.location = defaults.location;
authority.organization = defaults.organization;
authority.organizationalUnit = defaults.organizationalUnit;
});
};

View File

@ -29,9 +29,6 @@ angular.module('lemur')
total: 0, // length of data
getData: function ($defer, params) {
AuthorityApi.getList(params.url()).then(function (data) {
_.each(data, function(authority) {
AuthorityService.getRoles(authority);
});
params.total(data.total);
$defer.resolve(data);
});

View File

@ -104,11 +104,11 @@
<span style="padding-top: 15px" class="text-center col-sm-1">
<strong>- or -</strong>
</span>
<div class="col-sm-3">
<div class="input-group">
<input tooltip="Starting Date (yyyy/MM/dd)" class="form-control" datepicker-popup="yyyy/MM/dd"
is-open="$parent.openNotBefore.isOpen" min-date="certificate.authority.notBefore"
max-date="certificate.authority.maxDate" ng-model="certificate.validityStart"/>
<div class="col-sm-3">
<div class="input-group">
<input tooltip="Starting Date (yyyy/MM/dd)" class="form-control" datepicker-popup="yyyy/MM/dd"
is-open="$parent.openNotBefore.isOpen" min-date="certificate.authority.notBefore"
max-date="certificate.authority.notAfter" ng-model="certificate.validityStart"/>
<span class="input-group-btn">
<button class="btn btn-default" ng-click="openNotBefore($event)"><i
class="glyphicon glyphicon-calendar"></i></button>
@ -117,13 +117,12 @@
</div>
<span style="padding-top: 15px" class="text-center col-sm-1"><label><span
class="glyphicon glyphicon-resize-horizontal"></span></label></span>
<div class="col-sm-3">
<div>
<div class="input-group">
<input tooltip="Ending Date (yyyy/MM/dd)" class="form-control" datepicker-popup="yyyy/MM/dd"
is-open="$parent.openNotAfter.isOpen" min-date="certificate.authority.notBefore"
max-date="certificate.authority.maxDate" ng-model="certificate.validityEnd"/>
<div class="col-sm-3">
<div>
<div class="input-group">
<input tooltip="Ending Date (yyyy/MM/dd)" class="form-control" datepicker-popup="yyyy/MM/dd"
is-open="$parent.openNotAfter.isOpen" min-date="certificate.authority.notBefore"
max-date="certificate.authority.notAfter" ng-model="certificate.validityEnd"/>
<span class="input-group-btn">
<button class="btn btn-default" ng-click="openNotAfter($event)"><i
class="glyphicon glyphicon-calendar"></i></button>

View File

@ -53,7 +53,7 @@
</div>
</td>
</tr>
<tr class="warning" ng-show="certificate.toggle" ng-repeat-end>
<tr class="warning" ng-if="certificate.toggle" ng-repeat-end>
<td colspan="6">
<tabset justified="true" class="col-md-6">
<tab>
@ -80,8 +80,8 @@
<li class="list-group-item">
<strong>San</strong>
<span class="pull-right">
<i class="glyphicon glyphicon-ok" ng-show="certificate.san"></i>
<i class="glyphicon glyphicon-remove" ng-show="!certificate.san"></i>
<i class="glyphicon glyphicon-ok" ng-if="certificate.san"></i>
<i class="glyphicon glyphicon-remove" ng-if="!certificate.san"></i>
</span>
</li>
<li class="list-group-item">
@ -101,9 +101,9 @@
class="list-group-item">
<strong>Validity</strong>
<span class="pull-right">
<span ng-show="!certificate.status" class="label label-warning">Unknown</span>
<span ng-show="certificate.status == 'revoked'" class="label label-danger">Revoked</span>
<span ng-show="certificate.status == 'valid'" class="label label-success">Valid</span>
<span ng-if="!certificate.status" class="label label-warning">Unknown</span>
<span ng-if="certificate.status == 'revoked'" class="label label-danger">Revoked</span>
<span ng-if="certificate.status == 'valid'" class="label label-success">Valid</span>
</span>
</li>
<li class="list-group-item">

View File

@ -103,6 +103,13 @@ def certificate(session):
return c
@pytest.fixture
def role(session):
r = RoleFactory()
session.commit()
return r
@pytest.yield_fixture(scope="function")
def logged_in_user(app, user):
with app.test_request_context():

View File

@ -1,150 +1,160 @@
import pytest
from lemur.authorities.views import * # noqa
# def test_crud(session):
# role = create('role1')
# assert role.id > 0
#
# role = update(role.id, 'role_new', None, [])
# assert role.name == 'role_new'
# delete(role.id)
# assert get(role.id) == None
def test_authority_get(client):
assert client.get(api.url_for(Authorities, authority_id=1)).status_code == 401
def test_authority_post(client):
assert client.post(api.url_for(Authorities, authority_id=1), data={}).status_code == 405
def test_authority_put(client):
assert client.put(api.url_for(Authorities, authority_id=1), data={}).status_code == 401
def test_authority_delete(client):
assert client.delete(api.url_for(Authorities, authority_id=1)).status_code == 405
def test_authority_patch(client):
assert client.patch(api.url_for(Authorities, authority_id=1), data={}).status_code == 405
def test_authorities_get(client):
assert client.get(api.url_for(AuthoritiesList)).status_code == 401
def test_authorities_post(client):
assert client.post(api.url_for(AuthoritiesList), data={}).status_code == 401
def test_authorities_put(client):
assert client.put(api.url_for(AuthoritiesList), data={}).status_code == 405
def test_authorities_delete(client):
assert client.delete(api.url_for(AuthoritiesList)).status_code == 405
def test_authorities_patch(client):
assert client.patch(api.url_for(AuthoritiesList), data={}).status_code == 405
def test_certificate_authorities_get(client):
assert client.get(api.url_for(AuthoritiesList)).status_code == 401
def test_certificate_authorities_post(client):
assert client.post(api.url_for(AuthoritiesList), data={}).status_code == 401
def test_certificate_authorities_put(client):
assert client.put(api.url_for(AuthoritiesList), data={}).status_code == 405
def test_certificate_authorities_delete(client):
assert client.delete(api.url_for(AuthoritiesList)).status_code == 405
def test_certificate_authorities_patch(client):
assert client.patch(api.url_for(AuthoritiesList), data={}).status_code == 405
VALID_USER_HEADER_TOKEN = {
'Authorization': 'Basic ' + 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpYXQiOjE0MzUyMzMzNjksInN1YiI6MSwiZXhwIjoxNTIxNTQ2OTY5fQ.1qCi0Ip7mzKbjNh0tVd3_eJOrae3rNa_9MCVdA4WtQI'}
def test_auth_authority_get(client):
assert client.get(api.url_for(Authorities, authority_id=1), headers=VALID_USER_HEADER_TOKEN).status_code == 200
def test_auth_authority_post_(client):
assert client.post(api.url_for(Authorities, authority_id=1), data={}, headers=VALID_USER_HEADER_TOKEN).status_code == 405
def test_auth_authority_put(client):
assert client.put(api.url_for(Authorities, authority_id=1), data={}, headers=VALID_USER_HEADER_TOKEN).status_code == 400
def test_auth_authority_delete(client):
assert client.delete(api.url_for(Authorities, authority_id=1), headers=VALID_USER_HEADER_TOKEN).status_code == 405
def test_auth_authority_patch(client):
assert client.patch(api.url_for(Authorities, authority_id=1), data={}, headers=VALID_USER_HEADER_TOKEN).status_code == 405
def test_auth_authorities_get(client):
assert client.get(api.url_for(AuthoritiesList), headers=VALID_USER_HEADER_TOKEN).status_code == 200
def test_auth_authorities_post(client):
assert client.post(api.url_for(AuthoritiesList), data={}, headers=VALID_USER_HEADER_TOKEN).status_code == 400
def test_auth_certificates_authorities_get(client):
assert client.get(api.url_for(CertificateAuthority, certificate_id=1), headers=VALID_USER_HEADER_TOKEN).status_code == 404
VALID_ADMIN_HEADER_TOKEN = {
'Authorization': 'Basic ' + 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpYXQiOjE0MzUyNTAyMTgsInN1YiI6MiwiZXhwIjoxNTIxNTYzODE4fQ.6mbq4-Ro6K5MmuNiTJBB153RDhlM5LGJBjI7GBKkfqA'}
def test_admin_authority_get(client):
assert client.get(api.url_for(Authorities, authority_id=1), headers=VALID_ADMIN_HEADER_TOKEN).status_code == 200
def test_admin_authority_post(client):
assert client.post(api.url_for(Authorities, authority_id=1), data={}, headers=VALID_ADMIN_HEADER_TOKEN).status_code == 405
def test_admin_authority_put(client):
assert client.put(api.url_for(Authorities, authority_id=1), data={}, headers=VALID_ADMIN_HEADER_TOKEN).status_code == 400
def test_admin_authority_delete(client):
assert client.delete(api.url_for(Authorities, authority_id=1), headers=VALID_ADMIN_HEADER_TOKEN).status_code == 405
def test_admin_authority_patch(client):
assert client.patch(api.url_for(Authorities, authority_id=1), data={}, headers=VALID_ADMIN_HEADER_TOKEN).status_code == 405
def test_admin_authorities_get(client):
assert client.get(api.url_for(AuthoritiesList), headers=VALID_ADMIN_HEADER_TOKEN).status_code == 200
def test_admin_authorities_post(client):
assert client.post(api.url_for(AuthoritiesList), data={}, headers=VALID_ADMIN_HEADER_TOKEN).status_code == 400
def test_admin_authorities_put(client):
assert client.put(api.url_for(AuthoritiesList), data={}, headers=VALID_ADMIN_HEADER_TOKEN).status_code == 405
def test_admin_authorities_delete(client):
assert client.delete(api.url_for(AuthoritiesList), headers=VALID_ADMIN_HEADER_TOKEN).status_code == 405
def test_admin_certificate_authorities_get(client):
assert client.get(api.url_for(CertificateAuthority, certificate_id=1), headers=VALID_ADMIN_HEADER_TOKEN).status_code == 404
from .vectors import VALID_ADMIN_HEADER_TOKEN, VALID_USER_HEADER_TOKEN
def test_authority_input_schema(client, role):
from lemur.authorities.schemas import AuthorityInputSchema
input_data = {
'name': 'Example Authority',
'owner': 'jim@example.com',
'description': 'An example authority.',
'commonName': 'AnExampleAuthority',
'pluginName': {'slug': 'verisign-issuer'},
'type': 'root',
'signingAlgorithm': 'sha256WithRSA',
'keyType': 'RSA2048',
'sensitivity': 'medium'
}
data, errors = AuthorityInputSchema().load(input_data)
assert not errors
@pytest.mark.parametrize("token,status", [
(VALID_USER_HEADER_TOKEN, 404),
(VALID_ADMIN_HEADER_TOKEN, 404),
('', 401)
])
def test_authority_get(client, token, status):
assert client.get(api.url_for(Authorities, authority_id=1), headers=token).status_code == status
@pytest.mark.parametrize("token,status", [
(VALID_USER_HEADER_TOKEN, 405),
(VALID_ADMIN_HEADER_TOKEN, 405),
('', 405)
])
def test_authority_post(client, token, status):
assert client.post(api.url_for(Authorities, authority_id=1), data={}, headers=token).status_code == status
@pytest.mark.parametrize("token,status", [
(VALID_USER_HEADER_TOKEN, 400),
(VALID_ADMIN_HEADER_TOKEN, 400),
('', 401)
])
def test_authority_put(client, token, status):
assert client.put(api.url_for(Authorities, authority_id=1), data={}, headers=token).status_code == status
@pytest.mark.parametrize("token,status", [
(VALID_USER_HEADER_TOKEN, 405),
(VALID_ADMIN_HEADER_TOKEN, 405),
('', 405)
])
def test_authority_delete(client, token, status):
assert client.delete(api.url_for(Authorities, authority_id=1), headers=token).status_code == status
@pytest.mark.parametrize("token,status", [
(VALID_USER_HEADER_TOKEN, 405),
(VALID_ADMIN_HEADER_TOKEN, 405),
('', 405)
])
def test_authority_patch(client, token, status):
assert client.patch(api.url_for(Authorities, authority_id=1), data={}, headers=token).status_code == status
@pytest.mark.parametrize("token,status", [
(VALID_USER_HEADER_TOKEN, 200),
(VALID_ADMIN_HEADER_TOKEN, 200),
('', 401)
])
def test_authorities_get(client, token, status):
assert client.get(api.url_for(AuthoritiesList), headers=token).status_code == status
@pytest.mark.parametrize("token,status", [
(VALID_USER_HEADER_TOKEN, 400),
(VALID_ADMIN_HEADER_TOKEN, 400),
('', 401)
])
def test_authorities_post(client, token, status):
assert client.post(api.url_for(AuthoritiesList), data={}, headers=token).status_code == status
@pytest.mark.parametrize("token,status", [
(VALID_USER_HEADER_TOKEN, 405),
(VALID_ADMIN_HEADER_TOKEN, 405),
('', 405)
])
def test_authorities_put(client, token, status):
assert client.put(api.url_for(AuthoritiesList), data={}, headers=token).status_code == status
@pytest.mark.parametrize("token,status", [
(VALID_USER_HEADER_TOKEN, 405),
(VALID_ADMIN_HEADER_TOKEN, 405),
('', 405)
])
def test_authorities_delete(client, token, status):
assert client.delete(api.url_for(AuthoritiesList), headers=token).status_code == status
@pytest.mark.parametrize("token,status", [
(VALID_USER_HEADER_TOKEN, 405),
(VALID_ADMIN_HEADER_TOKEN, 405),
('', 405)
])
def test_authorities_patch(client, token, status):
assert client.patch(api.url_for(AuthoritiesList), data={}, headers=token).status_code == status
@pytest.mark.parametrize("token,status", [
(VALID_USER_HEADER_TOKEN, 200),
(VALID_ADMIN_HEADER_TOKEN, 200),
('', 401)
])
def test_certificate_authorities_get(client, token, status):
assert client.get(api.url_for(AuthoritiesList), headers=token).status_code == status
@pytest.mark.parametrize("token,status", [
(VALID_USER_HEADER_TOKEN, 400),
(VALID_ADMIN_HEADER_TOKEN, 400),
('', 401)
])
def test_certificate_authorities_post(client, token, status):
assert client.post(api.url_for(AuthoritiesList), data={}, headers=token).status_code == status
@pytest.mark.parametrize("token,status", [
(VALID_USER_HEADER_TOKEN, 405),
(VALID_ADMIN_HEADER_TOKEN, 405),
('', 405)
])
def test_certificate_authorities_put(client, token, status):
assert client.put(api.url_for(AuthoritiesList), data={}, headers=token).status_code == status
@pytest.mark.parametrize("token,status", [
(VALID_USER_HEADER_TOKEN, 405),
(VALID_ADMIN_HEADER_TOKEN, 405),
('', 405)
])
def test_certificate_authorities_delete(client, token, status):
assert client.delete(api.url_for(AuthoritiesList), headers=token).status_code == status
@pytest.mark.parametrize("token,status", [
(VALID_USER_HEADER_TOKEN, 405),
(VALID_ADMIN_HEADER_TOKEN, 405),
('', 405)
])
def test_certificate_authorities_patch(client, token, status):
assert client.patch(api.url_for(AuthoritiesList), data={}, headers=token).status_code == status

View File

@ -2,13 +2,14 @@ from __future__ import unicode_literals # at top of module
import pytest
import json
from lemur.certificates.views import * # noqa
from .vectors import VALID_ADMIN_HEADER_TOKEN, VALID_USER_HEADER_TOKEN
def test_authority_identifier_schema():
from lemur.certificates.schemas import AuthorityIdentifierSchema
from lemur.schemas import AuthorityIdentifierSchema
input_data = {'useAuthorityCert': True}
data, errors = AuthorityIdentifierSchema().load(input_data)
@ -22,7 +23,7 @@ def test_authority_identifier_schema():
def test_authority_key_identifier_schema():
from lemur.certificates.schemas import AuthorityKeyIdentifierSchema
from lemur.schemas import AuthorityKeyIdentifierSchema
input_data = {'useKeyIdentifier': True}
data, errors = AuthorityKeyIdentifierSchema().load(input_data)
@ -36,7 +37,7 @@ def test_authority_key_identifier_schema():
def test_certificate_info_access_schema():
from lemur.certificates.schemas import CertificateInfoAccessSchema
from lemur.schemas import CertificateInfoAccessSchema
input_data = {'includeAIA': True}
data, errors = CertificateInfoAccessSchema().load(input_data)
@ -49,7 +50,7 @@ def test_certificate_info_access_schema():
def test_subject_key_identifier_schema():
from lemur.certificates.schemas import SubjectKeyIdentifierSchema
from lemur.schemas import SubjectKeyIdentifierSchema
input_data = {'includeSKI': True}
@ -61,7 +62,7 @@ def test_subject_key_identifier_schema():
assert data == input_data
def test_extension_schema():
def test_extension_schema(client):
from lemur.certificates.schemas import ExtensionSchema
input_data = {
@ -194,7 +195,7 @@ def test_certificate_valid_dates(client, authority):
def test_sub_alt_name_schema():
from lemur.certificates.schemas import SubAltNameSchema, SubAltNamesSchema
from lemur.schemas import SubAltNameSchema, SubAltNamesSchema
input_data = {'nameType': 'DNSName', 'value': 'test.example.com'}
data, errors = SubAltNameSchema().load(input_data)
@ -217,7 +218,7 @@ def test_sub_alt_name_schema():
def test_key_usage_schema():
from lemur.certificates.schemas import KeyUsageSchema
from lemur.schemas import KeyUsageSchema
input_data = {
'useCRLSign': True,
@ -244,7 +245,7 @@ def test_key_usage_schema():
def test_extended_key_usage_schema():
from lemur.certificates.schemas import ExtendedKeyUsageSchema
from lemur.schemas import ExtendedKeyUsageSchema
input_data = {
'useServerAuthentication': True,