import requests import sqlite3 import http.cookies as ck import time import config import utils # This authentication provider assumes that a cookie containing a session ID # has been set by some unspecified means (e.g. a login panel). This session ID # is verified for authorization by calling a centralized verification endpoint # which returns any entitlements in JSON. # Authorized sessions are cached in a table in the local cargohold database # for a limited time. cookie_name = "session" validator = "https://stumpf.es/auth/cargohold" session_cache_interval = 60*15 db = sqlite3.connect(config.database, check_same_thread = False) def login(env, post): # Check if already using a known session user = get(env) if user: return utils.redirect("/admin") # Check if session cookie present cookies = ck.SimpleCookie(env.get('HTTP_COOKIE', '')) if cookie_name not in cookies: return utils.redirect(config.homepage) # Check if session ID valid req = requests.get(validator, headers = {"Cookie": cookie_name + "=" + cookies[cookie_name].value}) auth = req.json() if "entitlement" in auth and auth["entitlement"]["service"] == "cargohold": # Create the user if not known utils.ensure_user(auth["user"]) # Add to session cache db.cursor().execute("INSERT INTO sessions (id, user, expire) VALUES (:id, :user, :expire)", {"id": cookies[cookie_name].value, "user": auth["user"], "expire": int(time.time() + min(auth["expire_in"], session_cache_interval))}) db.commit() return utils.redirect("/admin") return utils.redirect(config.homepage) def get(env): # Check if session cookie present cookies = ck.SimpleCookie(env.get('HTTP_COOKIE', '')) if cookie_name not in cookies: return None # Check if session ID is in local cache data = db.cursor().execute("SELECT user, expire FROM sessions WHERE id = :id", {"id": cookies[cookie_name].value}) sess = data.fetchone() if sess and sess[1] > time.time(): return {"user": sess[0], "expire": sess[1]} if sess: # Prune expired sessions db.cursor().execute("DELETE FROM sessions WHERE expire < :time", {"time": time.time()}) db.commit() return None def logout(): # TODO return None