* Closes #147 * Fixing tests * Ensuring we can validate max dates.
This commit is contained in:
parent
bd727b825d
commit
656269ff17
|
@ -6,49 +6,35 @@
|
||||||
:license: Apache, see LICENSE for more details.
|
:license: Apache, see LICENSE for more details.
|
||||||
.. moduleauthor:: Kevin Glisson <kglisson@netflix.com>
|
.. moduleauthor:: Kevin Glisson <kglisson@netflix.com>
|
||||||
"""
|
"""
|
||||||
from cryptography import x509
|
|
||||||
from cryptography.hazmat.backends import default_backend
|
|
||||||
|
|
||||||
from sqlalchemy.orm import relationship
|
from sqlalchemy.orm import relationship
|
||||||
from sqlalchemy import Column, Integer, String, Text, func, ForeignKey, DateTime, PassiveDefault, Boolean
|
from sqlalchemy import Column, Integer, String, Text, func, ForeignKey, DateTime, PassiveDefault, Boolean
|
||||||
from sqlalchemy.dialects.postgresql import JSON
|
from sqlalchemy.dialects.postgresql import JSON
|
||||||
|
|
||||||
from lemur.database import db
|
from lemur.database import db
|
||||||
from lemur.models import roles_authorities
|
from lemur.models import roles_authorities
|
||||||
from lemur.common import defaults
|
|
||||||
|
|
||||||
|
|
||||||
class Authority(db.Model):
|
class Authority(db.Model):
|
||||||
__tablename__ = 'authorities'
|
__tablename__ = 'authorities'
|
||||||
id = Column(Integer, primary_key=True)
|
id = Column(Integer, primary_key=True)
|
||||||
owner = Column(String(128))
|
owner = Column(String(128), nullable=False)
|
||||||
name = Column(String(128), unique=True)
|
name = Column(String(128), unique=True)
|
||||||
body = Column(Text())
|
body = Column(Text())
|
||||||
chain = Column(Text())
|
chain = Column(Text())
|
||||||
bits = Column(Integer())
|
|
||||||
cn = Column(String(128))
|
|
||||||
not_before = Column(DateTime)
|
|
||||||
not_after = Column(DateTime)
|
|
||||||
active = Column(Boolean, default=True)
|
active = Column(Boolean, default=True)
|
||||||
date_created = Column(DateTime, PassiveDefault(func.now()), nullable=False)
|
|
||||||
plugin_name = Column(String(64))
|
plugin_name = Column(String(64))
|
||||||
description = Column(Text)
|
description = Column(Text)
|
||||||
options = Column(JSON)
|
options = Column(JSON)
|
||||||
|
date_created = Column(DateTime, PassiveDefault(func.now()), nullable=False)
|
||||||
roles = relationship('Role', secondary=roles_authorities, passive_deletes=True, backref=db.backref('authority'), lazy='dynamic')
|
roles = relationship('Role', secondary=roles_authorities, passive_deletes=True, backref=db.backref('authority'), lazy='dynamic')
|
||||||
user_id = Column(Integer, ForeignKey('users.id'))
|
user_id = Column(Integer, ForeignKey('users.id'))
|
||||||
certificates = relationship("Certificate", backref='authority')
|
authority_certificate = relationship("Certificate", backref='root_authority', uselist=False, foreign_keys='Certificate.root_authority_id')
|
||||||
|
certificates = relationship("Certificate", backref='authority', foreign_keys='Certificate.authority_id')
|
||||||
|
|
||||||
def __init__(self, name, owner, plugin_name, body, roles=None, chain=None, description=None):
|
def __init__(self, **kwargs):
|
||||||
cert = x509.load_pem_x509_certificate(bytes(body), default_backend())
|
self.owner = kwargs['owner']
|
||||||
self.name = name
|
self.roles = kwargs.get('roles', [])
|
||||||
self.body = body
|
self.name = kwargs.get('name')
|
||||||
self.chain = chain
|
self.description = kwargs.get('description')
|
||||||
self.owner = owner
|
self.authority_certificate = kwargs['authority_certificate']
|
||||||
self.description = description
|
self.plugin_name = kwargs['plugin']['slug']
|
||||||
self.plugin_name = plugin_name
|
|
||||||
self.cn = defaults.common_name(cert)
|
|
||||||
self.not_before = defaults.not_before(cert)
|
|
||||||
self.not_after = defaults.not_after(cert)
|
|
||||||
|
|
||||||
if roles:
|
|
||||||
self.roles = roles
|
|
||||||
|
|
|
@ -12,6 +12,7 @@ from marshmallow import validate
|
||||||
from marshmallow.exceptions import ValidationError
|
from marshmallow.exceptions import ValidationError
|
||||||
|
|
||||||
from lemur.schemas import PluginInputSchema, PluginOutputSchema, ExtensionSchema, AssociatedAuthoritySchema, AssociatedRoleSchema
|
from lemur.schemas import PluginInputSchema, PluginOutputSchema, ExtensionSchema, AssociatedAuthoritySchema, AssociatedRoleSchema
|
||||||
|
from lemur.users.schemas import UserNestedOutputSchema
|
||||||
from lemur.common.schema import LemurInputSchema, LemurOutputSchema
|
from lemur.common.schema import LemurInputSchema, LemurOutputSchema
|
||||||
from lemur.common import validators
|
from lemur.common import validators
|
||||||
|
|
||||||
|
@ -61,25 +62,39 @@ class AuthorityInputSchema(LemurInputSchema):
|
||||||
|
|
||||||
|
|
||||||
class AuthorityUpdateSchema(LemurInputSchema):
|
class AuthorityUpdateSchema(LemurInputSchema):
|
||||||
owner = fields.Email()
|
owner = fields.Email(required=True)
|
||||||
description = fields.String()
|
description = fields.String()
|
||||||
active = fields.Boolean()
|
active = fields.Boolean()
|
||||||
roles = fields.Nested(AssociatedRoleSchema(many=True))
|
roles = fields.Nested(AssociatedRoleSchema(many=True))
|
||||||
|
|
||||||
|
|
||||||
|
class RootAuthorityCertificateOutputSchema(LemurOutputSchema):
|
||||||
|
__envelope__ = False
|
||||||
|
id = fields.Integer()
|
||||||
|
active = fields.Boolean()
|
||||||
|
bits = fields.Integer()
|
||||||
|
body = fields.String()
|
||||||
|
chain = fields.String()
|
||||||
|
description = fields.String()
|
||||||
|
name = fields.String()
|
||||||
|
cn = fields.String()
|
||||||
|
not_after = fields.DateTime()
|
||||||
|
not_before = fields.DateTime()
|
||||||
|
owner = fields.Email()
|
||||||
|
status = fields.Boolean()
|
||||||
|
user = fields.Nested(UserNestedOutputSchema)
|
||||||
|
|
||||||
|
|
||||||
class AuthorityOutputSchema(LemurOutputSchema):
|
class AuthorityOutputSchema(LemurOutputSchema):
|
||||||
id = fields.Integer()
|
id = fields.Integer()
|
||||||
description = fields.String()
|
description = fields.String()
|
||||||
name = fields.String()
|
name = fields.String()
|
||||||
owner = fields.Email()
|
owner = fields.Email()
|
||||||
not_before = fields.DateTime()
|
|
||||||
not_after = fields.DateTime()
|
|
||||||
plugin = fields.Nested(PluginOutputSchema)
|
plugin = fields.Nested(PluginOutputSchema)
|
||||||
body = fields.String()
|
|
||||||
chain = fields.String()
|
|
||||||
active = fields.Boolean()
|
active = fields.Boolean()
|
||||||
options = fields.Dict()
|
options = fields.Dict()
|
||||||
roles = fields.List(fields.Nested(AssociatedRoleSchema))
|
roles = fields.List(fields.Nested(AssociatedRoleSchema))
|
||||||
|
authority_certificate = fields.Nested(RootAuthorityCertificateOutputSchema)
|
||||||
|
|
||||||
|
|
||||||
class AuthorityNestedOutputSchema(LemurOutputSchema):
|
class AuthorityNestedOutputSchema(LemurOutputSchema):
|
||||||
|
@ -87,13 +102,8 @@ class AuthorityNestedOutputSchema(LemurOutputSchema):
|
||||||
description = fields.String()
|
description = fields.String()
|
||||||
name = fields.String()
|
name = fields.String()
|
||||||
owner = fields.Email()
|
owner = fields.Email()
|
||||||
not_before = fields.DateTime()
|
|
||||||
not_after = fields.DateTime()
|
|
||||||
plugin = fields.Nested(PluginOutputSchema)
|
plugin = fields.Nested(PluginOutputSchema)
|
||||||
body = fields.String()
|
|
||||||
chain = fields.String()
|
|
||||||
active = fields.Boolean()
|
active = fields.Boolean()
|
||||||
options = fields.Dict()
|
|
||||||
|
|
||||||
|
|
||||||
authority_update_schema = AuthorityUpdateSchema()
|
authority_update_schema = AuthorityUpdateSchema()
|
||||||
|
|
|
@ -9,14 +9,13 @@
|
||||||
|
|
||||||
"""
|
"""
|
||||||
from flask import g
|
from flask import g
|
||||||
from flask import current_app
|
|
||||||
|
|
||||||
from lemur import database
|
from lemur import database
|
||||||
|
from lemur.extensions import metrics
|
||||||
from lemur.authorities.models import Authority
|
from lemur.authorities.models import Authority
|
||||||
from lemur.roles import service as role_service
|
from lemur.roles import service as role_service
|
||||||
from lemur.notifications import service as notification_service
|
|
||||||
|
|
||||||
from lemur.certificates.models import Certificate
|
from lemur.certificates.service import upload
|
||||||
|
|
||||||
|
|
||||||
def update(authority_id, description=None, owner=None, active=None, roles=None):
|
def update(authority_id, description=None, owner=None, active=None, roles=None):
|
||||||
|
@ -40,42 +39,28 @@ def update(authority_id, description=None, owner=None, active=None, roles=None):
|
||||||
return database.update(authority)
|
return database.update(authority)
|
||||||
|
|
||||||
|
|
||||||
def create(kwargs):
|
def mint(**kwargs):
|
||||||
"""
|
"""
|
||||||
Create a new authority.
|
Creates the authority based on the plugin provided.
|
||||||
|
"""
|
||||||
|
issuer = kwargs['plugin']['plugin_object']
|
||||||
|
body, chain, roles = issuer.create_authority(kwargs)
|
||||||
|
return body, chain, roles
|
||||||
|
|
||||||
|
|
||||||
|
def create_authority_roles(roles, **kwargs):
|
||||||
|
"""
|
||||||
|
Creates all of the necessary authority roles.
|
||||||
|
:param roles:
|
||||||
|
:param kwargs:
|
||||||
:return:
|
:return:
|
||||||
"""
|
"""
|
||||||
|
|
||||||
issuer = kwargs['plugin']['plugin_object']
|
|
||||||
|
|
||||||
kwargs['creator'] = g.current_user.email
|
|
||||||
cert_body, intermediate, issuer_roles = issuer.create_authority(kwargs)
|
|
||||||
|
|
||||||
cert = Certificate(body=cert_body, chain=intermediate, **kwargs)
|
|
||||||
|
|
||||||
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('name'), kwargs.get('parent'))
|
|
||||||
else:
|
|
||||||
cert.description = "This is the ROOT certificate for the {0} certificate authority.".format(
|
|
||||||
kwargs.get('name')
|
|
||||||
)
|
|
||||||
|
|
||||||
cert.user = g.current_user
|
|
||||||
|
|
||||||
cert.notifications = notification_service.create_default_expiration_notifications(
|
|
||||||
'DEFAULT_SECURITY',
|
|
||||||
current_app.config.get('LEMUR_SECURITY_TEAM_EMAIL')
|
|
||||||
)
|
|
||||||
|
|
||||||
# we create and attach any roles that the issuer gives us
|
|
||||||
role_objs = []
|
role_objs = []
|
||||||
for r in issuer_roles:
|
for r in roles:
|
||||||
role = role_service.create(
|
role = role_service.create(
|
||||||
r['name'],
|
r['name'],
|
||||||
password=r['password'],
|
password=r['password'],
|
||||||
description="{0} auto generated role".format(issuer.title),
|
description="Auto generated role for {0}".format(kwargs['plugin']['plugin_object'].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
|
||||||
|
@ -93,22 +78,39 @@ def create(kwargs):
|
||||||
)
|
)
|
||||||
|
|
||||||
role_objs.append(owner_role)
|
role_objs.append(owner_role)
|
||||||
|
return role_objs
|
||||||
|
|
||||||
authority = Authority(
|
|
||||||
kwargs.get('name'),
|
def create(**kwargs):
|
||||||
kwargs['owner'],
|
"""
|
||||||
issuer.slug,
|
Creates a new authority.
|
||||||
cert_body,
|
"""
|
||||||
description=kwargs['description'],
|
kwargs['creator'] = g.user.email
|
||||||
chain=intermediate,
|
body, chain, roles = mint(**kwargs)
|
||||||
roles=role_objs
|
|
||||||
|
kwargs['body'] = body
|
||||||
|
kwargs['chain'] = chain
|
||||||
|
|
||||||
|
kwargs['roles'] = create_authority_roles(roles, **kwargs)
|
||||||
|
|
||||||
|
if kwargs['type'] == 'subca':
|
||||||
|
description = "This is the ROOT certificate for the {0} sub certificate authority the parent \
|
||||||
|
authority is {1}.".format(kwargs.get('name'), kwargs.get('parent'))
|
||||||
|
else:
|
||||||
|
description = "This is the ROOT certificate for the {0} certificate authority.".format(
|
||||||
|
kwargs.get('name')
|
||||||
)
|
)
|
||||||
|
|
||||||
database.update(cert)
|
kwargs['description'] = description
|
||||||
|
|
||||||
|
cert = upload(**kwargs)
|
||||||
|
kwargs['authority_certificate'] = cert
|
||||||
|
|
||||||
|
authority = Authority(**kwargs)
|
||||||
authority = database.create(authority)
|
authority = database.create(authority)
|
||||||
|
g.user.authorities.append(authority)
|
||||||
|
|
||||||
g.current_user.authorities.append(authority)
|
metrics.send('authority_created', 'counter', 1, metric_tags=dict(owner=authority.owner))
|
||||||
|
|
||||||
return authority
|
return authority
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -167,7 +167,7 @@ class AuthoritiesList(AuthenticatedResource):
|
||||||
:statuscode 403: unauthenticated
|
:statuscode 403: unauthenticated
|
||||||
:statuscode 200: no error
|
:statuscode 200: no error
|
||||||
"""
|
"""
|
||||||
return service.create(data)
|
return service.create(**data)
|
||||||
|
|
||||||
|
|
||||||
class Authorities(AuthenticatedResource):
|
class Authorities(AuthenticatedResource):
|
||||||
|
|
|
@ -36,7 +36,7 @@ class Certificate(db.Model):
|
||||||
__tablename__ = 'certificates'
|
__tablename__ = 'certificates'
|
||||||
id = Column(Integer, primary_key=True)
|
id = Column(Integer, primary_key=True)
|
||||||
owner = Column(String(128), nullable=False)
|
owner = Column(String(128), nullable=False)
|
||||||
name = Column(String(128), unique=True)
|
name = Column(String(128)) # , unique=True) TODO make all names unique
|
||||||
description = Column(String(1024))
|
description = Column(String(1024))
|
||||||
active = Column(Boolean, default=True)
|
active = Column(Boolean, default=True)
|
||||||
|
|
||||||
|
@ -59,7 +59,9 @@ class Certificate(db.Model):
|
||||||
san = Column(String(1024)) # TODO this should be migrated to boolean
|
san = Column(String(1024)) # TODO this should be migrated to boolean
|
||||||
|
|
||||||
user_id = Column(Integer, ForeignKey('users.id'))
|
user_id = Column(Integer, ForeignKey('users.id'))
|
||||||
authority_id = Column(Integer, ForeignKey('authorities.id'))
|
authority_id = Column(Integer, ForeignKey('authorities.id', ondelete="CASCADE"))
|
||||||
|
root_authority_id = Column(Integer, ForeignKey('authorities.id', ondelete="CASCADE"))
|
||||||
|
|
||||||
notifications = relationship("Notification", secondary=certificate_notification_associations, backref='certificate')
|
notifications = relationship("Notification", secondary=certificate_notification_associations, backref='certificate')
|
||||||
destinations = relationship("Destination", secondary=certificate_destination_associations, backref='certificate')
|
destinations = relationship("Destination", secondary=certificate_destination_associations, backref='certificate')
|
||||||
sources = relationship("Source", secondary=certificate_source_associations, backref='certificate')
|
sources = relationship("Source", secondary=certificate_source_associations, backref='certificate')
|
||||||
|
|
|
@ -6,7 +6,6 @@
|
||||||
.. moduleauthor:: Kevin Glisson <kglisson@netflix.com>
|
.. moduleauthor:: Kevin Glisson <kglisson@netflix.com>
|
||||||
"""
|
"""
|
||||||
from flask import current_app
|
from flask import current_app
|
||||||
|
|
||||||
from marshmallow import fields, validates_schema, post_load
|
from marshmallow import fields, validates_schema, post_load
|
||||||
from marshmallow.exceptions import ValidationError
|
from marshmallow.exceptions import ValidationError
|
||||||
|
|
||||||
|
@ -17,7 +16,7 @@ from lemur.authorities.schemas import AuthorityNestedOutputSchema
|
||||||
from lemur.destinations.schemas import DestinationNestedOutputSchema
|
from lemur.destinations.schemas import DestinationNestedOutputSchema
|
||||||
from lemur.notifications.schemas import NotificationNestedOutputSchema
|
from lemur.notifications.schemas import NotificationNestedOutputSchema
|
||||||
from lemur.roles.schemas import RoleNestedOutputSchema
|
from lemur.roles.schemas import RoleNestedOutputSchema
|
||||||
# from lemur.domains.schemas import DomainNestedOutputSchema
|
from lemur.domains.schemas import DomainNestedOutputSchema
|
||||||
from lemur.users.schemas import UserNestedOutputSchema
|
from lemur.users.schemas import UserNestedOutputSchema
|
||||||
|
|
||||||
from lemur.common.schema import LemurInputSchema, LemurOutputSchema
|
from lemur.common.schema import LemurInputSchema, LemurOutputSchema
|
||||||
|
@ -115,7 +114,7 @@ class CertificateOutputSchema(LemurOutputSchema):
|
||||||
signing_algorithm = fields.String()
|
signing_algorithm = fields.String()
|
||||||
status = fields.Boolean()
|
status = fields.Boolean()
|
||||||
user = fields.Nested(UserNestedOutputSchema)
|
user = fields.Nested(UserNestedOutputSchema)
|
||||||
# domains = fields.Nested(DomainNestedOutputSchema)
|
domains = fields.Nested(DomainNestedOutputSchema)
|
||||||
destinations = fields.Nested(DestinationNestedOutputSchema, many=True)
|
destinations = fields.Nested(DestinationNestedOutputSchema, many=True)
|
||||||
notifications = fields.Nested(NotificationNestedOutputSchema, many=True)
|
notifications = fields.Nested(NotificationNestedOutputSchema, many=True)
|
||||||
replaces = fields.Nested(CertificateNestedOutputSchema, many=True)
|
replaces = fields.Nested(CertificateNestedOutputSchema, many=True)
|
||||||
|
|
|
@ -120,7 +120,6 @@ def mint(**kwargs):
|
||||||
Minting is slightly different for each authority.
|
Minting is slightly different for each authority.
|
||||||
Support for multiple authorities is handled by individual plugins.
|
Support for multiple authorities is handled by individual plugins.
|
||||||
|
|
||||||
:param issuer_options:
|
|
||||||
"""
|
"""
|
||||||
authority = kwargs['authority']
|
authority = kwargs['authority']
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
|
|
||||||
"""
|
"""
|
||||||
from functools import wraps
|
from functools import wraps
|
||||||
from flask import request
|
from flask import request, current_app
|
||||||
|
|
||||||
from sqlalchemy.orm.collections import InstrumentedList
|
from sqlalchemy.orm.collections import InstrumentedList
|
||||||
|
|
||||||
|
@ -135,6 +135,7 @@ def validate_schema(input_schema, output_schema):
|
||||||
try:
|
try:
|
||||||
resp = f(*args, **kwargs)
|
resp = f(*args, **kwargs)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
current_app.logger.exception(e)
|
||||||
return dict(message=e.message), 500
|
return dict(message=e.message), 500
|
||||||
|
|
||||||
if isinstance(resp, tuple):
|
if isinstance(resp, tuple):
|
||||||
|
|
|
@ -102,19 +102,19 @@ def dates(data):
|
||||||
raise ValidationError('Validity start must be before validity end.')
|
raise ValidationError('Validity start must be before validity end.')
|
||||||
|
|
||||||
if data.get('authority'):
|
if data.get('authority'):
|
||||||
if data.get('validity_start').replace(tzinfo=None) < data['authority'].not_before:
|
if data.get('validity_start').replace(tzinfo=None) < data['authority'].authority_certificate.not_before:
|
||||||
raise ValidationError('Validity start must not be before {0}'.format(data['authority'].not_before))
|
raise ValidationError('Validity start must not be before {0}'.format(data['authority'].authority_certificate.not_before))
|
||||||
|
|
||||||
if data.get('validity_end').replace(tzinfo=None) > data['authority'].not_after:
|
if data.get('validity_end').replace(tzinfo=None) > data['authority'].authority_certificate.not_after:
|
||||||
raise ValidationError('Validity end must not be after {0}'.format(data['authority'].not_after))
|
raise ValidationError('Validity end must not be after {0}'.format(data['authority'].authority_certificate.not_after))
|
||||||
|
|
||||||
if data.get('validity_years'):
|
if data.get('validity_years'):
|
||||||
now = arrow.utcnow()
|
now = arrow.utcnow()
|
||||||
end = now.replace(years=+data['validity_years'])
|
end = now.replace(years=+data['validity_years'])
|
||||||
|
|
||||||
if data.get('authority'):
|
if data.get('authority'):
|
||||||
if now.naive < data['authority'].not_before:
|
if now.naive < data['authority'].authority_certificate.not_before:
|
||||||
raise ValidationError('Validity start must not be before {0}'.format(data['authority'].not_before))
|
raise ValidationError('Validity start must not be before {0}'.format(data['authority'].authority_certificate.not_before))
|
||||||
|
|
||||||
if end.naive > data['authority'].not_after:
|
if end.naive > data['authority'].authority_certificate.not_after:
|
||||||
raise ValidationError('Validity end must not be after {0}'.format(data['authority'].not_after))
|
raise ValidationError('Validity end must not be after {0}'.format(data['authority'].authority_certificate.not_after))
|
||||||
|
|
|
@ -9,7 +9,7 @@ from marshmallow import fields
|
||||||
from lemur.common.schema import LemurInputSchema, LemurOutputSchema
|
from lemur.common.schema import LemurInputSchema, LemurOutputSchema
|
||||||
from lemur.schemas import AssociatedCertificateSchema
|
from lemur.schemas import AssociatedCertificateSchema
|
||||||
|
|
||||||
from lemur.certificates.schemas import CertificateNestedOutputSchema
|
# from lemur.certificates.schemas import CertificateNestedOutputSchema
|
||||||
|
|
||||||
|
|
||||||
class DomainInputSchema(LemurInputSchema):
|
class DomainInputSchema(LemurInputSchema):
|
||||||
|
@ -23,7 +23,7 @@ class DomainOutputSchema(LemurOutputSchema):
|
||||||
id = fields.Integer()
|
id = fields.Integer()
|
||||||
name = fields.String()
|
name = fields.String()
|
||||||
sensitive = fields.Boolean()
|
sensitive = fields.Boolean()
|
||||||
certificates = fields.Nested(CertificateNestedOutputSchema, many=True, missing=[])
|
# certificates = fields.Nested(CertificateNestedOutputSchema, many=True, missing=[])
|
||||||
|
|
||||||
|
|
||||||
class DomainNestedOutputSchema(DomainOutputSchema):
|
class DomainNestedOutputSchema(DomainOutputSchema):
|
||||||
|
|
|
@ -0,0 +1,58 @@
|
||||||
|
"""empty message
|
||||||
|
|
||||||
|
Revision ID: 3307381f3b88
|
||||||
|
Revises: 412b22cb656a
|
||||||
|
Create Date: 2016-05-20 17:33:04.360687
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
# revision identifiers, used by Alembic.
|
||||||
|
revision = '3307381f3b88'
|
||||||
|
down_revision = '412b22cb656a'
|
||||||
|
|
||||||
|
from alembic import op
|
||||||
|
import sqlalchemy as sa
|
||||||
|
from sqlalchemy.dialects import postgresql
|
||||||
|
|
||||||
|
def upgrade():
|
||||||
|
### commands auto generated by Alembic - please adjust! ###
|
||||||
|
op.alter_column('authorities', 'owner',
|
||||||
|
existing_type=sa.VARCHAR(length=128),
|
||||||
|
nullable=False)
|
||||||
|
op.drop_column('authorities', 'not_after')
|
||||||
|
op.drop_column('authorities', 'bits')
|
||||||
|
op.drop_column('authorities', 'cn')
|
||||||
|
op.drop_column('authorities', 'not_before')
|
||||||
|
op.add_column('certificates', sa.Column('root_authority_id', sa.Integer(), nullable=True))
|
||||||
|
op.alter_column('certificates', 'body',
|
||||||
|
existing_type=sa.TEXT(),
|
||||||
|
nullable=False)
|
||||||
|
op.alter_column('certificates', 'owner',
|
||||||
|
existing_type=sa.VARCHAR(length=128),
|
||||||
|
nullable=False)
|
||||||
|
op.drop_constraint(u'certificates_authority_id_fkey', 'certificates', type_='foreignkey')
|
||||||
|
op.create_foreign_key(None, 'certificates', 'authorities', ['authority_id'], ['id'], ondelete='CASCADE')
|
||||||
|
op.create_foreign_key(None, 'certificates', 'authorities', ['root_authority_id'], ['id'], ondelete='CASCADE')
|
||||||
|
### end Alembic commands ###
|
||||||
|
|
||||||
|
|
||||||
|
def downgrade():
|
||||||
|
### commands auto generated by Alembic - please adjust! ###
|
||||||
|
op.drop_constraint(None, 'certificates', type_='foreignkey')
|
||||||
|
op.drop_constraint(None, 'certificates', type_='foreignkey')
|
||||||
|
op.create_foreign_key(u'certificates_authority_id_fkey', 'certificates', 'authorities', ['authority_id'], ['id'])
|
||||||
|
op.alter_column('certificates', 'owner',
|
||||||
|
existing_type=sa.VARCHAR(length=128),
|
||||||
|
nullable=True)
|
||||||
|
op.alter_column('certificates', 'body',
|
||||||
|
existing_type=sa.TEXT(),
|
||||||
|
nullable=True)
|
||||||
|
op.drop_column('certificates', 'root_authority_id')
|
||||||
|
op.add_column('authorities', sa.Column('not_before', postgresql.TIMESTAMP(), autoincrement=False, nullable=True))
|
||||||
|
op.add_column('authorities', sa.Column('cn', sa.VARCHAR(length=128), autoincrement=False, nullable=True))
|
||||||
|
op.add_column('authorities', sa.Column('bits', sa.INTEGER(), autoincrement=False, nullable=True))
|
||||||
|
op.add_column('authorities', sa.Column('not_after', postgresql.TIMESTAMP(), autoincrement=False, nullable=True))
|
||||||
|
op.alter_column('authorities', 'owner',
|
||||||
|
existing_type=sa.VARCHAR(length=128),
|
||||||
|
nullable=True)
|
||||||
|
### end Alembic commands ###
|
|
@ -1,4 +1,4 @@
|
||||||
"""empty message
|
"""
|
||||||
|
|
||||||
Revision ID: 412b22cb656a
|
Revision ID: 412b22cb656a
|
||||||
Revises: 4c50b903d1ae
|
Revises: 4c50b903d1ae
|
||||||
|
|
|
@ -9,17 +9,15 @@
|
||||||
"""
|
"""
|
||||||
from marshmallow import fields, post_load, pre_load, post_dump, validates_schema
|
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.certificates.models import Certificate
|
from lemur.certificates.models import Certificate
|
||||||
from lemur.notifications.models import Notification
|
|
||||||
from lemur.users.models import User
|
|
||||||
|
|
||||||
from lemur.common import validators
|
from lemur.common import validators
|
||||||
from lemur.common.schema import LemurSchema, LemurInputSchema, LemurOutputSchema
|
from lemur.common.schema import LemurSchema, LemurInputSchema, LemurOutputSchema
|
||||||
|
from lemur.destinations.models import Destination
|
||||||
|
from lemur.notifications.models import Notification
|
||||||
from lemur.plugins import plugins
|
from lemur.plugins import plugins
|
||||||
|
from lemur.roles.models import Role
|
||||||
|
from lemur.users.models import User
|
||||||
|
|
||||||
|
|
||||||
class AssociatedAuthoritySchema(LemurInputSchema):
|
class AssociatedAuthoritySchema(LemurInputSchema):
|
||||||
|
|
|
@ -93,8 +93,8 @@
|
||||||
is-open="popup1.opened"
|
is-open="popup1.opened"
|
||||||
datepicker-options="dateOptions"
|
datepicker-options="dateOptions"
|
||||||
close-text="Close"
|
close-text="Close"
|
||||||
max-date="authority.authority.notAfter"
|
max-date="authority.authority.authorityCertificate.notAfter"
|
||||||
min-date="authority.authority.notBefore"
|
min-date="authority.authority.authorityCertificate.notBefore"
|
||||||
alt-input-formats="altInputFormats" />
|
alt-input-formats="altInputFormats" />
|
||||||
<span class="input-group-btn">
|
<span class="input-group-btn">
|
||||||
<button type="button" class="btn btn-default" ng-click="open1()"><i class="glyphicon glyphicon-calendar"></i></button>
|
<button type="button" class="btn btn-default" ng-click="open1()"><i class="glyphicon glyphicon-calendar"></i></button>
|
||||||
|
|
|
@ -16,7 +16,7 @@ angular.module('lemur')
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
|
|
||||||
.controller('AuthoritiesViewController', function ($scope, $q, $uibModal, $stateParams, AuthorityApi, AuthorityService, ngTableParams, toaster) {
|
.controller('AuthoritiesViewController', function ($scope, $q, $uibModal, $stateParams, AuthorityApi, AuthorityService, MomentService, ngTableParams, toaster) {
|
||||||
$scope.filter = $stateParams;
|
$scope.filter = $stateParams;
|
||||||
$scope.authoritiesTable = new ngTableParams({
|
$scope.authoritiesTable = new ngTableParams({
|
||||||
page: 1, // show first page
|
page: 1, // show first page
|
||||||
|
@ -35,6 +35,8 @@ angular.module('lemur')
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
$scope.momentService = MomentService;
|
||||||
|
|
||||||
$scope.updateActive = function (authority) {
|
$scope.updateActive = function (authority) {
|
||||||
AuthorityService.updateActive(authority).then(
|
AuthorityService.updateActive(authority).then(
|
||||||
function () {
|
function () {
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-md-12">
|
<div class="col-md-12">
|
||||||
<h2 class="featurette-heading">Authorities
|
<h2 class="featurette-heading">Authorities
|
||||||
<span class="text-muted"><small>The nail that sticks out farthest gets hammered the hardest</small></span></h2>
|
<span class="text-muted"><small>The nail that sticks out farthest gets hammered the hardest</small></span>
|
||||||
|
</h2>
|
||||||
<div class="panel panel-default">
|
<div class="panel panel-default">
|
||||||
<div class="panel-heading">
|
<div class="panel-heading">
|
||||||
<div class="btn-group pull-right">
|
<div class="btn-group pull-right">
|
||||||
|
@ -13,36 +14,104 @@
|
||||||
<div class="clearfix"></div>
|
<div class="clearfix"></div>
|
||||||
</div>
|
</div>
|
||||||
<div class="table-responsive">
|
<div class="table-responsive">
|
||||||
<table ng-table="authoritiesTable" class="table table-striped" template-pagination="angular/pager.html" show-filter="false">
|
<table ng-table="authoritiesTable" class="table table-striped" template-pagination="angular/pager.html"
|
||||||
|
show-filter="false">
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr ng-repeat="authority in $data track by $index">
|
<tr ng-repeat-start="authority in $data track by $index">
|
||||||
<td data-title="'Name'" sortable="'name'" filter="{ 'name': 'text' }">
|
<td data-title="'Name'" sortable="'name'" filter="{ 'name': 'text' }">
|
||||||
<ul class="list-unstyled">
|
<ul class="list-unstyled">
|
||||||
<li>{{ authority.name }}</li>
|
<li>{{ authority.name }}</li>
|
||||||
<li><span class="text-muted">{{ authority.description }}</span></li>
|
<li><span class="text-muted">{{ authority.owner }}</span></li>
|
||||||
</ul>
|
</ul>
|
||||||
</td>
|
</td>
|
||||||
<td data-title="'Active'" filter="{ 'active': 'select' }" filter-data="getAuthorityStatus()">
|
<td data-title="'Active'" filter="{ 'active': 'select' }" filter-data="getAuthorityStatus()">
|
||||||
<form>
|
<form>
|
||||||
<switch ng-change="updateActive(authority)" id="status" name="status" ng-model="authority.active" class="green small"></switch>
|
<switch ng-change="updateActive(authority)" id="status" name="status"
|
||||||
|
ng-model="authority.active" class="green small"></switch>
|
||||||
</form>
|
</form>
|
||||||
</td>
|
</td>
|
||||||
<td data-title="'Roles'"> <!--filter="{ 'select': 'role' }" filter-data="roleService.getRoleDropDown()">-->
|
<td data-title="'Common Name'" filter="{ 'cn': 'text'}">
|
||||||
<div class="btn-group">
|
{{ authority.authorityCertificate.cn }}
|
||||||
<a ng-click="editRole(role.id)" ng-repeat="role in authority.roles" class="btn btn-sm btn-danger">
|
|
||||||
{{ role.name }}
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
</td>
|
</td>
|
||||||
<td data-title="''">
|
<td data-title="''">
|
||||||
<div class="btn-group pull-right">
|
<div class="btn-group pull-right">
|
||||||
<a class="btn btn-sm btn-default" ui-sref="authority({name: authority.name})">Permalink</a>
|
<a class="btn btn-sm btn-default"
|
||||||
<button uib-tooltip="Edit Authority" ng-click="edit(authority.id)" class="btn btn-sm btn-info">
|
ui-sref="authority({name: authority.name})">Permalink</a>
|
||||||
|
<button ng-model="authority.toggle" class="btn btn-sm btn-info" uib-btn-checkbox
|
||||||
|
btn-checkbox-true="1"
|
||||||
|
btn-checkbox-false="0">More
|
||||||
|
</button>
|
||||||
|
<button uib-tooltip="Edit Authority" ng-click="edit(authority.id)"
|
||||||
|
class="btn btn-sm btn-warning">
|
||||||
Edit
|
Edit
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
<tr class="warning" ng-if="authority.toggle" ng-repeat-end>
|
||||||
|
<td colspan="12">
|
||||||
|
<uib-tabset justified="true" class="col-md-6">
|
||||||
|
<uib-tab>
|
||||||
|
<uib-tab-heading>Basic Info</uib-tab-heading>
|
||||||
|
<ul class="list-group">
|
||||||
|
<li class="list-group-item">
|
||||||
|
<strong>Creator</strong>
|
||||||
|
<span class="pull-right">
|
||||||
|
{{ authority.authorityCertificate.user.email }}
|
||||||
|
</span>
|
||||||
|
</li>
|
||||||
|
<li class="list-group-item">
|
||||||
|
<strong>Not Before</strong>
|
||||||
|
<span class="pull-right" uib-tooltip="{{ authority.authorityCertificate.notBefore }}">
|
||||||
|
{{ momentService.createMoment(authority.authorityCertificate.notBefore) }}
|
||||||
|
</span>
|
||||||
|
</li>
|
||||||
|
<li class="list-group-item">
|
||||||
|
<strong>Not After</strong>
|
||||||
|
<span class="pull-right" uib-tooltip="{{ authority.authorityCertificate.notAfter }}">
|
||||||
|
{{ momentService.createMoment(authority.authorityCertificate.notAfter) }}
|
||||||
|
</span>
|
||||||
|
</li>
|
||||||
|
<li class="list-group-item">
|
||||||
|
<strong>Description</strong>
|
||||||
|
<p>{{ authority.description }}</p>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</uib-tab>
|
||||||
|
<uib-tab>
|
||||||
|
<uib-tab-heading>Roles</uib-tab-heading>
|
||||||
|
<ul class="list-group">
|
||||||
|
<li class="list-group-item" ng-repeat="role in authority.roles">
|
||||||
|
<strong>{{ role.name }}</strong>
|
||||||
|
<span class="pull-right">{{ role.description }}</span>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</uib-tab>
|
||||||
|
</uib-tabset>
|
||||||
|
<uib-tabset justified="true" class="col-md-6">
|
||||||
|
<uib-tab>
|
||||||
|
<uib-tab-heading>
|
||||||
|
Chain
|
||||||
|
<button class="btn btn-xs btn-default clipboard-btn glyphicon glyphicon-copy"
|
||||||
|
uib-tooltip="Copy chain to clipboard" tooltip-trigger="mouseenter"
|
||||||
|
clipboard
|
||||||
|
text="authority.authorityCertificate.chain"></button>
|
||||||
|
</uib-tab-heading>
|
||||||
|
<pre style="width: 100%">{{ authority.authorityCertificate.chain }}</pre>
|
||||||
|
</uib-tab>
|
||||||
|
<uib-tab>
|
||||||
|
<uib-tab-heading>
|
||||||
|
Public Certificate
|
||||||
|
<button class="btn btn-xs btn-default clipboard-btn glyphicon glyphicon-copy"
|
||||||
|
uib-tooltip="Copy authority to clipboard" tooltip-trigger="mouseenter"
|
||||||
|
clipboard
|
||||||
|
text="authority.authorityCertificate.body"></button>
|
||||||
|
</uib-tab-heading>
|
||||||
|
<pre style="width: 100%">{{ authority.authorityCertificate.body }}</pre>
|
||||||
|
</uib-tab>
|
||||||
|
</uib-tabset>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -102,8 +102,8 @@
|
||||||
is-open="popup1.opened"
|
is-open="popup1.opened"
|
||||||
datepicker-options="dateOptions"
|
datepicker-options="dateOptions"
|
||||||
close-text="Close"
|
close-text="Close"
|
||||||
max-date="certificate.authority.notAfter"
|
max-date="certificate.authority.authorityCertificate.notAfter"
|
||||||
min-date="certificate.authority.notBefore"
|
min-date="certificate.authority.authorityCertificate.notBefore"
|
||||||
alt-input-formats="altInputFormats"/>
|
alt-input-formats="altInputFormats"/>
|
||||||
<span class="input-group-btn">
|
<span class="input-group-btn">
|
||||||
<button type="button" class="btn btn-default" ng-click="open1()"><i
|
<button type="button" class="btn btn-default" ng-click="open1()"><i
|
||||||
|
@ -121,8 +121,8 @@
|
||||||
is-open="popup2.opened"
|
is-open="popup2.opened"
|
||||||
datepicker-options="dateOptions"
|
datepicker-options="dateOptions"
|
||||||
close-text="Close"
|
close-text="Close"
|
||||||
max-date="certificate.authority.notAfter"
|
max-date="certificate.authority.authorityCertificate.notAfter"
|
||||||
min-date="certificate.authority.notBefore"
|
min-date="certificate.authority.authorityCertificate.notBefore"
|
||||||
alt-input-formats="altInputFormats"/>
|
alt-input-formats="altInputFormats"/>
|
||||||
<span class="input-group-btn">
|
<span class="input-group-btn">
|
||||||
<button type="button" class="btn btn-default" ng-click="open2()"><i
|
<button type="button" class="btn btn-default" ng-click="open2()"><i
|
||||||
|
|
|
@ -137,6 +137,7 @@ def issuer_plugin():
|
||||||
from lemur.plugins.base import register
|
from lemur.plugins.base import register
|
||||||
from .plugins.issuer_plugin import TestIssuerPlugin
|
from .plugins.issuer_plugin import TestIssuerPlugin
|
||||||
register(TestIssuerPlugin)
|
register(TestIssuerPlugin)
|
||||||
|
return TestIssuerPlugin
|
||||||
|
|
||||||
|
|
||||||
@pytest.yield_fixture(scope="function")
|
@pytest.yield_fixture(scope="function")
|
||||||
|
@ -147,7 +148,7 @@ def logged_in_user(app):
|
||||||
|
|
||||||
|
|
||||||
@pytest.yield_fixture(scope="function")
|
@pytest.yield_fixture(scope="function")
|
||||||
def logged_in_admin(app):
|
def logged_in_admin(session, app):
|
||||||
with app.test_request_context():
|
with app.test_request_context():
|
||||||
identity_changed.send(current_app._get_current_object(), identity=Identity(2))
|
identity_changed.send(current_app._get_current_object(), identity=Identity(2))
|
||||||
yield
|
yield
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
|
|
||||||
from datetime import date
|
from datetime import date
|
||||||
|
|
||||||
from factory import Sequence, post_generation
|
from factory import Sequence, post_generation, SubFactory
|
||||||
from factory.alchemy import SQLAlchemyModelFactory
|
from factory.alchemy import SQLAlchemyModelFactory
|
||||||
from factory.fuzzy import FuzzyChoice, FuzzyText, FuzzyDate
|
from factory.fuzzy import FuzzyChoice, FuzzyText, FuzzyDate
|
||||||
|
|
||||||
|
@ -14,7 +14,7 @@ from lemur.notifications.models import Notification
|
||||||
from lemur.users.models import User
|
from lemur.users.models import User
|
||||||
from lemur.roles.models import Role
|
from lemur.roles.models import Role
|
||||||
|
|
||||||
from .vectors import INTERNAL_VALID_LONG_STR, INTERNAL_VALID_SAN_STR, PRIVATE_KEY_STR
|
from .vectors import INTERNAL_VALID_SAN_STR, PRIVATE_KEY_STR
|
||||||
|
|
||||||
|
|
||||||
class BaseFactory(SQLAlchemyModelFactory):
|
class BaseFactory(SQLAlchemyModelFactory):
|
||||||
|
@ -26,27 +26,6 @@ class BaseFactory(SQLAlchemyModelFactory):
|
||||||
sqlalchemy_session = db.session
|
sqlalchemy_session = db.session
|
||||||
|
|
||||||
|
|
||||||
class AuthorityFactory(BaseFactory):
|
|
||||||
"""Authority factory."""
|
|
||||||
name = Sequence(lambda n: 'authority{0}'.format(n))
|
|
||||||
owner = 'joe@example.com'
|
|
||||||
plugin_name = 'test-issuer'
|
|
||||||
body = INTERNAL_VALID_LONG_STR
|
|
||||||
|
|
||||||
class Meta:
|
|
||||||
"""Factory configuration."""
|
|
||||||
model = Authority
|
|
||||||
|
|
||||||
@post_generation
|
|
||||||
def roles(self, create, extracted, **kwargs):
|
|
||||||
if not create:
|
|
||||||
return
|
|
||||||
|
|
||||||
if extracted:
|
|
||||||
for role in extracted:
|
|
||||||
self.roles.append(role)
|
|
||||||
|
|
||||||
|
|
||||||
class CertificateFactory(BaseFactory):
|
class CertificateFactory(BaseFactory):
|
||||||
"""Certificate factory."""
|
"""Certificate factory."""
|
||||||
name = Sequence(lambda n: 'certificate{0}'.format(n))
|
name = Sequence(lambda n: 'certificate{0}'.format(n))
|
||||||
|
@ -135,6 +114,27 @@ class CertificateFactory(BaseFactory):
|
||||||
self.roles.append(domain)
|
self.roles.append(domain)
|
||||||
|
|
||||||
|
|
||||||
|
class AuthorityFactory(BaseFactory):
|
||||||
|
"""Authority factory."""
|
||||||
|
name = Sequence(lambda n: 'authority{0}'.format(n))
|
||||||
|
owner = 'joe@example.com'
|
||||||
|
plugin = {'slug': 'test-issuer'}
|
||||||
|
authority_certificate = SubFactory(CertificateFactory)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
"""Factory configuration."""
|
||||||
|
model = Authority
|
||||||
|
|
||||||
|
@post_generation
|
||||||
|
def roles(self, create, extracted, **kwargs):
|
||||||
|
if not create:
|
||||||
|
return
|
||||||
|
|
||||||
|
if extracted:
|
||||||
|
for role in extracted:
|
||||||
|
self.roles.append(role)
|
||||||
|
|
||||||
|
|
||||||
class DestinationFactory(BaseFactory):
|
class DestinationFactory(BaseFactory):
|
||||||
"""Destination factory."""
|
"""Destination factory."""
|
||||||
plugin_name = Sequence(lambda n: 'destination{0}'.format(n))
|
plugin_name = Sequence(lambda n: 'destination{0}'.format(n))
|
||||||
|
|
|
@ -25,14 +25,6 @@ def test_authority_input_schema(client, role):
|
||||||
assert not errors
|
assert not errors
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize("token, count", [
|
|
||||||
(VALID_USER_HEADER_TOKEN, 0),
|
|
||||||
(VALID_ADMIN_HEADER_TOKEN, 1)
|
|
||||||
])
|
|
||||||
def test_admin_authority(client, authority, token, count):
|
|
||||||
assert client.get(api.url_for(AuthoritiesList), headers=token).json['total'] == count
|
|
||||||
|
|
||||||
|
|
||||||
def test_user_authority(session, client, authority, role, user):
|
def test_user_authority(session, client, authority, role, user):
|
||||||
assert client.get(api.url_for(AuthoritiesList), headers=user['token']).json['total'] == 0
|
assert client.get(api.url_for(AuthoritiesList), headers=user['token']).json['total'] == 0
|
||||||
u = user['user']
|
u = user['user']
|
||||||
|
@ -45,9 +37,23 @@ def test_user_authority(session, client, authority, role, user):
|
||||||
assert client.get(api.url_for(AuthoritiesList), headers=user['token']).json['total'] == 0
|
assert client.get(api.url_for(AuthoritiesList), headers=user['token']).json['total'] == 0
|
||||||
|
|
||||||
|
|
||||||
|
def test_create_authority(issuer_plugin, logged_in_admin):
|
||||||
|
from lemur.authorities.service import create
|
||||||
|
authority = create(plugin={'plugin_object': issuer_plugin, 'slug': issuer_plugin.slug}, owner='jim@example.com', type='root')
|
||||||
|
assert authority.authority_certificate
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize("token, count", [
|
||||||
|
(VALID_USER_HEADER_TOKEN, 0),
|
||||||
|
(VALID_ADMIN_HEADER_TOKEN, 3)
|
||||||
|
])
|
||||||
|
def test_admin_authority(client, authority, token, count):
|
||||||
|
assert client.get(api.url_for(AuthoritiesList), headers=token).json['total'] == count
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize("token,status", [
|
@pytest.mark.parametrize("token,status", [
|
||||||
(VALID_USER_HEADER_TOKEN, 404),
|
(VALID_USER_HEADER_TOKEN, 200),
|
||||||
(VALID_ADMIN_HEADER_TOKEN, 404),
|
(VALID_ADMIN_HEADER_TOKEN, 200),
|
||||||
('', 401)
|
('', 401)
|
||||||
])
|
])
|
||||||
def test_authority_get(client, token, status):
|
def test_authority_get(client, token, status):
|
||||||
|
@ -64,8 +70,8 @@ def test_authority_post(client, token, status):
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize("token,status", [
|
@pytest.mark.parametrize("token,status", [
|
||||||
(VALID_USER_HEADER_TOKEN, 404),
|
(VALID_USER_HEADER_TOKEN, 400),
|
||||||
(VALID_ADMIN_HEADER_TOKEN, 404),
|
(VALID_ADMIN_HEADER_TOKEN, 400),
|
||||||
('', 401)
|
('', 401)
|
||||||
])
|
])
|
||||||
def test_authority_put(client, token, status):
|
def test_authority_put(client, token, status):
|
||||||
|
|
|
@ -7,8 +7,8 @@ from .vectors import VALID_ADMIN_HEADER_TOKEN, VALID_USER_HEADER_TOKEN
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize("token,status", [
|
@pytest.mark.parametrize("token,status", [
|
||||||
(VALID_USER_HEADER_TOKEN, 404),
|
(VALID_USER_HEADER_TOKEN, 200),
|
||||||
(VALID_ADMIN_HEADER_TOKEN, 404),
|
(VALID_ADMIN_HEADER_TOKEN, 200),
|
||||||
('', 401)
|
('', 401)
|
||||||
])
|
])
|
||||||
def test_domain_get(client, token, status):
|
def test_domain_get(client, token, status):
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
.. moduleauthor:: Kevin Glisson <kglisson@netflix.com>
|
.. moduleauthor:: Kevin Glisson <kglisson@netflix.com>
|
||||||
"""
|
"""
|
||||||
from marshmallow import fields
|
from marshmallow import fields
|
||||||
|
|
||||||
from lemur.common.schema import LemurInputSchema, LemurOutputSchema
|
from lemur.common.schema import LemurInputSchema, LemurOutputSchema
|
||||||
from lemur.schemas import AssociatedRoleSchema, AssociatedCertificateSchema, AssociatedAuthoritySchema
|
from lemur.schemas import AssociatedRoleSchema, AssociatedCertificateSchema, AssociatedAuthoritySchema
|
||||||
|
|
||||||
|
@ -30,14 +31,14 @@ class UserOutputSchema(LemurOutputSchema):
|
||||||
authorities = fields.Nested(AssociatedAuthoritySchema, many=True)
|
authorities = fields.Nested(AssociatedAuthoritySchema, many=True)
|
||||||
|
|
||||||
|
|
||||||
|
user_input_schema = UserInputSchema()
|
||||||
|
user_output_schema = UserOutputSchema()
|
||||||
|
users_output_schema = UserOutputSchema(many=True)
|
||||||
|
|
||||||
|
|
||||||
class UserNestedOutputSchema(LemurOutputSchema):
|
class UserNestedOutputSchema(LemurOutputSchema):
|
||||||
__envelope__ = False
|
__envelope__ = False
|
||||||
id = fields.Integer()
|
id = fields.Integer()
|
||||||
username = fields.String()
|
username = fields.String()
|
||||||
email = fields.Email()
|
email = fields.Email()
|
||||||
active = fields.Boolean()
|
active = fields.Boolean()
|
||||||
|
|
||||||
|
|
||||||
user_input_schema = UserInputSchema()
|
|
||||||
user_output_schema = UserOutputSchema()
|
|
||||||
users_output_schema = UserOutputSchema(many=True)
|
|
||||||
|
|
Loading…
Reference in New Issue