Skip to content

Commit

Permalink
feature/rbac-roles - add role commands; namespaces.addgroup - use obj…
Browse files Browse the repository at this point in the history
…ect_roles, not object_permissions (#39)

* gitignore vim swapfiles

* namespaces.addgroup - use object_roles, not object_permissions

no object_permissions since ansible/galaxy_ng#1057

* galaxykit groups & roles - add roles, move perms to roles

```diff
+galaxykit group role *
+galaxykit role *
-galaxykit group perm *
+galaxykit role perm *
```

* remove client.set_permissions

 (not sure if unused, or if we just need to change it to call roles.set_permissions instead of groups.set_permissions)

* fix regex typo

* galaxykit role create: add -p alias for --permissions
  • Loading branch information
himdel authored Aug 17, 2022
1 parent b51d3c2 commit c5e8a94
Show file tree
Hide file tree
Showing 6 changed files with 222 additions and 62 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -105,3 +105,4 @@ venv.bak/
# Editors
.vscode/
.idea/
.*.sw[po]
6 changes: 0 additions & 6 deletions galaxykit/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -277,12 +277,6 @@ def delete_group(self, group_name):
"""
return groups.delete_group(self, group_name)

def set_permissions(self, group_name, permissions):
"""
Assigns the given permissions to the group
"""
return groups.set_permissions(self, group_name, permissions)

def get_container_readme(self, container):
return containers.get_readme(self, container)

Expand Down
115 changes: 93 additions & 22 deletions galaxykit/command.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,14 @@

from .client import GalaxyClient
from .utils import GalaxyClientError
from . import containers
from . import collections
from . import container_images
from . import containers
from . import groups
from . import namespaces
from . import users
from . import container_images
from . import registries
from . import roles
from . import users
from . import __version__ as VERSION

EXIT_OK = 0
Expand Down Expand Up @@ -248,31 +249,73 @@ def report_error(resp):
"create": {
"args": {
"name": {},
}
},
},
"delete": {
"args": {
"name": {},
}
},
},
"perm": {
"role": {
"subops": {
"list": {
"args": {
"groupname": {},
}
},
},
"add": {
"args": {
"groupname": {},
"perm": {},
}
"rolename": {},
},
},
"remove": {
"args": {
"groupname": {},
"rolename": {},
},
},
},
},
},
},
"role": {
"help": "RBAC Role",
"ops": {
"list": {"args": None},
"create": {
"args": {
"name": {},
"description": {},
"--permissions": {
"help": "Comma-separated list of permissions",
},
"-p": {"dest": "permissions"},
},
},
"delete": {
"args": {
"name": {},
},
},
"perm": {
"subops": {
"list": {
"args": {
"rolename": {},
},
},
"add": {
"args": {
"rolename": {},
"perm": {},
}
},
},
"remove": {
"args": {
"rolename": {},
"perm": {},
},
},
},
},
Expand Down Expand Up @@ -534,22 +577,50 @@ def main():
if not args.ignore:
print(e)
sys.exit(EXIT_NOT_FOUND)

elif args.operation == "role":
if args.subop == "list":
resp = groups.get_roles(client, args.groupname)
print(format_list(resp["results"], "role"))
elif args.subop == "add":
resp = groups.add_role(client, args.groupname, args.rolename)
elif args.subop == "remove":
resp = groups.remove_role(client, args.groupname, args.rolename)

elif args.kind == "role":
if args.operation == "list":
resp = roles.get_role_list(client)
print(format_list(resp["results"], "name"))
elif args.operation == "create":
permissions = args.permissions.split(",") if args.permissions else []
try:
resp = roles.create_role(
client, args.name, args.description, permissions
)
except ValueError as e:
if not args.ignore:
print(e)
sys.exit(EXIT_NOT_FOUND)
elif args.operation == "delete":
try:
resp = roles.delete_role(client, args.name)
except ValueError as e:
if not args.ignore:
print(e)
sys.exit(EXIT_NOT_FOUND)

elif args.operation == "perm":
if args.subop == "list":
groupname = args.groupname
resp = groups.get_permissions(client, groupname)
print(format_list(resp["data"], "permission"))
resp = roles.get_permissions(client, args.rolename)
print(resp)
elif args.subop == "add":
groupname, perm = args.groupname, args.perm
perms = [
p["permission"]
for p in groups.get_permissions(client, groupname)["data"]
]
perms = list(set(perms) | set([perm]))
resp = groups.set_permissions(client, groupname, perms)
resp = roles.set_permissions(
client, args.rolename, add_permissions=[args.perm]
)
elif args.subop == "remove":
groupname, perm = args.groupname, args.perm
resp = groups.delete_permission(client, groupname, perm)
resp = roles.set_permissions(
client, args.rolename, remove_permissions=[args.perm]
)

elif args.kind == "namespace":
if args.operation == "get":
Expand Down
67 changes: 34 additions & 33 deletions galaxykit/groups.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
import requests
import json
from pprint import pprint
from . import roles


def get_group(client, group_name):
Expand Down Expand Up @@ -38,46 +36,49 @@ def delete_group(client, group_name):
return client.delete(delete_url, parse_json=False)


def get_permissions(client, group_name):
group_id = get_group(client, group_name)["id"]
permissions_url = f"_ui/v1/groups/{group_id}/model-permissions/"
return client.get(permissions_url)
def get_roles(client, group_name):
group_id = get_group_id(client, group_name)
roles_url = f"pulp/api/v3/groups/{group_id}/roles/?content_object=null"
return client.get(roles_url)


def set_permissions(client, group_name, permissions):
def add_role(client, group_name, role_name):
"""
Assigns the given permissions to the group.
`permissions` must be a list of strings, each one recognized as a permission by the backend. See
them listed at the link below:
https://github.com/ansible/galaxy_ng/blob/ca503375077a225a5fb215e6fb2c6ae47e09cfd7/galaxy_ng/app/api/ui/serializers/user.py#L122
Container permissions are in another file:
https://github.com/ansible/galaxy_ng/blob/009385fb3a1a34d1df9ff369e2e15c3fa27869b3/galaxy_ng/app/access_control/statements/pulp_container.py#L139
Assigns the given role to the group.
The roles should match the "galaxy.role-name" format.
"""
group_id = get_group_id(client, group_name)
roles_url = f"pulp/api/v3/groups/{group_id}/roles/"
payload = {
"content_object": None,
"role": role_name,
}
return client.post(roles_url, payload)

The permissions are the ones that match the "namespace.permission-name" format.

def get_group_role_id(client, group_name, role_name):
"""
Returns the id for a given role in a group
"""
group_id = get_group(client, group_name)["id"]
permissions_url = f"_ui/v1/groups/{group_id}/model-permissions/"
for perm in permissions:
payload = {"permission": perm}
client.post(permissions_url, payload)
# TODO: Check the results of each and aggregate for a return value
group_id = get_group_id(client, group_name)
roles_url = (
f"pulp/api/v3/groups/{group_id}/roles/?content_object=null&role={role_name}"
)
resp = client.get(roles_url)
if resp["results"]:
return roles.pulp_href_to_id(resp["results"][0]["pulp_href"])
else:
raise ValueError(f"No role '{role_name}' found in group '{group_name}'.")


def delete_permission(client, group_name, permission):
def remove_role(client, group_name, role_name):
"""
Removes a permission from a group.
Removes a role from a group.
"""
group_id = get_group(client, group_name)["id"]
permissions_url = f"_ui/v1/groups/{group_id}/model-permissions/"
resp = client.get(permissions_url)
for perm in resp["data"]:
if perm["permission"] == permission:
perm_id = perm["id"]
perm_url = f"_ui/v1/groups/{group_id}/model-permissions/{perm_id}/"
client.delete(perm_url, parse_json=False)
group_id = get_group_id(client, group_name)
role_id = get_group_role_id(client, group_name, role_name)
roles_url = f"pulp/api/v3/groups/{group_id}/roles/{role_id}/"
return client.delete(roles_url, parse_json=False)


def get_group_list(client):
Expand Down
2 changes: 1 addition & 1 deletion galaxykit/namespaces.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ def add_group(client, ns_name, group_name):
{
"id": group["id"],
"name": group["name"],
"object_permissions": ["change_namespace", "upload_to_namespace"],
"object_roles": ["galaxy.namespace_owner"],
}
)
return update_namespace(client, namespace)
Expand Down
93 changes: 93 additions & 0 deletions galaxykit/roles.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
import re


def pulp_href_to_id(href):
uuid_regex = "[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}"

for section in href.split("/"):
if re.match(uuid_regex, section):
return section

return None


def get_role_list(client):
"""
Returns list of galaxy rbac roles in the system
"""
return client.get(f"pulp/api/v3/roles/?name__startswith=galaxy.")


def get_role(client, role_name):
"""
Returns the data of the role with role_name
"""
roles_url = f"pulp/api/v3/roles/?name={role_name}"
return client.get(roles_url)["results"][0]


def get_role_id(client, role_name):
"""
Returns the id for a given role
"""
roles_url = f"pulp/api/v3/roles/?name={role_name}"
resp = client.get(roles_url)
if resp["results"]:
return pulp_href_to_id(resp["results"][0]["pulp_href"])
else:
raise ValueError(f"No role '{role_name}' found.")


def create_role(client, role_name, description, permissions):
"""
Creates an rbac role
"""
payload = {
"description": description,
"name": role_name,
"permissions": permissions or [],
}
resp = client.post("pulp/api/v3/roles/", payload, parse_json=False)
if resp.status_code == 400:
raise ValueError(resp.json())
return resp


def delete_role(client, role_name):
role_id = get_role_id(client, role_name)
delete_url = f"pulp/api/v3/roles/{role_id}/"
return client.delete(delete_url, parse_json=False)


# `permissions` must be a list of strings, each one recognized as a permission by the backend.
#
# See them listed at the link below:
# https://github.com/ansible/galaxy_ng/blob/ca503375077a225a5fb215e6fb2c6ae47e09cfd7/galaxy_ng/app/api/ui/serializers/user.py#L122
#
# Container permissions are in another file:
# https://github.com/ansible/galaxy_ng/blob/009385fb3a1a34d1df9ff369e2e15c3fa27869b3/galaxy_ng/app/access_control/statements/pulp_container.py#L139
#
# The permissions are the ones that match the "namespace.permission-name" format.


def get_permissions(client, role_name):
return get_role(client, role_name)["permissions"]


def set_permissions(client, role_name, add_permissions=[], remove_permissions=[]):
"""
Assigns the given permissions to the role.
"""
role = get_role(client, role_name)
role_id = pulp_href_to_id(role["pulp_href"])
role_url = f"pulp/api/v3/roles/{role_id}/"

permissions = set(role["permissions"])
permissions = permissions | set(add_permissions)
permissions = permissions - set(remove_permissions)

payload = {"permissions": list(permissions)}
resp = client.patch(role_url, payload, parse_json=False)
if resp.status_code == 400:
raise ValueError(resp.json())
return resp

0 comments on commit c5e8a94

Please sign in to comment.