diff --git a/elab_users/__init__.py b/elab_users/__init__.py index e0219af..e4e08de 100644 --- a/elab_users/__init__.py +++ b/elab_users/__init__.py @@ -4,3 +4,208 @@ Manage elab (svn) users """ __version__ = "0.0.1" + +import os +import sys +import argparse +import subprocess # noqa: S404 +from pathlib import Path + +from .authz import AuthzConfigParser +from .constants import ( + USERS, + ADMINS, + ALUMNI, + READ_ACL, + WRITE_ACL, + RESTRICTED, + SVN_SUFFIX, + AUTHZ_FILE_NAME, + HTPWD_FILE_NAME, +) + +SVN_REPOS_PATH = Path(os.getenv("SVN_REPOS_PATH", default=".")) + +COMMANDS = ["user", "groups", "add", "restricted", "retire", "password"] + + +def get_config(svn_dir=SVN_REPOS_PATH, authz=AUTHZ_FILE_NAME): + authz_path = Path(svn_dir) / authz + if not authz_path.is_file(): + sys.exit(f"Could not find authz file at {authz_path}") + return AuthzConfigParser.from_file(authz_path) + + +def list_users(username, svn_dir=SVN_REPOS_PATH, authz=AUTHZ_FILE_NAME): + """list all users""" + config = get_config(svn_dir, authz) + groups = config.group_users() + for name, usernames in groups.items(): + print(f"Users in group '{name}':") + for name in sorted(usernames): + print(f" {name}") + + +def show_group_info(groupname, svn_dir=SVN_REPOS_PATH, authz=AUTHZ_FILE_NAME): + """show group information""" + config = get_config(svn_dir, authz) + groups = config.group_users() + if groupname not in groups: + sys.exit(f"Group '{groupname}' not found in authz file") + print("Users in group '{groupname}':") + for name in sorted(groups[groupname]): + print(f" {name}") + + +def add_new_user( + username, + group, + svn_dir=SVN_REPOS_PATH, + authz=AUTHZ_FILE_NAME, + htpwd=HTPWD_FILE_NAME, + handler=subprocess, +): + """add a user, restricted or regular""" + config = get_config(svn_dir, authz) + if username in config.elab_users: + sys.exit(f"Username '{username}' already in use") + if username.lower() in {i.lower() for i in svn_dir.iterdir()}: + sys.exit(f"Username '{username}' not allowed") + user = config.add_journal_acl_for(username, group) + user.create_new_repository(svn_dir, handler) + password = user.set_new_password(svn_dir / htpwd, handler=handler) + print("New password for :") + print(f"username: {username}") + print(f"password: {password}") + print(f"url: https://svn.cpi.imtek.uni-freiburg.de/{username}") + config.write_to_file() + + +def retire_user( + username, + svn_dir=SVN_REPOS_PATH, + authz=AUTHZ_FILE_NAME, + htpwd=HTPWD_FILE_NAME, + handler=subprocess, +): + config = get_config(svn_dir, authz) + if username not in config.elab_users: + sys.exit("User {username} not found.") + user = config.elab_users[username] + if user.group == ALUMNI: + sys.exit(f"User '{username}' is already in group '{ALUMNI}'") + if user.group == ADMINS: + sys.exit( + ( + f"User '{username}' is in group '{ADMINS}', " + f"will not moved to '{ALUMNI}'" + ) + ) + config.move_user_to_alumni(username) + config.write_to_file() + user.delete_password(svn_dir / htpwd, handler=handler) + + +def change_password( + username, + svn_dir=SVN_REPOS_PATH, + authz=AUTHZ_FILE_NAME, + htpwd=HTPWD_FILE_NAME, + handler=subprocess, +): + config = get_config(svn_dir, authz) + if username not in config.elab_users: + sys.exit("User {username} not found.") + user = config.elab_users[username] + password = user.set_new_password(svn_dir / htpwd, handler=handler) + print("New password for :") + print(f"username: {username}") + print(f"password: {password}") + + +def show_user_info(username, svn_dir=SVN_REPOS_PATH, authz=AUTHZ_FILE_NAME): + config = get_config(svn_dir, authz) + if username not in config.elab_users: + sys.exit("User {username} not found.") + + user = config.elab_users[username] + print("User {user.name} is in group '{user.group}':") + + # print the write acls for a user + if user.group == ADMINS: + print(" Write access is granted to all journals.") + elif user.write_acl: + write_acl = [item + SVN_SUFFIX for item in user.write_acl] + print(" Write access is granted to:", ", ".join(write_acl)) + else: + print(" Write access is NOT granted to any journals") + + # print the read acls for a user + if user.group == ADMINS: + print(" Read access is granted to all journals.") + elif user.group == USERS: + print(" Read access is granted to (nearly) all journals.") + elif user.read_acl: + read_acl = [item + SVN_SUFFIX for item in user.read_acl] + print(" Read access is granted to:", ", ".join(read_acl)) + else: + print(" Read access is NOT granted to any journals") + + journal = config.get_journal_info(username) + print(f"Labjournal {username}{SVN_SUFFIX}") + + # print the write acls for a journal + if journal[WRITE_ACL]: + print(" Write access granted to:", ", ".join(journal[WRITE_ACL])) + else: + print(" No write access granted to anybody") + + # print the read acls for a journal + if journal[READ_ACL]: + print(" Read access granted to:", ", ".join(journal[READ_ACL])) + else: + print(" No read access granted to anybody") + + +def main( + svn_dir=SVN_REPOS_PATH, + authz=AUTHZ_FILE_NAME, + htpwd=HTPWD_FILE_NAME, + handler=subprocess, +): + parser = argparse.ArgumentParser(prog="elab-users") + parser.add_argument( + "command", + nargs="?", + help="one of the commands: [" + ", ".join(COMMANDS) + "]", + ) + parser.add_argument( + "name", nargs="?", help="user or group to perform the command on" + ) + args = parser.parse_args() + print(args.command) + print(args.username) + + if not args.command: + list_users(svn_dir, authz) + + if args.command.lower() not in COMMANDS: + show_user_info(args.command, svn_dir, authz) + + if args.command.lower() == "user": + show_user_info(args.name, svn_dir, authz) + + if args.command.lower() == "groups": + show_group_info(args.name, svn_dir, authz) + + if args.command.lower() == "add": + add_new_user(args.name, USERS, svn_dir, authz, htpwd, handler) + + if args.command.lower() == "restricted": + add_new_user(args.name, RESTRICTED, svn_dir, authz, htpwd, handler) + + if args.command.lower() == "retire": + retire_user(args.name, svn_dir, authz, htpwd, handler) + + if args.command.lower() == "password": + change_password(args.name, svn_dir, authz, htpwd, handler) diff --git a/elab_users/authz.py b/elab_users/authz.py index 0db0a3f..1be9963 100644 --- a/elab_users/authz.py +++ b/elab_users/authz.py @@ -31,6 +31,7 @@ class AuthzConfigParser(configparser.ConfigParser): def __init__(self): """initialization of the class""" self.elab_users = {} + self.original_path = None super().__init__() def optionxform(self, value): @@ -40,9 +41,19 @@ class AuthzConfigParser(configparser.ConfigParser): def read(self, path): """set up the acl defaults after reading the file""" super().read(path) + self.original_path = path self._extract_user_info_from_config() - def write_to_file(self, path): + @classmethod + def from_file(cls, path): + instance = cls() + instance.read(path) + return instance + + def write_to_file(self, path=None): + path = path or self.original_path + if not path: + raise IOError("No path specified") with open(path, "w") as filehandle: self.write(filehandle) @@ -141,6 +152,7 @@ class AuthzConfigParser(configparser.ConfigParser): for group, acl in GROUP_DEFAULTS.items(): self.set(journal_path, "@" + group, acl) self._update_user_group_config() + return self.elab_users[username] def move_user_to_alumni(self, name): """moves a user to the alumni group and removes the acl privileges""" @@ -151,6 +163,7 @@ class AuthzConfigParser(configparser.ConfigParser): for access_to in user.read_acl: self.remove_option(access_to + SVN_SUFFIX, user.name) self._update_user_group_config() + return user def _update_user_group_config(self): """updates the config settings of the groups section""" diff --git a/elab_users/constants.py b/elab_users/constants.py index 2f6a200..fad70dc 100644 --- a/elab_users/constants.py +++ b/elab_users/constants.py @@ -1,9 +1,5 @@ -from pathlib import Path - -MOUNT_PATH = Path("/mnt") / "nfs-data-store-1" / "drive" -REPO_PATH = MOUNT_PATH / "svn-repository" -AUTHZ_PATH = REPO_PATH / "authz" -HTPWD_PATH = REPO_PATH / ".htpasswd" +AUTHZ_FILE_NAME = "authz" +HTPWD_FILE_NAME = ".htpasswd" ADMINS = "administrators" USERS = "users" diff --git a/manage_scrap.py b/manage_scrap.py deleted file mode 100644 index c6991e6..0000000 --- a/manage_scrap.py +++ /dev/null @@ -1,140 +0,0 @@ -#!/usr/bin/python - -# imports of modules -import optparse -import subprocess -import sys - - - - - - - -if __name__ == "__main__": - # create configparser instance - config = AuthzConfigParser() - # read config file - config.read(AUTHZ_PATH) - - # command line interface: - # no option: display info - # -g display users in a group - # -a add regular user - # -r add restricted user - # -m move to alumni - # -p reset user password - parser = optparse.OptionParser( - usage="usage: %prog [option] name", - description="shows and manipulates svn access rights", - epilog="to grant a restricted user access to another folder, you have to carefully edit the authz file") - parser.add_option("-g", "--groupinfo", action="store_const", dest="what", - const="g", help="display users in a group") - parser.add_option("-a", "--add", action="store_const", dest="what", - const="a", help="add a regular user") - parser.add_option("-r", "--restricted", action="store_const", dest="what", - const="r", help="add a restricted user") - parser.add_option("-m", "--move", action="store_const", dest="what", - const="m", help="move a user to alumni") - parser.add_option("-p", "--password", action="store_const", dest="what", - const="p", help="reset a user password") - options, args = parser.parse_args() - - if len(args)==0: - # no arguments? then display all the users! - groups = config.group_users() - for name, usernames in groups.items(): - print "Users in group '%s':" % name - for name in sorted(usernames): - print " " + name - sys.exit() - - if len(args)>1: - # more than one usename? not here, john boy - sys.exit("please provide only one name") - name = args[0] - - if options.what == "g": - # show group information - groups = config.group_users() - if name not in groups: - sys.exit("Group not found") - print "Users in group '%s':" % name - for usernamename in sorted(groups[name]): - print " " + usernamename - sys.exit() - - if options.what in ("a", "r"): - # add a user, restricted or regular - if name in config.elab_users: - sys.exit("Username '%s' already in use" % name) - group = RESTRICTED if options.what == "r" else USERS - config.add_journal_acl_for(name, group) - create_new_repository(name) - #subprocess.check_call(SVN_DIR_CREATOR + " " + name, shell=True) - password = set_new_password(name) - print "New password for :" - print "username: " + name - print "password: " + password - print "url: https://svn.cpi.imtek.uni-freiburg.de/" + name - config.write_to_file() - sys.exit() - - # from here downwards we need already existent usernames - if name not in config.elab_users: - sys.exit("User '%s' not found, use this without a name to get a list of users." % name) - - if options.what == "m": - # move user to alumni - user = config.elab_users[name] - if user.group == ALUMNI: - sys.exit("User '%s' is already in group '%s'" % (name, ALUMNI)) - if user.group == ADMINS: - sys.exit("User '%s' is in group '%s', will not moved to '%s'" % (name, ADMINS, ALUMNI)) - config.move_user_to_alumni(name) - config.write_to_file() - delete_password(name) - sys.exit() - - if options.what == "p": - # reset a password - password = set_new_password(name) - print "New password for :" - print "username: " + name - print "password: " + password - sys.exit() - - # no option, just a name: - user = config.elab_users[name] - print "User %s is in group '%s':" % (name, user.group) - # print the write acls for a user - if user.group == ADMINS: - print " Write access is granted to all journals." - elif user.write_acl: - write_acl = [ username + SVN_SUFFIX for username in user.write_acl ] - print " Write access is granted to '%s'. " % "', '".join(write_acl) - else: - print " Write access is NOT granted to any journals" - # print the read acls for a user - if user.group == ADMINS: - print " Read access is granted to all journals." - elif user.group == USERS: - print " Read access is granted to (nearly) all journals." - elif user.read_acl: - read_acl = [ username + SVN_SUFFIX for username in user.read_acl ] - print " Read access is granted to '%s'. " % "', '".join(read_acl) - else: - print " Read access is NOT granted to any journals" - - info = config.get_journal_info(name) - # print the write acls for a journal - print "Labjournal %s%s" % (name, SVN_SUFFIX) - if info[WRITE_ACL]: - print " Write access granted to: " + ", ".join(info[WRITE_ACL]) - else: - print " No write access granted to anybody" - # print the read acls for a journal - if info[READ_ACL]: - print " Read access granted to: " + ", ".join(info[READ_ACL]) - else: - print " No read access granted to anybody" diff --git a/pyproject.toml b/pyproject.toml index c6c0c34..1499f67 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -46,6 +46,9 @@ dev = [ "pre-commit", ] +[tool.flit.scripts] +elab-users = "elab_users:main" + [tool.black] line-length = 79 py37 = true