Permalink
Browse files

New api server (#177)

* make new server

* make bin file

* make new package for api

* remove api server tests from tanner server

* use config to get host and port

* update api name in setup file

* reduce poolsize for api
  • Loading branch information...
rnehra01 authored and afeena committed Jul 23, 2017
1 parent a88bbdc commit 0297c84b92e344fda5c267a5dc5ab1d83e96192b
View
@@ -0,0 +1,9 @@
#!/usr/bin/python3.5
from tanner.api import server
def main():
api = server.ApiServer()
api.start()
if __name__ == "__main__":
main()
View
@@ -9,6 +9,6 @@
author_email='glastopf@public.honeynet.org',
url='https://github.com/mushorg/tanner',
packages=find_packages(exclude=['*.pyc']),
scripts=['bin/tanner', 'bin/tannerweb'],
scripts=['bin/tanner', 'bin/tannerweb', 'bin/tannerapi'],
data_files=[('/opt/tanner/data/',['tanner/data/dorks.pickle'])]
)
View
No changes.
@@ -1,70 +1,14 @@
import json
import logging
import operator
import asyncio
import asyncio_redis
from aiohttp import web
class Api:
def __init__(self, redis_client):
self.logger = logging.getLogger('tanner.api.Api')
self.redis_client = redis_client
@staticmethod
def _make_response(msg):
response_message = dict(
version=1,
response=dict(message=msg)
)
return response_message
async def handle_index(self, request):
result = 'tanner api'
response_msg = self._make_response(result)
return web.json_response(response_msg)
async def handle_snares(self, request):
result = await self.return_snares()
response_msg = self._make_response(result)
return web.json_response(response_msg)
async def handle_snare_info(self, request):
snare_uuid = request.match_info['snare_uuid']
result = await self.return_snare_info(snare_uuid, 50)
response_msg = self._make_response(result)
return web.json_response(response_msg)
async def handle_snare_stats(self, request):
snare_uuid = request.match_info['snare_uuid']
result = await self.return_snare_stats(snare_uuid)
response_msg = self._make_response(result)
return web.json_response(response_msg)
async def handle_sessions(self, request):
params = request.url.query
applied_filters = {}
try:
if 'filters' in params:
applied_filters = {filt.split(':')[0] : filt.split(':')[1] for filt in params['filters'].split()}
if 'start_time' in applied_filters:
applied_filters['start_time'] = float(applied_filters['start_time'])
if 'end_time' in applied_filters:
applied_filters['end_time'] = float(applied_filters['end_time'])
except Exception as e:
self.logger.error('Filter error : %s' % e)
result = 'Invalid filter definition'
else:
result = await self.return_sessions(applied_filters)
response_msg = self._make_response(result)
return web.json_response(response_msg)
async def handle_session_info(self, request):
sess_uuid = request.match_info['sess_uuid']
result = await self.return_session_info(sess_uuid)
response_msg = self._make_response(result)
return web.json_response(response_msg)
async def return_snares(self):
query_res = []
try:
@@ -164,4 +108,4 @@ def apply_filter(self, filter_name, filter_value, sess):
else:
return available_filters[filter_name](filter_value, sess[filter_name])
except KeyError:
raise
raise
View
@@ -0,0 +1,94 @@
import asyncio
import logging
from tanner.api import api
from aiohttp import web
from tanner import redis_client
from tanner.config import TannerConfig
class ApiServer:
def __init__(self):
self.logger = logging.getLogger('tanner.api.ApiServer')
self.api = None
@staticmethod
def _make_response(msg):
response_message = dict(
version=1,
response=dict(message=msg)
)
return response_message
async def handle_index(self, request):
result = 'tanner api'
response_msg = self._make_response(result)
return web.json_response(response_msg)
async def handle_snares(self, request):
result = await self.api.return_snares()
response_msg = self._make_response(result)
return web.json_response(response_msg)
async def handle_snare_info(self, request):
snare_uuid = request.match_info['snare_uuid']
result = await self.api.return_snare_info(snare_uuid, 50)
response_msg = self._make_response(result)
return web.json_response(response_msg)
async def handle_snare_stats(self, request):
snare_uuid = request.match_info['snare_uuid']
result = await self.api.return_snare_stats(snare_uuid)
response_msg = self._make_response(result)
return web.json_response(response_msg)
async def handle_sessions(self, request):
snare_uuid = request.match_info['snare_uuid']
params = request.url.query
applied_filters = {'snare_uuid': snare_uuid}
try:
if 'filters' in params:
for filt in params['filters'].split():
applied_filters[filt.split(':')[0]] = filt.split(':')[1]
if 'start_time' in applied_filters:
applied_filters['start_time'] = float(applied_filters['start_time'])
if 'end_time' in applied_filters:
applied_filters['end_time'] = float(applied_filters['end_time'])
except Exception as e:
self.logger.error('Filter error : %s' % e)
result = 'Invalid filter definition'
else:
result = await self.api.return_sessions(applied_filters)
response_msg = self._make_response(result)
return web.json_response(response_msg)
async def handle_session_info(self, request):
sess_uuid = request.match_info['sess_uuid']
result = await self.api.return_session_info(sess_uuid)
response_msg = self._make_response(result)
return web.json_response(response_msg)
async def on_shutdown(self, app):
self.redis_client.close()
def setup_routes(self, app):
app.router.add_get('/', self.handle_index)
app.router.add_get('/snares', self.handle_snares)
app.router.add_resource('/snare/{snare_uuid}').add_route('GET', self.handle_snare_info)
app.router.add_resource('/snare-stats/{snare_uuid}').add_route('GET', self.handle_snare_stats)
app.router.add_resource('/{snare_uuid}/sessions').add_route('GET', self.handle_sessions)
app.router.add_resource('/session/{sess_uuid}').add_route('GET', self.handle_session_info)
def create_app(self, loop):
app = web.Application(loop=loop)
app.on_shutdown.append(self.on_shutdown)
self.setup_routes(app)
return app
def start(self):
loop = asyncio.get_event_loop()
self.redis_client = loop.run_until_complete(redis_client.RedisClient.get_redis_client(poolsize=20))
self.api = api.Api(self.redis_client)
app = self.create_app(loop)
host = TannerConfig.get('API', 'host')
port = TannerConfig.get('API', 'port')
web.run_app(app, host=host, port=port)
View
@@ -9,6 +9,7 @@
'vdocs': '/opt/tanner/data/vdocs.json'},
'TANNER': {'host': '0.0.0.0', 'port': 8090},
'WEB': {'host': '0.0.0.0', 'port': 8091},
'API': {'host': '0.0.0.0', 'port': 8092},
'REDIS': {'host': 'localhost', 'port': 6379, 'poolsize': 80, 'timeout': 1},
'EMULATORS': {'root_dir': '/opt/tanner',
'emulator_enabled': {'sqli': True, 'rfi': True, 'lfi': True, 'xss': True, 'cmd_exec': True}
View
@@ -22,7 +22,6 @@ def __init__(self):
self.session_manager = session_manager.SessionManager()
self.dorks = dorks_manager.DorksManager()
self.api = None
self.base_handler = base.BaseHandler(base_dir, db_name)
self.logger = logging.getLogger(__name__)
self.redis_client = None
@@ -87,19 +86,6 @@ def setup_routes(self, app):
app.router.add_post('/event', self.handle_event)
app.router.add_get('/dorks', self.handle_dorks)
def setup_api_routes(self, app):
app.router.add_get('/', self.api.handle_index)
app.router.add_get('/snares', self.api.handle_snares)
app.router.add_resource('/snare/{snare_uuid}').add_route('GET', self.api.handle_snare_info)
app.router.add_resource('/snare-stats/{snare_uuid}').add_route('GET', self.api.handle_snare_stats)
app.router.add_resource('/sessions').add_route('GET', self.api.handle_sessions)
app.router.add_resource('/session/{sess_uuid}').add_route('GET', self.api.handle_session_info)
def create_api_app(self, loop):
api_app = web.Application(loop=loop)
self.setup_api_routes(api_app)
return api_app
def create_app(self, loop):
app = web.Application(loop=loop)
app.on_shutdown.append(self.on_shutdown)
@@ -109,10 +95,7 @@ def create_app(self, loop):
def start(self):
loop = asyncio.get_event_loop()
self.redis_client = loop.run_until_complete(redis_client.RedisClient.get_redis_client())
self.api = api.Api(self.redis_client)
tanner_app = self.create_app(loop)
api_app = self.create_api_app(loop)
tanner_app.add_subapp('/api/', api_app)
app = self.create_app(loop)
host = TannerConfig.get('TANNER', 'host')
port = TannerConfig.get('TANNER', 'port')
web.run_app(tanner_app, host=host, port=port)
web.run_app(app, host=host, port=port)
@@ -13,6 +13,7 @@ def setUp(self):
'vdocs': '/tmp/user_tanner/data/vdocs.json'},
'TANNER': {'host': '0.0.0.0', 'port': '9000'},
'WEB': {'host': '0.0.0.0', 'port': '9001'},
'WEB': {'host': '0.0.0.0', 'port': '9002'},
'REDIS': {'host': 'localhost', 'port': '1337', 'poolsize': '40', 'timeout': '5'},
'EMULATORS': {'root_dir': '/tmp/user_tanner'},
'SQLI': {'type':'SQLITE', 'db_name': 'user_tanner_db', 'host':'localhost', 'user':'user_name', 'password':'user_pass'},
@@ -59,6 +60,7 @@ def test_get_when_file_dont_exists(self):
'vdocs': '/opt/tanner/data/vdocs.json'},
'TANNER': {'host': '0.0.0.0', 'port': 8090},
'WEB': {'host': '0.0.0.0', 'port': 8091},
'API': {'host': '0.0.0.0', 'port': 8092},
'REDIS': {'host': 'localhost', 'port': 6379, 'poolsize': 80, 'timeout': 1},
'EMULATORS': {'root_dir': '/opt/tanner'},
'SQLI': {'type':'SQLITE', 'db_name': 'tanner_db', 'host':'localhost', 'user':'root', 'password':'user_pass'},
@@ -4,7 +4,7 @@
from aiohttp.test_utils import AioHTTPTestCase, unittest_run_loop
from tanner import server, api
from tanner import server
from tanner.config import TannerConfig
@@ -49,7 +49,6 @@ def setUp(self):
redis.close = mock.Mock()
self.serv.dorks = dorks
self.serv.redis_client = redis
self.serv.api = api.Api(self.serv.redis_client)
super(TestServer, self).setUp()
@@ -61,8 +60,6 @@ def _make_coroutine(self):
def get_app(self):
app = self.serv.create_app(loop=self.loop)
api_app = self.serv.create_api_app(loop=self.loop)
app.add_subapp('/api/', api_app)
return app
@unittest_run_loop
@@ -98,76 +95,3 @@ def test_make_response(self):
assert request.status == 200
detection = await request.json()
self.assertDictEqual(detection, assert_content)
@unittest_run_loop
async def test_api_index_request(self):
assert_content = {"version": 1, "response": {"message": "tanner api"}}
request = await self.client.request("GET", "/api/")
assert request.status == 200
detection = await request.json()
self.assertDictEqual(detection, assert_content)
@unittest_run_loop
async def test_api_snares_request(self):
async def mock_return_snares():
return ["8fa6aa98-4283-4085-bfb9-a1cd3a9e56e4"]
assert_content = {"version": 1, "response": {"message": ["8fa6aa98-4283-4085-bfb9-a1cd3a9e56e4"]}}
self.serv.api.return_snares = mock_return_snares
request = await self.client.request("GET", "/api/snares")
assert request.status == 200
detection = await request.json()
self.assertDictEqual(detection, assert_content)
@unittest_run_loop
async def test_api_snare_info_request(self):
async def mock_return_snare_info(snare_uuid, count):
if snare_uuid == "8fa6aa98-4283-4085-bfb9-a1cd3a9e56e4" and count == 50:
return [{"test_sess1": "sess1_info"}, {"test_sess1": "sess2_info"}]
assert_content = {"version": 1, "response": {"message": [{"test_sess1": "sess1_info"}, {"test_sess1": "sess2_info"}]}}
self.serv.api.return_snare_info = mock_return_snare_info
request = await self.client.request("GET", "/api/snare/8fa6aa98-4283-4085-bfb9-a1cd3a9e56e4")
assert request.status == 200
detection = await request.json()
self.assertDictEqual(detection, assert_content)
@unittest_run_loop
async def test_api_snare_stats_request(self):
async def mock_return_snare_stats(snare_uuid):
if snare_uuid == "8fa6aa98-4283-4085-bfb9-a1cd3a9e56e4":
return {"total_sessions": 605, "total_duration": 865.560286283493, "attack_frequency": {"sqli": 0, "lfi": 0, "xss": 0, "rfi": 0, "cmd_exec": 0}}
assert_content = {"version": 1, "response": {"message": {"total_sessions": 605, "total_duration": 865.560286283493, "attack_frequency": {"sqli": 0, "lfi": 0, "xss": 0, "rfi": 0, "cmd_exec": 0}}}}
self.serv.api.return_snare_stats = mock_return_snare_stats
request = await self.client.request("GET", "/api/snare-stats/8fa6aa98-4283-4085-bfb9-a1cd3a9e56e4")
assert request.status == 200
detection = await request.json()
self.assertDictEqual(detection, assert_content)
@unittest_run_loop
async def test_api_sessions_request(self):
async def mock_return_sessions(filters):
if type(filters) is dict and filters['peer_ip'] == "127.0.0.1" and \
filters['start_time'] == 1497890400 and filters['user_agent'] == 'ngnix':
return ["f387d46eaeb1454cadf0713a4a55be49", "e85ae767b0bb4b1f91b421b3a28082ef"]
assert_content = {"version": 1, "response": {"message": ["f387d46eaeb1454cadf0713a4a55be49", "e85ae767b0bb4b1f91b421b3a28082ef"]}}
self.serv.api.return_sessions = mock_return_sessions
request = await self.client.request("GET", "/api/sessions?filters=peer_ip:127.0.0.1 start_time:1497890400 user_agent:ngnix")
assert request.status == 200
detection = await request.json()
self.assertDictEqual(detection, assert_content)
@unittest_run_loop
async def test_api_sessions_info_request(self):
async def mock_return_session_info(sess_uuid):
if sess_uuid == "4afd45d61b994d9eb3ba20faa81a45e1":
return {"test_sess1": "sess1_info"}
assert_content = {"version": 1, "response": {"message": {"test_sess1": "sess1_info"}}}
self.serv.api.return_session_info = mock_return_session_info
request = await self.client.request("GET", "/api/session/4afd45d61b994d9eb3ba20faa81a45e1")
assert request.status == 200
detection = await request.json()
self.assertDictEqual(detection, assert_content)
View
@@ -4,7 +4,8 @@
import logging
from aiohttp import web
from tanner import api, redis_client
from tanner.api import api
from tanner import redis_client
from tanner.config import TannerConfig
class TannerWebServer:

0 comments on commit 0297c84

Please sign in to comment.