Skip to content
Snippets Groups Projects
Commit dcedb1ad authored by Michal Kostenec's avatar Michal Kostenec
Browse files

SQL features

Authorization
Authentication
parent b8da1998
No related branches found
No related tags found
No related merge requests found
*.pem
......@@ -8,4 +8,4 @@
"get_events_limit": 1000,
"description": "Warden 3 not even alpha development server"
}
}
}
\ No newline at end of file
......@@ -155,7 +155,7 @@ class NoAuthenticator(Object):
return "anybody" # or None
def authorize(self, env, client, method, args):
def authorize(self, env, client, method, event, args):
return (client is not None)
......@@ -192,10 +192,29 @@ class X509Authenticator(NoAuthenticator):
return self.db.get_client_by_name(names)
def authorize(self, env, client, method, args):
return (client is not None) and client["rights"]=="whatever"
def authorize(self, env, client, method, event, args):
cl = None
service = event['Node'][0]['Name']
for i in range(len(client)):
if client[i]['service'] == service:
cl = client[i]
break
if cl is None:
return None
# logging.debug(cl)
# logging.debug(method)
# logging.debug(service)
# return True if (method == 'getEvents' and cl['read'])
if ((method == 'sendEvents' and cl['write'] == 1) or
(method == 'getDebug' and cl['debug'] == 1) or
(method == 'sendEvents' and cl['test'] == 1 and service == 'Test')):
return cl
return None
class NoValidator(Object):
......@@ -203,7 +222,6 @@ class NoValidator(Object):
return []
class JSONSchemaValidator(NoValidator):
def __init__(self, filename=None):
......@@ -256,14 +274,15 @@ class MySQL(Object):
def get_client_by_name(self, name):
return {
"name": name[0] if name else None,
"rights": "whatever"
}
format_strings = ','.join(['%s'] * len(name))
self.crs.execute("SELECT `id`, `hostname`, `service`, `identity`, `read`, `write`, `debug`, `test` FROM `clients2` WHERE `valid` = 1 AND `hostname` IN (%s)" % format_strings, tuple(name))
row = self.crs.fetchall()
return row if row else None
def get_debug(self):
self.crs.execute("SELECT VERSION() AS VER");
self.crs.execute("SELECT VERSION() AS VER")
row = self.crs.fetchone()
return {
"db": "MySQL",
......@@ -296,16 +315,176 @@ class MySQL(Object):
cat=None, nocat=None,
tag=None, notag=None,
group=None, nogroup=None):
sqlwhere = []
sqltemp = {}
if cat is not None and nocat is not None:
raise Error("Unrealizable conditions. Choose cat or nocat option.", 500, method='getEvents',
exc=sys.exc_info(), detail={'cat': cat, 'nocat' : nocat})
if cat is not None or nocat is not None:
if cat is not None:
sqltemp['cat'] = generateDynamicQuery(self, "Category", "category_id IN (%s)", json.loads(cat))
if nocat is not None:
sqltemp['cat'] = generateDynamicQuery(self, "Category", "category_id NOT IN (%s)", json.loads(nocat))
sqlwhere.append("e.id IN (SELECT event_id FROM event_category_mapping4 WHERE %s)" % sqltemp['cat'])
if tag is not None and notag is not None:
raise Error("Unrealizable conditions. Choose tag or notag option.", 500, method='getEvents',
exc=sys.exc_info(), detail={'tag': cat, 'notag' : nocat})
if tag is not None or notag is not None:
if tag is not None:
sqltemp['tag'] = generateDynamicQuery(self, "Tag", "tag_id IN (%s)", json.loads(tag))
if notag is not None:
sqltemp['tag'] = generateDynamicQuery(self, "Tag", "tag_id NOT IN (%s)", json.loads(notag))
sqlwhere.append("e.id IN (SELECT event_id FROM event_tag_mapping4 WHERE %s)" % sqltemp['tag'])
if group is not None and nogroup is not None:
raise Error("Unrealizable conditions. Choose group or nogroup option.", 500, method='getEvents',
exc=sys.exc_info(), detail={'tag': cat, 'notag' : nocat})
if group is not None or nogroup is not None:
sqltemp['group'] = ""
if group is not None:
for identity in json.loads(group):
sqltemp['group'] += ("cl.identity LIKE '%s' AND " % (identity))
if nogroup is not None:
for identity in json.loads(nogroup):
sqltemp['group'] += ("cl.identity NOT LIKE '%s' AND " % (identity))
# logging.debug(sqltemp['group'][:-4])
sqlwhere.append(sqltemp['group'][:-4])
sqlwhere_string = (" AND " . join(sqlwhere))
# logging.debug(sqlwhere_string)
# logging.debug(' AND ' . join(sqlwhere))
#sqlwhere = sqlwhere[:-4]
and_op = "" if not sqlwhere_string else "AND"
# logging.debug("SELECT e.id, e.data FROM clients2 cl RIGHT JOIN events4 e ON cl.id = e.client_id WHERE e.id > %s AND %s %s e.valid = 1 LIMIT %s" % (str(id), sqlwhere_string, and_op, str(count)))
self.crs.execute("SELECT e.id, e.data FROM clients2 cl RIGHT JOIN events4 e ON cl.id = e.client_id WHERE e.id > %s AND %s %s e.valid = 1 LIMIT %s" % (str(id), sqlwhere_string, and_op, str(count)))
row = self.crs.fetchall()
return {
"lastid": (id or 0)+count,
"events": [self.gen_random_idea() for i in range(count)]
"lastid": row[-1]['id'] if row else str(id),
"events": [row[i]['data'] for i in range(len(row))]
}
def store_events(self, client, events):
errs = [] # See sendEvents and validation, should return something similar
for event in events:
try:
# logging.debug("INSERT INTO events5 (detected,received,client_id,data) VALUES ('%s', NOW(), '%s', '%s')" % (event['DetectTime'], client['id'], self.con.escape_string(str(event))))
self.crs.execute("INSERT INTO events5 (detected,received,client_id,data) VALUES ('%s', NOW(), '%s', '%s')" % (event['DetectTime'], client['id'], self.con.escape_string(str(event))))
lastid = self.crs.lastrowid
# logging.debug(str(lastid))
for cat in event['Category']:
# logging.debug({'cat': cat})
cat_id = self.map_id('Category', cat) if self.map_id('Category', cat) else self.map_id('Category', 'Other.Other')
# logging.debug({'cat_id': cat_id})
# logging.debug("INSERT INTO event_category_mapping5 (event_id,category_id) VALUES ('%s', '%s')" % (str(lastid), str(cat_id)))
self.crs.execute("INSERT INTO event_category_mapping5 (event_id,category_id) VALUES ('%s', '%s')" % (str(lastid), str(cat_id)))
for tag in event['Node'][0]['Tags']:
tag_id = self.map_id('Tag', tag) if self.map_id('Tag', tag) else self.map_id('Tag', 'Other')
# logging.debug({'tag_id': tag_id})
# logging.debug("INSERT INTO event_tag_mapping5 (event_id,tag_id) VALUES ('%s', '%s')" % (str(lastid), tag_id))
self.crs.execute("INSERT INTO event_tag_mapping5 (event_id,tag_id) VALUES ('%s', '%s')" % (str(lastid), str(tag_id)))
self.con.commit()
except:
self.con.rollback()
raise Error("Data storing error", 00, detail={'event': event})
errs.append({"event": event})
return errs
def map_id (self, section, key):
# Should by placed in config file
data = {}
data['Tag'] = {
"Connection" : 1,
"Datagram" : 2,
"Content" : 3,
"Data" : 4,
"File" : 5,
"Flow" : 6,
"Log": 7,
"Protocol" : 8,
"Host" : 9,
"Network" : 10,
"Correlation" : 11,
"External" : 12,
"Reporting" : 13,
"Other" : 99
}
data['Category'] = {
"Abusive.Spam" : 101,
"Abusive.Harassment" : 102,
"Abusive.Child" : 103,
"Abusive.Sexual" : 104,
"Abusive.Violence" : 105,
"Malware.Virus" : 201,
"Malware.Worm" : 202,
"Malware.Trojan" : 203,
"Malware.Spyware" : 204,
"Malware.Dialer" : 205,
"Malware.Rootkit" : 206,
"Recon.Scanning" : 301,
"Recon.Sniffing" : 302,
"Recon.SocialEngineering" : 303,
"Recon.Searching" : 304,
"Attempt.Exploit" : 401,
"Attempt.Login" : 402,
"Attempt.NewSignature" : 403,
"Intrusion.AdminCompromise" : 501,
"Intrusion.UserCompromise" : 502,
"Intrusion.AppCompromise" : 503,
"Intrusion.Botnet" : 504,
"Availability.DoS" : 601,
"Availability.DDoS" : 602,
"Availability.Sabotage" : 603,
"Availability.Outage" : 604,
"Information.UnauthorizedAccess" : 701,
"Information.UnauthorizedModification" : 702,
"Fraud.UnauthorizedUsage" : 801,
"Fraud.Copyright" : 802,
"Fraud.Masquerade" : 803,
"Fraud.Phishing" : 804,
"Fraud.Scam" : 805,
"Vulnerable.Open" : 901,
"Anomaly.Traffic" : 1001,
"Anomaly.Connection" : 1002,
"Anomaly.Protocol" : 1003,
"Anomaly.System" : 1004,
"Anomaly.Application" : 1005,
"Anomaly.Behaviour" : 1006,
"Other" : 9998,
"Test" : 9999,
}
try:
return data[section][key]
except:
return data[section]['Other']
def generateDynamicQuery(self, section, query_string, variables):
variables_id = [self.map_id(section, v) for v in variables]
format_strings = ','.join(['\'%s\''] * len(variables_id))
temp_string = query_string % format_strings
return temp_string % tuple(variables_id)
def expose(meth):
......@@ -365,7 +544,7 @@ class Server(Object):
client = self.auth.authenticate(environ)
if not client:
raise Error("I'm watching YOU.", 403, method=path)
raise Error("I'm watching YOU. (Authenticate)", 403, method=path)
try:
events = json.loads(injson) if injson else None
......@@ -380,8 +559,8 @@ class Server(Object):
if events:
args["events"] = events
if not self.auth.authorize(environ, client, path, args):
raise Error("I'm watching YOU.", 403, method=path, detail={"client": client})
# if not self.auth.authorize(environ, client, path, args):
# raise Error("I'm watching YOU.", 403, method=path, detail={"client": client})
args = self.sanitize_args(path, method, args)
result = method(_env=environ, _client=client, **args) # call requested method
......@@ -428,10 +607,11 @@ class Server(Object):
class WardenHandler(Object):
def __init__(self, validator, db,
def __init__(self, validator, db, auth,
send_events_limit=100000, get_events_limit=100000,
description=None):
self.auth = auth
self.db = db
self.validator = validator
self.send_events_limit = send_events_limit
......@@ -507,13 +687,17 @@ class WardenHandler(Object):
okevents = []
valerrs = []
for event in events:
auth_cl = self.auth.authorize(_env, _client, 'sendEvents', event, None)
if not auth_cl:
raise Error("I'm watching YOU. (Authorization)", 403, method='sendEvents', detail={"client": _client})
verrs = self.validator.check(event)
if verrs:
valerrs.append({"errors": verrs, "event": event})
else:
okevents.append(event)
dberrs = self.db.store_events(_client, okevents)
dberrs = self.db.store_events(auth_cl, okevents)
if valerrs or dberrs:
raise Error("Event storage error", 500, method="sendEvents",
......@@ -633,12 +817,13 @@ def build_server(conf):
"host": {"type": str, "default": "localhost"},
"user": {"type": str, "default": "warden"},
"password": {"type": str, "default": ""},
"dbname": {"type": str, "default": "warden3"},
"dbname": {"type": str, "default": "warden3c"},
"port": {"type": natural, "default": 3306}
},
"WardenHandler": {
"validator": {"type": obj, "default": "validator"},
"db": {"type": obj, "default": "DB"},
"auth": {"type": obj, "default": "auth"},
"send_events_limit": {"type": natural, "default": 10000},
"get_events_limit": {"type": natural, "default": 10000},
"description": {"type": str, "default": ""}
......@@ -654,6 +839,8 @@ def build_server(conf):
sect_name = sect_name.lower()
sect_def = section_def[sect_name]
#logging.debug("Testing %s" % sect_name)
try: # Object type defined?
objtype = config["type"]
del config["type"]
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment