From c077296c51b35a737ada164e8589fff601aaef60 Mon Sep 17 00:00:00 2001 From: Sylvain Gaudan Date: Thu, 20 Feb 2025 09:36:44 +0100 Subject: [PATCH] add commands --- arlas/cli/configurations.py | 3 +- arlas/cli/org.py | 79 ++++++++++++++++++++++++++++++++++++- arlas/cli/service.py | 53 ++++++++++++++++++++++++- arlas/cli/user.py | 25 ++++++++++++ 4 files changed, 156 insertions(+), 4 deletions(-) diff --git a/arlas/cli/configurations.py b/arlas/cli/configurations.py index 5c5867b..6b733b7 100644 --- a/arlas/cli/configurations.py +++ b/arlas/cli/configurations.py @@ -181,4 +181,5 @@ def describe_configuration( if Configuration.settings.arlas.get(config, None) is None: print("Error: arlas configuration {} not found among [{}]".format(config, ", ".join(Configuration.settings.arlas.keys())), file=sys.stderr) exit(1) - print(yaml.dump(Configuration.settings.arlas[config].model_dump())) \ No newline at end of file + print(yaml.dump(Configuration.settings.arlas[config].model_dump())) + diff --git a/arlas/cli/org.py b/arlas/cli/org.py index b50d074..bca54c5 100644 --- a/arlas/cli/org.py +++ b/arlas/cli/org.py @@ -1,7 +1,9 @@ +import sys import typer from prettytable import PrettyTable from arlas.cli.service import Service +from arlas.cli.settings import Configuration from arlas.cli.variables import variables org = typer.Typer() @@ -18,9 +20,12 @@ def list_organisations(): @org.command(help="Create organisation with the given name", name="add", epilog=variables["help_epilog"]) -def create_organisation(organisation: str = typer.Argument(help="Organisation's name")): +def create_organisation(organisation: str = typer.Argument(default="", help="Organisation's name")): config = variables["arlas"] - print(Service.create_organisation(config, organisation).get("id")) + if organisation: + print(Service.create_organisation(config, organisation).get("id")) + else: + print(Service.create_organisation_from_user_domain(config, organisation).get("id")) @org.command(help="Delete the organisation", name="delete", epilog=variables["help_epilog"]) @@ -148,3 +153,73 @@ def delete_user_from_group(org_id: str = typer.Argument(help="Organisation's ide group_id: str = typer.Argument(help="Group identifier")): config = variables["arlas"] print(Service.delete_permission_from_group_in_organisation(config, org_id, user_id, group_id)) + + +@org.command(help="Add and returns an new API Key with permissions associated to provided groups. Use the key id and key secret with the arlas-api-key-id and arlas-api-key-secret headers.", name="add-apikey", + epilog=variables["help_epilog"]) +def add_apikey(org_id: str = typer.Argument(help="Organisation's identifier"), + name: str = typer.Argument(help="API Key name"), + user_id: str = typer.Option(help="User identifier", default=None), + ttlInDays: int = typer.Option(help="Time To Live in days", default=365), + gids: list[str] = typer.Option(help="Group identifiers. If not provided, all groups of the user are used.", default=None) + ): + config = variables["arlas"] + if not user_id: + if Configuration.settings.arlas.get(config) and Configuration.settings.arlas.get(config).authorization and Configuration.settings.arlas.get(config).authorization.token_url and Configuration.settings.arlas.get(config).authorization.token_url.login: + user_id = Service.get_user_from_organisation(config, org_id, Configuration.settings.arlas.get(config).authorization.token_url.login)[0] + if not user_id: + print("Error : user id not found for {}.".format(config), file=sys.stderr) + sys.exit(1) + else: + print("Error : no login found for {}.".format(config), file=sys.stderr) + sys.exit(1) + if not gids or len(gids) == 0: + gids = list(map(lambda arr: arr[0], Service.list_organisation_groups(config, org_id) + Service.list_organisation_roles(config, org_id))) + print(Service.create_api_key(config, org_id, name, ttlInDays, user_id, gids)) + + +@org.command(help="Delete an API Key", name="delete-apikey", + epilog=variables["help_epilog"]) +def delete_apikey(org_id: str = typer.Argument(help="Organisation's identifier"), + key_id: str = typer.Argument(help="API Key identifier"), + user_id: str = typer.Option(help="User identifier", default=None), + ): + config = variables["arlas"] + if not user_id: + if Configuration.settings.arlas.get(config) and Configuration.settings.arlas.get(config).authorization and Configuration.settings.arlas.get(config).authorization.token_url and Configuration.settings.arlas.get(config).authorization.token_url.login: + user_id = Service.get_user_from_organisation(config, org_id, Configuration.settings.arlas.get(config).authorization.token_url.login)[0] + if not user_id: + print("Error : user id not found for {}.".format(config), file=sys.stderr) + sys.exit(1) + else: + print("Error : no login found for {}.".format(config), file=sys.stderr) + sys.exit(1) + print(Service.delete_api_key(config, org_id, user_id, key_id)) + + +@org.command(help="Check if user's organisation exists", name="check", + epilog=variables["help_epilog"]) +def check(): + config = variables["arlas"] + print(Service.check_organisation(config)) + + +@org.command(help="List forbidden organisations.", name="forbidden", + epilog=variables["help_epilog"]) +def forbidden(): + config = variables["arlas"] + print(Service.forbidden_organisation(config)) + + +@org.command(help="Forbid an organisation name.", name="forbid", + epilog=variables["help_epilog"]) +def forbid(name: str = typer.Argument(help="Name of the organisation to forbid")): + config = variables["arlas"] + print(Service.forbid_organisation(config, name)) + + +@org.command(help="Remove an organisation name from the forbidden list.", name="authorize", + epilog=variables["help_epilog"]) +def authorize(name: str = typer.Argument(help="Name of the organisation to authorize")): + config = variables["arlas"] + print(Service.authorize_organisation(config, name)) diff --git a/arlas/cli/service.py b/arlas/cli/service.py index 9da477f..cf431d5 100644 --- a/arlas/cli/service.py +++ b/arlas/cli/service.py @@ -58,6 +58,23 @@ def test_es(arlas: str): def create_user(arlas: str, email: str): return Service.__arlas__(arlas, "users", post=json.dumps({"email": email}), service=Services.iam) + def describe_user(arlas: str, id: str): + return Service.__arlas__(arlas, "/".join(["users", id]), service=Services.iam) + + def update_user(arlas: str, id: str, oldPassword: str = None, newPassword: str = None, locale: str = None, timezone: str = None, firstName: str = None, lastName: str = None): + data = {"oldPassword": oldPassword} + if newPassword: + data["newPassword"] = newPassword + if locale: + data["locale"] = locale + if timezone: + data["timezone"] = timezone + if firstName: + data["firstName"] = firstName + if lastName: + data["lastName"] = lastName + return Service.__arlas__(arlas, "/".join(["users", id]), put=json.dumps(data), service=Services.iam) + def delete_user(arlas: str, id: str): return Service.__arlas__(arlas, "/".join(["users", id]), delete=True, service=Services.iam) @@ -67,6 +84,9 @@ def activate(arlas: str, id: str): def deactivate(arlas: str, id: str): return Service.__arlas__(arlas, "/".join(["users", id, "deactivate"]), post="{}", service=Services.iam) + def reset_password(arlas: str, email: str): + return Service.__arlas__(arlas, "/".join(["users", "resetpassword"]), post=email, service=Services.iam) + def list_organisations(arlas: str) -> list[list[str]]: data = Service.__arlas__(arlas, "organisations", service=Services.iam) table = [["id", "name", "Am I owner?"]] @@ -81,8 +101,11 @@ def list_organisations(arlas: str) -> list[list[str]]: def create_organisation(arlas: str, org: str): return Service.__arlas__(arlas, "/".join(["organisations", org]), post="{}", service=Services.iam) + def create_organisation_from_user_domain(arlas: str, org: str): + return Service.__arlas__(arlas, "organisations", post="{}", service=Services.iam) + def delete_organisation(arlas: str, oid: str): - return Service.__arlas__(arlas, "/".join(["organisations", oid]), delete="{}", service=Services.iam) + return Service.__arlas__(arlas, "/".join(["organisations", oid]), delete=True, service=Services.iam) def list_organisation_collections(arlas: str, oid: str): return Service.__arlas__(arlas, "/".join(["organisations", oid, "collections"]), service=Services.iam) @@ -95,6 +118,16 @@ def list_organisation_users(arlas: str, oid: str): "\n".join(list(map(lambda role: role.get("fullName"), user.get("member").get("roles"))))], users)) + def get_user_from_organisation(arlas: str, oid: str, user: str): + users: list = Service.__arlas__(arlas, "/".join(["organisations", oid, "users"]), service=Services.iam) + users: list = list(filter(lambda u: u.get("member").get("email") == user, users)) + if len(users) > 0: + return list(map(lambda user: [user.get("member").get("id"), + user.get("member").get("email"), + user.get("isOwner"), + "\n".join(list(map(lambda role: role.get("fullName"), user.get("member").get("roles"))))], users))[0] + return None + def list_organisation_groups(arlas: str, oid: str): groups: list = Service.__arlas__(arlas, "/".join(["organisations", oid, "groups"]), service=Services.iam) return list(map(lambda user: [user.get("id"), @@ -407,6 +440,24 @@ def persistence_describe(arlas: str, id: str): table.append(["writers", ", ".join(r.get("doc_writers", []))]) return table + def create_api_key(arlas: str, oid: str, name: str, ttlInDays: int, uid: str, gids: list[str]): + return Service.__arlas__(arlas, "/".join(["organisations", oid, "users", uid, "apikeys"]), post=json.dumps({"name": name, "ttlInDays": ttlInDays, "roleIds": gids}), service=Services.iam) + + def delete_api_key(arlas: str, oid: str, uid: str, keyid: str): + return Service.__arlas__(arlas, "/".join(["organisations", oid, "users", uid, "apikeys", keyid]), delete=True, service=Services.iam) + + def check_organisation(arlas: str): + return Service.__arlas__(arlas, "/".join(["organisations", "check"]), service=Services.iam) + + def forbidden_organisation(arlas: str): + return Service.__arlas__(arlas, "/".join(["organisations", "forbidden"]), service=Services.iam) + + def forbid_organisation(arlas: str, name: str): + return Service.__arlas__(arlas, "/".join(["organisations", "forbidden"]), post=json.dumps({"name": name}), service=Services.iam) + + def authorize_organisation(arlas: str, name: str): + return Service.__arlas__(arlas, "/".join(["organisations", "forbidden", name]), delete=True, service=Services.iam) + def __index_bulk__(arlas: str, index: str, bulk: []): data = os.linesep.join([json.dumps(line) for line in bulk]) + os.linesep result = json.loads(Service.__es__(arlas, "/".join([index, "_bulk"]), post=data, exit_on_failure=False, headers={"Content-Type": "application/x-ndjson"})) diff --git a/arlas/cli/user.py b/arlas/cli/user.py index af4839b..bce5639 100644 --- a/arlas/cli/user.py +++ b/arlas/cli/user.py @@ -12,6 +12,25 @@ def add(email: str = typer.Argument(help="User's email")): print(Service.create_user(config, email).get("id")) +@user.command(help="Describe user", name="describe", epilog=variables["help_epilog"]) +def describe(uid: str = typer.Argument(help="User's identifier")): + config = variables["arlas"] + print(Service.describe_user(config, uid)) + + +@user.command(help="Update user", name="update", epilog=variables["help_epilog"]) +def update(uid: str = typer.Argument(help="User's identifier"), + oldPassword: str = typer.Option(help="Old password", default=None), + newPassword: str = typer.Option(help="New password", default=None), + locale: str = typer.Option(help="Locale", default=None), + timezone: str = typer.Option(help="Timezone", default=None), + firstname: str = typer.Option(help="Firstname", default=None), + lastname: str = typer.Option(help="Lastname", default=None) + ): + config = variables["arlas"] + print(Service.update_user(config, uid, oldPassword, newPassword, locale, timezone, firstname, lastname)) + + @user.command(help="Delete user", name="delete", epilog=variables["help_epilog"]) def delete(id: str = typer.Argument(help="User's identifier")): config = variables["arlas"] @@ -28,3 +47,9 @@ def activate(id: str = typer.Argument(help="User's identifier")): def deactivate(id: str = typer.Argument(help="User's identifier")): config = variables["arlas"] print(Service.deactivate(config, id).get("message")) + + +@user.command(help="Deactivate user account", name="reset-password", epilog=variables["help_epilog"]) +def reset_password(email: str = typer.Argument(help="User's email")): + config = variables["arlas"] + print(Service.reset_password(config, email).get("message"))