Beispiel #1
0
    def setup_subparser(cls, subparser):
        """Add the output get subparser: manage.py output get [options]"""
        outputs = sorted(StreamAlertOutput.get_all_outputs().keys())

        get_parser = generate_subparser(
            subparser,
            'get',
            description=cls.description,
            help=cls.description,
            subcommand=True,
        )

        # Add the positional arg of service
        get_parser.add_argument(
            'service',
            choices=outputs,
            metavar='SERVICE',
            help=
            'Service to pull configured outputs and their secrets, select from: {}'
            .format(', '.join(outputs)))

        # Add the optional ability to pass multiple descriptors
        get_parser.add_argument(
            '--descriptors',
            '-d',
            nargs="+",
            default=False,
            help=
            'Pass descriptor and service to pull back the relevant configuration'
        )
Beispiel #2
0
    def setup_subparser(cls, subparser):
        """Add generate-skeleton subparser to the output subparser"""
        outputs = sorted(StreamAlertOutput.get_all_outputs().keys())

        # Create the generate-skeleton parser
        generate_skeleton_parser = generate_subparser(
            subparser,
            'generate-skeleton',
            description=cls.description,
            help=cls.description,
            subcommand=True)

        # Add the optional ability to pass services
        generate_skeleton_parser.add_argument(
            '--services',
            choices=outputs,
            nargs='+',
            metavar='SERVICE',
            default=outputs,
            help=
            'Pass the services to generate the skeleton for from services: {}'.
            format(', '.join(outputs)))

        # Add the optional file flag
        generate_skeleton_parser.add_argument(
            '--file',
            '-f',
            default=OUTPUTS_FILE,
            help='File to write to, relative to the current working directory')
Beispiel #3
0
    def handler(cls, options, config):
        """Generate a skeleton file for use with set-from-file
        Args:
            options (argparse.Namespace): Basically a namedtuple with the service setting
            config (StreamAlert.config): The configuration of StreamAlert
        Returns:
            bool: False if errors occurred, True otherwise
        """

        skeleton = {}
        for service in options.services:
            # Retrieve the proper service class to handle dispatching the alerts of this services
            # No need to safeguard, as choices are defined on --services
            output = StreamAlertOutput.get_dispatcher(service)

            # get dictionary of OutputProperty items to be used for user prompting
            properties = output.get_user_defined_properties()
            skeleton[service] = [{
                name:
                'desc: {}, restrictions: {}'.format(prop.description,
                                                    prop.input_restrictions)
                for name, prop in properties.items()
            }]

        try:
            with open(options.file, 'w') as json_file_fp:
                json.dump(skeleton, json_file_fp, indent=2, sort_keys=True)
        except Exception as err:  # pylint: disable=broad-except
            LOGGER.error(err)
            return False

        LOGGER.info(
            'Successfully generated the Skeleton file %s for services: %s',
            options.file, options.services)
        return True
Beispiel #4
0
    def setup_subparser(cls, subparser):
        """Setup: manage.py output set [options]

        Args:
            outputs (list): List of available output services
        """
        outputs = sorted(StreamAlertOutput.get_all_outputs().keys())

        set_parser = generate_subparser(subparser,
                                        'set',
                                        description=cls.description,
                                        help=cls.description,
                                        subcommand=True)

        # Add the required positional arg of service
        set_parser.add_argument(
            'service',
            choices=outputs,
            metavar='SERVICE',
            help=
            'Create a new StreamAlert output for one of the available services: {}'
            .format(', '.join(outputs)))

        # Add the optional update flag, which allows existing outputs to be updated
        set_parser.add_argument(
            '--update',
            '-u',
            action='store_true',
            default=False,
            help='If the output already exists, overwrite it')
Beispiel #5
0
def test_output_loading():
    """OutputDispatcher - Loading Output Classes"""
    loaded_outputs = set(StreamAlertOutput.get_all_outputs())
    # Add new outputs to this list to make sure they're loaded properly
    expected_outputs = {
        'aws-firehose', 'aws-lambda', 'aws-s3', 'aws-ses', 'aws-sns',
        'aws-sqs', 'aws-cloudwatch-log', 'carbonblack', 'demisto', 'github',
        'jira', 'komand', 'pagerduty', 'pagerduty-v2', 'pagerduty-incident',
        'phantom', 'slack', 'teams'
    }
    assert_count_equal(loaded_outputs, expected_outputs)
Beispiel #6
0
    def handler(cls, options, config):
        """Configure multiple outputs for multiple services
        Args:
            options (argparse.Namespace): Basically a namedtuple with the service setting
            config (StreamAlert.config): The configuration of StreamAlert
        Returns:
            bool: False if errors occurred, True otherwise
        """
        try:
            with open(options.file, 'r') as json_file_fp:
                file_contents = json.load(json_file_fp)
        except Exception:  # pylint: disable=broad-except
            LOGGER.error("Error opening file %s", options.file)
            return False

        if not file_contents:
            LOGGER.error('File %s is empty', options.file)
            return False

        for service, configurations in file_contents.items():
            LOGGER.debug('Setting outputs for service %s', service)
            # Retrieve the proper service class to handle dispatching the alerts of this service
            output = StreamAlertOutput.get_dispatcher(service)

            for configuration in configurations:
                properties = cls.convert_configuration_to_properties(
                    configuration, output)
                if not properties:
                    # Configuration was not valid
                    return False

                if not options.update and output_exists(
                        config['outputs'], properties, service):
                    # If the output already exists and update is not set
                    # return early
                    return False

                # For each configuration for this service, save the creds and update the config
                if not cls.save_credentials(service, config, properties):
                    return False
                cls.update_config(options, config, properties, output, service)

            LOGGER.info('Saved %s configurations for service: %s',
                        len(configurations), service)

        LOGGER.info('Finished setting all configurations for services: %s',
                    file_contents.keys())
        return True
Beispiel #7
0
    def handler(cls, options, config):
        """Configure a new output for this service
        Args:
            options (argparse.Namespace): Basically a namedtuple with the service setting
            config (StreamAlert.config): The configuration of StreamAlert
        Returns:
            bool: False if errors occurred, True otherwise
        """
        # Retrieve the proper service class to handle dispatching the alerts of this services
        output = StreamAlertOutput.get_dispatcher(options.service)

        # If an output for this service has not been defined, the error is logged
        # prior to this
        if not output:
            return False

        # get dictionary of OutputProperty items to be used for user prompting
        properties = output.get_user_defined_properties()

        for name, prop in properties.items():
            # pylint: disable=protected-access
            properties[name] = prop._replace(value=user_input(
                prop.description, prop.mask_input, prop.input_restrictions))

        service = output.__service__

        if not options.update and output_exists(config['outputs'], properties,
                                                service):
            # If the output already exists and update is not set
            # ask for user input again for a unique configuration
            return cls.handler(options, config)

        if not cls.save_credentials(service, config, properties):
            # Error message is already logged so no need to log a new one
            return False

        cls.update_config(options, config, properties, output, service)

        LOGGER.info(
            'Successfully saved \'%s\' output configuration for service \'%s\'',
            properties['descriptor'].value, service)
        return True
Beispiel #8
0
    def setup_subparser(cls, subparser):
        """Add the output list subparser: manage.py output list [options]"""
        outputs = sorted(StreamAlertOutput.get_all_outputs().keys())

        list_parser = generate_subparser(
            subparser,
            'list',
            description=cls.description,
            help=cls.description,
            subcommand=True,
        )

        # Add the optional arg of service
        list_parser.add_argument(
            '--service',
            '-s',
            choices=outputs,
            default=outputs,
            nargs='*',
            metavar='SERVICE',
            help=
            'Pass Services to list configured output descriptors, select from: {}'
            .format(', '.join(outputs)))
Beispiel #9
0
    def handler(cls, options, config):
        """Fetches the configuration for a service
        Args:
            options (argparse.Namespace): Basically a namedtuple with the service setting
            config (StreamAlert.config): The configuration of StreamAlert
        Returns:
            bool: False if errors occurred, True otherwise
        """
        service = options.service
        output = StreamAlertOutput.create_dispatcher(service, config)

        # Get the descriptors for the service. No need to check service
        # as this is handled by argparse choices
        configured_descriptors = [
            descriptor for descriptor in config["outputs"][service]
            if 'sample' not in descriptor
        ]

        # Set the descriptors to get the secrets for
        descriptors = options.descriptors if options.descriptors else configured_descriptors

        LOGGER.debug('Getting secrets for service %s and descriptors %s',
                     service, descriptors)

        credentials = []
        for descriptor in descriptors:
            if descriptor not in configured_descriptors:
                LOGGER.error('Invalid descriptor %s, it doesn\'t exist',
                             descriptor)
                return False

            creds = output._load_creds(descriptor)  # pylint: disable=protected-access
            creds['descriptor'] = descriptor
            credentials.append(creds)

        print('\nService Name:', service)
        print(json.dumps(credentials, indent=2, sort_keys=True), '\n')
Beispiel #10
0
    def _create_dispatcher(self, output):
        """Create a dispatcher for the given output.

        Args:
            output (str): Alert output, e.g. "aws-sns:topic-name"

        Returns:
            OutputDispatcher: Based on the output type.
                Returns None if the output is invalid or not defined in the config.
        """
        try:
            service, descriptor = output.split(':')
        except ValueError:
            LOGGER.error(
                'Improperly formatted output [%s]. Outputs for rules must '
                'be declared with both a service and a descriptor for the '
                'integration (ie: \'slack:my_channel\')', output)
            return None

        if service not in self.config or descriptor not in self.config[service]:
            LOGGER.error('The output \'%s\' does not exist!', output)
            return None

        return StreamAlertOutput.create_dispatcher(service, self.config)
Beispiel #11
0
def test_user_defined_properties():
    """OutputDispatcher - User Defined Properties"""
    for output in list(StreamAlertOutput.get_all_outputs().values()):
        props = output.get_user_defined_properties()
        # The user defined properties should at a minimum contain a descriptor
        assert_is_not_none(props.get('descriptor'))
Beispiel #12
0
def test_create_dispatcher():
    """StreamAlertOutput - Create Dispatcher"""
    dispatcher = StreamAlertOutput.create_dispatcher('aws-s3', CONFIG)
    assert_is_instance(dispatcher, S3Output)
Beispiel #13
0
def test_get_dispatcher_bad(log_mock):
    """StreamAlertOutput - Get Invalid Dispatcher"""
    dispatcher = StreamAlertOutput.get_dispatcher('aws-s4')
    assert_is_none(dispatcher)
    log_mock.assert_called_with('Designated output service [%s] does not exist', 'aws-s4')
Beispiel #14
0
def test_get_dispatcher_good():
    """StreamAlertOutput - Get Valid Dispatcher"""
    dispatcher = StreamAlertOutput.get_dispatcher('aws-s3')
    assert_is_not_none(dispatcher)