diff --git a/owrx/controllers/session.py b/owrx/controllers/session.py index 7ebd1b1..3a9d342 100644 --- a/owrx/controllers/session.py +++ b/owrx/controllers/session.py @@ -2,6 +2,7 @@ from .template import WebpageController from urllib.parse import parse_qs from uuid import uuid4 from http.cookies import SimpleCookie +from owrx.users import UserList class SessionStorage(object): @@ -40,18 +41,18 @@ class SessionController(WebpageController): def processLoginAction(self): data = parse_qs(self.get_body().decode("utf-8")) data = {k: v[0] for k, v in data.items()} + userlist = UserList.getSharedInstance() if "user" in data and "password" in data: - # TODO actually check user and password - if data["user"] == "admin" and data["password"] == "password": - # TODO pass the final destination - key = SessionStorage.getSharedInstance().startSession({"user": data["user"]}) - cookie = SimpleCookie() - cookie["owrx-session"] = key - self.send_redirect("/admin", cookies=cookie) - else: - self.send_redirect("/login") - else: - self.send_response("invalid request", code=400) + if data["user"] in userlist: + user = userlist[data["user"]] + if user.password.is_valid(data["password"]): + # TODO pass the final destination + key = SessionStorage.getSharedInstance().startSession({"user": user.name}) + cookie = SimpleCookie() + cookie["owrx-session"] = key + self.send_redirect("/admin", cookies=cookie) + return + self.send_redirect("/login") def logoutAction(self): self.send_redirect("logout happening here") diff --git a/owrx/users.py b/owrx/users.py new file mode 100644 index 0000000..43e0865 --- /dev/null +++ b/owrx/users.py @@ -0,0 +1,80 @@ +from abc import ABC, abstractmethod +import json + +import logging + +logger = logging.getLogger(__name__) + + +class PasswordException(Exception): + pass + + +class Password(ABC): + @staticmethod + def from_dict(d: dict): + if "encoding" not in d: + raise PasswordException("password encoding not set") + if d["encoding"] == "string": + return CleartextPassword(d) + raise PasswordException("invalid passord encoding: {0}".format(d["type"])) + + def __init__(self, pwinfo: dict): + self.pwinfo = pwinfo + + @abstractmethod + def is_valid(self, inp: str): + pass + + +class CleartextPassword(Password): + def is_valid(self, inp: str): + return self.pwinfo['value'] == inp + + +class User(object): + def __init__(self, name: str, enabled: bool, password: Password): + self.name = name + self.enabled = enabled + self.password = password + + +class UserList(object): + sharedInstance = None + + @staticmethod + def getSharedInstance(): + if UserList.sharedInstance is None: + UserList.sharedInstance = UserList() + return UserList.sharedInstance + + def __init__(self): + self.users = self._loadUsers() + + def _loadUsers(self): + for file in ["/etc/openwebrx/users.json", "users.json"]: + try: + f = open(file, "r") + users_json = json.load(f) + f.close() + + return {u.name: u for u in [self.buildUser(d) for d in users_json]} + except FileNotFoundError: + pass + except json.JSONDecodeError: + logger.exception("error while parsing users file %s", file) + return {} + except Exception: + logger.exception("error while processing users from %s", file) + return {} + return {} + + def buildUser(self, d): + if "user" in d and "password" in d and "enabled" in d: + return User(d["user"], d["enabled"], Password.from_dict(d["password"])) + + def __getitem__(self, item): + return self.users[item] + + def __contains__(self, item): + return item in self.users diff --git a/users.json b/users.json new file mode 100644 index 0000000..298d7f2 --- /dev/null +++ b/users.json @@ -0,0 +1,11 @@ +[ + { + "user": "admin", + "password": { + "encoding": "string", + "value": "password", + "force_change": true + }, + "enabled": true + } +] \ No newline at end of file