| # Licensed to the Apache Software Foundation (ASF) under one or more |
| # contributor license agreements. See the NOTICE file distributed with |
| # this work for additional information regarding copyright ownership. |
| # The ASF licenses this file to You under the Apache License, Version 2.0 |
| # (the "License"); you may not use this file except in compliance with |
| # the License. You may obtain a copy of the License at |
| # |
| # http://www.apache.org/licenses/LICENSE-2.0 |
| # |
| # Unless required by applicable law or agreed to in writing, software |
| # distributed under the License is distributed on an "AS IS" BASIS, |
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| # See the License for the specific language governing permissions and |
| # limitations under the License. |
| |
| from urllib import * |
| from xuserrest.utility.utils import * |
| import uuid |
| import string |
| import pytest |
| import requests |
| from datetime import datetime |
| import random |
| |
| @pytest.mark.usefixtures("ranger_config", "ranger_key_admin_config") |
| @pytest.mark.xuserrest |
| class TestUsers: |
| SERVICE_NAME = "admin" |
| |
| @pytest.fixture(autouse=True, scope="class") |
| def _setup( |
| self, |
| request, |
| temp_secure_user, |
| temp_keyadmin_user, |
| default_headers, |
| ranger_config, |
| ): |
| cls = request.cls |
| |
| # ---------- primary users ---------- |
| cls.admin, _ = temp_secure_user(["admin"]) |
| cls.ranger_key_admin, _ = temp_keyadmin_user() |
| cls.audit, _ = temp_secure_user(["auditor"]) |
| cls.user, _ = temp_secure_user(["user"]) |
| |
| cls.ranger_admin_config = (cls.admin["name"], "Test@123") |
| cls.ranger_key_admin_config = (cls.ranger_key_admin["name"], "Test@123") |
| cls.ranger_auditor_config = (cls.audit["name"], "Test@123") |
| cls.ranger_user_config = (cls.user["name"], "Test@123") |
| |
| cls.ranger_admin_id = cls.admin["id"] |
| cls.ranger_key_admin_id = cls.ranger_key_admin["id"] |
| cls.ranger_auditor_id = cls.audit["id"] |
| cls.ranger_user_id = cls.user["id"] |
| |
| # ---------- secondary users ---------- |
| cls.admin1, _ = temp_secure_user(["admin"]) |
| cls.ranger_key_admin1, _ = temp_keyadmin_user() |
| cls.audit1, _ = temp_secure_user(["auditor"]) |
| cls.user1, _ = temp_secure_user(["user"]) |
| |
| cls.ranger_admin_config1 = (cls.admin1["name"], "Test@123") |
| cls.ranger_key_admin_config1 = (cls.ranger_key_admin1["name"], "Test@123") |
| cls.ranger_auditor_config1 = (cls.audit1["name"], "Test@123") |
| cls.ranger_user_config1 = (cls.user1["name"], "Test@123") |
| |
| cls.ranger_admin_id1 = cls.admin1["id"] |
| cls.ranger_key_admin_id1 = cls.ranger_key_admin1["id"] |
| cls.ranger_auditor_id1 = cls.audit1["id"] |
| cls.ranger_user_id1 = cls.user1["id"] |
| |
| # ---------- common ---------- |
| cls.headers = default_headers |
| cls.base_url = ranger_config["base_url"] |
| |
| init_configs( |
| cls.ranger_admin_config, |
| cls.ranger_key_admin_config, |
| cls.ranger_auditor_config, |
| cls.ranger_user_config, |
| ) |
| |
| # Positive Test Cases |
| @pytest.mark.positive |
| @pytest.mark.get |
| @pytest.mark.parametrize( |
| "role, auth", |
| [("admin", "ranger_admin_config"),("keyadmin", "ranger_key_admin_config"), ("auditor", "ranger_auditor_config"), ("user", "ranger_user_config")], |
| ids=["admin", "keyadmin", "auditor", "user"], |
| ) |
| def test_get_users(self, role, auth, request): |
| auth = getattr(self, auth) |
| |
| url = f"{self.base_url}/xusers/users" |
| response = requests.get( |
| url, |
| auth=auth, |
| headers=self.headers |
| ) |
| |
| assert_response(response, 200, f"Failed to fetch users list: {response.status_code}") |
| |
| data = response.json() |
| assert "vXUsers" in data, "Invalid users list schema" |
| |
| users = data["vXUsers"] |
| assert isinstance(users, list) |
| assert len(users) > 0, "No users found in Ranger" |
| |
| @pytest.mark.positive |
| @pytest.mark.get |
| @pytest.mark.parametrize( |
| "role, auth", |
| [("admin", "ranger_admin_config"),("keyadmin", "ranger_key_admin_config"), ("auditor", "ranger_auditor_config"), ("user", "ranger_user_config")], |
| ids=["admin", "keyadmin", "auditor", "user"], |
| ) |
| def test_get_user_count(self, role, auth, request): |
| auth = getattr(self, auth) |
| |
| url = f"{self.base_url}/xusers/users/count" |
| response = requests.get( |
| url, |
| auth = auth, |
| headers=self.headers |
| ) |
| |
| assert_response(response, 200, f"Failed to fetch user count: {response.status_code}") |
| |
| data = response.json() |
| print(f"Total user count response: {data['value']}, auth : {auth[0]}") |
| assert isinstance(data["value"], int), "User count not found in response" |
| |
| @pytest.mark.positive |
| @pytest.mark.get |
| @pytest.mark.parametrize("auth_role, user_role, auth", [ |
| ("admin", "user", "ranger_admin_config"), |
| ("admin", "auditor", "ranger_admin_config"), |
| ("admin", "admin", "ranger_admin_config"), |
| ("keyadmin", "keyadmin", "ranger_key_admin_config"), |
| ("keyadmin", "user", "ranger_key_admin_config"), |
| ("auditor", "admin", "ranger_auditor_config"), |
| ("auditor", "auditor", "ranger_auditor_config"), |
| ("auditor", "user", "ranger_auditor_config"), |
| ("user", "same_user", "ranger_user_config") |
| ]) |
| def test_get_user_by_id(self, auth_role, user_role, auth): |
| auth = getattr(self, auth) |
| |
| if user_role == "same_user": |
| user, user_id = self.user, self.ranger_user_id |
| elif user_role == "keyadmin": |
| user, user_id = self.ranger_key_admin1, self.ranger_key_admin_id1 |
| elif user_role == "admin": |
| user, user_id = self.admin1, self.ranger_admin_id1 |
| elif user_role == "auditor": |
| user, user_id = self.audit1, self.ranger_auditor_id1 |
| elif user_role == "user": |
| user, user_id = self.user1, self.ranger_user_id1 |
| |
| response = requests.get( |
| f"{self.base_url}/xusers/users/{user_id}", |
| auth = auth, |
| headers=self.headers |
| ) |
| |
| assert_response(response, 200, f"Failed to fetch user of role {user_role} using {auth_role}") |
| |
| data = response.json() |
| validate_user_schema(data) |
| assert data["id"] == user_id, "Fetched user ID does not match requested ID" |
| |
| @pytest.mark.positive |
| @pytest.mark.get |
| @pytest.mark.parametrize("auth_role, user_role, auth", [ |
| ("admin", "user", "ranger_admin_config"), |
| ("admin", "auditor", "ranger_admin_config"), |
| ("admin", "admin", "ranger_admin_config"), |
| ("keyadmin", "keyadmin", "ranger_key_admin_config"), |
| ("keyadmin", "user", "ranger_key_admin_config"), |
| ("auditor", "admin", "ranger_auditor_config"), |
| ("auditor", "auditor", "ranger_auditor_config"), |
| ("auditor", "user", "ranger_auditor_config"), |
| ("user", "same_user", "ranger_user_config") |
| ]) |
| def test_get_users_by_username(self, auth_role, user_role, auth): |
| auth = getattr(self, auth) |
| |
| if user_role == "same_user": |
| user, user_id = self.user, self.ranger_user_id |
| elif user_role == "keyadmin": |
| user, user_id = self.ranger_key_admin1, self.ranger_key_admin_id1 |
| elif user_role == "admin": |
| user, user_id = self.admin1, self.ranger_admin_id1 |
| elif user_role == "auditor": |
| user, user_id = self.audit1, self.ranger_auditor_id1 |
| elif user_role == "user": |
| user, user_id = self.user1, self.ranger_user_id1 |
| |
| response = requests.get( |
| f"{self.base_url}/xusers/users/userName/{user['name']}", |
| auth=auth, |
| headers=self.headers |
| ) |
| |
| assert_response(response, 200, f"Failed to fetch user of role {user_role} using {auth_role}") |
| |
| data = response.json() |
| validate_user_schema(data) |
| assert data["id"] == user_id, "Fetched user ID does not match requested ID" |
| |
| @pytest.mark.positive |
| @pytest.mark.post |
| @pytest.mark.parametrize("auth_role, auth", [("admin", "ranger_admin_config")]) |
| def test_create_user(self, auth_role, auth): |
| if auth_role != "admin": |
| assert False, "Test requires admin privileges" |
| |
| auth = getattr(self, auth) |
| |
| print("\nCreating a new secure user") |
| |
| username = f"mine_pytest_fixture_{uuid.uuid4().hex[:8]}" |
| |
| payload = { |
| "name": username, |
| "password": "Test@123" |
| } |
| |
| response = requests.post( |
| f"{self.base_url}/xusers/users", |
| json=payload, |
| auth=auth, |
| headers=self.headers |
| ) |
| |
| assert_response(response, 200) |
| data = response.json() |
| user_id = data["id"] |
| |
| print(f"\nCreated user: {username} | ID: {user_id}") |
| |
| try: |
| validate_user_schema(data) # since it will always return default users skip this |
| assert data["name"] == username |
| # Verify persistence |
| verify_response = requests.get( |
| f"{self.base_url}/xusers/users/{user_id}", |
| auth=auth, |
| headers=self.headers |
| ) |
| |
| assert_response(verify_response, 200) |
| |
| verify_data = verify_response.json() |
| assert verify_data["id"] == user_id |
| print(response.json()) |
| finally: |
| |
| delete_user(user_id, auth, self.base_url, self.headers) |
| |
| @pytest.mark.positive |
| @pytest.mark.post |
| @pytest.mark.parametrize("auth_role, auth", [("admin", "ranger_admin_config")]) |
| def test_create_users_external(self, auth_role, auth): |
| if auth_role != "admin": |
| assert False, "Test requires admin privileges" |
| |
| auth = getattr(self, auth) |
| |
| print("\nCreating a new external user") |
| |
| username = f"external_pytest_fixture_{uuid.uuid4().hex[:8]}" |
| |
| payload = { |
| "name": username |
| } |
| |
| response = requests.post( |
| f"{self.base_url}/xusers/users/external", |
| json=payload, |
| auth=auth, |
| headers=self.headers |
| ) |
| |
| assert_response(response, 204) # since it wont return anything for new users. |
| |
| try : |
| response = requests.post( |
| f"{self.base_url}/xusers/users/external", |
| json=payload, |
| auth=auth, |
| headers=self.headers |
| ) |
| |
| data = response.json() |
| assert_response(response, 200) # since it will return existing user details for existing users. |
| user_id = data["id"] |
| |
| print(f"\nCreated external user: {username} | ID: {user_id}") |
| finally: |
| response = requests.delete( |
| f"{self.base_url}/xusers/users/{user_id}", |
| params={"forceDelete": "true"}, |
| auth=auth, |
| headers={**self.headers, "X-Requested-By": "ranger"} |
| ) |
| assert_response(response, 204) |
| |
| @pytest.mark.positive |
| @pytest.mark.post |
| @pytest.mark.parametrize("auth_role, auth", [("admin", "ranger_admin_config")]) |
| def test_create_user_userinfo(self, request, auth_role, auth): |
| |
| if auth_role != "admin": |
| assert False, "Test requires admin privileges" |
| |
| auth = getattr(self, auth) |
| |
| test_user, test_id = request.getfixturevalue("temp_secure_user")(["user"]) |
| |
| print(f"\nCreating a new secure user with userinfo endpoint") |
| assert user_exists(test_id, auth, self.base_url, self.headers), "User should exist before performing userinfo based creation" |
| |
| grp_name = random.choice(string.ascii_letters) + ''.join(random.choices(string.ascii_letters + string.digits, k=7)) |
| payload = { |
| "xuserInfo": { |
| "name": test_user["name"] |
| }, |
| "xgroupInfo": [ |
| { |
| "name": grp_name, |
| "groupType": 1, |
| "groupSource": 1, |
| "description": "this is for test" |
| |
| } |
| ] |
| } |
| |
| assert payload["xuserInfo"]["name"] == test_user["name"], "User info name should match the test user name" |
| assert len(payload["xgroupInfo"]) >= 1, "There should be at least one group info" |
| |
| response = requests.post( |
| f"{self.base_url}/xusers/users/userinfo", |
| json=payload, |
| auth=auth, |
| headers=self.headers |
| ) |
| |
| assert_response(response, 200) |
| |
| data = response.json() |
| |
| validate_xgroup_schema(data["xgroupInfo"][0]) |
| |
| assert data["xgroupInfo"][0]["name"] == payload["xgroupInfo"][0]["name"], "Response group name should match the test user name" |
| |
| grp_id = data["xgroupInfo"][0]["id"] |
| # cleanup |
| params = {"forceDelete": "true"} |
| del_req = requests.delete( |
| f"{self.base_url}/xusers/groups/{grp_id}", |
| auth=auth, |
| headers=self.headers, |
| params=params |
| ) |
| print(f"Deleted group {grp_name} created during test, status code: {del_req.status_code}") |
| |
| @pytest.mark.positive |
| @pytest.mark.post |
| @pytest.mark.parametrize("auth_role, auth", [("admin", "ranger_admin_config")]) |
| def test_create_roleassignment(self, auth_role, auth, request): |
| |
| if auth_role != "admin": |
| pytest.fail("Test requires admin privileges") |
| auth = getattr(self, auth) |
| |
| users = [request.getfixturevalue("temp_secure_user")(["user"])[0] for _ in range(8)] |
| for u in users: |
| assert u["userSource"] == 1, f"{u['name']} should be external user" |
| |
| uA, uB, uC, uD, uE, uF, uG, uH = [u["name"] for u in users] |
| |
| group_admin = f"grp_admin_{uuid.uuid4().hex[:6]}" |
| group_auditor = f"grp_aud_{uuid.uuid4().hex[:6]}" |
| group_user = f"grp_user_{uuid.uuid4().hex[:6]}" |
| |
| assign_groups_to_user(uB, [group_auditor], auth, self.base_url, self.headers) # groupMap |
| assign_groups_to_user(uE, [group_admin], auth, self.base_url, self.headers) # wlGroup |
| assign_groups_to_user(uF, [group_admin], auth, self.base_url, self.headers) # override userMap |
| assign_groups_to_user(uG, [group_user], auth, self.base_url, self.headers) # override groupMap |
| assign_groups_to_user(uH, [group_admin], auth, self.base_url, self.headers) # wlUser vs wlGroup |
| |
| user_map = { |
| uA: "ROLE_SYS_ADMIN", |
| uF: "ROLE_ADMIN_AUDITOR", # will be overridden by whitelist group |
| } |
| |
| group_map = { |
| group_auditor: "ROLE_ADMIN_AUDITOR", |
| } |
| |
| white_user_map = { |
| uD: "ROLE_ADMIN_AUDITOR", |
| uH: "ROLE_SYS_ADMIN", # overrides whitelist group |
| } |
| |
| white_group_map = { |
| group_admin: "ROLE_SYS_ADMIN", |
| group_user: "ROLE_USER", |
| } |
| |
| payload = { |
| "users": [uA, uB, uC, uD, uE, uF, uG, uH], |
| "userRoleAssignments": user_map, |
| "groupRoleAssignments": group_map, |
| "whiteListUserRoleAssignments": white_user_map, |
| "whiteListGroupRoleAssignments": white_group_map, |
| "isReset": False, |
| "isLastPage": False |
| } |
| |
| response = requests.post( |
| f"{self.base_url}/xusers/users/roleassignments", |
| json=payload, |
| auth=auth, |
| headers=self.headers |
| ) |
| |
| assert_response(response, 200) |
| |
| expected = { |
| uA: "ROLE_SYS_ADMIN", # userMap |
| uB: "ROLE_ADMIN_AUDITOR", # groupMap |
| uC: "ROLE_USER", # default |
| uD: "ROLE_ADMIN_AUDITOR", # whitelist user |
| uE: "ROLE_SYS_ADMIN", # whitelist group |
| uF: "ROLE_SYS_ADMIN", # wlGroup > userMap |
| uG: "ROLE_USER", # wlGroup > groupMap |
| uH: "ROLE_SYS_ADMIN", # wlUser > wlGroup |
| } |
| |
| for user, expected_role in expected.items(): |
| resp = requests.get( |
| f"{self.base_url}/xusers/users/userName/{user}", |
| auth=auth, |
| headers=self.headers |
| ) |
| |
| assert resp.status_code == 200, f"Failed to fetch {user}" |
| data = resp.json() |
| validate_user_schema(data) |
| |
| actual_roles = data["userRoleList"] |
| print(f"{user} → {actual_roles}") |
| assert expected_role in actual_roles, \ |
| f"{user}: expected {expected_role}, got {actual_roles}" |
| |
| # cleanup of created groups |
| for group in [group_admin, group_auditor, group_user]: |
| resp = requests.get( |
| f"{self.base_url}/xusers/groups/groupName/{group}", |
| auth=auth, |
| headers=self.headers |
| ) |
| if resp.status_code == 200: |
| group_id = resp.json()["id"] |
| params = {"forceDelete": "true"} |
| requests.delete( |
| f"{self.base_url}/xusers/groups/{group_id}", |
| params=params, |
| auth=auth, |
| headers={**self.headers, "X-Requested-By": "ranger"} |
| ) |
| print(f"Deleted group {group} created during test") |
| assert_response(resp, 200, f"Failed to delete group {group} during cleanup") |
| |
| @pytest.mark.positive |
| @pytest.mark.put |
| @pytest.mark.parametrize("auth_role", ["admin", "keyadmin"]) |
| def test_update_user(self, auth_role, request): |
| |
| user, user_id = request.getfixturevalue("temp_secure_user")(["user"]) |
| |
| print(f"\nUpdating user: {user['name']} | ID: {user_id}") |
| |
| payload = { |
| "id": user_id, |
| "name": user["name"], |
| "firstName": "updatedfirstname", |
| "lastName": "updatedlastname", |
| "emailAddress": f"updated_{user['emailAddress']}", |
| "status": 1, |
| "isVisible": 1, |
| "userRoleList": ["ROLE_USER"], |
| "groupIdList": [], |
| "groupNameList": [] |
| } |
| |
| mandatory_fields = ["id", "name", "userRoleList", "firstName"] |
| missing = [k for k in mandatory_fields if k not in payload] |
| assert not missing, f"Missing mandatory fields in payload: {missing}" |
| |
| if auth_role == "admin": |
| auth = self.ranger_admin_config |
| assert "ROLE_KEY_ADMIN" not in payload["userRoleList"], "Admin can not promote any one to keyadmin role" |
| assert "ROLE_KEY_ADMIN" not in user["userRoleList"], "Admin can not update keyadmin role" |
| elif auth_role == "keyadmin": |
| auth = self.ranger_key_admin_config |
| assert "ROLE_SYS_ADMIN" not in payload["userRoleList"], "Key Admin can not promote any one to admin role" |
| assert "ROLE_ADMIN_AUDITOR" not in payload["userRoleList"], "Key Admin can not promote any one to auditor role" |
| assert "ROLE_SYS_ADMIN" not in user["userRoleList"], "Key Admin can not update admin role" |
| assert "ROLE_ADMIN_AUDITOR" not in user["userRoleList"], "Key Admin can not update auditor role" |
| |
| resp = requests.get( |
| f"{self.base_url}/xusers/users/{user_id}", |
| auth=self.ranger_admin_config, |
| headers=self.headers |
| ) |
| resp = resp.json() |
| |
| for i in ["id", "name"]: |
| assert resp[i] == payload[i], f"Miss-match mandatory field in response: {i}" |
| |
| response = requests.put( |
| f"{self.base_url}/xusers/users", |
| json=payload, |
| auth=auth, |
| headers=self.headers |
| ) |
| |
| assert_response(response, 200) |
| |
| data = response.json() |
| validate_user_schema(data) |
| assert data["firstName"].lower() == "updatedfirstname" |
| assert data["lastName"].lower() == "updatedlastname" |
| assert data["emailAddress"].lower() == f"updated_{user['emailAddress']}".lower() |
| |
| @pytest.mark.positive |
| @pytest.mark.delete |
| def test_delete_user(self, request, client_roles): |
| if "ROLE_SYS_ADMIN" not in client_roles: |
| assert False, "Test requires admin privileges" |
| |
| user, user_id = request.getfixturevalue("temp_secure_user")(["user"]) |
| |
| print(f"\nDeleting user: {user['name']} | ID: {user_id}") |
| |
| assert user_exists(user_id, self.ranger_admin_config, self.base_url, self.headers), "User should exist before deletion" |
| |
| response = requests.delete( |
| f"{self.base_url}/xusers/users/{user_id}", |
| params={"forceDelete": "true"}, |
| auth=self.ranger_admin_config, |
| headers={**self.headers, "X-Requested-By": "ranger"} |
| ) |
| assert response, "User deletion failed" |
| assert_response(response, 204) |
| |
| @pytest.mark.positive |
| @pytest.mark.delete |
| def test_delete_external_user_by_username(self, request, client_roles): |
| if "ROLE_SYS_ADMIN" not in client_roles: |
| assert False, "Test requires admin privileges" |
| |
| user, user_id = request.getfixturevalue("temp_secure_user")(["user"]) |
| userName = user["name"] |
| |
| print(f"\nDeleting external user: {user['name']} | ID: {user_id}") |
| |
| assert user_exists(user_id, self.ranger_admin_config, self.base_url, self.headers), "User should exist before deletion" |
| |
| response = requests.delete( |
| f"{self.base_url}/xusers/users/userName/{userName}", |
| params={"forceDelete": "true"}, |
| auth=self.ranger_admin_config, |
| headers={**self.headers, "X-Requested-By": "ranger"} |
| ) |
| assert response, "External user deletion failed" |
| assert_response(response, 204) |
| |
| # Negative Test Cases |
| |
| @pytest.mark.negative |
| @pytest.mark.get |
| def test_get_users_using_invalid_auth(self): |
| random_num = random.randint(100000, 999999) |
| url = self.base_url + f'/xusers/users/{random_num}' |
| |
| response = requests.get( |
| url, |
| auth=self.ranger_admin_config, |
| headers=self.headers |
| ) |
| |
| assert_response(response, 400, "Expected status code not returned for invalid user ID") |
| |
| @pytest.mark.negative |
| @pytest.mark.get |
| @pytest.mark.parametrize("auth_role, user_role", [ |
| ("admin", "keyadmin"), |
| ("auditor", "keyadmin"), |
| ("keyadmin","admin"), |
| ("keyadmin","auditor"), |
| ("user", "admin"), |
| ("user", "auditor"), |
| ("user", "user"), |
| ("user", "keyadmin"), |
| ]) |
| def test_get_user_by_id_using_invalid_auth(self, auth_role, user_role, request): |
| if auth_role == "keyadmin": |
| auth = self.ranger_key_admin_config |
| elif auth_role == "admin": |
| auth = self.ranger_admin_config |
| elif auth_role == "auditor": |
| auth = self.ranger_auditor_config |
| elif auth_role == "user": |
| auth = self.ranger_user_config |
| |
| |
| if user_role == "keyadmin": |
| user_id = self.ranger_key_admin_id1 |
| elif user_role == "admin": |
| user_id = self.ranger_admin_id1 |
| elif user_role == "auditor": |
| user_id = self.ranger_auditor_id1 |
| elif user_role == "user": |
| user_id = self.ranger_user_id1 |
| |
| |
| response = requests.get( |
| f"{self.base_url}/xusers/users/{user_id}", |
| auth=auth, |
| headers=self.headers |
| ) |
| |
| assert_response(response, 403, f"{auth_role} should not have permission to access user of role {user_role}") |
| |
| @pytest.mark.negative |
| @pytest.mark.get |
| @pytest.mark.parametrize("auth_role, user_role", [ |
| ("admin", "keyadmin"), |
| ("keyadmin", "admin"), |
| ("keyadmin", "auditor"), |
| ("auditor", "keyadmin"), |
| ("user", "admin"), |
| ("user", "auditor"), |
| ("user", "keyadmin"), |
| ("user", "user") |
| ]) |
| def test_get_users_by_username_with_invalid_role(self, request, auth_role, user_role): |
| if auth_role == "keyadmin": |
| auth = self.ranger_key_admin_config |
| elif auth_role == "admin": |
| auth = self.ranger_admin_config |
| if self.admin["name"].lower() == "rangerusersync": |
| assert True, "If any admin's username is rangerusersync it has access to all users irrespective of role" |
| return |
| elif auth_role == "auditor": |
| auth_user, auth_id = self.audit, self.ranger_auditor_id |
| auth = self.ranger_auditor_config |
| elif auth_role == "user": |
| auth_user, auth_id = self.user, self.ranger_user_id |
| auth = self.ranger_user_config |
| |
| if user_role == "keyadmin": |
| user, user_id = self.ranger_key_admin1, self.ranger_key_admin_id1 |
| elif user_role == "admin": |
| user, user_id = self.admin1, self.ranger_admin_id1 |
| elif user_role == "auditor": |
| user, user_id = self.audit1, self.ranger_auditor_id1 |
| elif user_role == "user": |
| user, user_id = self.user1, self.ranger_user_id1 |
| |
| userName = user["name"] |
| response = requests.get( |
| f"{self.base_url}/xusers/users/userName/{userName}", |
| auth=auth, |
| headers=self.headers |
| ) |
| |
| assert_response(response, 403, f"Unauthorized access should be denied for {auth_role} to access user of role {user_role}") |
| |
| @pytest.mark.post |
| @pytest.mark.negative |
| def test_create_secure_user_missing_mandatory_field(self): |
| |
| payload = { |
| "name" : "missing_night2d2", |
| } |
| |
| response = requests.post( |
| f"{self.base_url}/xusers/users", |
| json=payload, |
| auth=self.ranger_admin_config, |
| headers=self.headers |
| ) |
| |
| assert_response(response, 400) |
| |
| @pytest.mark.post |
| @pytest.mark.negative |
| def test_create_user_via_invalid_roles(self, request): |
| |
| normal_user, n_id = request.getfixturevalue("temp_secure_user")(["user"]) |
| |
| auditor_user, a_id = request.getfixturevalue("temp_secure_user")(["auditor"]) |
| |
| |
| users_to_test = [ |
| (normal_user["name"], "Test@123"), |
| (auditor_user["name"], "Test@123"), |
| self.ranger_key_admin_config, |
| ] |
| |
| for username, password in users_to_test: |
| |
| random_suffix = ''.join(random.choices(string.ascii_lowercase, k=5)) |
| blocked_username = f"blocked_{random_suffix}" |
| |
| payload = { |
| "name": blocked_username, |
| "firstName": "Blocked", |
| "lastName": "User", |
| "emailAddress": f"{blocked_username}@test.com", |
| "password": "Test@123", |
| "status": 1, |
| "isVisible": 1, |
| "userRoleList": ["ROLE_USER"], |
| "groupIdList": [], |
| "groupNameList": [] |
| } |
| |
| response = requests.post( |
| f"{self.base_url}/xusers/users", |
| json=payload, |
| auth=(username, password), |
| headers=self.headers |
| ) |
| |
| print(f"{username} → {response.status_code}") |
| assert_response(response, 404, f"{username} should not have permission to create users and expected 404 due to spring silent failure, but got {response.status_code}") |
| |
| @pytest.mark.negative |
| @pytest.mark.post |
| @pytest.mark.parametrize("auth_role", ["auditor", "user", "keyadmin"]) |
| def test_create_external_user_using_invalid_roles(self, request, auth_role): |
| if auth_role == "auditor": |
| auth = self.ranger_auditor_config |
| elif auth_role == "user": |
| auth = self.ranger_user_config |
| elif auth_role == "keyadmin": |
| auth = self.ranger_key_admin_config |
| random_suffix = ''.join(random.choices(string.ascii_lowercase, k=5)) |
| username = f"external_{random_suffix}" |
| payload = { |
| "name": username |
| } |
| response = requests.post( |
| f"{self.base_url}/xusers/users/external", |
| json=payload, |
| auth=auth, |
| headers=self.headers |
| ) |
| assert_response(response, 404, f"{auth_role} is expected to return 404 due to spring's silent failure and should not have permission to create external users, but got {response.status_code}") |
| |
| @pytest.mark.negative |
| @pytest.mark.post |
| @pytest.mark.parametrize("auth_role", ["auditor", "user", "keyadmin"]) |
| def test_create_user_userinfo_with_invalid_roles(self, request, auth_role): |
| if auth_role == "auditor": |
| auth = self.ranger_auditor_config |
| elif auth_role == "user": |
| auth = self.ranger_user_config |
| elif auth_role == "keyadmin": |
| auth = self.ranger_key_admin_config |
| |
| test_user, test_id = self.user, self.ranger_user_id |
| assert user_exists(test_id, self.ranger_admin_config, self.base_url, self.headers), "User should exist before performing userinfo based creation" |
| |
| payload = { |
| "xuserInfo": { |
| "name": test_user["name"] |
| }, |
| "xgroupInfo": [ |
| { |
| "name": random.choice(string.ascii_letters) + ''.join(random.choices(string.ascii_letters + string.digits, k=7)), |
| "groupType": 1, |
| "groupSource": 1, |
| "description": "this is for test" |
| |
| } |
| ] |
| } |
| |
| response = requests.post( |
| f"{self.base_url}/xusers/users/userinfo", |
| json=payload, |
| auth=auth, |
| headers=self.headers |
| ) |
| |
| assert_response(response, 404, f"{auth_role} expected 404 due to spring's silent failure and should not have permission to create users using userinfo endpoint") |
| |
| @pytest.mark.negative |
| @pytest.mark.post |
| @pytest.mark.parametrize("missing_field", ["name", "xuserInfo_name"]) |
| def test_create_user_userinfo_with_invalid_payload(self, request, missing_field): |
| auth = self.ranger_admin_config |
| |
| if missing_field == "name": |
| username= f"non_exister_userinfo_{''.join(random.choices(string.ascii_lowercase, k=5))}" |
| x_group_name = "sample" |
| elif missing_field == "xuserInfo_name": |
| username = self.user["name"] |
| x_group_name = None |
| payload = { |
| "xuserInfo": { |
| "name": username |
| }, |
| "xgroupInfo": [ |
| { |
| "name": x_group_name, |
| } |
| ] |
| } |
| |
| response = requests.post( |
| f"{self.base_url}/xusers/users/userinfo", |
| json=payload, |
| auth=auth, |
| headers=self.headers |
| ) |
| |
| assert_response(response, 404, f"Userinfo creation should not be allowed with missing field: {missing_field}") |
| |
| @pytest.mark.negative |
| @pytest.mark.post |
| @pytest.mark.parametrize("auth_role", ["auditor", "user", "keyadmin"]) |
| def test_create_roleassignment_with_invalid_roles(self, request, auth_role): |
| |
| if auth_role == "auditor": |
| auth = self.ranger_auditor_config |
| elif auth_role == "user": |
| auth = self.ranger_user_config |
| elif auth_role == "keyadmin": |
| auth = self.ranger_key_admin_config |
| |
| payload = { |
| "users": [self.user1["name"]], |
| "userRoleAssignments": {self.user1["name"]: "ROLE_SYS_ADMIN"}, |
| "groupRoleAssignments": {}, |
| "whiteListUserRoleAssignments": {}, |
| "whiteListGroupRoleAssignments": {}, |
| "isReset": False, |
| "isLastPage": False |
| } |
| |
| response = requests.post( |
| f"{self.base_url}/xusers/users/roleassignments", |
| json=payload, |
| auth=auth, |
| headers=self.headers |
| ) |
| |
| assert_response(response, 404, f"{auth_role} is expected to return 404 due to spring's silent failure and should not have permission to assign roles, but got {response.status_code}") |
| |
| @pytest.mark.negative |
| @pytest.mark.post |
| @pytest.mark.parametrize("invalid_role", ["ROLE_NON_EXISTEN", "ROLE_KEY_ADMIN"]) |
| def test_create_roleassignment_to_invalid_assignment(self, invalid_role): |
| auth = self.ranger_admin_config |
| |
| payload = { |
| "users": [self.user1["name"]], |
| "userRoleAssignments": {self.user1["name"]: invalid_role}, |
| "groupRoleAssignments": {}, |
| "whiteListUserRoleAssignments": {}, |
| "whiteListGroupRoleAssignments": {}, |
| "isReset": False, |
| "isLastPage": False |
| } |
| |
| response = requests.post( |
| f"{self.base_url}/xusers/users/roleassignments", |
| json=payload, |
| auth=auth, |
| headers=self.headers |
| ) |
| if invalid_role == "ROLE_NON_EXISTEN": |
| expected_status = 400 |
| elif invalid_role == "ROLE_KEY_ADMIN": |
| expected_status = 403 # since ROLE_KEY_ADMIN is not a valid role but it has admin keyword so it will be blocked by permission check before role validation |
| assert_response(response, expected_status, f"Assigning non-existent role should fail with {expected_status}, but got {response.status_code}") |
| |
| @pytest.mark.negative |
| @pytest.mark.put |
| @pytest.mark.parametrize( |
| "auth_role,user_role", |
| [ |
| ("admin", ["ROLE_KEY_ADMIN"]), |
| ("auditor", ["ROLE_USER"]), |
| ("user", ["ROLE_USER"]), |
| ("keyadmin", ["ROLE_SYS_ADMIN"]), |
| ("keyadmin", ["ROLE_ADMIN_AUDITOR"]), |
| ],) |
| def test_update_user_using_invalid_access(self, temp_secure_user, auth_role, user_role): |
| |
| user, user_id = temp_secure_user(["user"]) |
| |
| print(f"\nUpdating user: {user['name']} | ID: {user_id}") |
| |
| if auth_role == "auditor": |
| auth_user = self.audit |
| auth = self.ranger_auditor_config |
| |
| assert "ROLE_ADMIN_AUDITOR" in auth_user["userRoleList"], "User does not have auditor role" |
| |
| elif auth_role == "user": |
| auth_user = self.user |
| auth = self.ranger_user_config |
| assert "ROLE_USER" in auth_user["userRoleList"], "User does not have user role" |
| |
| elif auth_role == "admin": |
| auth = self.ranger_admin_config |
| |
| elif auth_role == "keyadmin": |
| auth = self.ranger_key_admin_config |
| |
| payload = { |
| "id": user_id, |
| "name": user["name"], |
| "firstName": "updatedfirstname", |
| "lastName": "updatedlastname", |
| "emailAddress": f"updated_{user['emailAddress']}", |
| "status": 1, |
| "isVisible": 1, |
| "userRoleList": user_role , |
| "groupIdList": [], |
| "groupNameList": [] |
| } |
| |
| response = requests.put( |
| f"{self.base_url}/xusers/users", |
| json=payload, |
| auth=auth, |
| headers=self.headers |
| ) |
| if auth_role in ["auditor", "user"]: |
| assert_response(response, 403, f"{auth_role} should not have permission to update users, but got {response.status_code}") |
| elif auth_role in ["admin", "keyadmin"]: |
| assert_response(response, 400, f"{auth_role} should not have permission to update {user_role} role, expected 400 but got {response.status_code}") |
| |
| @pytest.mark.negative |
| @pytest.mark.put |
| def test_update_user_using_invalid_data(self): |
| rand_id = random.randint(100000, 999999) |
| payload = { |
| "id": rand_id, |
| "name": "name", |
| "firstName": "updatedfirstname", |
| "userRoleList": ["RANDOM_ROLE"] |
| |
| } |
| response = requests.put( |
| f"{self.base_url}/xusers/users", |
| json=payload, |
| auth=self.ranger_admin_config, |
| headers=self.headers |
| ) |
| print(response.status_code, response.text) |
| assert_response(response, 403, "Operation is expected to be denied") |
| |
| |
| @pytest.mark.negative |
| @pytest.mark.delete |
| def test_delete_user_using_invalid_id(self): |
| |
| #rand_id = random.randint(100000, 999999) |
| rand_id = 89999 |
| |
| response = requests.delete( |
| f"{self.base_url}/xusers/users/{rand_id}", |
| params={"forceDelete": "true"}, |
| auth=self.ranger_admin_config, |
| headers={**self.headers, "X-Requested-By": "ranger"} |
| ) |
| assert_response(response, [400, 404], f"Expected status code not returned for invalid user ID, got {response.status_code}") |
| |
| @pytest.mark.negative |
| @pytest.mark.delete |
| @pytest.mark.parametrize("auth_role", ["auditor", "user", "keyadmin"]) |
| def test_delete_user_using_invalid_roles(self, auth_role, request): |
| if auth_role == "auditor": |
| auth_user = self.audit |
| auth = self.ranger_auditor_config |
| assert "ROLE_ADMIN_AUDITOR" in auth_user["userRoleList"], "User does not have auditor role" |
| elif auth_role == "user": |
| auth_user = self.user |
| auth = self.ranger_user_config |
| assert "ROLE_USER" in auth_user["userRoleList"], "User does not have user role" |
| elif auth_role == "keyadmin": |
| auth = self.ranger_key_admin_config |
| |
| test_user, test_id = request.getfixturevalue("temp_secure_user")(["user"]) |
| |
| |
| response = requests.delete( |
| f"{self.base_url}/xusers/users/{test_id}", |
| params={"forceDelete": "true"}, |
| auth=auth, |
| headers={**self.headers, "X-Requested-By": "ranger"} |
| ) |
| assert_response(response, 404, f"{auth_role} is expected to return 404 due to spring's silent failure and should not have permission to delete users") |
| |
| |
| @pytest.mark.negative |
| @pytest.mark.delete |
| @pytest.mark.parametrize("auth_role", ["auditor", "user", "keyadmin"]) |
| def test_delete_external_user_with_invalid_role(self,request, auth_role): |
| if auth_role == "auditor": |
| auth_user = self.audit |
| auth = self.ranger_auditor_config |
| assert "ROLE_ADMIN_AUDITOR" in auth_user["userRoleList"], "User does not have auditor role" |
| elif auth_role == "user": |
| auth_user = self.user |
| auth = self.ranger_user_config |
| assert "ROLE_USER" in auth_user["userRoleList"], "User does not have user role" |
| elif auth_role == "keyadmin": |
| auth = self.ranger_key_admin_config |
| |
| test_user, test_id = request.getfixturevalue("temp_secure_user")(["user"]) |
| |
| userName = test_user["name"] |
| response = requests.delete( |
| f"{self.base_url}/xusers/users/userName/{userName}", |
| params={"forceDelete": "true"}, |
| auth=auth, |
| headers={**self.headers, "X-Requested-By": "ranger"} |
| ) |
| assert_response(response, 404, f"{auth_role} is expected to return 404 due to spring's silent failure and should not have permission to delete users") |