cidr-based autologin
This commit is contained in:
		
							parent
							
								
									aba680b6c2
								
							
						
					
					
						commit
						b7f9bf5a28
					
				
							
								
								
									
										17
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										17
									
								
								README.md
									
									
									
									
									
								
							| @ -80,6 +80,7 @@ turn almost any device into a file server with resumable uploads/downloads using | ||||
|     * [event hooks](#event-hooks) - trigger a program on uploads, renames etc ([examples](./bin/hooks/)) | ||||
|         * [upload events](#upload-events) - the older, more powerful approach ([examples](./bin/mtag/)) | ||||
|     * [handlers](#handlers) - redefine behavior with plugins ([examples](./bin/handlers/)) | ||||
|     * [ip auth](#ip-auth) - autologin based on IP range (CIDR) | ||||
|     * [identity providers](#identity-providers) - replace copyparty passwords with oauth and such | ||||
|     * [user-changeable passwords](#user-changeable-passwords) - if permitted, users can change their own passwords | ||||
|     * [using the cloud as storage](#using-the-cloud-as-storage) - connecting to an aws s3 bucket and similar | ||||
| @ -1432,6 +1433,22 @@ redefine behavior with plugins ([examples](./bin/handlers/)) | ||||
| replace 404 and 403 errors with something completely different (that's it for now) | ||||
| 
 | ||||
| 
 | ||||
| ## ip auth | ||||
| 
 | ||||
| autologin based on IP range (CIDR)  , using the global-option `--ipu` | ||||
| 
 | ||||
| for example, if everyone with an IP that starts with `192.168.123` should automatically log in as the user `spartacus`, then you can either specify `--ipu=192.168.123.0/24=spartacus` as a commandline option, or put this in a config file: | ||||
| 
 | ||||
| ```yaml | ||||
| [global] | ||||
|   ipu: 192.168.123.0/24=spartacus | ||||
| ``` | ||||
| 
 | ||||
| repeat the option to map additional subnets | ||||
| 
 | ||||
| **be careful with this one!** if you have a reverseproxy, then you definitely want to make sure you have [real-ip](#real-ip) configured correctly, and it's probably a good idea to nullmap the reverseproxy's IP just in case; so if your reverseproxy is sending requests from `172.24.27.9` then that would be `--ipu=172.24.27.9/32=` | ||||
| 
 | ||||
| 
 | ||||
| ## identity providers | ||||
| 
 | ||||
| replace copyparty passwords with oauth and such | ||||
|  | ||||
| @ -1087,6 +1087,7 @@ def add_auth(ap): | ||||
|     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-len", metavar="CHARS", type=int, default=20, help="session key length; default is 120 bits ((20//4)*4*6)") | ||||
|     ap2.add_argument("--no-ses", action="store_true", help="disable sessions; use plaintext passwords in cookies") | ||||
|     ap2.add_argument("--ipu", metavar="CIDR=USR", type=u, action="append", help="users with IP matching \033[33mCIDR\033[0m are auto-authenticated as username \033[33mUSR\033[0m; example: [\033[32m172.16.24.0/24=dave]") | ||||
| 
 | ||||
| 
 | ||||
| def add_chpw(ap): | ||||
|  | ||||
| @ -76,6 +76,7 @@ class FtpAuth(DummyAuthorizer): | ||||
|             else: | ||||
|                 raise AuthenticationFailed("banned") | ||||
| 
 | ||||
|         args = self.hub.args | ||||
|         asrv = self.hub.asrv | ||||
|         uname = "*" | ||||
|         if username != "anonymous": | ||||
| @ -86,6 +87,9 @@ class FtpAuth(DummyAuthorizer): | ||||
|                     uname = zs | ||||
|                     break | ||||
| 
 | ||||
|         if args.ipu and uname == "*": | ||||
|             uname = args.ipu_iu[args.ipu_nm.map(ip)] | ||||
| 
 | ||||
|         if not uname or not (asrv.vfs.aread.get(uname) or asrv.vfs.awrite.get(uname)): | ||||
|             g = self.hub.gpwd | ||||
|             if g.lim: | ||||
|  | ||||
| @ -589,6 +589,9 @@ class HttpCli(object): | ||||
|                 or "*" | ||||
|             ) | ||||
| 
 | ||||
|         if self.args.ipu and self.uname == "*": | ||||
|             self.uname = self.conn.ipu_iu[self.conn.ipu_nm.map(self.ip)] | ||||
| 
 | ||||
|         self.rvol = self.asrv.vfs.aread[self.uname] | ||||
|         self.wvol = self.asrv.vfs.awrite[self.uname] | ||||
|         self.avol = self.asrv.vfs.aadmin[self.uname] | ||||
|  | ||||
| @ -59,6 +59,8 @@ class HttpConn(object): | ||||
|         self.asrv: AuthSrv = hsrv.asrv  # mypy404 | ||||
|         self.u2fh: Util.FHC = hsrv.u2fh  # mypy404 | ||||
|         self.pipes: Util.CachedDict = hsrv.pipes  # mypy404 | ||||
|         self.ipu_iu: Optional[dict[str, str]] = hsrv.ipu_iu | ||||
|         self.ipu_nm: Optional[NetMap] = hsrv.ipu_nm | ||||
|         self.ipa_nm: Optional[NetMap] = hsrv.ipa_nm | ||||
|         self.xff_nm: Optional[NetMap] = hsrv.xff_nm | ||||
|         self.xff_lan: NetMap = hsrv.xff_lan  # type: ignore | ||||
|  | ||||
| @ -69,6 +69,7 @@ from .util import ( | ||||
|     build_netmap, | ||||
|     has_resource, | ||||
|     ipnorm, | ||||
|     load_ipu, | ||||
|     load_resource, | ||||
|     min_ex, | ||||
|     shut_socket, | ||||
| @ -175,6 +176,11 @@ class HttpSrv(object): | ||||
|         self.j2 = {x: env.get_template(x + ".html") for x in jn} | ||||
|         self.prism = has_resource(self.E, "web/deps/prism.js.gz") | ||||
| 
 | ||||
|         if self.args.ipu: | ||||
|             self.ipu_iu, self.ipu_nm = load_ipu(self.log, self.args.ipu) | ||||
|         else: | ||||
|             self.ipu_iu = self.ipu_nm = None | ||||
| 
 | ||||
|         self.ipa_nm = build_netmap(self.args.ipa) | ||||
|         self.xff_nm = build_netmap(self.args.xff_src) | ||||
|         self.xff_lan = build_netmap("lan") | ||||
|  | ||||
| @ -60,6 +60,7 @@ from .util import ( | ||||
|     alltrace, | ||||
|     ansi_re, | ||||
|     build_netmap, | ||||
|     load_ipu, | ||||
|     min_ex, | ||||
|     mp, | ||||
|     odfusion, | ||||
| @ -221,6 +222,11 @@ class SvcHub(object): | ||||
|             noch.update([x for x in zsl if x]) | ||||
|         args.chpw_no = noch | ||||
| 
 | ||||
|         if args.ipu: | ||||
|             iu, nm = load_ipu(self.log, args.ipu) | ||||
|             setattr(args, "ipu_iu", iu) | ||||
|             setattr(args, "ipu_nm", nm) | ||||
| 
 | ||||
|         if not self.args.no_ses: | ||||
|             self.setup_session_db() | ||||
| 
 | ||||
|  | ||||
| @ -665,11 +665,15 @@ class HLog(logging.Handler): | ||||
| 
 | ||||
| 
 | ||||
| class NetMap(object): | ||||
|     def __init__(self, ips: list[str], cidrs: list[str], keep_lo=False) -> None: | ||||
|     def __init__( | ||||
|         self, ips: list[str], cidrs: list[str], keep_lo=False, strict_cidr=False | ||||
|     ) -> None: | ||||
|         """ | ||||
|         ips: list of plain ipv4/ipv6 IPs, not cidr | ||||
|         cidrs: list of cidr-notation IPs (ip/prefix) | ||||
|         """ | ||||
|         self.mutex = threading.Lock() | ||||
| 
 | ||||
|         if "::" in ips: | ||||
|             ips = [x for x in ips if x != "::"] + list( | ||||
|                 [x.split("/")[0] for x in cidrs if ":" in x] | ||||
| @ -696,7 +700,7 @@ class NetMap(object): | ||||
|             bip = socket.inet_pton(fam, ip.split("/")[0]) | ||||
|             self.bip.append(bip) | ||||
|             self.b2sip[bip] = ip.split("/")[0] | ||||
|             self.b2net[bip] = (IPv6Network if v6 else IPv4Network)(ip, False) | ||||
|             self.b2net[bip] = (IPv6Network if v6 else IPv4Network)(ip, strict_cidr) | ||||
| 
 | ||||
|         self.bip.sort(reverse=True) | ||||
| 
 | ||||
| @ -707,8 +711,10 @@ class NetMap(object): | ||||
|         try: | ||||
|             return self.cache[ip] | ||||
|         except: | ||||
|             pass | ||||
|             with self.mutex: | ||||
|                 return self._map(ip) | ||||
| 
 | ||||
|     def _map(self, ip: str) -> str: | ||||
|         v6 = ":" in ip | ||||
|         ci = IPv6Address(ip) if v6 else IPv4Address(ip) | ||||
|         bip = next((x for x in self.bip if ci in self.b2net[x]), None) | ||||
| @ -2678,6 +2684,31 @@ def build_netmap(csv: str): | ||||
|     return NetMap(ips, cidrs, True) | ||||
| 
 | ||||
| 
 | ||||
| def load_ipu(log: "RootLogger", ipus: list[str]) -> tuple[dict[str, str], NetMap]: | ||||
|     ip_u = {"": "*"} | ||||
|     cidr_u = {} | ||||
|     for ipu in ipus: | ||||
|         try: | ||||
|             cidr, uname = ipu.split("=") | ||||
|             cip, csz = cidr.split("/") | ||||
|         except: | ||||
|             t = "\n  invalid value %r for argument --ipu; must be CIDR=UNAME (192.168.0.0/16=amelia)" | ||||
|             raise Exception(t % (ipu,)) | ||||
|         uname2 = cidr_u.get(cidr) | ||||
|         if uname2 is not None: | ||||
|             t = "\n  invalid value %r for argument --ipu; cidr %s already mapped to %r" | ||||
|             raise Exception(t % (ipu, cidr, uname2)) | ||||
|         cidr_u[cidr] = uname | ||||
|         ip_u[cip] = uname | ||||
|     try: | ||||
|         nm = NetMap(["::"], list(cidr_u.keys()), True, True) | ||||
|     except Exception as ex: | ||||
|         t = "failed to translate --ipu into netmap, probably due to invalid config: %r" | ||||
|         log("root", t % (ex,), 1) | ||||
|         raise | ||||
|     return ip_u, nm | ||||
| 
 | ||||
| 
 | ||||
| def yieldfile(fn: str, bufsz: int) -> Generator[bytes, None, None]: | ||||
|     readsz = min(bufsz, 128 * 1024) | ||||
|     with open(fsenc(fn), "rb", bufsz) as f: | ||||
|  | ||||
| @ -128,7 +128,7 @@ class Cfg(Namespace): | ||||
|         ex = "dedup dotpart dotsrch hook_v no_dhash no_fastboot no_fpool no_htp no_rescan no_sendfile no_ses no_snap no_up_list no_voldump re_dhash plain_ip" | ||||
|         ka.update(**{k: True for k in ex.split()}) | ||||
| 
 | ||||
|         ex = "ah_cli ah_gen css_browser hist js_browser js_other mime mimes no_forget no_hash no_idx nonsus_urls og_tpl og_ua" | ||||
|         ex = "ah_cli ah_gen css_browser hist ipu js_browser js_other mime mimes no_forget no_hash no_idx nonsus_urls og_tpl og_ua" | ||||
|         ka.update(**{k: None for k in ex.split()}) | ||||
| 
 | ||||
|         ex = "hash_mt safe_dedup srch_time u2abort u2j u2sz" | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user
	 ed
						ed