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.roles.models import Role
|
||||||
from lemur.certificates.models import Certificate
|
from lemur.certificates.models import Certificate
|
||||||
|
|
||||||
from lemur.plugins.base import plugins
|
|
||||||
|
|
||||||
|
|
||||||
def update(authority_id, description=None, owner=None, active=None, roles=None):
|
def update(authority_id, description=None, owner=None, active=None, roles=None):
|
||||||
"""
|
"""
|
||||||
|
@ -49,20 +47,20 @@ def create(kwargs):
|
||||||
:return:
|
:return:
|
||||||
"""
|
"""
|
||||||
|
|
||||||
issuer = plugins.get(kwargs.get('pluginName'))
|
issuer = kwargs['plugin']
|
||||||
|
|
||||||
kwargs['creator'] = g.current_user.email
|
kwargs['creator'] = g.current_user.email
|
||||||
cert_body, intermediate, issuer_roles = issuer.create_authority(kwargs)
|
cert_body, intermediate, issuer_roles = issuer.create_authority(kwargs)
|
||||||
|
|
||||||
cert = Certificate(cert_body, chain=intermediate)
|
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 \
|
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:
|
else:
|
||||||
cert.description = "This is the ROOT certificate for the {0} certificate authority.".format(
|
cert.description = "This is the ROOT certificate for the {0} certificate authority.".format(
|
||||||
kwargs.get('caName')
|
kwargs.get('name')
|
||||||
)
|
)
|
||||||
|
|
||||||
cert.user = g.current_user
|
cert.user = g.current_user
|
||||||
|
@ -79,7 +77,7 @@ def create(kwargs):
|
||||||
role = role_service.create(
|
role = role_service.create(
|
||||||
r['name'],
|
r['name'],
|
||||||
password=r['password'],
|
password=r['password'],
|
||||||
description="{0} auto generated role".format(kwargs.get('pluginName')),
|
description="{0} auto generated role".format(kwargs['plugin'].title),
|
||||||
username=r['username'])
|
username=r['username'])
|
||||||
|
|
||||||
# the user creating the authority should be able to administer it
|
# the user creating the authority should be able to administer it
|
||||||
|
@ -89,11 +87,11 @@ def create(kwargs):
|
||||||
role_objs.append(role)
|
role_objs.append(role)
|
||||||
|
|
||||||
authority = Authority(
|
authority = Authority(
|
||||||
kwargs.get('caName'),
|
kwargs.get('name'),
|
||||||
kwargs['ownerEmail'],
|
kwargs['owner'],
|
||||||
kwargs['pluginName'],
|
kwargs['plugin'].slug,
|
||||||
cert_body,
|
cert_body,
|
||||||
description=kwargs['caDescription'],
|
description=kwargs['description'],
|
||||||
chain=intermediate,
|
chain=intermediate,
|
||||||
roles=role_objs
|
roles=role_objs
|
||||||
)
|
)
|
||||||
|
@ -102,10 +100,10 @@ def create(kwargs):
|
||||||
authority = database.create(authority)
|
authority = database.create(authority)
|
||||||
|
|
||||||
# the owning dl or role should have this authority associated with it
|
# 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:
|
if not owner_role:
|
||||||
owner_role = role_service.create(kwargs['ownerEmail'])
|
owner_role = role_service.create(kwargs['owner'])
|
||||||
|
|
||||||
owner_role.authority = authority
|
owner_role.authority = authority
|
||||||
|
|
||||||
|
@ -170,10 +168,6 @@ def render(args):
|
||||||
:return:
|
:return:
|
||||||
"""
|
"""
|
||||||
query = database.session_query(Authority)
|
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')
|
filt = args.pop('filter')
|
||||||
|
|
||||||
if filt:
|
if filt:
|
||||||
|
@ -191,9 +185,4 @@ def render(args):
|
||||||
authority_ids.append(role.authority.id)
|
authority_ids.append(role.authority.id)
|
||||||
query = query.filter(Authority.id.in_(authority_ids))
|
query = query.filter(Authority.id.in_(authority_ids))
|
||||||
|
|
||||||
query = database.find_all(query, Authority, args)
|
return database.sort_and_page(query, Authority, args)
|
||||||
|
|
||||||
if sort_by and sort_dir:
|
|
||||||
query = database.sort(query, Authority, sort_by, sort_dir)
|
|
||||||
|
|
||||||
return database.paginate(query, page, count)
|
|
||||||
|
|
|
@ -6,31 +6,19 @@
|
||||||
.. moduleauthor:: Kevin Glisson <kglisson@netflix.com>
|
.. moduleauthor:: Kevin Glisson <kglisson@netflix.com>
|
||||||
"""
|
"""
|
||||||
from flask import Blueprint, g
|
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.common.utils import paginated_parser
|
||||||
from lemur.roles import service as role_service
|
from lemur.common.schema import validate_schema
|
||||||
from lemur.certificates import service as certificate_service
|
|
||||||
from lemur.auth.service import AuthenticatedResource
|
from lemur.auth.service import AuthenticatedResource
|
||||||
|
|
||||||
from lemur.auth.permissions import AuthorityPermission
|
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__)
|
mod = Blueprint('authorities', __name__)
|
||||||
api = Api(mod)
|
api = Api(mod)
|
||||||
|
@ -42,7 +30,7 @@ class AuthoritiesList(AuthenticatedResource):
|
||||||
self.reqparse = reqparse.RequestParser()
|
self.reqparse = reqparse.RequestParser()
|
||||||
super(AuthoritiesList, self).__init__()
|
super(AuthoritiesList, self).__init__()
|
||||||
|
|
||||||
@marshal_items(FIELDS)
|
@validate_schema(None, authorities_output_schema)
|
||||||
def get(self):
|
def get(self):
|
||||||
"""
|
"""
|
||||||
.. http:get:: /authorities
|
.. http:get:: /authorities
|
||||||
|
@ -98,8 +86,8 @@ class AuthoritiesList(AuthenticatedResource):
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
return service.render(args)
|
return service.render(args)
|
||||||
|
|
||||||
@marshal_items(FIELDS)
|
@validate_schema(authority_input_schema, authority_output_schema)
|
||||||
def post(self):
|
def post(self, data=None):
|
||||||
"""
|
"""
|
||||||
.. http:post:: /authorities
|
.. http:post:: /authorities
|
||||||
|
|
||||||
|
@ -180,25 +168,7 @@ class AuthoritiesList(AuthenticatedResource):
|
||||||
:statuscode 403: unauthenticated
|
:statuscode 403: unauthenticated
|
||||||
:statuscode 200: no error
|
:statuscode 200: no error
|
||||||
"""
|
"""
|
||||||
self.reqparse.add_argument('caName', type=str, location='json', required=True)
|
return service.create(data)
|
||||||
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)
|
|
||||||
|
|
||||||
|
|
||||||
class Authorities(AuthenticatedResource):
|
class Authorities(AuthenticatedResource):
|
||||||
|
@ -206,7 +176,7 @@ class Authorities(AuthenticatedResource):
|
||||||
self.reqparse = reqparse.RequestParser()
|
self.reqparse = reqparse.RequestParser()
|
||||||
super(Authorities, self).__init__()
|
super(Authorities, self).__init__()
|
||||||
|
|
||||||
@marshal_items(FIELDS)
|
@validate_schema(None, authority_output_schema)
|
||||||
def get(self, authority_id):
|
def get(self, authority_id):
|
||||||
"""
|
"""
|
||||||
.. http:get:: /authorities/1
|
.. http:get:: /authorities/1
|
||||||
|
@ -248,8 +218,8 @@ class Authorities(AuthenticatedResource):
|
||||||
"""
|
"""
|
||||||
return service.get(authority_id)
|
return service.get(authority_id)
|
||||||
|
|
||||||
@marshal_items(FIELDS)
|
@validate_schema(authority_input_schema, authority_output_schema)
|
||||||
def put(self, authority_id):
|
def put(self, authority_id, data=None):
|
||||||
"""
|
"""
|
||||||
.. http:put:: /authorities/1
|
.. http:put:: /authorities/1
|
||||||
|
|
||||||
|
@ -295,12 +265,6 @@ class Authorities(AuthenticatedResource):
|
||||||
:statuscode 200: no error
|
:statuscode 200: no error
|
||||||
:statuscode 403: unauthenticated
|
: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)
|
authority = service.get(authority_id)
|
||||||
role = role_service.get_by_name(authority.owner)
|
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
|
# we want to make sure that we cannot add roles that we are not members of
|
||||||
if not g.current_user.is_admin:
|
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])
|
user_role_ids = set([r.id for r in g.current_user.roles])
|
||||||
|
|
||||||
if not role_ids.issubset(user_role_ids):
|
if not role_ids.issubset(user_role_ids):
|
||||||
|
@ -322,10 +286,10 @@ class Authorities(AuthenticatedResource):
|
||||||
if permission.can():
|
if permission.can():
|
||||||
return service.update(
|
return service.update(
|
||||||
authority_id,
|
authority_id,
|
||||||
owner=args['owner'],
|
owner=data['owner'],
|
||||||
description=args['description'],
|
description=data['description'],
|
||||||
active=args['active'],
|
active=data['active'],
|
||||||
roles=args['roles']
|
roles=data['roles']
|
||||||
)
|
)
|
||||||
|
|
||||||
return dict(message="You are not authorized to update this authority"), 403
|
return dict(message="You are not authorized to update this authority"), 403
|
||||||
|
@ -333,10 +297,9 @@ class Authorities(AuthenticatedResource):
|
||||||
|
|
||||||
class CertificateAuthority(AuthenticatedResource):
|
class CertificateAuthority(AuthenticatedResource):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.reqparse = reqparse.RequestParser()
|
|
||||||
super(CertificateAuthority, self).__init__()
|
super(CertificateAuthority, self).__init__()
|
||||||
|
|
||||||
@marshal_items(FIELDS)
|
@validate_schema(None, authority_output_schema)
|
||||||
def get(self, certificate_id):
|
def get(self, certificate_id):
|
||||||
"""
|
"""
|
||||||
.. http:get:: /certificates/1/authority
|
.. http:get:: /certificates/1/authority
|
||||||
|
|
|
@ -7,197 +7,20 @@
|
||||||
"""
|
"""
|
||||||
from flask import current_app
|
from flask import current_app
|
||||||
|
|
||||||
import arrow
|
from marshmallow import fields, validates_schema
|
||||||
|
|
||||||
from marshmallow import fields, validates_schema, pre_load, post_dump
|
|
||||||
from marshmallow.exceptions import ValidationError
|
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, \
|
from lemur.schemas import AssociatedAuthoritySchema, AssociatedDestinationSchema, AssociatedCertificateSchema, \
|
||||||
AssociatedNotificationSchema, PluginSchema
|
AssociatedNotificationSchema, PluginSchema, ExtensionSchema
|
||||||
from lemur.common.schema import LemurInputSchema, LemurOutputSchema, LemurSchema
|
from lemur.common.schema import LemurInputSchema, LemurOutputSchema
|
||||||
|
from lemur.common import validators
|
||||||
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))
|
|
||||||
|
|
||||||
|
|
||||||
class CertificateInputSchema(LemurInputSchema):
|
class CertificateInputSchema(LemurInputSchema):
|
||||||
name = fields.String()
|
name = fields.String()
|
||||||
owner = fields.Email(required=True)
|
owner = fields.Email(required=True)
|
||||||
description = fields.String()
|
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)
|
authority = fields.Nested(AssociatedAuthoritySchema, required=True)
|
||||||
|
|
||||||
validity_start = fields.DateTime()
|
validity_start = fields.DateTime()
|
||||||
|
@ -208,7 +31,7 @@ class CertificateInputSchema(LemurInputSchema):
|
||||||
notifications = fields.Nested(AssociatedNotificationSchema, missing=[], many=True)
|
notifications = fields.Nested(AssociatedNotificationSchema, missing=[], many=True)
|
||||||
replacements = fields.Nested(AssociatedCertificateSchema, 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
|
# certificate body fields
|
||||||
organizational_unit = fields.String(missing=lambda: current_app.config.get('LEMUR_DEFAULT_ORGANIZATIONAL_UNIT'))
|
organizational_unit = fields.String(missing=lambda: current_app.config.get('LEMUR_DEFAULT_ORGANIZATIONAL_UNIT'))
|
||||||
|
@ -221,34 +44,7 @@ class CertificateInputSchema(LemurInputSchema):
|
||||||
|
|
||||||
@validates_schema
|
@validates_schema
|
||||||
def validate_dates(self, data):
|
def validate_dates(self, data):
|
||||||
if not data.get('validity_start') and data.get('validity_end'):
|
validators.dates(data)
|
||||||
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))
|
|
||||||
|
|
||||||
|
|
||||||
class CertificateOutputSchema(LemurOutputSchema):
|
class CertificateOutputSchema(LemurOutputSchema):
|
||||||
|
@ -276,9 +72,9 @@ class CertificateUploadInputSchema(LemurInputSchema):
|
||||||
description = fields.String()
|
description = fields.String()
|
||||||
active = fields.Boolean(missing=True)
|
active = fields.Boolean(missing=True)
|
||||||
|
|
||||||
private_key = fields.String(validate=validate_private_key)
|
private_key = fields.String(validate=validators.private_key)
|
||||||
public_cert = fields.String(required=True, validate=validate_public_certificate)
|
public_cert = fields.String(required=True, validate=validators.public_certificate)
|
||||||
chain = fields.String(validate=validate_public_certificate)
|
chain = fields.String(validate=validators.public_certificate) # TODO this could be multiple certificates
|
||||||
|
|
||||||
destinations = fields.Nested(AssociatedDestinationSchema, missing=[], many=True)
|
destinations = fields.Nested(AssociatedDestinationSchema, missing=[], many=True)
|
||||||
notifications = fields.Nested(AssociatedNotificationSchema, missing=[], many=True)
|
notifications = fields.Nested(AssociatedNotificationSchema, missing=[], many=True)
|
||||||
|
|
|
@ -253,7 +253,7 @@ def create(**kwargs):
|
||||||
cert.name = kwargs['name']
|
cert.name = kwargs['name']
|
||||||
|
|
||||||
database.create(cert)
|
database.create(cert)
|
||||||
cert.description = kwargs['description']
|
cert.description = kwargs.get('description')
|
||||||
g.user.certificates.append(cert)
|
g.user.certificates.append(cert)
|
||||||
database.update(g.user)
|
database.update(g.user)
|
||||||
|
|
||||||
|
|
|
@ -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()
|
total = query.count()
|
||||||
|
|
||||||
|
# offset calculated at zero
|
||||||
|
page -= 1
|
||||||
items = query.offset(count * page).limit(count).all()
|
items = query.offset(count * page).limit(count).all()
|
||||||
return dict(items=items, total=total)
|
return dict(items=items, total=total)
|
||||||
|
|
122
lemur/schemas.py
122
lemur/schemas.py
|
@ -7,26 +7,48 @@
|
||||||
.. moduleauthor:: Kevin Glisson <kglisson@netflix.com>
|
.. 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.authorities.models import Authority
|
||||||
from lemur.destinations.models import Destination
|
from lemur.destinations.models import Destination
|
||||||
from lemur.certificates.models import Certificate
|
from lemur.certificates.models import Certificate
|
||||||
from lemur.notifications.models import Notification
|
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
|
from lemur.plugins import plugins
|
||||||
|
|
||||||
|
|
||||||
class AssociatedAuthoritySchema(LemurInputSchema):
|
class AssociatedAuthoritySchema(LemurInputSchema):
|
||||||
id = fields.Int(required=True)
|
id = fields.Int()
|
||||||
|
name = fields.String()
|
||||||
|
|
||||||
@post_load
|
@post_load
|
||||||
def get_object(self, data, many=False):
|
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):
|
class AssociatedDestinationSchema(LemurInputSchema):
|
||||||
id = fields.Int(required=True)
|
id = fields.Int(required=True)
|
||||||
|
name = fields.String()
|
||||||
|
|
||||||
@post_load
|
@post_load
|
||||||
def get_object(self, data, many=False):
|
def get_object(self, data, many=False):
|
||||||
|
@ -71,3 +93,95 @@ class PluginSchema(LemurInputSchema):
|
||||||
return [plugins.get(plugin['slug']) for plugin in data]
|
return [plugins.get(plugin['slug']) for plugin in data]
|
||||||
else:
|
else:
|
||||||
return plugins.get(data['slug'])
|
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){
|
.controller('AuthorityEditController', function ($scope, $modalInstance, AuthorityApi, AuthorityService, RoleService, toaster, editId){
|
||||||
AuthorityApi.get(editId).then(function (authority) {
|
AuthorityApi.get(editId).then(function (authority) {
|
||||||
AuthorityService.getRoles(authority);
|
|
||||||
$scope.authority = authority;
|
$scope.authority = authority;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -69,6 +68,7 @@ angular.module('lemur')
|
||||||
|
|
||||||
PluginService.getByType('issuer').then(function (plugins) {
|
PluginService.getByType('issuer').then(function (plugins) {
|
||||||
$scope.plugins = plugins;
|
$scope.plugins = plugins;
|
||||||
|
$scope.authority.plugin = plugins[0];
|
||||||
});
|
});
|
||||||
|
|
||||||
$scope.roleService = RoleService;
|
$scope.roleService = RoleService;
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
Country
|
Country
|
||||||
</label>
|
</label>
|
||||||
<div class="col-sm-10">
|
<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>
|
<p ng-show="dnForm.country.$invalid && !dnForm.country.$pristine" class="help-block">You must enter a country</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -16,7 +16,7 @@
|
||||||
State
|
State
|
||||||
</label>
|
</label>
|
||||||
<div class="col-sm-10">
|
<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>
|
<p ng-show="dnForm.state.$invalid && !dnForm.state.$pristine" class="help-block">You must enter a state</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -26,7 +26,7 @@
|
||||||
Location
|
Location
|
||||||
</label>
|
</label>
|
||||||
<div class="col-sm-10">
|
<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>
|
<p ng-show="dnForm.location.$invalid && !dnForm.location.$pristine" class="help-block">You must enter a location</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -36,7 +36,7 @@
|
||||||
Organization
|
Organization
|
||||||
</label>
|
</label>
|
||||||
<div class="col-sm-10">
|
<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>
|
<p ng-show="dnForm.organization.$invalid && !dnForm.organization.$pristine" class="help-block">You must enter a organization</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -46,7 +46,7 @@
|
||||||
Organizational Unit
|
Organizational Unit
|
||||||
</label>
|
</label>
|
||||||
<div class="col-sm-10">
|
<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>
|
<p ng-show="dnForm.organization.$invalid && !dnForm.organizationalUnit.$pristine" class="help-block">You must enter a organizational unit</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,30 +1,10 @@
|
||||||
<div class="form-horizontal">
|
<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">
|
<div class="form-group">
|
||||||
<label class="control-label col-sm-2">
|
<label class="control-label col-sm-2">
|
||||||
Signing Algorithm
|
Signing Algorithm
|
||||||
</label>
|
</label>
|
||||||
<div class="col-sm-10">
|
<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>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
|
@ -32,7 +12,7 @@
|
||||||
Sensitivity
|
Sensitivity
|
||||||
</label>
|
</label>
|
||||||
<div class="col-sm-10">
|
<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>
|
</div>
|
||||||
<div class="form-group">
|
<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>
|
<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>
|
</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">
|
<label class="control-label col-sm-2">
|
||||||
Key Name
|
Key Name
|
||||||
</label>
|
</label>
|
||||||
|
@ -56,7 +36,7 @@
|
||||||
Serial Number
|
Serial Number
|
||||||
</label>
|
</label>
|
||||||
<div class="col-sm-10">
|
<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>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
|
@ -64,7 +44,7 @@
|
||||||
First Serial Number
|
First Serial Number
|
||||||
</label>
|
</label>
|
||||||
<div class="col-sm-10">
|
<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>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
|
@ -72,7 +52,7 @@
|
||||||
Plugin
|
Plugin
|
||||||
</label>
|
</label>
|
||||||
<div class="col-sm-10">
|
<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>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,33 +1,33 @@
|
||||||
<form name="trackingForm" novalidate>
|
<form name="trackingForm" novalidate>
|
||||||
<div class="form-horizontal">
|
<div class="form-horizontal">
|
||||||
<div class="form-group"
|
<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">
|
<label class="control-label col-sm-2">
|
||||||
Name
|
Name
|
||||||
</label>
|
</label>
|
||||||
<div class="col-sm-10">
|
<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/>
|
<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.caName.$invalid && !trackingForm.caName.$pristine" class="help-block">You must enter a valid authority name, spaces are not allowed</p>
|
<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>
|
</div>
|
||||||
<div class="form-group"
|
<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">
|
<label class="control-label col-sm-2">
|
||||||
Owner
|
Owner
|
||||||
</label>
|
</label>
|
||||||
<div class="col-sm-10">
|
<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/>
|
<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.ownerEmail.$invalid && !trackingForm.ownerEmail.$pristine" class="help-block">You must enter an Certificate Authority owner</p>
|
<p ng-show="trackingForm.owner.$invalid && !trackingForm.owner.$pristine" class="help-block">You must enter an Certificate Authority owner</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group"
|
<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">
|
<label class="control-label col-sm-2">
|
||||||
Description
|
Description
|
||||||
</label>
|
</label>
|
||||||
<div class="col-sm-10">
|
<div class="col-sm-10">
|
||||||
<textarea name="caDescription" ng-model="authority.caDescription" placeholder="Something elegant" class="form-control" ng-maxlength="250" required></textarea>
|
<textarea name="description" ng-model="authority.description" 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>
|
<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>
|
</div>
|
||||||
<div class="form-group"
|
<div class="form-group"
|
||||||
|
@ -36,19 +36,51 @@
|
||||||
Common Name
|
Common Name
|
||||||
</label>
|
</label>
|
||||||
<div class="col-sm-10">
|
<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>
|
<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>
|
</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"
|
<div class="form-group"
|
||||||
ng-class="{'has-error': trackingForm.validityEnd.$invalid || trackingForm.validityStart.$invalid, 'has-success': !trackingForm.$invalid&&trackingForm.validityEnd.$dirty&&trackingForm.validityStart.$dirty}">
|
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">
|
<label class="control-label col-sm-2">
|
||||||
Validity Range
|
Validity Range
|
||||||
</label>
|
</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>
|
||||||
<div class="input-group">
|
<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>
|
<p ng-show="trackingForm.validityStart.$invalid && !trackingForm.validityStart.$pristine" class="help-block">A start date is required!</p>
|
||||||
<span class="input-group-btn">
|
<span class="input-group-btn">
|
||||||
<button class="btn btn-default" ng-click="open($event)"><i class="glyphicon glyphicon-calendar"></i></button>
|
<button class="btn btn-default" ng-click="open($event)"><i class="glyphicon glyphicon-calendar"></i></button>
|
||||||
|
@ -56,11 +88,12 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<span style="padding-top: 15px" class="text-center col-sm-2"><label><span class="glyphicon glyphicon-resize-horizontal"></span></label></span>
|
<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-4">
|
<div class="col-sm-3">
|
||||||
<div>
|
<div>
|
||||||
<div class="input-group">
|
<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>
|
<p ng-show="trackingForm.validityEnd.$invalid && !trackingForm.validityEnd.$pristine" class="help-block">A end date is required!</p>
|
||||||
<span class="input-group-btn">
|
<span class="input-group-btn">
|
||||||
<button class="btn btn-default" ng-click="open2($event)"><i class="glyphicon glyphicon-calendar"></i></button>
|
<button class="btn btn-default" ng-click="open2($event)"><i class="glyphicon glyphicon-calendar"></i></button>
|
||||||
|
|
|
@ -94,11 +94,11 @@ angular.module('lemur')
|
||||||
|
|
||||||
AuthorityService.getDefaults = function (authority) {
|
AuthorityService.getDefaults = function (authority) {
|
||||||
return DefaultService.get().then(function (defaults) {
|
return DefaultService.get().then(function (defaults) {
|
||||||
authority.caDN.country = defaults.country;
|
authority.country = defaults.country;
|
||||||
authority.caDN.state = defaults.state;
|
authority.state = defaults.state;
|
||||||
authority.caDN.location = defaults.location;
|
authority.location = defaults.location;
|
||||||
authority.caDN.organization = defaults.organization;
|
authority.organization = defaults.organization;
|
||||||
authority.caDN.organizationalUnit = defaults.organizationalUnit;
|
authority.organizationalUnit = defaults.organizationalUnit;
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -29,9 +29,6 @@ angular.module('lemur')
|
||||||
total: 0, // length of data
|
total: 0, // length of data
|
||||||
getData: function ($defer, params) {
|
getData: function ($defer, params) {
|
||||||
AuthorityApi.getList(params.url()).then(function (data) {
|
AuthorityApi.getList(params.url()).then(function (data) {
|
||||||
_.each(data, function(authority) {
|
|
||||||
AuthorityService.getRoles(authority);
|
|
||||||
});
|
|
||||||
params.total(data.total);
|
params.total(data.total);
|
||||||
$defer.resolve(data);
|
$defer.resolve(data);
|
||||||
});
|
});
|
||||||
|
|
|
@ -104,11 +104,11 @@
|
||||||
<span style="padding-top: 15px" class="text-center col-sm-1">
|
<span style="padding-top: 15px" class="text-center col-sm-1">
|
||||||
<strong>- or -</strong>
|
<strong>- or -</strong>
|
||||||
</span>
|
</span>
|
||||||
<div class="col-sm-3">
|
<div class="col-sm-3">
|
||||||
<div class="input-group">
|
<div class="input-group">
|
||||||
<input tooltip="Starting Date (yyyy/MM/dd)" class="form-control" datepicker-popup="yyyy/MM/dd"
|
<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"
|
is-open="$parent.openNotBefore.isOpen" min-date="certificate.authority.notBefore"
|
||||||
max-date="certificate.authority.maxDate" ng-model="certificate.validityStart"/>
|
max-date="certificate.authority.notAfter" ng-model="certificate.validityStart"/>
|
||||||
<span class="input-group-btn">
|
<span class="input-group-btn">
|
||||||
<button class="btn btn-default" ng-click="openNotBefore($event)"><i
|
<button class="btn btn-default" ng-click="openNotBefore($event)"><i
|
||||||
class="glyphicon glyphicon-calendar"></i></button>
|
class="glyphicon glyphicon-calendar"></i></button>
|
||||||
|
@ -117,13 +117,12 @@
|
||||||
</div>
|
</div>
|
||||||
<span style="padding-top: 15px" class="text-center col-sm-1"><label><span
|
<span style="padding-top: 15px" class="text-center col-sm-1"><label><span
|
||||||
class="glyphicon glyphicon-resize-horizontal"></span></label></span>
|
class="glyphicon glyphicon-resize-horizontal"></span></label></span>
|
||||||
|
<div class="col-sm-3">
|
||||||
<div class="col-sm-3">
|
<div>
|
||||||
<div>
|
<div class="input-group">
|
||||||
<div class="input-group">
|
<input tooltip="Ending Date (yyyy/MM/dd)" class="form-control" datepicker-popup="yyyy/MM/dd"
|
||||||
<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"
|
||||||
is-open="$parent.openNotAfter.isOpen" min-date="certificate.authority.notBefore"
|
max-date="certificate.authority.notAfter" ng-model="certificate.validityEnd"/>
|
||||||
max-date="certificate.authority.maxDate" ng-model="certificate.validityEnd"/>
|
|
||||||
<span class="input-group-btn">
|
<span class="input-group-btn">
|
||||||
<button class="btn btn-default" ng-click="openNotAfter($event)"><i
|
<button class="btn btn-default" ng-click="openNotAfter($event)"><i
|
||||||
class="glyphicon glyphicon-calendar"></i></button>
|
class="glyphicon glyphicon-calendar"></i></button>
|
||||||
|
|
|
@ -53,7 +53,7 @@
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr class="warning" ng-show="certificate.toggle" ng-repeat-end>
|
<tr class="warning" ng-if="certificate.toggle" ng-repeat-end>
|
||||||
<td colspan="6">
|
<td colspan="6">
|
||||||
<tabset justified="true" class="col-md-6">
|
<tabset justified="true" class="col-md-6">
|
||||||
<tab>
|
<tab>
|
||||||
|
@ -80,8 +80,8 @@
|
||||||
<li class="list-group-item">
|
<li class="list-group-item">
|
||||||
<strong>San</strong>
|
<strong>San</strong>
|
||||||
<span class="pull-right">
|
<span class="pull-right">
|
||||||
<i class="glyphicon glyphicon-ok" ng-show="certificate.san"></i>
|
<i class="glyphicon glyphicon-ok" ng-if="certificate.san"></i>
|
||||||
<i class="glyphicon glyphicon-remove" ng-show="!certificate.san"></i>
|
<i class="glyphicon glyphicon-remove" ng-if="!certificate.san"></i>
|
||||||
</span>
|
</span>
|
||||||
</li>
|
</li>
|
||||||
<li class="list-group-item">
|
<li class="list-group-item">
|
||||||
|
@ -101,9 +101,9 @@
|
||||||
class="list-group-item">
|
class="list-group-item">
|
||||||
<strong>Validity</strong>
|
<strong>Validity</strong>
|
||||||
<span class="pull-right">
|
<span class="pull-right">
|
||||||
<span ng-show="!certificate.status" class="label label-warning">Unknown</span>
|
<span ng-if="!certificate.status" class="label label-warning">Unknown</span>
|
||||||
<span ng-show="certificate.status == 'revoked'" class="label label-danger">Revoked</span>
|
<span ng-if="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 == 'valid'" class="label label-success">Valid</span>
|
||||||
</span>
|
</span>
|
||||||
</li>
|
</li>
|
||||||
<li class="list-group-item">
|
<li class="list-group-item">
|
||||||
|
|
|
@ -103,6 +103,13 @@ def certificate(session):
|
||||||
return c
|
return c
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def role(session):
|
||||||
|
r = RoleFactory()
|
||||||
|
session.commit()
|
||||||
|
return r
|
||||||
|
|
||||||
|
|
||||||
@pytest.yield_fixture(scope="function")
|
@pytest.yield_fixture(scope="function")
|
||||||
def logged_in_user(app, user):
|
def logged_in_user(app, user):
|
||||||
with app.test_request_context():
|
with app.test_request_context():
|
||||||
|
|
|
@ -1,150 +1,160 @@
|
||||||
|
|
||||||
|
import pytest
|
||||||
from lemur.authorities.views import * # noqa
|
from lemur.authorities.views import * # noqa
|
||||||
|
|
||||||
# def test_crud(session):
|
from .vectors import VALID_ADMIN_HEADER_TOKEN, VALID_USER_HEADER_TOKEN
|
||||||
# role = create('role1')
|
|
||||||
# assert role.id > 0
|
|
||||||
#
|
def test_authority_input_schema(client, role):
|
||||||
# role = update(role.id, 'role_new', None, [])
|
from lemur.authorities.schemas import AuthorityInputSchema
|
||||||
# assert role.name == 'role_new'
|
|
||||||
# delete(role.id)
|
input_data = {
|
||||||
# assert get(role.id) == None
|
'name': 'Example Authority',
|
||||||
|
'owner': 'jim@example.com',
|
||||||
|
'description': 'An example authority.',
|
||||||
def test_authority_get(client):
|
'commonName': 'AnExampleAuthority',
|
||||||
assert client.get(api.url_for(Authorities, authority_id=1)).status_code == 401
|
'pluginName': {'slug': 'verisign-issuer'},
|
||||||
|
'type': 'root',
|
||||||
|
'signingAlgorithm': 'sha256WithRSA',
|
||||||
def test_authority_post(client):
|
'keyType': 'RSA2048',
|
||||||
assert client.post(api.url_for(Authorities, authority_id=1), data={}).status_code == 405
|
'sensitivity': 'medium'
|
||||||
|
}
|
||||||
|
|
||||||
def test_authority_put(client):
|
data, errors = AuthorityInputSchema().load(input_data)
|
||||||
assert client.put(api.url_for(Authorities, authority_id=1), data={}).status_code == 401
|
|
||||||
|
assert not errors
|
||||||
|
|
||||||
def test_authority_delete(client):
|
|
||||||
assert client.delete(api.url_for(Authorities, authority_id=1)).status_code == 405
|
@pytest.mark.parametrize("token,status", [
|
||||||
|
(VALID_USER_HEADER_TOKEN, 404),
|
||||||
|
(VALID_ADMIN_HEADER_TOKEN, 404),
|
||||||
def test_authority_patch(client):
|
('', 401)
|
||||||
assert client.patch(api.url_for(Authorities, authority_id=1), data={}).status_code == 405
|
])
|
||||||
|
def test_authority_get(client, token, status):
|
||||||
|
assert client.get(api.url_for(Authorities, authority_id=1), headers=token).status_code == status
|
||||||
def test_authorities_get(client):
|
|
||||||
assert client.get(api.url_for(AuthoritiesList)).status_code == 401
|
|
||||||
|
@pytest.mark.parametrize("token,status", [
|
||||||
|
(VALID_USER_HEADER_TOKEN, 405),
|
||||||
def test_authorities_post(client):
|
(VALID_ADMIN_HEADER_TOKEN, 405),
|
||||||
assert client.post(api.url_for(AuthoritiesList), data={}).status_code == 401
|
('', 405)
|
||||||
|
])
|
||||||
|
def test_authority_post(client, token, status):
|
||||||
def test_authorities_put(client):
|
assert client.post(api.url_for(Authorities, authority_id=1), data={}, headers=token).status_code == status
|
||||||
assert client.put(api.url_for(AuthoritiesList), data={}).status_code == 405
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize("token,status", [
|
||||||
def test_authorities_delete(client):
|
(VALID_USER_HEADER_TOKEN, 400),
|
||||||
assert client.delete(api.url_for(AuthoritiesList)).status_code == 405
|
(VALID_ADMIN_HEADER_TOKEN, 400),
|
||||||
|
('', 401)
|
||||||
|
])
|
||||||
def test_authorities_patch(client):
|
def test_authority_put(client, token, status):
|
||||||
assert client.patch(api.url_for(AuthoritiesList), data={}).status_code == 405
|
assert client.put(api.url_for(Authorities, authority_id=1), data={}, headers=token).status_code == status
|
||||||
|
|
||||||
|
|
||||||
def test_certificate_authorities_get(client):
|
@pytest.mark.parametrize("token,status", [
|
||||||
assert client.get(api.url_for(AuthoritiesList)).status_code == 401
|
(VALID_USER_HEADER_TOKEN, 405),
|
||||||
|
(VALID_ADMIN_HEADER_TOKEN, 405),
|
||||||
|
('', 405)
|
||||||
def test_certificate_authorities_post(client):
|
])
|
||||||
assert client.post(api.url_for(AuthoritiesList), data={}).status_code == 401
|
def test_authority_delete(client, token, status):
|
||||||
|
assert client.delete(api.url_for(Authorities, authority_id=1), headers=token).status_code == status
|
||||||
|
|
||||||
def test_certificate_authorities_put(client):
|
|
||||||
assert client.put(api.url_for(AuthoritiesList), data={}).status_code == 405
|
@pytest.mark.parametrize("token,status", [
|
||||||
|
(VALID_USER_HEADER_TOKEN, 405),
|
||||||
|
(VALID_ADMIN_HEADER_TOKEN, 405),
|
||||||
def test_certificate_authorities_delete(client):
|
('', 405)
|
||||||
assert client.delete(api.url_for(AuthoritiesList)).status_code == 405
|
])
|
||||||
|
def test_authority_patch(client, token, status):
|
||||||
|
assert client.patch(api.url_for(Authorities, authority_id=1), data={}, headers=token).status_code == status
|
||||||
def test_certificate_authorities_patch(client):
|
|
||||||
assert client.patch(api.url_for(AuthoritiesList), data={}).status_code == 405
|
|
||||||
|
@pytest.mark.parametrize("token,status", [
|
||||||
|
(VALID_USER_HEADER_TOKEN, 200),
|
||||||
VALID_USER_HEADER_TOKEN = {
|
(VALID_ADMIN_HEADER_TOKEN, 200),
|
||||||
'Authorization': 'Basic ' + 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpYXQiOjE0MzUyMzMzNjksInN1YiI6MSwiZXhwIjoxNTIxNTQ2OTY5fQ.1qCi0Ip7mzKbjNh0tVd3_eJOrae3rNa_9MCVdA4WtQI'}
|
('', 401)
|
||||||
|
])
|
||||||
|
def test_authorities_get(client, token, status):
|
||||||
def test_auth_authority_get(client):
|
assert client.get(api.url_for(AuthoritiesList), headers=token).status_code == status
|
||||||
assert client.get(api.url_for(Authorities, authority_id=1), headers=VALID_USER_HEADER_TOKEN).status_code == 200
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize("token,status", [
|
||||||
def test_auth_authority_post_(client):
|
(VALID_USER_HEADER_TOKEN, 400),
|
||||||
assert client.post(api.url_for(Authorities, authority_id=1), data={}, headers=VALID_USER_HEADER_TOKEN).status_code == 405
|
(VALID_ADMIN_HEADER_TOKEN, 400),
|
||||||
|
('', 401)
|
||||||
|
])
|
||||||
def test_auth_authority_put(client):
|
def test_authorities_post(client, token, status):
|
||||||
assert client.put(api.url_for(Authorities, authority_id=1), data={}, headers=VALID_USER_HEADER_TOKEN).status_code == 400
|
assert client.post(api.url_for(AuthoritiesList), data={}, headers=token).status_code == status
|
||||||
|
|
||||||
|
|
||||||
def test_auth_authority_delete(client):
|
@pytest.mark.parametrize("token,status", [
|
||||||
assert client.delete(api.url_for(Authorities, authority_id=1), headers=VALID_USER_HEADER_TOKEN).status_code == 405
|
(VALID_USER_HEADER_TOKEN, 405),
|
||||||
|
(VALID_ADMIN_HEADER_TOKEN, 405),
|
||||||
|
('', 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_authorities_put(client, token, status):
|
||||||
|
assert client.put(api.url_for(AuthoritiesList), data={}, headers=token).status_code == status
|
||||||
|
|
||||||
def test_auth_authorities_get(client):
|
|
||||||
assert client.get(api.url_for(AuthoritiesList), headers=VALID_USER_HEADER_TOKEN).status_code == 200
|
@pytest.mark.parametrize("token,status", [
|
||||||
|
(VALID_USER_HEADER_TOKEN, 405),
|
||||||
|
(VALID_ADMIN_HEADER_TOKEN, 405),
|
||||||
def test_auth_authorities_post(client):
|
('', 405)
|
||||||
assert client.post(api.url_for(AuthoritiesList), data={}, headers=VALID_USER_HEADER_TOKEN).status_code == 400
|
])
|
||||||
|
def test_authorities_delete(client, token, status):
|
||||||
|
assert client.delete(api.url_for(AuthoritiesList), headers=token).status_code == status
|
||||||
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
|
|
||||||
|
@pytest.mark.parametrize("token,status", [
|
||||||
|
(VALID_USER_HEADER_TOKEN, 405),
|
||||||
VALID_ADMIN_HEADER_TOKEN = {
|
(VALID_ADMIN_HEADER_TOKEN, 405),
|
||||||
'Authorization': 'Basic ' + 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpYXQiOjE0MzUyNTAyMTgsInN1YiI6MiwiZXhwIjoxNTIxNTYzODE4fQ.6mbq4-Ro6K5MmuNiTJBB153RDhlM5LGJBjI7GBKkfqA'}
|
('', 405)
|
||||||
|
])
|
||||||
|
def test_authorities_patch(client, token, status):
|
||||||
def test_admin_authority_get(client):
|
assert client.patch(api.url_for(AuthoritiesList), data={}, headers=token).status_code == status
|
||||||
assert client.get(api.url_for(Authorities, authority_id=1), headers=VALID_ADMIN_HEADER_TOKEN).status_code == 200
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize("token,status", [
|
||||||
def test_admin_authority_post(client):
|
(VALID_USER_HEADER_TOKEN, 200),
|
||||||
assert client.post(api.url_for(Authorities, authority_id=1), data={}, headers=VALID_ADMIN_HEADER_TOKEN).status_code == 405
|
(VALID_ADMIN_HEADER_TOKEN, 200),
|
||||||
|
('', 401)
|
||||||
|
])
|
||||||
def test_admin_authority_put(client):
|
def test_certificate_authorities_get(client, token, status):
|
||||||
assert client.put(api.url_for(Authorities, authority_id=1), data={}, headers=VALID_ADMIN_HEADER_TOKEN).status_code == 400
|
assert client.get(api.url_for(AuthoritiesList), headers=token).status_code == status
|
||||||
|
|
||||||
|
|
||||||
def test_admin_authority_delete(client):
|
@pytest.mark.parametrize("token,status", [
|
||||||
assert client.delete(api.url_for(Authorities, authority_id=1), headers=VALID_ADMIN_HEADER_TOKEN).status_code == 405
|
(VALID_USER_HEADER_TOKEN, 400),
|
||||||
|
(VALID_ADMIN_HEADER_TOKEN, 400),
|
||||||
|
('', 401)
|
||||||
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_certificate_authorities_post(client, token, status):
|
||||||
|
assert client.post(api.url_for(AuthoritiesList), data={}, headers=token).status_code == status
|
||||||
|
|
||||||
def test_admin_authorities_get(client):
|
|
||||||
assert client.get(api.url_for(AuthoritiesList), headers=VALID_ADMIN_HEADER_TOKEN).status_code == 200
|
@pytest.mark.parametrize("token,status", [
|
||||||
|
(VALID_USER_HEADER_TOKEN, 405),
|
||||||
|
(VALID_ADMIN_HEADER_TOKEN, 405),
|
||||||
def test_admin_authorities_post(client):
|
('', 405)
|
||||||
assert client.post(api.url_for(AuthoritiesList), data={}, headers=VALID_ADMIN_HEADER_TOKEN).status_code == 400
|
])
|
||||||
|
def test_certificate_authorities_put(client, token, status):
|
||||||
|
assert client.put(api.url_for(AuthoritiesList), data={}, headers=token).status_code == status
|
||||||
def test_admin_authorities_put(client):
|
|
||||||
assert client.put(api.url_for(AuthoritiesList), data={}, headers=VALID_ADMIN_HEADER_TOKEN).status_code == 405
|
|
||||||
|
@pytest.mark.parametrize("token,status", [
|
||||||
|
(VALID_USER_HEADER_TOKEN, 405),
|
||||||
def test_admin_authorities_delete(client):
|
(VALID_ADMIN_HEADER_TOKEN, 405),
|
||||||
assert client.delete(api.url_for(AuthoritiesList), headers=VALID_ADMIN_HEADER_TOKEN).status_code == 405
|
('', 405)
|
||||||
|
])
|
||||||
|
def test_certificate_authorities_delete(client, token, status):
|
||||||
def test_admin_certificate_authorities_get(client):
|
assert client.delete(api.url_for(AuthoritiesList), headers=token).status_code == status
|
||||||
assert client.get(api.url_for(CertificateAuthority, certificate_id=1), headers=VALID_ADMIN_HEADER_TOKEN).status_code == 404
|
|
||||||
|
|
||||||
|
@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 pytest
|
||||||
import json
|
import json
|
||||||
|
|
||||||
from lemur.certificates.views import * # noqa
|
from lemur.certificates.views import * # noqa
|
||||||
|
|
||||||
from .vectors import VALID_ADMIN_HEADER_TOKEN, VALID_USER_HEADER_TOKEN
|
from .vectors import VALID_ADMIN_HEADER_TOKEN, VALID_USER_HEADER_TOKEN
|
||||||
|
|
||||||
|
|
||||||
def test_authority_identifier_schema():
|
def test_authority_identifier_schema():
|
||||||
from lemur.certificates.schemas import AuthorityIdentifierSchema
|
from lemur.schemas import AuthorityIdentifierSchema
|
||||||
input_data = {'useAuthorityCert': True}
|
input_data = {'useAuthorityCert': True}
|
||||||
|
|
||||||
data, errors = AuthorityIdentifierSchema().load(input_data)
|
data, errors = AuthorityIdentifierSchema().load(input_data)
|
||||||
|
@ -22,7 +23,7 @@ def test_authority_identifier_schema():
|
||||||
|
|
||||||
|
|
||||||
def test_authority_key_identifier_schema():
|
def test_authority_key_identifier_schema():
|
||||||
from lemur.certificates.schemas import AuthorityKeyIdentifierSchema
|
from lemur.schemas import AuthorityKeyIdentifierSchema
|
||||||
input_data = {'useKeyIdentifier': True}
|
input_data = {'useKeyIdentifier': True}
|
||||||
|
|
||||||
data, errors = AuthorityKeyIdentifierSchema().load(input_data)
|
data, errors = AuthorityKeyIdentifierSchema().load(input_data)
|
||||||
|
@ -36,7 +37,7 @@ def test_authority_key_identifier_schema():
|
||||||
|
|
||||||
|
|
||||||
def test_certificate_info_access_schema():
|
def test_certificate_info_access_schema():
|
||||||
from lemur.certificates.schemas import CertificateInfoAccessSchema
|
from lemur.schemas import CertificateInfoAccessSchema
|
||||||
input_data = {'includeAIA': True}
|
input_data = {'includeAIA': True}
|
||||||
|
|
||||||
data, errors = CertificateInfoAccessSchema().load(input_data)
|
data, errors = CertificateInfoAccessSchema().load(input_data)
|
||||||
|
@ -49,7 +50,7 @@ def test_certificate_info_access_schema():
|
||||||
|
|
||||||
|
|
||||||
def test_subject_key_identifier_schema():
|
def test_subject_key_identifier_schema():
|
||||||
from lemur.certificates.schemas import SubjectKeyIdentifierSchema
|
from lemur.schemas import SubjectKeyIdentifierSchema
|
||||||
|
|
||||||
input_data = {'includeSKI': True}
|
input_data = {'includeSKI': True}
|
||||||
|
|
||||||
|
@ -61,7 +62,7 @@ def test_subject_key_identifier_schema():
|
||||||
assert data == input_data
|
assert data == input_data
|
||||||
|
|
||||||
|
|
||||||
def test_extension_schema():
|
def test_extension_schema(client):
|
||||||
from lemur.certificates.schemas import ExtensionSchema
|
from lemur.certificates.schemas import ExtensionSchema
|
||||||
|
|
||||||
input_data = {
|
input_data = {
|
||||||
|
@ -194,7 +195,7 @@ def test_certificate_valid_dates(client, authority):
|
||||||
|
|
||||||
|
|
||||||
def test_sub_alt_name_schema():
|
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'}
|
input_data = {'nameType': 'DNSName', 'value': 'test.example.com'}
|
||||||
|
|
||||||
data, errors = SubAltNameSchema().load(input_data)
|
data, errors = SubAltNameSchema().load(input_data)
|
||||||
|
@ -217,7 +218,7 @@ def test_sub_alt_name_schema():
|
||||||
|
|
||||||
|
|
||||||
def test_key_usage_schema():
|
def test_key_usage_schema():
|
||||||
from lemur.certificates.schemas import KeyUsageSchema
|
from lemur.schemas import KeyUsageSchema
|
||||||
|
|
||||||
input_data = {
|
input_data = {
|
||||||
'useCRLSign': True,
|
'useCRLSign': True,
|
||||||
|
@ -244,7 +245,7 @@ def test_key_usage_schema():
|
||||||
|
|
||||||
|
|
||||||
def test_extended_key_usage_schema():
|
def test_extended_key_usage_schema():
|
||||||
from lemur.certificates.schemas import ExtendedKeyUsageSchema
|
from lemur.schemas import ExtendedKeyUsageSchema
|
||||||
|
|
||||||
input_data = {
|
input_data = {
|
||||||
'useServerAuthentication': True,
|
'useServerAuthentication': True,
|
||||||
|
|
Loading…
Reference in New Issue