diff options
Diffstat (limited to 'src/wsgi.py')
-rwxr-xr-x | src/wsgi.py | 63 |
1 files changed, 41 insertions, 22 deletions
diff --git a/src/wsgi.py b/src/wsgi.py index aed3513..98efc6f 100755 --- a/src/wsgi.py +++ b/src/wsgi.py @@ -8,27 +8,29 @@ from db import DictDB import time from base64 import b64decode +import authn + class CollectorResource(): - def __init__(self, db): + def __init__(self, db, users): self._db = db + self._users = users def parse_error(data): return "I want valid JSON but got this:\n{}\n".format(data) - def user_authn(self, auth_header, authfun): + def user_auth(self, auth_header, authfun): if not auth_header: - return None # Fail. + return None, None # Fail. BAlit, b64 = auth_header.split() if BAlit != "Basic": - return None # Fail + return None, None # Fail userbytes, pwbytes = b64decode(b64).split(b':') try: - user = userbytes.decode('ascii') + user = userbytes.decode('utf-8') + pw = pwbytes.decode('utf-8') except: - return None # Fail - if authfun(user, pwbytes): - return user # Success. - return None # Fail. + return None, None # Fail + return authfun(user, pw) class EPGet(CollectorResource): @@ -37,13 +39,14 @@ class EPGet(CollectorResource): resp.content_type = falcon.MEDIA_JSON out = [] - userid = self.user_authn(req.auth, lambda user,_pw: user is not None) - if not userid: + orgs = self.user_auth(req.auth, self._users.read_perms) + if not orgs: resp.status = falcon.HTTP_401 - resp.text = 'Invalid user or password\n' + resp.text = 'Invalid username or password\n' return - out = [{time.ctime(key): dict} for (key, dict) in self._db.search('domain', dict_val=userid)] + for org in orgs: + out += [{time.ctime(key): dict} for (key, dict) in self._db.search('domain', dict_val=org)] resp.text = json.dumps(out) + '\n' @@ -54,12 +57,15 @@ class EPAdd(CollectorResource): resp.content_type = falcon.MEDIA_TEXT self._indata = [] - if self.user_authn(req.auth, - lambda u,p: u == 'admin' and p == b'admin') is None: + orgs = self.user_auth(req.auth, self._users.write_perms) + if not orgs: resp.status = falcon.HTTP_401 resp.text = 'Invalid user or password\n' return + # NOTE: Allowing writing to _any_ org! + # TODO: Allow only input where input.domain in orgs == True. + # TODO: can we do json.load(req.bounded_stream, # cls=customDecoder) where our decoder calls JSONDecoder after # decoding UTF-8? @@ -100,15 +106,28 @@ def init(url_res_map, addr = '', port = 8000): def main(): - # Simple demo. - # Try adding some observations, basic auth admin:admin, and - # include {"domain": "foo.se"} in some of them. - # Try retreiving all observations for user 'foo.se' (basic auth - # foo.se:whatever). + # Simple demo. Run it from the demo directory where a sample user + # database can be found: + # + # $ cd demo && ../src/wsgi.py + # Serving on port 8000... + # + # 1. Try adding some observations, basic auth user:pw from + # wsgi_demo_users.yaml, including {"domain": "sunet.se"} in at + # least one of them: + # + # $ echo '[{"ip": "192.168.0.1", "port": 80, "domain": "sunet.se"}]' | curl -s -u user3:pw3 --data-binary @- http://localhost:8000/sc/v0/add + # + # 2. Try retreiving all observations for a user with read access + # to 'sunet.se': + # + # $ curl -s -u user1:pw1 http://localhost:8000/sc/v0/get | json_pp -json_opt utf8,pretty db = DictDB('wsgi_demo.db') - httpd = init([('/sc/v0/add', EPAdd(db)), - ('/sc/v0/get', EPGet(db))]) + users = authn.UserDB('wsgi_demo_users.yaml') + + httpd = init([('/sc/v0/add', EPAdd(db, users)), + ('/sc/v0/get', EPGet(db, users))]) print('Serving on port 8000...') httpd.serve_forever() |