From c485f1499fb45ac8c6a8b8f157722c8211b9a856 Mon Sep 17 00:00:00 2001 From: Daniel McKnight Date: Wed, 6 Nov 2024 18:24:09 -0800 Subject: [PATCH] Update Docker default config to include sqlite database Prevent update requests from modifying users without validating a token or password Prevent update requests from allowing an escalation of privileges --- docker_overlay/etc/neon/diana.yaml | 4 ++++ neon_users_service/mq_connector.py | 16 ++++++++++++++++ 2 files changed, 20 insertions(+) diff --git a/docker_overlay/etc/neon/diana.yaml b/docker_overlay/etc/neon/diana.yaml index 1ab7df3..a757764 100644 --- a/docker_overlay/etc/neon/diana.yaml +++ b/docker_overlay/etc/neon/diana.yaml @@ -7,3 +7,7 @@ logs: - filelock info: [] debug: [] +neon_users_service: + module: sqlite + sqlite: + db_path: /data/neon-users-db.sqlite \ No newline at end of file diff --git a/neon_users_service/mq_connector.py b/neon_users_service/mq_connector.py index 8983892..abceefb 100644 --- a/neon_users_service/mq_connector.py +++ b/neon_users_service/mq_connector.py @@ -21,8 +21,15 @@ def __init__(self, config: Optional[dict], service_name: str = "neon_users_servi self.service = NeonUsersService(module_config) def parse_mq_request(self, mq_req: dict) -> dict: + """ + Handle a request to interact with the user database. Requests should be + validated to ensure the user has proper permissions to perform the + requested action. + """ mq_req = UserDbRequest(**mq_req) + # TODO: Define method for an admin user to modify other users (incl. permissions) + # Ensure supplied `user` object is consistent with request params if mq_req.user and mq_req.username != mq_req.user.username: return {"success": False, @@ -35,6 +42,7 @@ def parse_mq_request(self, mq_req: dict) -> dict: return {"success": False, "error": "Empty password provided"} if not mq_req.user: + # TODO: Should this be allowed? mq_req.user = User(username=mq_req.username, password_hash=mq_req.password) mq_req.user.password_hash = mq_req.password @@ -48,10 +56,18 @@ def parse_mq_request(self, mq_req: dict) -> dict: user = self.service.read_unauthenticated_user( mq_req.username) elif mq_req.operation == "update": + # Get the existing user, maybe raising an AuthenticationError + existing = self.service.read_authenticated_user(mq_req.username, + mq_req.password, + mq_req.access_token) if mq_req.password: mq_req.user.password_hash = mq_req.password + + # Do not allow permissions changes via this endpoint + mq_req.user.permissions = existing.permissions user = self.service.update_user(mq_req.user) elif mq_req.operation == "delete": + # If the passed User object isn't an exact match, it will fail user = self.service.delete_user(mq_req.user) else: raise RuntimeError(f"Invalid operation requested: "