#!/usr/bin/python3 """The auth proxy of rclone's WebDAV server of the web sites' folders (vpn-router-webdav.service). rclone runs it for each new user and password with {"user", "pass"} on standard input. The user signs in with the password of the router's directory, followed by the TOTP code for an enrolled user. A member of vpnrouter_users.ADMIN_GROUP sees the folders of all sites, any other user those of the sites whose editors group the user is a member of (vpnrouter_sites.editable), each as a folder named after its site. The answer on standard output is rclone's combine backend of those folders; a failed sign-in, a user with no site or any failure is a message on standard error and the exit status 1, which rclone refuses the user with. """ import json import os import sys sys.path.insert(0, os.path.dirname(os.path.realpath(__file__))) import ldap import vpnrouter_ldap import vpnrouter_sites import vpnrouter_users def main(): try: request = json.load(sys.stdin) name, password = request['user'], request['pass'] vpnrouter_users.login(name, password, None) connection = vpnrouter_ldap.manager() try: groups = vpnrouter_users.groups_of(connection, name) finally: connection.unbind_s() if vpnrouter_users.ADMIN_GROUP in groups: sites = [site['name'] for site in vpnrouter_sites.listing()] else: sites = vpnrouter_sites.editable(groups) except (ValueError, KeyError, TypeError, OSError, ldap.LDAPError, vpnrouter_users.Failure, vpnrouter_sites.DatabaseError) as exc: sys.exit(f'webdav-auth: refused: {exc}') if not sites: sys.exit(f'webdav-auth: refused: {name} may change no site') vpnrouter_sites.ensure_folders(sites) upstreams = ' '.join(f'{site}={vpnrouter_sites.SITES_DIR / site}' for site in sites) json.dump({'type': 'combine', '_root': '', 'upstreams': upstreams}, sys.stdout) return 0 if __name__ == '__main__': sys.exit(main())