def create_subscription(apps, subscription_dict):
    """
    Saves a subscription to the database

    :param apps: Django apps instance.
    :param subscription_dict: arguments to set up a subscription, as a dict.
    """
    subscription_model = apps.get_model('p_soc_auto_base', 'Subscription')

    user = get_or_create_user()

    # TODO can I have alternate_email_subject='', do we even need the alt?
    subscription_defaults = {
        'emails_list': TO_EMAILS,
        'from_email': '*****@*****.**',
        'template_dir': 'p_soc_auto_base/template/',
        'template_prefix': 'email/',
        'created_by_id': user.id,
        'updated_by_id': user.id,
        'enabled': True,
    }

    subscription_dict.update(subscription_defaults)

    subscription = subscription_model(**subscription_dict)

    subscription.save()
Esempio n. 2
0
def add_default_ssl_port(apps, schema_editor):
    port = 443

    model = apps.get_model('ssl_cert_tracker', 'SslProbePort')

    user = get_or_create_user()

    ssl_port = model(port=port, created_by_id=user.id, updated_by_id=user.id)
    ssl_port.save()
 def test_getorcreateuser(self):
     """
     Tests that getorcreateuser does create a user.
     :return:
     """
     test_user = get_or_create_user('testuser')
     self.assertTrue(
         get_user_model().objects.filter(username='******').exists())
     test_user.delete()
Esempio n. 4
0
    def get_or_create_from_borg(cls, borg):
        """
        maintain the host information based on data in the `Windows` log event

        If a :class:`WinlogbeatHost` instance matching the information in the
        `borg` argument doesn't exist, one will be created.

        This `class method
        <https://docs.python.org/3.6/library/functions.html?highlight=classmethod#classmethod>`__
        is invoked from the :func:`citrus_borg.tasks.store_borg_data` task.

        :arg borg: a :func:`collections.namedtuple` with the processed `Windows`
            log event data

            See the functions in the :mod:`citrus_borg.locutus.assimilation`
            module for the structure of the :func:`namedtuple
            <collections.namedtuple>`.

        :returns: the :class:`WinlogbeatHost` instance
        """

        if borg.event_source == 'ControlUp Logon Monitor':
            last_seen = now()
        else:
            last_seen = None

        if borg.event_source == 'BorgExchangeMonitor':
            exch_last_seen = now()
        else:
            exch_last_seen = None

        winloghost = cls.objects.filter(
            host_name__iexact=borg.source_host.host_name)

        if winloghost.exists():
            winloghost = winloghost.get()
            if last_seen:
                winloghost.last_seen = last_seen
            if exch_last_seen:
                winloghost.exchange_last_seen = exch_last_seen
        else:
            user = get_or_create_user(settings.CITRUS_BORG_SERVICE_USER)
            winloghost = cls(host_name=borg.source_host.host_name,
                             last_seen=last_seen,
                             ip_address=borg.source_host.ip_address,
                             created_by=user,
                             exchange_last_seen=exch_last_seen,
                             updated_by=user)

        winloghost.save()
        return winloghost
Esempio n. 5
0
def failure_cluster_check(sender, instance, *args, **kwargs):
    """
    Send an alert if there has been a cluster of failed winlogevents, as defined
    by the appropriate preferences: citrusborgux__cluster_event_ids.,
    citrusborgux__cluster_length, citrusborgux__cluster_size. See preference
    definitions for more details.
    """
    failure_ids = get_int_list_preference('citrusborgux__cluster_event_ids')
    if instance.event_id not in failure_ids:
        return

    recent_failures = WinlogEvent.active.filter(
        timestamp__gte=instance.timestamp -
        get_preference('citrusborgux__cluster_length'),
        timestamp__lte=instance.timestamp,
        event_id__in=failure_ids,
        cluster__isnull=True)
    recent_failures_count = recent_failures.count()

    LOG.debug('there have been %d failures recently', recent_failures_count)

    if recent_failures_count >= get_preference('citrusborgux__cluster_size'):
        default_user = get_or_create_user()

        new_cluster = EventCluster(created_by=default_user,
                                   updated_by=default_user)

        new_cluster.save()

        new_cluster.winlogevent_set.add(*list(recent_failures))

        # TODO could this be done on the server side?
        # Note that this count includes the cluster we just created, hence <=
        if (len([
                cluster for cluster in EventCluster.active.all()
                if cluster.end_time > timezone.now() -
                get_preference('citrusborgux__backoff_time')
        ]) <= get_preference('citrusborgux__backoff_limit')):
            Email.send_email(
                None,
                Subscription.get_subscription('Citrix Cluster Alert'),
                False,
                start_time=new_cluster.start_time,
                end_time=new_cluster.end_time.astimezone(
                    timezone.get_current_timezone()).time(),
                bots=new_cluster.winlogevent_set.all())
            LOG.debug('sent cluster email')
        else:
            new_cluster.enabled = False
            new_cluster.save()
            LOG.info('Cluster created, but alert skipped due to frequency.')
Esempio n. 6
0
def save_citrix_login_event(borg):
    """
    Save data received from a citrix bot.
    :param borg: Message received from bot.
    :raises: Any exception raised during
    """
    def reraise(msg):
        LOG.exception('%s %s.', msg, borg)
        # This function should only be called from inside an except block
        # If an Exception is not being handled it will cause a RuntimeError
        raise  # pylint: disable=misplaced-bare-raise

    event_host = WinlogbeatHost.get_or_create_from_borg(borg)
    event_broker = KnownBrokeringDevice.get_or_create_from_borg(borg)
    try:
        event_source = AllowedEventSource.objects.get(
            source_name=borg.event_source)
    except AllowedEventSource.DoesNotExist:
        reraise('Cannot match event source for event')

    try:
        windows_log = WindowsLog.objects.get(log_name=borg.windows_log)
    except WindowsLog.DoesNotExist:
        reraise('Cannot match windows log info for event')

    user = get_or_create_user(get_preference('citrusborgcommon__service_user'))

    winlogevent = WinlogEvent(
        source_host=event_host,
        record_number=borg.record_number,
        event_source=event_source,
        windows_log=windows_log,
        event_state=borg.borg_message.state,
        xml_broker=event_broker,
        event_test_result=borg.borg_message.test_result,
        storefront_connection_duration
        =borg.borg_message.storefront_connection_duration,
        receiver_startup_duration=borg.borg_message.receiver_startup_duration,
        connection_achieved_duration
        =borg.borg_message.connection_achieved_duration,
        logon_achieved_duration=borg.borg_message.logon_achieved_duration,
        logoff_achieved_duration=borg.borg_message.logoff_achieved_duration,
        failure_reason=borg.borg_message.failure_reason,
        failure_details=borg.borg_message.failure_details,
        raw_message=borg.borg_message.raw_message,
        event_id=borg.event_id,
        timestamp=borg.timestamp,
        created_by=user, updated_by=user)
    winlogevent.save()

    LOG.info('saved event: %s', winlogevent.uuid)
def add_new_perf_buckets(apps, schema_editor):
    user = get_or_create_user()

    user_dict = {
        'created_by_id': user.id,
        'updated_by_id': user.id,
    }

    perf_buckets = [
        {
            'name': 'Alert at 10 ms',
            'avg_warn_threshold': .0025,
            'avg_err_threshold': .005,
            'alert_threshold': .01,
            'notes': '',
            'is_default': False,
        },
        {
            'name': 'Alert at 100 ms',
            'avg_warn_threshold': .025,
            'avg_err_threshold': .05,
            'alert_threshold': .1,
            'notes': '',
            'is_default': False,
        },
        {
            'name': 'Alert at 1 s',
            'avg_warn_threshold': .25,
            'avg_err_threshold': .5,
            'alert_threshold': 1,
            'notes': '',
            'is_default': False,
        },
        {
            'name': 'Alert at 10 s',
            'avg_warn_threshold': 2.5,
            'avg_err_threshold': 5,
            'alert_threshold': 10,
            'notes': '',
            'is_default': True,
        },
    ]

    perf_bucket_model = apps.get_model('ldap_probe', 'ADNodePerfBucket')
    for perf_bucket_dict in perf_buckets:
        perf_bucket_dict.update(user_dict)
        perf_bucket = perf_bucket_model(**perf_bucket_dict)
        perf_bucket.save()
def populate_ac_orion_nodes(apps, schema_editor):
    user = get_or_create_user()
    ldap_bind_cred = apps.get_model(
        'ldap_probe', 'LDAPBindCred').objects.filter(is_default=True).get()

    orion_nodes = apps.get_model(
        'orion_integration', 'OrionDomainControllerNode').objects.\
        filter(program_application_type='DomainController').all()

    ac_nodes_model = apps.get_model('ldap_probe', 'OrionADNode')

    for node in orion_nodes:
        ac_node = ac_nodes_model(node=node,
                                 ldap_bind_cred=ldap_bind_cred,
                                 created_by_id=user.id,
                                 updated_by_id=user.id)
        ac_node.save()
def populate_ldap_cred_default(apps, schema_editor):
    user = get_or_create_user()

    default_cred_dict = {
        'domain': 'VCH',
        'username': '******',
        'password': '******',
        'is_default': True,
        'created_by_id': user.id,
        'updated_by_id': user.id,
    }

    ldap_cred_model = apps.get_model('ldap_probe', 'LDAPBindCred')

    if ldap_cred_model.objects.filter(
            domain__iexact=default_cred_dict['domain'],
            username__iexact=default_cred_dict['username']).exists():
        return

    default_ldap_cred = ldap_cred_model(**default_cred_dict)
    default_ldap_cred.save()
Esempio n. 10
0
    def get_or_create_from_borg(cls, borg):
        """
        maintain the `Citrix` application servers information based on data in
        the `Windows` log event

        If a :class:`KnownBrokeringDevice` instance matching the information in
        the `borg` argument doesn't exist, one will be created.

        This `class method
        <https://docs.python.org/3.6/library/functions.html#classmethod>`__
        is invoked from the :func:`citrus_borg.tasks.store_borg_data` task.

        :arg borg: a :func:`collections.namedtuple` with the processed `Windows`
            log event data

            See the functions in the :mod:`citrus_borg.locutus.assimilation`
            module for the structure of the :func:`namedtuple
            <collections.namedtuple>`.

        :returns: the :class:`KnownBrokeringDevice` instance
        """
        if borg.borg_message.broker is None:
            return None

        broker = cls.objects.filter(
            broker_name__iexact=borg.borg_message.broker)

        if broker.exists():
            broker = broker.get()
            broker.last_seen = now()
        else:
            user = get_or_create_user(settings.CITRUS_BORG_SERVICE_USER)
            broker = cls(broker_name=borg.borg_message.broker,
                         created_by=user,
                         updated_by=user,
                         last_seen=now())

        broker.save()
        return broker
    def get_or_create(
            cls, ssl_issuer, username=settings.NMAP_SERVICE_USER):
        """
        create (if it doesn't exist already) and retrieve a
        :class:`SslCertificateIssuer` instance

        :arg dict ssl_issuer:

            data about the `Certificate authority
            <https://en.wikipedia.org/wiki/Public_key_certificate#Certificate_authorities>`__

        :arg str username:

            the key for the :class:`django.contrib.auth.models.User` (or its
            `replacement
            <https://docs.djangoproject.com/en/2.2/topics/auth/customizing/#substituting-a-custom-user-model>`__)
            instance representing the user that is maintaining the
            :class:`SslCertificateIssuer` instance

            By default, this value is picked from
            :attr:`p_soc_auto.settings.NMAP_SERVICE_USER` and if that user
            doesn't exist, it will be created.

        :returns: a :class:`SslCertificateIssuer` instance
        """
        ssl_certificate_issuer = cls._meta.model.objects.\
            filter(common_name__iexact=ssl_issuer.get('commonName'))
        if ssl_certificate_issuer.exists():
            return ssl_certificate_issuer.get()

        user = get_or_create_user(username)
        ssl_certificate_issuer = cls(
            common_name=ssl_issuer.get('commonName'),
            organization_name=ssl_issuer.get('organizationName'),
            country_name=ssl_issuer.get('countryName'),
            created_by=user, updated_by=user)
        ssl_certificate_issuer.save()

        return ssl_certificate_issuer
def maintain_ad_orion_nodes():
    """
    synchronize :class:`ldap_probe.models.OrionADNode` with
    :class:`orion_integration.models.OrionDomainControllerNode`

    This is needed because `AD` `Orion` nodes may change outside this
    application
    """
    known_nodes_model = apps.get_model('ldap_probe.orionadnode')
    new_nodes_model = apps.get_model(
        'orion_integration.oriondomaincontrollernode')

    known_node_ids = known_nodes_model.objects.values_list(
        'node_id', flat=True)

    new_nodes = new_nodes_model.objects.exclude(id__in=known_node_ids)

    if not new_nodes.exists():
        LOG.debug('did not find any unknown AD nodes in Orion')
        return

    service_user = get_or_create_user(
        name=get_preference('ldapprobe__service_user'))
    ldap_bind_cred = apps.get_model('ldap_probe.ldapbindcred').default()

    for node in new_nodes:
        new_ad_orion_node = known_nodes_model(
            node=node, ldap_bind_cred=ldap_bind_cred,
            created_by=service_user, updated_by=service_user)
        try:
            new_ad_orion_node.save()
        except Exception as error:
            LOG.exception(error)
            raise error

    LOG.info('created %s AD nodes from Orion', new_nodes.count())
def populate_ac_nodes(apps, schema_editor):
    user = get_or_create_user()

    ldap_bind_cred = apps.get_model(
        'ldap_probe', 'LDAPBindCred').objects.filter(is_default=True).get()

    ac_nodes = [
        'alpha.fraserhealth.org',
        'atlas.fraserhealth.org',
        'blackcomb.fraserhealth.org',
        'cypress.fraserhealth.org',
        'dcns0002.fraserhealth.org',
        'dcns0004.fraserhealth.org',
        'denman.fraserhealth.org ',
        'everest.fraserhealth.org',
        'fuji.fraserhealth.org ',
        'janus.fraserhealth.org',
        'laila.fraserhealth.org ',
        'olympus.fraserhealth.org',
        'phcdc3.phcnet.ca',
        'phcdc5.phcnet.ca',
        'phcdc7.phcnet.ca',
        'phcdc21.phcnet.ca',
        'phcdc41.phcnet.ca',
        'phcdc42.phcnet.ca',
        'phsacdcldcphc3.phcnet.ca',
        'phsacdcldcphc4.phcnet.ca',
        'phsacdcldcphsa3.phsabc.ehcnet.ca',
        'phsacdcldcphsa4.phsabc.ehcnet.ca',
        'phsacdcldcvch3.vch.ca',
        'phsacdcldcvch4.vch.ca',
        'phsacdcldcvrhb3.main.vrhb.local',
        'phsacdcldcvrhb4.main.vrhb.local',
        'proteus.fraserhealth.org',
        'rainier.fraserhealth.org',
        'rhsdc2.main.vrhb.local',
        'robson.fraserhealth.org',
        'rootdc4.vrhb.local',
        'rootdc5.vrhb.local',
        'rootdc6.vrhb.local',
        'spdc0001.healthbc.org',
        'spdc0002.healthbc.org',
        'spdc0003.healthbc.org',
        'spdc0004.healthbc.org',
        'spdc0005.healthbc.org',
        'spdc0006.healthbc.org',
        'spdc0007.healthbc.org',
        'spdc0008.healthbc.org',
        'spdc0009.healthbc.org',
        'spdc0010.healthbc.org',
        'spdc0011.healthbc.org',
        'spdc0012.healthbc.org',
        'spdc0013.healthbc.org',
        'spdc0014.healthbc.org',
        'spdc0015.healthbc.org',
        'spdc0016.healthbc.org',
        'spdc0017.healthbc.org',
        'spdcphc001.phcnet.ca',
        'spdcphsa001.phsabc.ehcnet.ca',
        'spdcvrhb006.main.vrhb.local',
        'srvcs01.phsabc.ehcnet.ca',
        'srvcs02.phsabc.ehcnet.ca',
        'srvcs03.phsabc.ehcnet.ca',
        'srvcs04.phsabc.ehcnet.ca',
        'srvcs41.phsabc.ehcnet.ca',
        'srvfr01.ehcnet.ca',
        'srvfr02.ehcnet.ca',
        'srvpngcs01.phsapng.ca',
        'srvpngcs02.phsapng.ca',
        'svmcs06.phsabc.ehcnet.ca',
        'svmcs10.phsabc.ehcnet.ca',
        'svmcs15-new.phsabc.ehcnet.ca',
        'svmcs15.phsabc.ehcnet.ca',
        'svmcs16-new.phsabc.ehcnet.ca',
        'svmcs16.phsabc.ehcnet.ca',
        'svmfr03.ehcnet.ca',
        'vchdc1.vch.ca',
        'vchdc2.vch.ca',
        'vchdc3.vch.ca',
        'vchdc4.vch.ca',
        'vchdc5.vch.ca',
        'vchdc6.vch.ca',
        'vchdc7.vch.ca',
        'vchdc8.vch.ca',
        'vchdc9.vch.ca',
        'vchdc12.vch.ca',
        'vchdc13.vch.ca',
        'vchdc14.vch.ca',
        'vchdc16.vch.ca',
        'vchdc41.vch.ca',
        'vesuvius.fraserhealth.org ',
        'vrhbdc5.main.vrhb.local',
        'vrhbdc6.main.vrhb.local',
        'vrhbdc7.main.vrhb.local',
        'vrhbdc41.main.vrhb.local',
        'whistler.fraserhealth.org',
        'whitney.fraserhealth.org',
    ]

    ac_nodes_model = apps.get_model('ldap_probe', 'NonOrionADNode')

    for node_dns in ac_nodes:
        ac_node = ac_nodes_model(node_dns=node_dns,
                                 ldap_bind_cred=ldap_bind_cred,
                                 created_by_id=user.id,
                                 updated_by_id=user.id)
        ac_node.save()
def populate_ldap_errors(apps, schema_editor):
    user = get_or_create_user()

    ldap_errors = [
        {
            'error_unique_identifier': '525',
            'short_description': 'LDAP_NO_SUCH_OBJECT',
            'notes': 'Entry does not exist',
            'comments': None,
        },
        {
            'error_unique_identifier':
            '52e',
            'short_description':
            'ERROR_LOGON_FAILURE',
            'notes': ('Returns when username is valid but password/credential'
                      ' is invalid.'),
            'comments': ('Will prevent most other errors from being displayed'
                         ' as noted.'),
        },
        {
            'error_unique_identifier':
            '52f',
            'short_description':
            'ERROR_ACCOUNT_RESTRICTION',
            'notes':
            ('Account Restrictions are preventing this user from signing in.'),
            'comments': ('For example: blank passwords are not allowed,'
                         ' sign-in times are limited, or a policy restriction'
                         ' has been enforced.'),
        },
        {
            'error_unique_identifier': '530',
            'short_description': 'ERROR_INVALID_LOGON_HOURS',
            'notes': 'Time Restriction:Entry logon time restriction violation',
            'comments': None,
        },
        {
            'error_unique_identifier': '531',
            'short_description': 'ERROR_INVALID_WORKSTATION',
            'notes':
            'Device Restriction:Entry not allowed to log on to this computer.',
            'comments': None,
        },
        {
            'error_unique_identifier':
            '532',
            'short_description':
            'ERROR_PASSWORD_EXPIRED',
            'notes':
            ('Password Expiration: Entry password has expired LDAP'
             ' User-Account-Control Attribute - ERROR_PASSWORD_EXPIRED'),
            'comments':
            'Returns only when presented with valid username and password/credential. ',
        },
        {
            'error_unique_identifier':
            '533',
            'short_description':
            'ERROR_ACCOUNT_DISABLED',
            'notes':
            'Administratively Disabled: LDAP User-Account-Control Attribute - ACCOUNTDISABLE',
            'comments':
            'Returns only when presented with valid username and password/credential.',
        },
        {
            'error_unique_identifier':
            '568',
            'short_description':
            'ERROR_TOO_MANY_CONTEXT_IDS',
            'notes':
            ("During a logon attempt, the user's security context"
             " accumulated too many security Identifiers. (ie Group-AD)"),
            'comments':
            None,
        },
        {
            'error_unique_identifier':
            '701',
            'short_description':
            'ERROR_ACCOUNT_EXPIRED',
            'notes':
            'LDAP Password Expiration: User-Account-Control Attribute - ACCOUNTEXPIRED',
            'comments':
            'Returns only when presented with valid username and password/credential.',
        },
        {
            'error_unique_identifier':
            '773',
            'short_description':
            'ERROR_PASSWORD_MUST_CHANGE',
            'notes':
            ("Password Expiration: Entry's password must be changed"
             " before logging on LDAP pwdLastSet: value of 0 indicates"
             " admin-required password change - MUST_CHANGE_PASSWD"),
            'comments':
            'Returns only when presented with valid username and password/credential. ',
        },
        {
            'error_unique_identifier':
            '775',
            'short_description':
            'ERROR_ACCOUNT_LOCKED_OUT',
            'notes':
            ('Intruder Detection:Entry is currently locked out and may'
             ' not be logged on to LDAP User-Account-Control Attribute - LOCKOUT'
             ),
            'comments':
            'Returns even if invalid password is presented',
        },
    ]

    ldap_error_model = apps.get_model('ldap_probe', 'LdapCredError')
    for ldap_error in ldap_errors:
        ldap_error.update(created_by_id=user.id, updated_by_id=user.id)
        ldap_error_entry = ldap_error_model(**ldap_error)
        ldap_error_entry.save()
def add_ssl_ports(apps, schema_editor):
    user = get_or_create_user()

    ports = [
        {
            'port': 261,
            'enabled': False,
            'notes': 'Nsiiops',
        },
        {
            'port': 443,
            'enabled': True,
            'notes': 'HTTPS',
        },
        {
            'port': 446,
            'enabled': False,
            'notes': 'Openfiler management interface',
        },
        {
            'port': 448,
            'enabled': False,
            'notes': 'ddm-ssl',
        },
        {
            'port': 465,
            'enabled': False,
            'notes': 'SMTPS',
        },
        {
            'port': 563,
            'enabled': False,
            'notes': 'NNTPS',
        },
        {
            'port': 585,
            'enabled': False,
            'notes': 'imap4-ssl',
        },
        {
            'port': 614,
            'enabled': False,
            'notes': 'SSLshell',
        },
        {
            'port': 636,
            'enabled': False,
            'notes': 'LDAPS',
        },
        {
            'port': 684,
            'enabled': False,
            'notes': 'Corba IIOP SSL',
        },
        {
            'port': 695,
            'enabled': False,
            'notes': 'IEEE-MMS-SSL',
        },
        {
            'port': 902,
            'enabled': False,
            'notes': 'VMWare Auth Daemon',
        },
        {
            'port': 989,
            'enabled': False,
            'notes': 'FTPS data',
        },
    ]

    port_model = apps.get_model('ssl_cert_tracker', 'SslProbePort')

    for port_dict in ports:
        port_dict.update({'created_by_id': user.id, 'updated_by_id': user.id})
        port_model.objects.get_or_create(**port_dict)
Esempio n. 16
0
    def update_or_create_from_orion(cls):
        """
        update or create instances of :class:`django.db.models.Model` classes
        inheriting from this class using data from the `Orion`  server

        :arg str username: the :attr:`username` of the
            :class:`django.contrib.auth.models.User` instance when creating the
            model instance

            .. todo::

                We are picking the default value for this argument from the
                `Django` `settings` file. We need to use a dynamic preference
                instead.

        :raises:

            :exc:`OrionQueryError` if the :attr:`orion_query` attribute is not
            defined in the model

            :exc:`OrionMappingsError` if the :attr:`orion_mappings` attribute
            is not defined in the model

        :returns: a :class:`dictionary <dict>` with these keys

            * status

            * model: the `model` that executed this method

            * orion_rows: the number of rows returned by the `Orion` `REST`
              call

            * updated_records: the number of objects that have been updated
              during the `Orion` `REST` call

            * created_records: the number of objects that have been created
              during the `Orion` `REST` call

            * errored_records: the number of objects that threw an error
              during the `Orion` `REST` call
        """
        return_dict = dict(model=cls._meta.verbose_name,
                           orion_rows=0,
                           updated_records=0,
                           created_records=0,
                           errored_records=0)
        if cls.orion_query is None:
            raise OrionQueryError(
                '%s is not providing a value for the Orion query' %
                cls._meta.label)

        if not cls.orion_mappings:
            raise OrionMappingsError(
                '%s is not providing an Orion value mapping' % cls._meta.label)

        user = get_or_create_user(settings.ORION_USER)
        data = OrionClient.query(orion_query=cls.orion_query)
        return_dict['orion_rows'] = len(data)
        for data_item in data:
            orion_mapping = dict()
            for mapping in cls.orion_mappings:
                if mapping[2] is None:
                    orion_mapping[mapping[0]] = data_item[mapping[1]]
                else:
                    app, model = mapping[2].split('.')
                    model = apps.get_model(app, model)
                    orion_mapping[mapping[0]] = model.objects.filter(
                        orion_id__exact=data_item[mapping[1]]).get()

            orion_mapping.update(updated_by=user, created_by=user)

            try:
                qs = cls.objects.filter(
                    orion_id__exact=orion_mapping['orion_id'])
                if qs.exists():
                    orion_mapping.pop('orion_id')
                    orion_mapping.pop('created_by', None)
                    return_dict['updated_records'] += 1

                    # we do not want to use qs.update(88orion_mapping) because
                    # it bypasses the pre- and post-save signals
                    # thus, setattr in a loop
                    instance = qs.get()
                    for attr, value in orion_mapping.items():
                        setattr(instance, attr, value)

                else:
                    # it is a new instance
                    return_dict['created_records'] += 1
                    instance = cls(**orion_mapping)

                instance.save()

            except Exception as error:
                return_dict['errored_records'] += 1
                LOG.error('%s when acquiring Orion object %s', str(error),
                          orion_mapping)

        return return_dict
Esempio n. 17
0
 def setUpClass(cls):
     super().setUpClass()
     user = get_or_create_user()
     cls.USER_ARGS = {'created_by': user, 'updated_by': user}
Esempio n. 18
0
def add_ssl_ports(apps, schema_editor):
    ports = [
        (
            261,
            False,
            'Nsiiops',
        ),
        (
            443,
            True,
            'HTTPS',
        ),
        (
            446,
            False,
            'Openfiler management interface',
        ),
        (
            448,
            False,
            'ddm-ssl',
        ),
        (
            465,
            False,
            'SMTPS',
        ),
        (
            563,
            False,
            'NNTPS',
        ),
        (
            585,
            False,
            'imap4-ssl',
        ),
        (
            614,
            False,
            'SSLshell',
        ),
        (
            636,
            False,
            'LDAPS',
        ),
        (
            684,
            False,
            'Corba IIOP SSL',
        ),
        (
            695,
            False,
            'IEEE-MMS-SSL',
        ),
        (
            902,
            False,
            'VMWare Auth Daemon',
        ),
        (
            989,
            False,
            'FTPS data',
        ),
    ]

    model = apps.get_model('ssl_cert_tracker', 'SslProbePort')

    user = get_or_create_user()

    for port in ports:

        ssl_port = model.objects.filter(port=port[0])
        if ssl_port.exists():
            ssl_port = ssl_port.get()
        else:
            ssl_port = model(port=port[0],
                             created_by_id=user.id,
                             updated_by_id=user.id)
            ssl_port.enabled = port[1]

        ssl_port.notes = port[2]
        ssl_port.save()
    def create_or_update(cls, ssl_certificate, orion_id=None,
                         external_id=None,
                         username=settings.NMAP_SERVICE_USER):
        """
        create or update a :class:`SslCertificate` instance

        Currently, we are uniquely identifying an `SSL` certificate by the
        ('network address', 'network port') tuple where the certificate is being
        served. This approach is fully justified from an operational
        perspective; it is not possible to serve more than one certificate per
        the network tuple.

        However, a (valid) SSL certificate is an ephemeral construct. When it
        expires, it cannot be extended. It can only be replaced by a new `SSL`
        certificate. This method needs to be able to detect such a change and
        handle the instance update accordingly.

        In this method, we look for the network tuple in the underlying table:

        * if not found, this is a new `SSL` certificate, the method creates a
          new :class:`SslCertificate` instance

        * if found, compare the `MD5 <https://en.wikipedia.org/wiki/MD5>`_
          checksum already present in the :class:`SslCertificate` instance as
          :attr:`pk_md5` with the one present in the :attr:`ssl_md5` attribute
          of the `ssl_certificate` argument

          * if the `MD5` values match, the whole `SSL` certificate matches;
            the method will only update the :attr:`SslCertificate.last_seen`
            field

          * if the `MD5` values don't match, this is a new `SSL` certificate;
            the method will update all the fields in the
            :class:`SslCertificate` instance

        :Note:

            In :class:`SslCetificate`, the network address is hiding behind
            the :attr:`SslCertificate.orion_id` which is a
            :class:`django.db.models.ForeignKey` to
            :class:`orion_integration.models.OrionNode`.

        :arg int orion_id: the reference to the
            :class:`orion_integration.models.OrionNode` instance for the
            network node from where the `SSL` certificate is served

        :arg ssl_certificate: all the data collected by the `NMAP
            <https://nmap.org/>`_ scan
        :type ssl_certificate: :class:`ssl_cert_tracker.nmap.SslProbe`

        :arg str username: :attr:`django.contrib.auth.models.User.username`
            of the user (or its `replacement
            <https://docs.djangoproject.com/en/2.2/topics/auth/customizing/#substituting-a-custom-user-model>`__)
            maintaining the :class:`SslCertificate` instance

            The default value is picked from
            :attr:`p_soc_auto.settings.NMAP_SERVICE_USER`. If a matching
            :class:`django.contrib.auth.models.User` instance doesn't exist,
            one will be created.
        """
        user = get_or_create_user(username)
        issuer = SslCertificateIssuer.get_or_create(
            ssl_certificate.ssl_issuer, username)

        if orion_id:
            node_id = {'orion_id': orion_id}
        elif external_id:
            node_id = {'external_node_id': external_id}
        else:
            raise ValueError(
                "Id for the node the Certificate came from was not supplied.")

        ssl_obj = cls._meta.model.objects.filter(**node_id,
            port__port=ssl_certificate.port)

        if ssl_obj.exists():
            ssl_obj = ssl_obj.get()
            if ssl_obj.pk_md5 != ssl_certificate.ssl_md5:
                # host and port are the same but the checksum has changed,
                # ergo the certificate has been replaced. we need to save
                # the new data
                ssl_obj.common_name = ssl_certificate.ssl_subject.\
                    get('commonName')
                ssl_obj.organization_name = ssl_certificate.ssl_subject.\
                    get('organizationName')
                ssl_obj.country_name = ssl_certificate.ssl_subject.\
                    get('countryName')
                ssl_obj.issuer = issuer
                ssl_obj.hostnames = ssl_certificate.hostnames
                ssl_obj.not_before = ssl_certificate.ssl_not_before
                ssl_obj.not_after = ssl_certificate.ssl_not_after
                ssl_obj.pem = ssl_certificate.ssl_pem
                ssl_obj.pk_bits = ssl_certificate.ssl_pk_bits
                ssl_obj.pk_type = ssl_certificate.ssl_pk_type
                ssl_obj.pk_md5 = ssl_certificate.ssl_md5
                ssl_obj.pk_sha1 = ssl_certificate.ssl_sha1
                ssl_obj.updated_by = user

            ssl_obj.last_seen = timezone.now()
            ssl_obj.save()

            return False, ssl_obj

        port = SslProbePort.objects.get(port=int(ssl_certificate.port))
        ssl_obj = cls(
            common_name=ssl_certificate.ssl_subject.get('commonName'),
            organization_name=ssl_certificate.ssl_subject.get(
                'organizationName'),
            country_name=ssl_certificate.ssl_subject.get('countryName'),
            orion_id=orion_id, external_node_id=external_id, port=port,
            issuer=issuer,
            hostnames=ssl_certificate.hostnames,
            not_before=ssl_certificate.ssl_not_before,
            not_after=ssl_certificate.ssl_not_after,
            pem=ssl_certificate.ssl_pem, pk_bits=ssl_certificate.ssl_pk_bits,
            pk_type=ssl_certificate.ssl_pk_type,
            pk_md5=ssl_certificate.ssl_md5, pk_sha1=ssl_certificate.ssl_sha1,
            created_by=user, updated_by=user, last_seen=timezone.now())
        ssl_obj.save()

        return True, ssl_obj