Authorities marshmallow addition (#303)
This commit is contained in:
parent
776e0fcd11
commit
df0ad4d875
@ -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)
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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
120
lemur/common/validators.py
Normal 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))
|
@ -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)
|
||||
|
122
lemur/schemas.py
122
lemur/schemas.py
@ -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))
|
||||
|
@ -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;
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
10
lemur/static/app/angular/authorities/services.js
vendored
10
lemur/static/app/angular/authorities/services.js
vendored
@ -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;
|
||||
});
|
||||
};
|
||||
|
||||
|
@ -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);
|
||||
});
|
||||
|
@ -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>
|
||||
|
@ -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">
|
||||
|
@ -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():
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
|
Loading…
Reference in New Issue
Block a user