From 59688bc8d72faeece46f8a0cdd1c140bc1f4a54e Mon Sep 17 00:00:00 2001 From: ed Date: Sun, 24 Dec 2023 13:46:12 +0100 Subject: [PATCH] * rename `hdr-au-usr` to `idp-h-usr` * ensure lowercase idp-h-*, xff-hdr * more macos support in tooling --- README.md | 2 +- copyparty/__main__.py | 12 ++++++++---- copyparty/httpcli.py | 4 ++-- copyparty/svchub.py | 4 ++++ scripts/run-tests.sh | 15 ++++++++++++++- tests/util.py | 2 +- 6 files changed, 30 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 2b3ea3ef..f5b67d57 100644 --- a/README.md +++ b/README.md @@ -1217,7 +1217,7 @@ replace copyparty passwords with oauth and such work is [ongoing](https://github.com/9001/copyparty/issues/62) to support authenticating / authorizing users based on a separate authentication proxy, which makes it possible to support oauth, single-sign-on, etc. -it is currently possible to specify `--hdr-au-usr x-username`; copyparty will then skip password validation and blindly trust the username specified in the `X-Username` request header +it is currently possible to specify `--idp-h-usr x-username`; copyparty will then skip password validation and blindly trust the username specified in the `X-Username` request header the remaining stuff (accepting user groups through another header, creating volumes on the fly) are still to-do diff --git a/copyparty/__main__.py b/copyparty/__main__.py index 32f841e8..d8937008 100755 --- a/copyparty/__main__.py +++ b/copyparty/__main__.py @@ -879,7 +879,7 @@ def add_network(ap): ap2.add_argument("-p", metavar="PORT", type=u, default="3923", help="ports to bind (comma/range)") ap2.add_argument("--ll", action="store_true", help="include link-local IPv4/IPv6 in mDNS replies, even if the NIC has routable IPs (breaks some mDNS clients)") ap2.add_argument("--rproxy", metavar="DEPTH", type=int, default=1, help="which ip to associate clients with; [\033[32m0\033[0m]=tcp, [\033[32m1\033[0m]=origin (first x-fwd, unsafe), [\033[32m2\033[0m]=outermost-proxy, [\033[32m3\033[0m]=second-proxy, [\033[32m-1\033[0m]=closest-proxy") - ap2.add_argument("--xff-hdr", metavar="NAME", type=u, default="x-forwarded-for", help="if reverse-proxied, which http header to read the client's real ip from (argument must be lowercase, but not the actual header)") + ap2.add_argument("--xff-hdr", metavar="NAME", type=u, default="x-forwarded-for", help="if reverse-proxied, which http header to read the client's real ip from") ap2.add_argument("--xff-src", metavar="IP", type=u, default="127., ::1", help="comma-separated list of trusted reverse-proxy IPs; only accept the real-ip header (\033[33m--xff-hdr\033[0m) if the incoming connection is from an IP starting with either of these. Can be disabled with [\033[32many\033[0m] if you are behind cloudflare (or similar) and are using \033[32m--xff-hdr=cf-connecting-ip\033[0m (or similar)") ap2.add_argument("--ipa", metavar="PREFIX", type=u, default="", help="only accept connections from IP-addresses starting with \033[33mPREFIX\033[0m; example: [\033[32m127., 10.89., 192.168.\033[0m]") ap2.add_argument("--rp-loc", metavar="PATH", type=u, default="", help="if reverse-proxying on a location instead of a dedicated domain/subdomain, provide the base location here; example: [\033[32m/foo/bar\033[0m]") @@ -926,8 +926,9 @@ def add_cert(ap, cert_path): def add_auth(ap): - ap2 = ap.add_argument_group('user authentication options') - ap2.add_argument("--hdr-au-usr", metavar="HN", type=u, default="", help="bypass the copyparty authentication checks and assume the request-header \033[33mHN\033[0m contains the username of the requesting user (for use with authentik/oauth/...)\n\033[1;31mWARNING:\033[0m if you enable this, make sure clients are unable to specify this header themselves; must be washed away and replaced by a reverse-proxy. Also, the argument must be lowercase, but not the actual header") + ap2 = ap.add_argument_group('IdP / identity provider / user authentication options') + ap2.add_argument("--idp-h-usr", metavar="HN", type=u, default="", help="bypass the copyparty authentication checks and assume the request-header \033[33mHN\033[0m contains the username of the requesting user (for use with authentik/oauth/...)\n\033[1;31mWARNING:\033[0m if you enable this, make sure clients are unable to specify this header themselves; must be washed away and replaced by a reverse-proxy") + ap2.add_argument("--idp-h-grp", metavar="HN", type=u, default="", help="assume the request-header \033[33mHN\033[0m contains the groupname of the requesting user; can be referenced in config files for group-based access control") def add_zeroconf(ap): @@ -1387,7 +1388,10 @@ def main(argv: Optional[list[str]] = None) -> None: supp = args_from_cfg(v) argv.extend(supp) - deprecated: list[tuple[str, str]] = [("--salt", "--warksalt")] + deprecated: list[tuple[str, str]] = [ + ("--salt", "--warksalt"), + ("--hdr-au-usr", "--idp-h-usr"), + ] for dk, nk in deprecated: idx = -1 ov = "" diff --git a/copyparty/httpcli.py b/copyparty/httpcli.py index c0ae801d..15eb703b 100644 --- a/copyparty/httpcli.py +++ b/copyparty/httpcli.py @@ -452,9 +452,9 @@ class HttpCli(object): except: pass - if self.args.hdr_au_usr: + if self.args.idp_h_usr: self.pw = "" - self.uname = self.headers.get(self.args.hdr_au_usr) or "*" + self.uname = self.headers.get(self.args.idp_h_usr) or "*" if self.uname not in self.asrv.vfs.aread: self.log("unknown username: [%s]" % (self.uname), 1) self.uname = "*" diff --git a/copyparty/svchub.py b/copyparty/svchub.py index 1a84ad35..763de049 100644 --- a/copyparty/svchub.py +++ b/copyparty/svchub.py @@ -437,6 +437,10 @@ class SvcHub(object): elif al.ban_url == "no": al.sus_urls = None + al.xff_hdr = al.xff_hdr.lower() + al.idp_h_usr = al.idp_h_usr.lower() + al.idp_h_grp = al.idp_h_grp.lower() + al.xff_re = self._ipa2re(al.xff_src) al.ipa_re = self._ipa2re(al.ipa) al.ftp_ipa_re = self._ipa2re(al.ftp_ipa or al.ipa) diff --git a/scripts/run-tests.sh b/scripts/run-tests.sh index f14df573..10083ba7 100755 --- a/scripts/run-tests.sh +++ b/scripts/run-tests.sh @@ -1,6 +1,17 @@ #!/bin/bash set -ex +# osx support +gtar=$(command -v gtar || command -v gnutar) || true +[ ! -z "$gtar" ] && command -v gfind >/dev/null && { + tar() { $gtar "$@"; } + sed() { gsed "$@"; } + find() { gfind "$@"; } + sort() { gsort "$@"; } + command -v grealpath >/dev/null && + realpath() { grealpath "$@"; } +} + rm -rf unt mkdir -p unt/srv cp -pR copyparty tests unt/ @@ -30,9 +41,11 @@ for py in python{2,3}; do [ "${1:0:6}" = python ] && [ "$1" != $py ] && continue PYTHONPATH= - [ $py = python2 ] && PYTHONPATH=../scripts/py2:../sfx/py37 + [ $py = python2 ] && PYTHONPATH=../scripts/py2:../sfx/py37:../sfx/j2 export PYTHONPATH + [ $py = python2 ] && py=$(command -v python2.7 || echo $py) + nice $py -m unittest discover -s tests >/dev/null & pids+=($!) done diff --git a/tests/util.py b/tests/util.py index 4593b848..72428f2f 100644 --- a/tests/util.py +++ b/tests/util.py @@ -128,7 +128,7 @@ class Cfg(Namespace): ex = "db_act df loris re_maxage rproxy rsp_jtr rsp_slp s_wr_slp snap_wri theme themes turbo" ka.update(**{k: 0 for k in ex.split()}) - ex = "ah_alg bname doctitle exit favico hdr_au_usr html_head lg_sbf log_fk md_sbf name textfiles unlist vname R RS SR" + ex = "ah_alg bname doctitle exit favico idp_h_usr html_head lg_sbf log_fk md_sbf name textfiles unlist vname R RS SR" ka.update(**{k: "" for k in ex.split()}) ex = "on403 on404 xad xar xau xban xbd xbr xbu xiu xm"