""" .. module: lemur.endpoints.models :platform: unix :synopsis: This module contains all of the models need to create an authority within Lemur. :copyright: (c) 2018 by Netflix Inc., see AUTHORS for more :license: Apache, see LICENSE for more details. .. moduleauthor:: Kevin Glisson """ import arrow from sqlalchemy.orm import relationship from sqlalchemy.ext.associationproxy import association_proxy from sqlalchemy import Column, Integer, String, Boolean, ForeignKey from sqlalchemy.ext.hybrid import hybrid_property from sqlalchemy.sql.expression import case from sqlalchemy_utils import ArrowType from lemur.database import db from lemur.models import policies_ciphers BAD_CIPHERS = [ 'Protocol-SSLv3', 'Protocol-SSLv2', 'Protocol-TLSv1' ] class Cipher(db.Model): __tablename__ = 'ciphers' id = Column(Integer, primary_key=True) name = Column(String(128), nullable=False) @hybrid_property def deprecated(self): return self.name in BAD_CIPHERS @deprecated.expression def deprecated(cls): return case( [ (cls.name in BAD_CIPHERS, True) ], else_=False ) class Policy(db.Model): ___tablename__ = 'policies' id = Column(Integer, primary_key=True) name = Column(String(128), nullable=True) ciphers = relationship('Cipher', secondary=policies_ciphers, backref='policy') class Endpoint(db.Model): __tablename__ = 'endpoints' id = Column(Integer, primary_key=True) owner = Column(String(128)) name = Column(String(128)) dnsname = Column(String(256)) type = Column(String(128)) active = Column(Boolean, default=True) port = Column(Integer) policy_id = Column(Integer, ForeignKey('policy.id')) policy = relationship('Policy', backref='endpoint') certificate_id = Column(Integer, ForeignKey('certificates.id')) source_id = Column(Integer, ForeignKey('sources.id')) sensitive = Column(Boolean, default=False) source = relationship('Source', back_populates='endpoints') last_updated = Column(ArrowType, default=arrow.utcnow, nullable=False) date_created = Column(ArrowType, default=arrow.utcnow, onupdate=arrow.utcnow, nullable=False) replaced = association_proxy('certificate', 'replaced') @property def issues(self): issues = [] for cipher in self.policy.ciphers: if cipher.deprecated: issues.append({'name': 'deprecated cipher', 'value': '{0} has been deprecated consider removing it.'.format(cipher.name)}) if self.certificate.expired: issues.append({'name': 'expired certificate', 'value': 'There is an expired certificate attached to this endpoint consider replacing it.'}) if self.certificate.revoked: issues.append({'name': 'revoked', 'value': 'There is a revoked certificate attached to this endpoint consider replacing it.'}) return issues def __repr__(self): return "Endpoint(name={name})".format(name=self.name)