From 1f747af6d380e99c3e0ad5fd772e8f377afcd951 Mon Sep 17 00:00:00 2001 From: "Peter J. Holzer" Date: Fri, 2 Sep 2022 18:41:19 +0200 Subject: [PATCH] Authenticate reporting nodes --- app.py | 37 +++++++++++++++++++++++++++++++++++-- 1 file changed, 35 insertions(+), 2 deletions(-) diff --git a/app.py b/app.py index 18b64c2..ba75393 100644 --- a/app.py +++ b/app.py @@ -1,7 +1,9 @@ -import logging +import hmac import json +import logging +import os -from flask import (Flask, request, jsonify) +from flask import (Flask, request, jsonify, abort) from ltsdb_json import LTS @@ -23,6 +25,8 @@ def report(): n_dp = 0 for d in data: d["description"]["remote_addr"] = request.remote_addr + d["description"]["node"] = verify_node(d) + log.info("received %s", json.dumps(d)) ts = LTS(d["description"]) for dp in d["data"]: @@ -31,3 +35,32 @@ def report(): n_dp += 1 n_ts += 1 return jsonify({ "success": True, "timeseries": n_ts, "datapoints": n_dp }) + +def verify_node(d): + node = d["auth"]["node"] + timestamp = d["auth"]["timestamp"] + digest1 = d["auth"]["hmac"] + if "/" in node: + raise ValueError("invalid node name %s", node) + try: + log.info("gettingg client config from %s", "config/" + node) + with open("config/" + node) as fh: + node_conf = json.load(fh) + except Exception as e: + log.warning("got %s opening %s", e, "config/" + node) + abort(401, "unknown client") + last = node_conf["last"] + for key in node_conf["keys"]: + msg = (node + " " + str(timestamp)).encode("UTF-8") + hmac2 = hmac.new(key.encode("UTF-8"), msg, "SHA-256") + digest2 = hmac2.hexdigest() + if hmac.compare_digest(digest1, digest2): + if timestamp > node_conf["last"]: + node_conf["last"] = timestamp + os.replace("config/" + node, "config/" + node + ".old") + with open("config/" + node, "w") as fh: + json.dump(node_conf, fh) # XXX + return node + else: + abort(409, "timestamp out of sync") + abort(401, "auth failed")