Commit fdd9aff3 authored by mhellka's avatar mhellka
Browse files

Added 'acl show' and changed 'acl set' to accept SUBJECT=ALLOW parameters.

parent c1d456e7
......@@ -34,7 +34,7 @@ setup(
zip_safe=False,
platforms="any",
python_requires=">=3.5",
install_requires=["requests", "requests-toolbelt", "tqdm", "iso8601"],
install_requires=["requests", "requests-toolbelt", "tqdm", "iso8601", "tabulate"],
extras_require={
"dev": ["flake8", "wheel", "twine", "tox", "black"],
"test": ["mock", "pytest", "pytest-cov", "coverage", "responses"],
......
......@@ -358,6 +358,15 @@ class CDStar:
""" Remove a archive file. This cannot be undone. """
return self.raw("DELETE", vault, archive, file).ok
def acl_info(self, vault, archive, explode=False) -> JsonObject:
""" Get the access control list (ACL) for an archive. """
mode = "explode" if explode else "group"
return self.rest("GET", vault, archive, params={"acl": mode})
def set_acl(self, vault, archive, acl_info) -> JsonObject:
""" Set (replace) the access control list (ACL) for an archive """
return self.rest("PUT", vault, archive, params={"acl": ""}, json=acl_info)
def scroll(self, vault, start="", limit=1024) -> JsonObject:
return self.rest("GET", vault, params={"scroll": start, "limit": limit})
......
......@@ -23,14 +23,18 @@ def hbytes(n, units=None):
raise AssertionError("Number out of range")
def kvtype(val):
class KvArgType:
""" Argparse type that parses a KEY=VALUE parameter into a tuple.
The value may be empty, but the '=' is required. """
k, _, v = val.partition("=")
if not _:
raise argparse.ArgumentTypeError("Expected KAY=VALUE argument.")
return k, v
def __init__(self, split="="):
self.split = split
def __call__(self, val):
k, _, v = val.partition(self.split)
if not _:
raise argparse.ArgumentTypeError("Expected KAYVALUE argument.")
return k, v
def globtype(str):
......
"""
Manage access control lists (ACL)
"""
import json
from tabulate import tabulate
from pycdstar3 import FormUpdate
from pycdstar3.cli._utils import KvArgType
def register(subparsers):
......@@ -12,30 +17,64 @@ def register(subparsers):
pset = sub.add_parser("set")
pset.add_argument("ARCHIVE", help="Archive ID")
pset.add_argument("SUBJECT", help="Subject do modify")
pset.add_argument(
"PERMISSIONS", nargs="*", help="Permissions to set for this subject."
"ALLOW",
metavar="SUBJECT=ALLOW",
nargs="*",
type=KvArgType("="),
help="Set archive level permissions for a subject. ALLOW can be a "
"comma-separated list of permission or permission-set names. Leave the "
"ALLOW part empty to revoke all permissions for a subject.",
)
pset.set_defaults(main=acl_set)
pshow = sub.add_parser("show")
pshow.add_argument("ARCHIVE", help="Archive ID")
pshow.add_argument(
"-e",
"--explode",
action="store_true",
help="Explode permission sets into individual permissions",
)
pshow.add_argument("--json", action="store_true", help="Print as JSON")
pshow.set_defaults(main=acl_show)
def acl_set(ctx, args):
client = ctx.client
vault = ctx.vault
archive = args.ARCHIVE
subject = args.SUBJECT
permissions = args.PERMISSIONS
ctx.print(
"Set ACL for {!r} on /{}/{} -> [{}]",
subject,
vault,
archive,
", ".join(permissions),
)
with archive.api.begin(autocommit=True):
update = FormUpdate()
update.acl(subject, *permissions)
client.update_archive(vault, archive, form=update)
ctx.print("Done")
changes = {}
for sub, allow in args.ALLOW:
all = changes.setdefault(sub, set())
if allow:
all.update(allow.split(","))
update = FormUpdate()
for sub, allow in sorted(changes.items()):
update.acl(sub, *allow)
if len(allow):
ctx.print("ACL for {} => {}", sub, ", ".join(sorted(allow)))
else:
ctx.print("ACL for {} => [revoked]", sub)
client.update_archive(vault, archive, form=update)
ctx.print("Done!")
def acl_show(ctx, args):
client = ctx.client
vault = ctx.vault
archive = args.ARCHIVE
acl = client.acl_info(vault, archive, explode=args.explode)
if args.json:
print(json.dumps(acl, indent=4))
else:
print(
tabulate(
sorted((k, ",".join(v)) for (k, v) in acl.items()),
headers=["Subject", "Permissions"],
)
)
......@@ -20,7 +20,7 @@ from contextlib import ExitStack
from pycdstar3 import FormUpdate
from pycdstar3.cli import CliError
from pycdstar3.cli._utils import hbytes, kvtype, globtype
from pycdstar3.cli._utils import hbytes, KvArgType, globtype
import collections
import iso8601
......@@ -92,19 +92,19 @@ def register(subparsers):
parser.add_argument(
"--meta",
metavar="KEY=VAL",
type=kvtype,
type=KvArgType,
action="append",
help="Set archive metadata attributes. An empty value removes the attribute."
" Can be repeated to set multiple values for the same attribute.",
)
parser.add_argument(
"--acl",
metavar="SUBJECT=PERM",
type=kvtype,
metavar="SUBJECT=ALLOW",
type=KvArgType,
action="append",
help="Set ACL entries. PERM can be a comma separated list of permissions or"
" permission sets. An empty PERM value removes all permissions for that"
" SUBJECT.",
help="Set archive level permissions for a subject. ALLOW can be a "
"comma-separated list of permission or permission-set names. "
"Leave the ALLOW part empty to revoke all permissions for a subject.",
)
parser.add_argument(
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment