class PlannerApi(BaseObjectApi): def __init__(self, services): super().__init__(description='planner', obj_class=Planner, schema=PlannerSchema, ram_key='planners', id_property='planner_id', auth_svc=services['auth_svc']) self._api_manager = BaseApiManager(data_svc=services['data_svc'], file_svc=services['file_svc']) def add_routes(self, app: web.Application): router = app.router router.add_get('/planners', self.get_planners) router.add_get('/planners/{planner_id}', self.get_planner_by_id) @aiohttp_apispec.docs(tags=['planners']) @aiohttp_apispec.querystring_schema(BaseGetAllQuerySchema) @aiohttp_apispec.response_schema(PlannerSchema(many=True, partial=True)) async def get_planners(self, request: web.Request): planners = await self.get_all_objects(request) return web.json_response(planners) @aiohttp_apispec.docs(tags=['planners']) @aiohttp_apispec.querystring_schema(BaseGetOneQuerySchema) @aiohttp_apispec.response_schema(PlannerSchema(partial=True)) async def get_planner_by_id(self, request: web.Request): planner = await self.get_object(request) return web.json_response(planner)
class OperationSchema(ma.Schema): id = ma.fields.String() name = ma.fields.String(required=True) host_group = ma.fields.List(ma.fields.Nested(AgentSchema()), attribute='agents', dump_only=True) adversary = ma.fields.Nested(AdversarySchema()) jitter = ma.fields.String() planner = ma.fields.Nested(PlannerSchema()) start = ma.fields.DateTime(format=BaseObject.TIME_FORMAT, dump_only=True) state = ma.fields.String() obfuscator = ma.fields.String() autonomous = ma.fields.Integer() chain = ma.fields.Function(lambda obj: [lnk.display for lnk in obj.chain]) auto_close = ma.fields.Boolean() visibility = ma.fields.Integer() objective = ma.fields.Nested(ObjectiveSchema()) use_learning_parsers = ma.fields.Boolean() group = ma.fields.String(missing='') source = ma.fields.Nested(SourceSchema()) @ma.pre_load() def remove_properties(self, data, **_): data.pop('host_group', None) data.pop('start', None) data.pop('chain', None) data.pop('objective', None) return data @ma.post_load def build_operation(self, data, **kwargs): return None if kwargs.get('partial') is True else Operation(**data)
async def _construct_and_dump_planner(self, planner_id: str): planner = await self.services['data_svc'].locate( 'planners', match=dict(planner_id=planner_id)) if not planner: planner = await self.services['data_svc'].locate( 'planners', match=dict(name='atomic')) return PlannerSchema().dump(planner[0])
def test_planner(event_loop): expected_planner = { 'name': 'test planner', 'description': 'test planner', 'module': 'test', 'stopping_conditions': [], 'params': {}, 'allow_repeatable_abilities': False, 'ignore_enforcement_modules': [], 'id': '123' } test_planner = PlannerSchema().load(expected_planner) event_loop.run_until_complete( BaseService.get_service('data_svc').store(test_planner)) return test_planner
def test_operation(test_adversary, test_planner, test_source): expected_operation = { 'name': '123', 'adversary': AdversarySchema().dump(test_adversary), 'state': 'paused', 'id': '123', 'group': 'red', 'autonomous': 0, 'planner': PlannerSchema().dump(test_planner), 'source': SourceSchema().dump(test_source), 'jitter': '2/8', 'visibility': 50, 'auto_close': False, 'obfuscator': 'plain-text', 'use_learning_parsers': False } return expected_operation
class OperationSchema(ma.Schema): id = ma.fields.Integer() name = ma.fields.String() host_group = ma.fields.List(ma.fields.Nested(AgentSchema()), attribute='agents') adversary = ma.fields.Nested(AdversarySchema()) jitter = ma.fields.String() planner = ma.fields.Nested(PlannerSchema()) start = ma.fields.DateTime(format='%Y-%m-%d %H:%M:%S') state = ma.fields.String() obfuscator = ma.fields.String() autonomous = ma.fields.Integer() chain = ma.fields.Function(lambda obj: [lnk.display for lnk in obj.chain]) auto_close = ma.fields.Boolean() visibility = ma.fields.Integer() @ma.post_load def build_planner(self, data, **_): return Operation(**data)
class PlannerApi(BaseApi): def __init__(self, services): super().__init__(auth_svc=services['auth_svc']) self._api_manager = BaseApiManager(data_svc=services['data_svc']) def add_routes(self, app: web.Application): router = app.router router.add_get('/planners', self.get_planners) router.add_get('/planners/{planner_id}', self.get_planner_by_id) @aiohttp_apispec.docs(tags=['planners']) @aiohttp_apispec.querystring_schema(BaseGetAllQuerySchema) @aiohttp_apispec.response_schema(PlannerSchema(many=True)) async def get_planners(self, request: web.Request): sort = request['querystring'].get('sort', 'name') include = request['querystring'].get('include') exclude = request['querystring'].get('exclude') planners = self._api_manager.get_objects_with_filters('planners', sort=sort, include=include, exclude=exclude) return web.json_response(planners) @aiohttp_apispec.docs(tags=['planners']) @aiohttp_apispec.querystring_schema(BaseGetOneQuerySchema) @aiohttp_apispec.response_schema(PlannerSchema) async def get_planner_by_id(self, request: web.Request): planner_id = request.match_info['planner_id'] include = request['querystring'].get('include') exclude = request['querystring'].get('exclude') search = dict(planner_id=planner_id) planner = self._api_manager.get_object_with_filters('planners', search=search, include=include, exclude=exclude) if not planner: raise JsonHttpNotFound(f'Planner not found: {planner_id}') return web.json_response(planner)
class PlannerApi(BaseObjectApi): def __init__(self, services): super().__init__(description='planner', obj_class=Planner, schema=PlannerSchema, ram_key='planners', id_property='planner_id', auth_svc=services['auth_svc']) self._api_manager = BaseApiManager(data_svc=services['data_svc'], file_svc=services['file_svc']) def add_routes(self, app: web.Application): router = app.router router.add_get('/planners', self.get_planners) router.add_get('/planners/{planner_id}', self.get_planner_by_id) @aiohttp_apispec.docs( tags=['planners'], summary='Retrieve planners', description= 'Retrieve CALDERA planners by criteria. Supply fields from the `PlannerSchema` ' 'to the `include` and `exclude` fields of the `BaseGetAllQuerySchema` in the ' 'request body to filter retrieved planners.') @aiohttp_apispec.querystring_schema(BaseGetAllQuerySchema) @aiohttp_apispec.response_schema( PlannerSchema(many=True, partial=True), description= 'Returns a list of matching planners in `PlannerSchema` format.') async def get_planners(self, request: web.Request): planners = await self.get_all_objects(request) return web.json_response(planners) @aiohttp_apispec.docs( tags=['planners'], summary='Retrieve a planner by planner id', description= 'Retrieve one CALDERA planner based on the planner id (String `UUID`). ' 'Supply fields from the `PlannerSchema` to the `include` and `exclude` fields ' 'of the `BaseGetOneQuerySchema` in the request body to filter retrieved ' 'planners.', parameters=[{ 'in': 'path', 'name': 'planner_id', 'schema': { 'type': 'string' }, 'required': 'true', 'description': 'UUID of the Planner object to be retrieved.' }]) @aiohttp_apispec.querystring_schema(BaseGetOneQuerySchema) @aiohttp_apispec.response_schema( PlannerSchema(partial=True), description= 'Returns a planner with the specified id in `PlannerSchema` format.') async def get_planner_by_id(self, request: web.Request): planner = await self.get_object(request) return web.json_response(planner)