This is an automated email from the ASF dual-hosted git repository. madhan pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/ranger.git
commit 7d46e05ff7f98c082a12505c3641c1a06f839f87 Author: Madhan Neethiraj <mad...@apache.org> AuthorDate: Sun Oct 8 12:57:20 2023 -0700 RANGER-4465: Python client for managing users, groups, user-group associations --- intg/src/main/python/README.md | 140 ++++++++++++++- .../client/ranger_user_mgmt_client.py | 194 +++++++++++++++++++++ .../python/apache_ranger/model/ranger_user_mgmt.py | 119 +++++++++++++ intg/src/main/python/setup.py | 2 +- .../sample-client/src/main/python/user_mgmt.py | 137 +++++++++++++++ 5 files changed, 589 insertions(+), 3 deletions(-) diff --git a/intg/src/main/python/README.md b/intg/src/main/python/README.md index 0af1aa093..90e8ff6b8 100644 --- a/intg/src/main/python/README.md +++ b/intg/src/main/python/README.md @@ -36,7 +36,7 @@ Verify if apache-ranger client is installed: Package Version ------------ --------- -apache-ranger 0.0.11 +apache-ranger 0.0.12 ``` ## Usage @@ -229,4 +229,140 @@ kms_client.delete_key(key_name) print('delete_key(' + key_name + ')') ``` -For more examples, checkout `sample-client` python project in [ranger-examples](https://github.com/apache/ranger/blob/master/ranger-examples/sample-client/src/main/python/sample_client.py) module. +```python test_ranger_user_mgmt.py``` +```python +# test_ranger_user_mgmt.py +from apache_ranger.client.ranger_client import * +from apache_ranger.utils import * +from apache_ranger.model.ranger_user_mgmt import * +from apache_ranger.client.ranger_user_mgmt_client import * +from datetime import datetime + +## +## Step 1: create a client to connect to Apache Ranger +## +ranger_url = 'http://localhost:6080' +ranger_auth = ('admin', 'rangerR0cks!') + +# For Kerberos authentication +# +# from requests_kerberos import HTTPKerberosAuth +# +# ranger_auth = HTTPKerberosAuth() +# +# For HTTP Basic authentication +# +# ranger_auth = ('admin', 'rangerR0cks!') + +ranger = RangerClient(ranger_url, ranger_auth) +user_mgmt = RangerUserMgmtClient(ranger) + + + +## +## Step 2: Let's call User Management APIs +## + +print('\nListing users') + +users = user_mgmt.find_users() + +print(f' {len(users.list)} users found') + +for user in users.list: + print(f' id: {user.id}, name: {user.name}') + + +print('\nListing groups') + +groups = user_mgmt.find_groups() + +print(f' {len(groups.list)} groups found') + +for group in groups.list: + print(f' id: {group.id}, name: {group.name}') + +print('\nListing group-users') + +group_users = user_mgmt.find_group_users() + +print(f' {len(group_users.list)} group-users found') + +for group_user in group_users.list: + print(f' id: {group_user.id}, groupId: {group_user.parentGroupId}, userId: {group_user.userId}') + + +now = datetime.now() + +name_suffix = '-' + now.strftime('%Y%m%d-%H%M%S-%f') +user_name = 'test-user' + name_suffix +group_name = 'test-group' + name_suffix + + +user = RangerUser({ 'name': user_name, 'firstName': user_name, 'lastName': 'user', 'emailAddress': user_name + '@test.org', 'password': 'Welcome1', 'userRoleList': [ 'ROLE_USER' ], 'otherAttributes': '{ "dept": "test" }' }) + +print(f'\nCreating user: name={user.name}') + +created_user = user_mgmt.create_user(user) + +print(f' created user: {created_user}') + + +group = RangerGroup({ 'name': group_name, 'otherAttributes': '{ "dept": "test" }' }) + +print(f'\nCreating group: name={group.name}') + +created_group = user_mgmt.create_group(group) + +print(f' created group: {created_group}') + + +group_user = RangerGroupUser({ 'name': created_group.name, 'parentGroupId': created_group.id, 'userId': created_user.id }) + +print(f'\nAdding user {created_user.name} to group {created_group.name}') + +created_group_user = user_mgmt.create_group_user(group_user) + +print(f' created group-user: {created_group_user}') + + +print('\nListing group-users') + +group_users = user_mgmt.find_group_users() + +print(f' {len(group_users.list)} group-users found') + +for group_user in group_users.list: + print(f' id: {group_user.id}, groupId: {group_user.parentGroupId}, userId: {group_user.userId}') + + +print(f'\nListing users for group {group.name}') + +users = user_mgmt.get_users_in_group(group.name) + +print(f' users: {users}') + + +print(f'\nListing groups for user {user.name}') + +groups = user_mgmt.get_groups_for_user(user.name) + +print(f' groups: {groups}') + + +print(f'\nDeleting group-user {created_group_user.id}') + +user_mgmt.delete_group_user_by_id(created_group_user.id) + + +print(f'\nDeleting group {group.name}') + +user_mgmt.delete_group_by_id(created_group.id, True) + + +print(f'\nDeleting user {user.name}') + +user_mgmt.delete_user_by_id(created_user.id, True) +``` + +For more examples, checkout `sample-client` python project in [ranger-examples](https://github.com/apache/ranger/blob/master/ranger-examples/sample-client/src/main/python) module. diff --git a/intg/src/main/python/apache_ranger/client/ranger_user_mgmt_client.py b/intg/src/main/python/apache_ranger/client/ranger_user_mgmt_client.py new file mode 100644 index 000000000..3a0b44278 --- /dev/null +++ b/intg/src/main/python/apache_ranger/client/ranger_user_mgmt_client.py @@ -0,0 +1,194 @@ +#!/usr/bin/env python + +# +# 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. + + +import logging +from apache_ranger.model.ranger_user_mgmt import * +from apache_ranger.utils import * + +LOG = logging.getLogger(__name__) + +class RangerUserMgmtClient: + def __init__(self, ranger_client): + self.client_http = ranger_client.client_http + + def create_user(self, user): + resp = self.client_http.call_api(RangerUserMgmtClient.CREATE_USER, request_data=user) + + return type_coerce(resp, RangerUser) + + def update_user_by_id(self, user_id, user): + resp = self.client_http.call_api(RangerUserMgmtClient.UPDATE_USER.format_path({'id': user_id}), request_data=user) + + return type_coerce(resp, RangerUser) + + def delete_user_by_id(self, user_id, is_force_delete=False): + self.client_http.call_api(RangerUserMgmtClient.DELETE_USER.format_path({'id': user_id}), query_params={'forceDelete': is_force_delete}) + + def get_user_by_id(self, user_id): + resp = self.client_http.call_api(RangerUserMgmtClient.GET_USER_BY_ID.format_path({'id': user_id})) + + return type_coerce(resp, RangerUser) + + def get_user(self, user_name): + resp = self.find_users({ 'name': user_name }) + + if resp is not None and resp.list is not None: + for user in resp.list: + if user.name == user_name: + return user + + return None + + def get_groups_for_user(self, name): + user = self.get_user(name) + + if user is not None and user.groupNameList is not None: + ret = user.groupNameList + else: + ret = None + + return ret + + def find_users(self, filter=None): + resp = self.client_http.call_api(RangerUserMgmtClient.FIND_USERS, filter) + + vList = PList(resp) + + vList.list = resp.get('vXUsers') + + vList.type_coerce_list(RangerUser) + + return vList + + + def create_group(self, group): + resp = self.client_http.call_api(RangerUserMgmtClient.CREATE_GROUP, request_data=group) + + return type_coerce(resp, RangerGroup) + + def update_group_by_id(self, group_id, group): + resp = self.client_http.call_api(RangerUserMgmtClient.UPDATE_GROUP.format_path({'id': group_id}), request_data=group) + + return type_coerce(resp, RangerGroup) + + def delete_group_by_id(self, group_id, is_force_delete=False): + self.client_http.call_api(RangerUserMgmtClient.DELETE_GROUP.format_path({'id': group_id}), query_params={'forceDelete': is_force_delete}) + + def get_group_by_id(self, group_id): + resp = self.client_http.call_api(RangerUserMgmtClient.GET_GROUP_BY_ID.format_path({'id': group_id})) + + return type_coerce(resp, RangerGroup) + + def get_group(self, group_name): + resp = self.find_groups({ 'name': group_name }) + + if resp is not None and resp.list is not None: + for group in resp.list: + if group.name == group_name: + return group + + return None + + def get_users_in_group(self, name): + group_users = self.get_group_users_for_group(name) + + if group_users is not None and group_users.users is not None: + ret = [] + for user in group_users.users: + ret.append(user.name) + else: + ret = None + + return ret + + def find_groups(self, filter=None): + resp = self.client_http.call_api(RangerUserMgmtClient.FIND_GROUPS, filter) + + vList = PList(resp) + + vList.list = resp.get('vXGroups') + + vList.type_coerce_list(RangerGroup) + + return vList + + + def create_group_user(self, group_user): + resp = self.client_http.call_api(RangerUserMgmtClient.CREATE_GROUP_USER, request_data=group_user) + + return type_coerce(resp, RangerGroupUser) + + def update_group_user(self, group_user): + resp = self.client_http.call_api(RangerUserMgmtClient.UPDATE_GROUP_USER, request_data=group_user) + + return type_coerce(resp, RangerGroupUser) + + def delete_group_user_by_id(self, group_user_id): + self.client_http.call_api(RangerUserMgmtClient.DELETE_GROUP_USER.format_path({'id': group_user_id})) + + def find_group_users(self, filter=None): + resp = self.client_http.call_api(RangerUserMgmtClient.FIND_GROUP_USERS, filter) + + vList = PList(resp) + + vList.list = resp.get('vXGroupUsers') + + vList.type_coerce_list(RangerGroupUser) + + return vList + + def get_group_users_for_group(self, name): + resp = self.client_http.call_api(RangerUserMgmtClient.GET_GROUP_USERS_FOR_GROUP.format_path({'name': name})) + + return type_coerce(resp, RangerGroupUsers) + + # URIs + URI_XUSERS_BASE = 'service/xusers' + URI_XUSERS_USERS = URI_XUSERS_BASE + '/users' + URI_XUSERS_SECURE_USERS = URI_XUSERS_BASE + '/secure/users' + URI_XUSERS_SECURE_USER_BY_ID = URI_XUSERS_SECURE_USERS + '/{id}' + URI_XUSERS_DELETE_USER = URI_XUSERS_USERS + '/{id}' + URI_XUSERS_GROUPS = URI_XUSERS_BASE + '/groups' + URI_XUSERS_SECURE_GROUPS = URI_XUSERS_BASE + '/secure/groups' + URI_XUSERS_SECURE_GROUP_BY_ID = URI_XUSERS_SECURE_GROUPS + '/{id}' + URI_XUSERS_DELETE_GROUP = URI_XUSERS_GROUPS + '/{id}' + URI_XUSERS_GROUP_USERS = URI_XUSERS_BASE + '/groupusers' + URI_XUSERS_GROUP_USER_BY_ID = URI_XUSERS_GROUP_USERS + '/{id}' + URI_XUSERS_GROUP_USERS_FOR_GROUP = URI_XUSERS_GROUP_USERS + '/groupName/{name}' + + + # APIs + CREATE_USER = API(URI_XUSERS_SECURE_USERS, HttpMethod.POST, HTTPStatus.OK) + UPDATE_USER = API(URI_XUSERS_SECURE_USER_BY_ID, HttpMethod.PUT, HTTPStatus.OK) + DELETE_USER = API(URI_XUSERS_DELETE_USER, HttpMethod.DELETE, HTTPStatus.NO_CONTENT) + GET_USER_BY_ID = API(URI_XUSERS_SECURE_USER_BY_ID, HttpMethod.GET, HTTPStatus.OK) + FIND_USERS = API(URI_XUSERS_USERS, HttpMethod.GET, HTTPStatus.OK) + + CREATE_GROUP = API(URI_XUSERS_SECURE_GROUPS, HttpMethod.POST, HTTPStatus.OK) + UPDATE_GROUP = API(URI_XUSERS_SECURE_GROUP_BY_ID, HttpMethod.PUT, HTTPStatus.OK) + DELETE_GROUP = API(URI_XUSERS_DELETE_GROUP, HttpMethod.DELETE, HTTPStatus.NO_CONTENT) + GET_GROUP_BY_ID = API(URI_XUSERS_SECURE_GROUP_BY_ID, HttpMethod.GET, HTTPStatus.OK) + FIND_GROUPS = API(URI_XUSERS_GROUPS, HttpMethod.GET, HTTPStatus.OK) + + CREATE_GROUP_USER = API(URI_XUSERS_GROUP_USERS, HttpMethod.POST, HTTPStatus.OK) + UPDATE_GROUP_USER = API(URI_XUSERS_GROUP_USERS, HttpMethod.PUT, HTTPStatus.OK) + DELETE_GROUP_USER = API(URI_XUSERS_GROUP_USER_BY_ID, HttpMethod.DELETE, HTTPStatus.NO_CONTENT) + FIND_GROUP_USERS = API(URI_XUSERS_GROUP_USERS, HttpMethod.GET, HTTPStatus.OK) + + GET_GROUP_USERS_FOR_GROUP = API(URI_XUSERS_GROUP_USERS_FOR_GROUP, HttpMethod.GET, HTTPStatus.OK) diff --git a/intg/src/main/python/apache_ranger/model/ranger_user_mgmt.py b/intg/src/main/python/apache_ranger/model/ranger_user_mgmt.py new file mode 100644 index 000000000..244ed55fc --- /dev/null +++ b/intg/src/main/python/apache_ranger/model/ranger_user_mgmt.py @@ -0,0 +1,119 @@ +#!/usr/bin/env python + +# +# 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 apache_ranger.model.ranger_base import * +from apache_ranger.utils import * + +class RangerUser(RangerBase): + def __init__(self, attrs=None): + if attrs is None: + attrs = {} + + RangerBaseModelObject.__init__(self, attrs) + + self.id = attrs.get('id') + self.createDate = attrs.get('createDate') + self.updateDate = attrs.get('updateDate') + self.owner = attrs.get('owner') + self.updatedBy = attrs.get('updatedBy') + + self.name = attrs.get('name') + self.description = attrs.get('description') + self.firstName = attrs.get('firstName') + self.lastName = attrs.get("lastName") + self.emailAddress = attrs.get('emailAddress') + self.password = attrs.get('password') + self.credStoreId = attrs.get("credStoreId") + self.status = attrs.get('status') + self.isVisible = attrs.get('isVisible') + self.userSource = attrs.get('userSource') + self.userRoleList = attrs.get('userRoleList') + self.otherAttributes = attrs.get('otherAttributes') + self.syncSource = attrs.get('syncSource') + self.groupIdList = attrs.get('groupIdList') + self.groupNameList = attrs.get('groupNameList') + + if self.status is None: + self.status = 1 + + if self.userRoleList is None: + self.userRoleList = [ 'ROLE_USER' ] + + +class RangerGroup(RangerBase): + def __init__(self, attrs=None): + if attrs is None: + attrs = {} + + RangerBaseModelObject.__init__(self, attrs) + + self.id = attrs.get('id') + self.createDate = attrs.get('createDate') + self.updateDate = attrs.get('updateDate') + self.owner = attrs.get('owner') + self.updatedBy = attrs.get('updatedBy') + + self.name = attrs.get('name') + self.description = attrs.get('description') + self.groupType = attrs.get('groupType') + self.groupSource = attrs.get("groupSource") + self.credStoreId = attrs.get("credStoreId") + self.isVisible = attrs.get('isVisible') + self.otherAttributes = attrs.get('otherAttributes') + self.syncSource = attrs.get('syncSource') + +class RangerGroupUser(RangerBase): + def __init__(self, attrs=None): + if attrs is None: + attrs = {} + + RangerBaseModelObject.__init__(self, attrs) + + self.id = attrs.get('id') + self.createDate = attrs.get('createDate') + self.updateDate = attrs.get('updateDate') + self.owner = attrs.get('owner') + self.updatedBy = attrs.get('updatedBy') + + self.name = attrs.get('name') + self.parentGroupId = attrs.get('parentGroupId') + self.userId = attrs.get('userId') + + +class RangerGroupUsers(RangerBase): + def __init__(self, attrs=None): + if attrs is None: + attrs = {} + + RangerBaseModelObject.__init__(self, attrs) + + self.id = attrs.get('id') + self.createDate = attrs.get('createDate') + self.updateDate = attrs.get('updateDate') + self.owner = attrs.get('owner') + self.updatedBy = attrs.get('updatedBy') + + self.group = attrs.get('xgroupInfo') + self.users = attrs.get('xuserInfo') + + def type_coerce_attrs(self): + super(RangerGroupUsers, self).type_coerce_attrs() + + self.group = type_coerce(self.group, RangerGroup) + self.users = type_coerce_list(self.users, RangerUser) diff --git a/intg/src/main/python/setup.py b/intg/src/main/python/setup.py index c7dfaa0b4..89db40e64 100644 --- a/intg/src/main/python/setup.py +++ b/intg/src/main/python/setup.py @@ -27,7 +27,7 @@ with open("README.md", "r") as fh: setup( name="apache-ranger", - version="0.0.11", + version="0.0.12", author="Apache Ranger", author_email="d...@ranger.apache.org", description="Apache Ranger Python client", diff --git a/ranger-examples/sample-client/src/main/python/user_mgmt.py b/ranger-examples/sample-client/src/main/python/user_mgmt.py new file mode 100644 index 000000000..97bbd05eb --- /dev/null +++ b/ranger-examples/sample-client/src/main/python/user_mgmt.py @@ -0,0 +1,137 @@ +#!/usr/bin/env python + +# +# 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 apache_ranger.client.ranger_client import * +from apache_ranger.utils import * +from apache_ranger.model.ranger_user_mgmt import * +from apache_ranger.client.ranger_user_mgmt_client import * +from datetime import datetime + +## create a client to connect to Apache Ranger admin server +ranger_url = 'http://localhost:6080' +ranger_auth = ('admin', 'rangerR0cks!') + +# For Kerberos authentication +# +# from requests_kerberos import HTTPKerberosAuth +# +# ranger_auth = HTTPKerberosAuth() + + +print(f'\nUsing Ranger at {ranger_url}'); + +ranger = RangerClient(ranger_url, ranger_auth) + +user_mgmt = RangerUserMgmtClient(ranger) + + +print('\nListing users') + +users = user_mgmt.find_users() + +print(f' {len(users.list)} users found') + +for user in users.list: + print(f' id: {user.id}, name: {user.name}') + + +print('\nListing groups') + +groups = user_mgmt.find_groups() + +print(f' {len(groups.list)} groups found') + +for group in groups.list: + print(f' id: {group.id}, name: {group.name}') + +print('\nListing group-users') + +group_users = user_mgmt.find_group_users() + +print(f' {len(group_users.list)} group-users found') + +for group_user in group_users.list: + print(f' id: {group_user.id}, groupId: {group_user.parentGroupId}, userId: {group_user.userId}') + + +now = datetime.now() + +name_suffix = '-' + now.strftime('%Y%m%d-%H%M%S-%f') +user_name = 'test-user' + name_suffix +group_name = 'test-group' + name_suffix + + +user = RangerUser({ 'name': user_name, 'firstName': user_name, 'lastName': 'user', 'emailAddress': user_name + '@test.org', 'password': 'Welcome1', 'userRoleList': [ 'ROLE_USER' ], 'otherAttributes': '{ "dept": "test" }' }) + +print(f'\nCreating user: name={user.name}') + +created_user = user_mgmt.create_user(user) + +print(f' created user: {created_user}') + + +group = RangerGroup({ 'name': group_name, 'otherAttributes': '{ "dept": "test" }' }) + +print(f'\nCreating group: name={group.name}') + +created_group = user_mgmt.create_group(group) + +print(f' created group: {created_group}') + + +group_user = RangerGroupUser({ 'name': created_group.name, 'parentGroupId': created_group.id, 'userId': created_user.id }) + +print(f'\nAdding user {created_user.name} to group {created_group.name}') + +created_group_user = user_mgmt.create_group_user(group_user) + +print(f' created group-user: {created_group_user}') + + +print('\nListing group-users') + +group_users = user_mgmt.find_group_users() + +print(f' {len(group_users.list)} group-users found') + +for group_user in group_users.list: + print(f' id: {group_user.id}, groupId: {group_user.parentGroupId}, userId: {group_user.userId}') + + +print(f'\nListing users for group {group.name}') + +group_users = user_mgmt.get_group_users_for_group(group.name) + +print(f' group: {group_users.group}') +print(f' users: {group_users.users}') + + +print(f'\nDeleting group-user {created_group_user.id}') + +user_mgmt.delete_group_user_by_id(created_group_user.id) + + +print(f'\nDeleting group {group.name}') + +user_mgmt.delete_group_by_id(created_group.id, True) + + +print(f'\nDeleting user {user.name}') + +user_mgmt.delete_user_by_id(created_user.id, True)