Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refs #RHIROS-1312 - handle inventory and hosts admin #373

Merged
merged 2 commits into from
Sep 22, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 14 additions & 1 deletion ros/api/common/add_group_filter.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@


def group_filtered_query(query):
if able_to_access_all_systems():
return query

total_groups_from_request = get_host_groups()
len_of_total_groups = len(total_groups_from_request)
no_none_groups = [grp for grp in total_groups_from_request if grp is not None]
Expand All @@ -29,5 +32,15 @@ def get_host_groups():
try:
host_groups = [gid for gid in request.host_groups]
except AttributeError as e:
logger.debug(f"Can't parse the host groups, inventory groups feature is not available?: {e}")
logger.debug(f"Can't parse the host_groups, setting host_groups attr to default empty array([])!: {e}")
return host_groups


def able_to_access_all_systems():
access_all_systems = False
try:
access_all_systems = request.able_to_access_all_systems
except AttributeError as e:
logger.debug("Can't parse the able_to_access_all_systems,"
f"setting able_to_access_all_systems attr to default False value!: {e}")
return access_all_systems
18 changes: 15 additions & 3 deletions ros/lib/rbac_interface.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
VALID_HTTP_VERBS = ["get", "options", "head", "post", "put", "patch", "delete"]
LOG = get_logger(__name__)
host_group_attr = 'host_groups'
access_all_systems = 'able_to_access_all_systems'


def fetch_url(url, auth_header, logger, method="get"):
Expand Down Expand Up @@ -157,19 +158,27 @@ def set_host_groups(rbac_response):
return

role_list = rbac_response['data']
host_groups = []

host_groups = set()
able_to_access_all_systems = False
for role in role_list:
if 'permission' not in role:
continue
if role['permission'] not in ['inventory:hosts:read', 'inventory:hosts:*', 'inventory:*:read', 'inventory:*:*']:
continue

# ignore the failure modes, try moving on to other roles that
# also match this permission
if 'resourceDefinitions' not in role:
continue
if not isinstance(role['resourceDefinitions'], list):
continue

if len(role['resourceDefinitions']) == 0 and role['permission'] in ['inventory:hosts:*', 'inventory:hosts:read',
'inventory:*:*', 'inventory:*:read']:
able_to_access_all_systems = True
# If user is inventory or hosts admin then we break the loop and don't check for next roles
break

for rscdef in role['resourceDefinitions']:
if not isinstance(rscdef, dict):
continue
Expand All @@ -192,9 +201,12 @@ def set_host_groups(rbac_response):
continue
# Finally, we have the right key: add them to our list
# The host_groups may have duplicate group_ids
host_groups.extend(value)
host_groups.update(value)

# If we found any host groups at the end of that, store them
if host_groups:
setattr(request, host_group_attr, host_groups)
LOG.info(f"User has host groups {host_groups}")

# Set admin even if we don't find it true
setattr(request, access_all_systems, able_to_access_all_systems)
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
{
"meta": {
"count": 5,
"limit": 1000,
"offset": 0
},
"links": {

"first": "/api/rbac/v1/access/?application=ros%2Cinventory&limit=1000&offset=0",
"next": null,
"previous": null,
"last": "/api/rbac/v1/access/?application=ros%2Cinventory&limit=1000&offset=0"
},
"data": [
{
"resourceDefinitions": [],
"permission": "ros:*:*"
},
{
"resourceDefinitions": [
{
"attributeFilter": {
"key": "group.id",
"value": [
"12345678-fe1b-4191-8408-cbadbd47f7a3"
],
"operation": "in"
}
}
],
"permission": "inventory:groups:read"
},
{
"resourceDefinitions": [],
"permission": "inventory:hosts:read"
},
{
"resourceDefinitions": [
{
"attributeFilter": {
"key": "group.id",
"_comment": "The test-group id",
"value": [
"abcdefgh-d97e-4ed0-9095-ef07d73b4839"
],
"operation": "in"
}
}
],
"permission": "inventory:hosts:read"
}
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
{
"meta": {
"count": 5,
"limit": 1000,
"offset": 0
},
"links": {

"first": "/api/rbac/v1/access/?application=ros%2Cinventory&limit=1000&offset=0",
"next": null,
"previous": null,
"last": "/api/rbac/v1/access/?application=ros%2Cinventory&limit=1000&offset=0"
},
"data": [
{
"resourceDefinitions": [],
"permission": "ros:*:*"
},
{
"resourceDefinitions": [
{
"attributeFilter": {
"key": "group.id",
"value": [
"12345678-fe1b-4191-8408-cbadbd47f7a3"
],
"operation": "in"
}
}
],
"permission": "inventory:groups:read"
},
{
"resourceDefinitions": [],
"permission": "inventory:hosts:*"
},
{
"resourceDefinitions": [
{
"attributeFilter": {
"key": "group.id",
"_comment": "The test-group id",
"value": [
"abcdefgh-d97e-4ed0-9095-ef07d73b4839"
],
"operation": "in"
}
}
],
"permission": "inventory:hosts:read"
}
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
{
"meta": {
"count": 5,
"limit": 1000,
"offset": 0
},
"links": {

"first": "/api/rbac/v1/access/?application=ros%2Cinventory&limit=1000&offset=0",
"next": null,
"previous": null,
"last": "/api/rbac/v1/access/?application=ros%2Cinventory&limit=1000&offset=0"
},
"data": [
{
"resourceDefinitions": [],
"permission": "ros:*:*"
},
{
"resourceDefinitions": [
{
"attributeFilter": {
"key": "group.id",
"value": [
"12345678-fe1b-4191-8408-cbadbd47f7a3"
],
"operation": "in"
}
}
],
"permission": "inventory:groups:read"
},
{
"resourceDefinitions": [],
"permission": "inventory:*:read"
},
{
"resourceDefinitions": [
{
"attributeFilter": {
"key": "group.id",
"_comment": "The test-group id",
"value": [
"abcdefgh-d97e-4ed0-9095-ef07d73b4839"
],
"operation": "in"
}
}
],
"permission": "inventory:hosts:read"
}
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
{
"meta": {
"count": 5,
"limit": 1000,
"offset": 0
},
"links": {

"first": "/api/rbac/v1/access/?application=ros%2Cinventory&limit=1000&offset=0",
"next": null,
"previous": null,
"last": "/api/rbac/v1/access/?application=ros%2Cinventory&limit=1000&offset=0"
},
"data": [
{
"resourceDefinitions": [],
"permission": "ros:*:*"
},
{
"resourceDefinitions": [
{
"attributeFilter": {
"key": "group.id",
"value": [
"12345678-fe1b-4191-8408-cbadbd47f7a3"
],
"operation": "in"
}
}
],
"permission": "inventory:groups:read"
},
{
"resourceDefinitions": [],
"permission": "inventory:*:*"
},
{
"resourceDefinitions": [
{
"attributeFilter": {
"key": "group.id",
"_comment": "The test-group id",
"value": [
"abcdefgh-d97e-4ed0-9095-ef07d73b4839"
],
"operation": "in"
}
}
],
"permission": "inventory:hosts:read"
}
]
}
30 changes: 30 additions & 0 deletions tests/test_api_endpoints.py
Original file line number Diff line number Diff line change
Expand Up @@ -629,3 +629,33 @@ def test_systems_array_of_groups_with_ungrouped(
assert response.json["data"][1]["groups"][0]["name"] == "test-group"
assert response.json["data"][2]["groups"][0]["name"] == "example-group"
assert response.json["data"][3]["groups"] == []


def test_access_of_all_systems(
auth_token,
db_setup,
db_create_account,
db_create_system,
system_with_example_group,
system_with_test_group,
system_with_foo_group,
db_create_performance_profile,
create_performance_profiles,
mocker):
"""When user has 'inventory:hosts:*' or 'inventory:hosts:read' or 'inventory:*:*' or 'inventory:*:read' permissions
and resource definition does not have any groups it means user can see all the systems on ROS"""
with app.test_client() as client:
mock_enable_rbac(mocker)
rbac_mocks = ['mock_rbac_returns_inventory_hosts_star_without_groups.json',
'mock_rbac_returns_inventory_hosts_read_without_groups.json',
'mock_rbac_returns_inventory_star_star_without_groups.json',
'mock_rbac_returns_inventory_star_read_without_groups.json']
for mocks in rbac_mocks:
mock_rbac(get_rbac_mock_file(mocks), mocker)
response = client.get('/api/ros/v1/systems', headers={"x-rh-identity": auth_token})
assert response.status_code == 200
assert response.json["meta"]["count"] == 4
assert response.json["data"][0]["groups"][0]["name"] == "foo-group"
assert response.json["data"][1]["groups"][0]["name"] == "test-group"
assert response.json["data"][2]["groups"][0]["name"] == "example-group"
assert response.json["data"][3]["groups"] == []
Loading