Closes 262 (#324)

Moves the authority -> role relationship from a 1 -> many to a many -> many. This will allow one role to control and have access to many authorities.
This commit is contained in:
kevgliss
2016-05-19 13:37:05 -07:00
parent 112c6252d6
commit 615df76dd5
18 changed files with 499 additions and 346 deletions

View File

@ -14,7 +14,8 @@ from sqlalchemy import Column, Integer, String, Text, func, ForeignKey, DateTime
from sqlalchemy.dialects.postgresql import JSON
from lemur.database import db
from lemur.certificates.models import get_cn, get_not_after, get_not_before
from lemur.models import roles_authorities
from lemur.common import defaults
class Authority(db.Model):
@ -33,28 +34,21 @@ class Authority(db.Model):
plugin_name = Column(String(64))
description = Column(Text)
options = Column(JSON)
roles = relationship('Role', 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'))
certificates = relationship("Certificate", backref='authority')
def __init__(self, name, owner, plugin_name, body, roles=None, chain=None, description=None):
cert = x509.load_pem_x509_certificate(bytes(body), default_backend())
self.name = name
self.body = body
self.chain = chain
self.owner = owner
self.description = description
self.plugin_name = plugin_name
cert = x509.load_pem_x509_certificate(bytes(body), default_backend())
self.cn = get_cn(cert)
self.not_before = get_not_before(cert)
self.not_after = get_not_after(cert)
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
def as_dict(self):
return {c.name: getattr(self, c.name) for c in self.__table__.columns}
def serialize(self):
blob = self.as_dict()
return blob

View File

@ -63,6 +63,7 @@ class AuthorityInputSchema(LemurInputSchema):
class AuthorityUpdateSchema(LemurInputSchema):
owner = fields.Email()
description = fields.String()
active = fields.Boolean()
roles = fields.Nested(AssociatedRoleSchema(many=True))

View File

@ -16,7 +16,6 @@ from lemur.authorities.models import Authority
from lemur.roles import service as role_service
from lemur.notifications import service as notification_service
from lemur.roles.models import Role
from lemur.certificates.models import Certificate
@ -29,8 +28,9 @@ def update(authority_id, description=None, owner=None, active=None, roles=None):
:return:
"""
authority = get(authority_id)
if roles:
authority = database.update_list(authority, 'roles', Role, roles)
authority.roles = roles
if active:
authority.active = active
@ -52,8 +52,7 @@ def create(kwargs):
kwargs['creator'] = g.current_user.email
cert_body, intermediate, issuer_roles = issuer.create_authority(kwargs)
cert = Certificate(cert_body, chain=intermediate)
cert.owner = kwargs['owner']
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 \
@ -73,7 +72,6 @@ def create(kwargs):
# we create and attach any roles that the issuer gives us
role_objs = []
for r in issuer_roles:
role = role_service.create(
r['name'],
password=r['password'],
@ -86,6 +84,16 @@ def create(kwargs):
role_objs.append(role)
# create an role for the owner and assign it
owner_role = role_service.get_by_name(kwargs['owner'])
if not owner_role:
owner_role = role_service.create(
kwargs['owner'],
description="Auto generated role based on owner: {0}".format(kwargs['owner'])
)
role_objs.append(owner_role)
authority = Authority(
kwargs.get('name'),
kwargs['owner'],
@ -99,14 +107,6 @@ def create(kwargs):
database.update(cert)
authority = database.create(authority)
# the owning dl or role should have this authority associated with it
owner_role = role_service.get_by_name(kwargs['owner'])
if not owner_role:
owner_role = role_service.create(kwargs['owner'])
owner_role.authority = authority
g.current_user.authorities.append(authority)
return authority
@ -181,8 +181,8 @@ def render(args):
if not g.current_user.is_admin:
authority_ids = []
for role in g.current_user.roles:
if role.authority:
authority_ids.append(role.authority.id)
for authority in role.authorities:
authority_ids.append(authority.id)
query = query.filter(Authority.id.in_(authority_ids))
return database.sort_and_page(query, Authority, args)

View File

@ -279,15 +279,15 @@ class Authorities(AuthenticatedResource):
roles.append(role)
permission = AuthorityPermission(authority_id, roles)
# we want to make sure that we cannot add roles that we are not members of
if not g.current_user.is_admin:
role_ids = set([r.id for r in data['roles']])
user_role_ids = set([r.id for r in g.current_user.roles])
if not role_ids.issubset(user_role_ids):
return dict(message="You are not allowed to associate a role which you are not a member of"), 400
if permission.can():
# we want to make sure that we cannot add roles that we are not members of
if not g.current_user.is_admin:
role_ids = set([r.id for r in data['roles']])
user_role_ids = set([r.id for r in g.current_user.roles])
if not role_ids.issubset(user_role_ids):
return dict(message="You are not allowed to associate a role which you are not a member of."), 403
return service.update(
authority_id,
owner=data['owner'],
@ -296,7 +296,7 @@ class Authorities(AuthenticatedResource):
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
class CertificateAuthority(AuthenticatedResource):
@ -345,7 +345,7 @@ class CertificateAuthority(AuthenticatedResource):
"""
cert = certificate_service.get(certificate_id)
if not cert:
return dict(message="Certificate not found"), 404
return dict(message="Certificate not found."), 404
return cert.authority