add idp-cookie; for high-traffic / glitchy auth servers

This commit is contained in:
ed 2025-08-03 23:27:53 +00:00
parent ae5eefc528
commit f9502c3df3
4 changed files with 23 additions and 1 deletions

View file

@ -1894,6 +1894,8 @@ you can disable the built-in password-based login system, and instead replace it
* the regular config-defined users will be used as a fallback for requests which don't include a valid (trusted) IdP username header * the regular config-defined users will be used as a fallback for requests which don't include a valid (trusted) IdP username header
* if your IdP-server is slow, consider `--idp-cookie` and let requests with the cookie `cppws` bypass the IdP; experimental sessions-based feature added for a party
some popular identity providers are [Authelia](https://www.authelia.com/) (config-file based) and [authentik](https://goauthentik.io/) (GUI-based, more complex) some popular identity providers are [Authelia](https://www.authelia.com/) (config-file based) and [authentik](https://goauthentik.io/) (GUI-based, more complex)
there is a [docker-compose example](./docs/examples/docker/idp-authelia-traefik) which is hopefully a good starting point (alternatively see [./docs/idp.md](./docs/idp.md) if you're the DIY type) there is a [docker-compose example](./docs/examples/docker/idp-authelia-traefik) which is hopefully a good starting point (alternatively see [./docs/idp.md](./docs/idp.md) if you're the DIY type)

View file

@ -1150,6 +1150,7 @@ def add_auth(ap):
ap2.add_argument("--idp-db", metavar="PATH", type=u, default=idp_db, help="where to store the known IdP users/groups (if you run multiple copyparty instances, make sure they use different DBs)") ap2.add_argument("--idp-db", metavar="PATH", type=u, default=idp_db, help="where to store the known IdP users/groups (if you run multiple copyparty instances, make sure they use different DBs)")
ap2.add_argument("--idp-store", metavar="N", type=int, default=1, help="how to use \033[33m--idp-db\033[0m; [\033[32m0\033[0m] = entirely disable, [\033[32m1\033[0m] = write-only (effectively disabled), [\033[32m2\033[0m] = remember users, [\033[32m3\033[0m] = remember users and groups.\nNOTE: Will remember and restore the IdP-volumes of all users for all eternity if set to 2 or 3, even when user is deleted from your IdP") ap2.add_argument("--idp-store", metavar="N", type=int, default=1, help="how to use \033[33m--idp-db\033[0m; [\033[32m0\033[0m] = entirely disable, [\033[32m1\033[0m] = write-only (effectively disabled), [\033[32m2\033[0m] = remember users, [\033[32m3\033[0m] = remember users and groups.\nNOTE: Will remember and restore the IdP-volumes of all users for all eternity if set to 2 or 3, even when user is deleted from your IdP")
ap2.add_argument("--idp-adm", metavar="U,U", type=u, default="", help="comma-separated list of users allowed to use /?idp (the cache management UI)") ap2.add_argument("--idp-adm", metavar="U,U", type=u, default="", help="comma-separated list of users allowed to use /?idp (the cache management UI)")
ap2.add_argument("--idp-cookie", metavar="S", type=int, default=0, help="generate a session-token for IdP users which is written to cookie \033[33mcppws\033[0m (or \033[33mcppwd\033[0m if plaintext), to reduce the load on the IdP server, lifetime \033[33mS\033[0m seconds.\n └─note: The expiration time is a client hint only; the actual lifetime of the session-token is infinite (until next restart with \033[33m--ses-db\033[0m wiped)")
ap2.add_argument("--no-bauth", action="store_true", help="disable basic-authentication support; do not accept passwords from the 'Authenticate' header at all. NOTE: This breaks support for the android app") ap2.add_argument("--no-bauth", action="store_true", help="disable basic-authentication support; do not accept passwords from the 'Authenticate' header at all. NOTE: This breaks support for the android app")
ap2.add_argument("--bauth-last", action="store_true", help="keeps basic-authentication enabled, but only as a last-resort; if a cookie is also provided then the cookie wins") ap2.add_argument("--bauth-last", action="store_true", help="keeps basic-authentication enabled, but only as a last-resort; if a cookie is also provided then the cookie wins")
ap2.add_argument("--ses-db", metavar="PATH", type=u, default=ses_db, help="where to store the sessions database (if you run multiple copyparty instances, make sure they use different DBs)") ap2.add_argument("--ses-db", metavar="PATH", type=u, default=ses_db, help="where to store the sessions database (if you run multiple copyparty instances, make sure they use different DBs)")

View file

@ -2869,7 +2869,10 @@ class AuthSrv(object):
n = [] n = []
q = "insert into us values (?,?,?)" q = "insert into us values (?,?,?)"
for uname in self.acct: accs = list(self.acct)
if self.args.idp_h_usr and self.args.idp_cookie:
accs.extend(self.idp_accs.keys())
for uname in accs:
if uname not in ases: if uname not in ases:
sid = ub64enc(os.urandom(blen)).decode("ascii") sid = ub64enc(os.urandom(blen)).decode("ascii")
cur.execute(q, (uname, sid, int(time.time()))) cur.execute(q, (uname, sid, int(time.time())))

View file

@ -658,6 +658,9 @@ class HttpCli(object):
self.pw = "" self.pw = ""
self.uname = idp_usr self.uname = idp_usr
self.html_head += "<script>var is_idp=1</script>\n" self.html_head += "<script>var is_idp=1</script>\n"
zs = self.asrv.ases.get(idp_usr)
if zs:
self.set_idp_cookie(zs)
else: else:
self.log("unknown username: %r" % (idp_usr,), 1) self.log("unknown username: %r" % (idp_usr,), 1)
@ -3029,6 +3032,19 @@ class HttpCli(object):
return dur > 0, msg return dur > 0, msg
def set_idp_cookie(self, ases) -> None:
k = "cppws" if self.is_https else "cppwd"
ck = gencookie(
k,
ases,
self.args.R,
self.args.cookie_lax,
self.is_https,
self.args.idp_cookie,
"; HttpOnly",
)
self.out_headers["Set-Cookie"] = ck
def handle_mkdir(self) -> bool: def handle_mkdir(self) -> bool:
assert self.parser # !rm assert self.parser # !rm
new_dir = self.parser.require("name", 512) new_dir = self.parser.require("name", 512)