async def get_watchlist_users(self, watchlists: dict, query: Optional[Query] = Query()) -> Results: """ Args: watchlists (dict): {<watchlist_id>: <watchlist_name>} query (OptionL[Query]): Returns: results (Results): """ if not self.logged_in: await self.login() results = Results(data=[]) for k, v in watchlists.items(): logger.debug(f'Getting watchlist {k}: {v}, users from Exabeam...') tasks = [asyncio.create_task(self.request(method='get', end_point=f'/uba/api/watchlist/{k}/', request_id=uuid4().hex, params=query.dict()))] res = await self.process_results(Results(data=await asyncio.gather(*tasks)), 'users') for r in res.success: r['watchlist'] = v results.data.extend(res.data) results.success.extend(res.success) results.failure.extend(res.failure) logger.debug(f'-> Complete; Retrieved {len(results.data)}, watchlist users.') return results
async def delete_records( self, query: Union[List[ArtifactQuery], List[ContainerQuery]]) -> Results: """ Args: query (List[Union[ArtifactQuery, ContainerQuery]]): Returns: results (Results)""" logger.debug(f'Deleting {type(query)}, record(s)...') if not type(query) is list: query = [query] tasks = [ asyncio.create_task( self.request(method='delete', end_point=q.end_point, request_id=uuid4().hex)) for q in query ] results = Results(data=await asyncio.gather(*tasks)) logger.debug('-> Complete.') return await self.process_results(results)
async def login(self) -> Results: payload = { 'username': self.cfg['Auth']['Username'], 'password': self.cfg['Auth']['Password'] } logger.debug('Logging in to Bricata...') tasks = [ asyncio.create_task( self.request(method='post', end_point='/login/', request_id=uuid4().hex, json=payload)) ] results = Results(data=await asyncio.gather(*tasks)) logger.debug('-> Complete.') results = await self.process_results(results) self.header = { **self.HDR, **{ 'Authorization': f'{results.success[0]["token_type"]} {results.success[0]["token"]}' } } await self.session.close() self.session = aio.ClientSession(headers=self.header, json_serialize=rapidjson.dumps) return results
async def update_records( self, requests: List[Union[ContainerRequest, ArtifactRequest]]) -> Results: """ Args: requests (Union[ ContainerRequest, ArtifactRequest, List[Union[ContainerRequest, ArtifactRequest]]]): Returns: results (Results)""" logger.debug(f'Updating record(s)...') if not type(requests) is list: requests = [requests] tasks = [ asyncio.create_task( self.request(method='post', end_point=r.end_point, request_id=uuid4().hex, json=r.dict())) for r in requests ] results = Results(data=await asyncio.gather(*tasks)) logger.debug('-> Complete.') return await self.process_results(results)
async def get_record_count( self, query: Union[ArtifactQuery, ContainerQuery, UserQuery]) -> Results: """ Performs a single page query to get the 'results_count' & 'num_paqges' based on specified Query. Args: query (Optional[ContainerQuery]): Returns: results (Results) """ logger.debug(f'Getting {type(query)} record count...') if not query.page: query.page = 0 if not query.page_size: query.page_size = 1 tasks = [ asyncio.create_task( self.request(method='get', end_point=query.end_point, request_id=uuid4().hex, params=query.dict())) ] logger.debug('-> Complete.') return await self.process_results( Results(data=await asyncio.gather(*tasks)))
async def get_records( self, query: Union[Query, ComputerQuery, UserQuery]) -> Results: entries = self.connection.extend.standard.paged_search( search_base=query.search_base or self.cfg['Defaults']['SearchBase'], search_filter=query.search_filter, search_scope=query.search_scope, attributes=query.attributes, paged_size=query.paged_size) return Results(data=entries, success=[e['attributes'] for e in entries])
async def check_credentials(self, username, password) -> Results: """ Args: username (str): password (str): Returns: results (Results)""" connection: Connection = Connection( self.adserver, user=username, password=password, authentication=self.cfg['Auth']['Type'] or None) connection.bind() cr = connection.result if cr['description'] == 'success': return Results(data=connection.result, success=[cr]) else: return Results(data=connection.result, failure=[cr])
async def delete_tag(self, tag_name: str) -> Results: await self.__check_login() logger.debug(f'Deleting tag: {tag_name}, from Bricata...') tasks = [ asyncio.create_task( self.request(method='delete', end_point=f'/tags/{tag_name}/', request_id=uuid4().hex)) ] results = Results(data=await asyncio.gather(*tasks)) logger.debug('-> Complete.') return await self.process_results(results)
async def untag_alert(self, uuid: str, tag: str): await self.__check_login() logger.debug(f'Untagging: {tag} from alert: {uuid}, in Bricata...') tasks = [ asyncio.create_task( self.request(method='delete', end_point=f'/alerts/{uuid}/tag/{tag}/', request_id=uuid4().hex)) ] results = Results(data=await asyncio.gather(*tasks)) logger.debug('-> Complete.') return await self.process_results(results)
async def get_alert(self, uuid: str) -> Results: await self.__check_login() logger.debug(f'Getting alert: {uuid}, from Bricata...') tasks = [ asyncio.create_task( self.request(method='get', end_point=f'/alert/{uuid}', request_id=uuid4().hex)) ] results = Results(data=await asyncio.gather(*tasks)) logger.debug('-> Complete.') return await self.process_results(results)
async def put_tag(self, tag: TagRequest) -> Results: await self.__check_login() logger.debug(f'Creating tag: {tag} in Bricata...') tasks = [ asyncio.create_task( self.request(method='put', end_point=f'/tags/{tag.name}/', request_id=uuid4().hex, json=tag.dict)) ] results = Results(data=await asyncio.gather(*tasks)) logger.debug('-> Complete.') return await self.process_results(results)
async def get_tags(self) -> Results: await self.__check_login() logger.debug('Getting tags from Bricata...') tasks = [ asyncio.create_task( self.request( method='get', end_point='/tags/', request_id=uuid4().hex, )) ] results = Results(data=await asyncio.gather(*tasks)) logger.debug('-> Complete.') return await self.process_results(results)
async def get_alerts(self, filters: Optional[AlertsFilter] = None) -> Results: await self.__check_login() logger.debug('Getting alerts from Bricata...') tasks = [ asyncio.create_task( self.request(method='get', end_point='/alerts/', request_id=uuid4().hex, params=filters.dict if filters else None)) ] results = Results(data=await asyncio.gather(*tasks)) logger.debug(f'-> Complete; Retrieved {len(results.data)}, alerts.') return await self.process_results(results, 'objects')
async def logout(self) -> Results: payload = {'username': self.cfg['Auth']['Username']} logger.debug('Logging out of Bricata...') tasks = [ asyncio.create_task( self.request(method='post', end_point='/logout/', request_id=uuid4().hex, json=payload)) ] results = Results(data=await asyncio.gather(*tasks)) logger.debug('-> Complete.') self.header = None return await self.process_results(results)
async def __date_filter(query: Union[ContainerQuery], results: Results) -> Results: """Date Filter - Filters Results by date Args: query (Union[ContainerQuery]): results (Results): Returns: results (Results): """ results.success = [ r for r in results.success if query.date_filter_start <= parse(r[query.date_filter_field], dayfirst=False) <= query.date_filter_end ] return results
async def login(self) -> Results: """ Returns: results (Results): """ payload = {'username': self.cfg['Auth']['Username'], 'password': self.cfg['Auth']['Password']} logger.debug('Logging in to Exabeam...') tasks = [asyncio.create_task(self.request(method='post', end_point='/api/auth/login', request_id=uuid4().hex, json=payload))] results = Results(data=await asyncio.gather(*tasks)) logger.debug('-> Complete.') self.logged_in = True return await self.process_results(results)
async def get_case_count(self, query: Optional[Query] = Query(maxRecords=1, offset=0)) -> Results: """ Performs a single page query to get the 'totalResult' based on specified Query. Args: query (Optional[Query]): Returns: results (Results) """ # todo: need to see actual output to verify this logger.debug('Getting case count...') tasks = [asyncio.create_task(self.request(method='get', end_point='/cases', request_id=uuid4().hex, params=query.params()))] results = Results(data=await asyncio.gather(*tasks)) logger.debug('-> Complete.') return await self.process_results(results)
async def get_records( self, query: Union[ArtifactQuery, AuditQuery, ContainerQuery]) -> Results: """ Args: query (ContainerQuery): Returns: results (Results)""" logger.debug(f'Getting {type(query)}, record(s)...') if type(query) is AuditQuery: page_limit = 1 else: if not query.id: page_limit = ( await self.get_record_count(query)).success[0]['num_pages'] else: # When we're getting a single container we can skip paging page_limit = 1 tasks = [ asyncio.create_task( self.request(method='get', end_point=query.end_point, request_id=uuid4().hex, params={ **query.dict(), 'page': i })) for i in range(0, page_limit) ] results = await self.process_results( Results(data=await asyncio.gather(*tasks)), query.data_key) if query.date_filter_field: results = await self.__date_filter(query=query, results=results) logger.debug('-> Complete.') return results
async def get_cases(self, case_id: Optional[str], query: Optional[Query] = Query()) -> Results: """ Can retrieve: - All cases - A single case Args: case_id (Optional[int]): query (Optional[Query]): Returns: results (Results) """ if case_id: ep = f'/cases/{case_id}' else: ep = '/cases' if not case_id: # todo: rewrite for phishlabs # page_limit = (await self.get_case_count(query=query)).success[0]['num_pages'] page_limit = 0 else: # When we're getting a single container we can skip paging page_limit = 1 logger.debug('Getting cases(s)...') tasks = [asyncio.create_task(self.request(method='get', end_point=ep, request_id=uuid4().hex, params=query.params(offset=i))) for i in range(0, page_limit, query.maxRecords)] results = Results(data=await asyncio.gather(*tasks)) logger.debug('-> Complete.') return await self.process_results(results, 'data')
async def get_notable_users(self, query: Optional[NotableUsersQuery] = NotableUsersQuery()) -> Results: """ Args: query (OptionL[NotableUsersQuery]): Returns: results (Results): """ if not self.logged_in: await self.login() logger.debug('Getting notable users from Exabeam...') tasks = [asyncio.create_task(self.request(method='get', end_point='/uba/api/users/notable', request_id=uuid4().hex, params=query.dict()))] results = Results(data=await asyncio.gather(*tasks)) logger.debug(f'-> Complete; Retrieved {len(results.data)}, notable users.') return await self.process_results(results, 'users')
async def create_containers( self, containers: Union[List[ContainerRequest], ContainerRequest] ) -> Tuple[Results, Any]: # todo: handle revert_failure # todo: handle failure (already exists) # todo: handle update_existing if type(containers) is not list: containers = [containers] logger.debug('Creating container(s)...') tasks = [ asyncio.create_task( self.request(method='post', end_point='/container', request_id=c.data['request_id'], json=c.dict())) for c in containers ] container_results = await self.process_results( Results(data=await asyncio.gather(*tasks))) logger.debug('-> Complete.') # print('container_results:\n', container_results) [ c.update_id( next((_['id'] for _ in container_results.success if _['request_id'] == c.data['request_id']), None)) for c in containers ] artifact_results, containers = await self.create_artifacts(containers) container_results.success.extend(artifact_results.success) container_results.failure.extend(artifact_results.failure) return container_results, containers
async def create_artifacts( self, containers: Union[List[ContainerRequest], ContainerRequest] ) -> Tuple[Results, List[ContainerRequest]]: # todo: handle failure (already exists?) logger.debug('Creating artifact(s)...') if type(containers) is not list: containers = [containers] # if type(containers[0]) is ContainerRequest: tasks = [ asyncio.create_task( self.request(method='post', end_point='/artifact', request_id=a.data['request_id'], json=a.dict())) for x in containers for a in x.artifacts ] # else: # ArtifactRequest # tasks = [asyncio.create_task(self.request(method='post', # end_point='/artifact', # request_id=a.data['request_id'], # json=a.dict())) for a in containers] results = await self.process_results( Results(data=await asyncio.gather(*tasks))) [ a.update_id( next((_['id'] for _ in results.success if _['request_id'] == a.data['request_id']), None)) for x in containers for a in x.artifacts ] logger.debug('-> Complete.') return results, containers
async def get_records(self, query: Union[AlertQuery]) -> Results: """ Args: query (Union[AlertQuery]): Returns: results (Results)""" await self.__check_login() logger.debug(f'Getting {type(query)}, record(s)...') tasks = [ asyncio.create_task( self.request(method='get', end_point=query.end_point, request_id=uuid4().hex, params=query.dict())) ] results = await self.process_results( Results(data=await asyncio.gather(*tasks)), query.data_key) logger.debug('-> Complete.') return results