예제 #1
0
def get_report(network_id, report_type, ran_at, interval=None):
    """
    Returns a report in details for given network and network type.

    :param network_id: Network id
    :param report_type: Report type
    :param ran_at: A datetime object that shows start time of the script
    :param interval: Report interval
    :return: report details
    """
    LOGGER.info("Getting report %s for network id %s", report_type, network_id)

    end_point = API_URL + f'/reporting/{network_id}'

    params = {'type': report_type}

    if interval:
        params['rangeEnd'] = int(ran_at.timestamp())
        params['rangeStart'] = \
            int((ran_at - timedelta(minutes=int(interval))).timestamp())
        params['interval'] = f'{interval}%20mins'

    response = call_api(end_point, params=params)

    return response.json()
예제 #2
0
def get_networks():
    """
    Returns all the networks under current customer.

    :return: list of networks
    """
    LOGGER.info("Getting all the networks...")

    end_point = API_URL + '/networks'

    params = {'pageSize': 10, 'page': 0}

    networks = []
    while True:
        response = call_api(end_point, params=params)

        result = response.json()
        networks.extend(result['items'])

        if not result.get('hasNext'):
            break

        params['page'] += 1

    return networks
예제 #3
0
def call_api(end_point, params=None, headers=None):
    """

    :param end_point: API end point
    :param params: API parameters
    :param headers: headers to call the API
    :return: Http response
    """
    access_token = AUTHENTICATOR.get_access_token()

    default_headers = {
        'Authorization': f'Bearer {access_token}',
        'Content-Type': 'application/json'
    }

    if headers:
        default_headers.update(headers)

    LOGGER.debug("Calling API end point %s - Params: %s - Headers: %s",
                 end_point, str(params), str(default_headers))

    response = requests.get(end_point, headers=default_headers, params=params)

    LOGGER.debug("Response Status Code: %s - Response Content: %s",
                 response.status_code, response.json())

    # pylint: disable=no-member
    if response.status_code != requests.codes.ok:
        response.raise_for_status()

    return response
예제 #4
0
    def _re_login(self):
        """
        Uses refresh token to refresh the access token. This method set global
        variable TOKEN with obtained credentials.
        """
        LOGGER.info('Refreshing the token...')

        refresh_token = self.__token['refresh_token']
        client_id = self.__client_id
        client_secret = self.__client_secret
        data = f"client_id={client_id}&client_secret={client_secret}&" \
               f"grant_type=re_login&re_login={refresh_token}"

        response = requests.post(
            CONFIG['DEFENZ']['LOGIN_ENDPOINT'],
            headers={'Content-Type': 'application/x-www-form-urlencoded'},
            data=data)

        result = response.json()

        # pylint: disable=no-member
        if response.status_code != requests.codes.ok:
            raise Exception('Unsuccessful Re-Login! Status Code: {} '
                            '- Error: {} - Error Description: {}'.format(
                                response.status_code, result.get('error'),
                                result.get('error_description')))

        self.__token.update(result)
        self.__token['created_at'] = datetime.now()

        LOGGER.info('The token has been refreshed successfully!')
예제 #5
0
def get_network(network_id):
    """
    Returns a specific network by given network id.

    :param network_id: network id
    :return: network details
    """
    LOGGER.info("Getting details of network %s", network_id)

    end_point = API_URL + f'/networks/{network_id}'

    response = call_api(end_point)

    return response.json()
예제 #6
0
    def _validate_token(self):
        """
        Validate the access token if it's expired. If expired, does a re-login to
        refresh the token.
        """
        LOGGER.info('Validating the token...')

        if not self.__token:
            raise Exception('Invalid token! Please try to login first.')

        if datetime.now() > self.__token['created_at'] + timedelta(
                seconds=self.__token['expires_in']):
            LOGGER.warning('The token is expired!')
            self._re_login()
예제 #7
0
def generate_email_content(report_details, block_type, network, interval):
    """
    Generates email body content for the alert.

    :param report_details: Report detail object
    :param network: Network object
    :param block_type: Block report type
    :param interval: Report interval in minute
    :return: String as email content
    """
    LOGGER.info("Generating email content for block report %s and network %s",
                block_type, network['id'])

    email_body_template = """
Malicious events detected in past {interval} minutes in your network.

BLOCK TYPE: {block_type}
NETWORK: {network_id} - {network_name}

{blocks}

"""

    if block_type in (MALWARE_PHISHING_BLOCKS, WEB_FILTER_BLOCKS):
        blocks = \
            _generate_malware_phishing_email_content(report_details) \
            if report_details else "No data found!"
    elif block_type == BOT_NET_BLOCKS:
        blocks = str(report_details) if report_details else "No data found!"
    else:
        raise Exception("Invalid block report type!")

    email_body = email_body_template.format(
        interval=interval,
        block_type=block_type,
        network_id=network['id'],
        network_name=network['name'],
        blocks=blocks,
    )

    return email_body
예제 #8
0
def _get_email_recipients(network_id, default_report_email=None):
    """
    Returns report email recipients from network details.

    :param network_id: network id.
    :param default_report_email: list of email addresses. Will be return if no
        email addresses have been set on the network.
    :return: list of email addresses
    """
    LOGGER.info("Getting report email recipients for network %s", network_id)

    network = get_network(network_id)
    report_emails = network['reportEmails']

    recipients = []
    if report_emails:
        recipients.extend([e['address'] for e in report_emails])

    if default_report_email:
        recipients.append(default_report_email)

    return recipients
예제 #9
0
def get_all_reports(network_id, ran_at, interval=None):
    """
    Returns all the summary reports for given network.

    :param network_id: Network id
    :param ran_at: A datetime object that shows start time of the script
    :param interval: Report interval
    :return: list of reports
    """
    LOGGER.info("Getting all the report for network id %s", network_id)

    end_point = CONFIG['DEFENZ']['API_URL'] + f'/reporting/alldata/{network_id}'

    params = {}

    if interval:
        params['rangeEnd'] = int(ran_at.timestamp())
        params['rangeStart'] = \
            int((ran_at - timedelta(minutes=int(interval))).timestamp())

    response = call_api(end_point, params=params)

    return response.json()
예제 #10
0
    def login(self, username, password, client_id, client_secret):
        """
        Login to get access token. This method set global variable TOKEN with
        obtained credentials.

        :param username: Defenz username
        :param password: Defenz password
        :param client_id: Defenz client id or customer name
        :param client_secret: Defenz client secret
        """
        LOGGER.info("Logging in to get the access token.")

        data = f"client_id={client_id}&client_secret={client_secret}&" \
               f"grant_type=password&username={username}&" \
               f"password={password}"

        response = requests.post(
            CONFIG['DEFENZ']['LOGIN_ENDPOINT'],
            headers={'Content-Type': 'application/x-www-form-urlencoded'},
            data=data)

        result = response.json()

        # pylint: disable=no-member
        if response.status_code != requests.codes.ok:
            raise Exception('Unsuccessful Login! Status Code: {} - '
                            'Error: {} - Error Description: {}'.format(
                                response.status_code, result.get('error'),
                                result.get('error_description')))

        result['created_at'] = datetime.now()
        self.__client_id = client_id
        self.__client_secret = client_secret
        self.__token = result

        LOGGER.info('The token has been obtained successfully!')
예제 #11
0
def main():
    """
    The main function of the script.
    """

    try:
        args = get_command_line_arguments()

        if args.verbose:
            console_handler = logging.StreamHandler()
            console_handler.setLevel(logging.DEBUG)
            console_handler.setFormatter(
                logging.Formatter('%(asctime)s - %(levelname)s: %(message)s'))
            LOGGER.addHandler(console_handler)

        validate_arguments(args)

        AUTHENTICATOR.login(args.username, args.password, args.client_id,
                            args.client_secret)

        networks = []
        if args.network_ids:
            for network_id in args.network_ids:
                networks.append(get_network(network_id))
        else:
            networks = get_networks()

        # We need to be consistent about report time throughout the script
        now = datetime.now()

        for net in networks:
            try:
                reports = get_all_reports(net['id'], now, args.interval)
                for report_type in args.report_types:
                    report_type = report_type.strip()
                    if reports[report_type]['results']:
                        send_alert(net, report_type, now, args.interval,
                                   args.report_email)
            except Exception as ex:  # pylint: disable=broad-except
                LOGGER.error("%s %s", str(ex), traceback.format_exc())
    except Exception as ex:  # pylint: disable=broad-except
        LOGGER.error("%s %s", str(ex), traceback.format_exc())
예제 #12
0
def send_email(email_content, recipients):
    """
    Sends an alert email for found anomaly events.

    :param email_content: Email content
    :param recipients: List of email addresses
    """

    if not CONFIG['EMAIL']['SMTP_SERVER'] or \
        not CONFIG['EMAIL']['SMTP_PORT'] or \
        not CONFIG['EMAIL']['SMTP_USER'] or \
        not CONFIG['EMAIL']['SMTP_PASSWORD'] or \
        not CONFIG['EMAIL']['SENDER_EMAIL_ADDRESS']:
        LOGGER.warning("Email configs have not been provided correctly. "
                       "The email can't be send. "
                       "Please check email configs in the config file.")
        return

    if not recipients:
        LOGGER.warning("No report email is set on this network or provided by"
                       "command line/config. So the alert won't be sent.")
        return

    LOGGER.info("Sending email to %s", ', '.join(recipients))

    msg = EmailMessage()
    msg.set_content(email_content)
    msg['Subject'] = CONFIG['EMAIL']['SUBJECT']
    msg['From'] = CONFIG['EMAIL']['SENDER_EMAIL_ADDRESS']
    msg['To'] = ', '.join(recipients)

    with smtplib.SMTP(CONFIG['EMAIL']['SMTP_SERVER'],
                      CONFIG['EMAIL']['SMTP_PORT']) as server:
        server.login(CONFIG['EMAIL']['SMTP_USER'],
                     CONFIG['EMAIL']['SMTP_PASSWORD'])
        server.send_message(msg)