You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ranger.apache.org by dh...@apache.org on 2026/09/22 16:51:20 UTC
(ranger) branch master updated: RANGER-5800 : UserGroup API require additional checks (#1245)
This is an automated email from the ASF dual-hosted git repository.
dhavalshah9131 pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/ranger.git
The following commit(s) were added to refs/heads/master by this push:
new fb2025626 RANGER-5800 : UserGroup API require additional checks (#1245)
fb2025626 is described below
commit fb2025626862761c7a70929dfbd5ef1e803c310b
Author: dhavalshah9131 <dh...@gmail.com>
AuthorDate: Tue Sep 22 22:21:14 2026 +0530
RANGER-5800 : UserGroup API require additional checks (#1245)
* RANGER-5800 : UserGroup API require additional checks
* RANGER-5800 : UserGroup API require additional checks UI changes
---------
Co-authored-by: Dhaval Shah <dh...@gmail.com>
Co-authored-by: Dhaval Rajpara <dh...@apache.org>
---
.../main/java/org/apache/ranger/biz/XUserMgr.java | 21 +++++++++++
.../users_details/UserForm.jsx | 11 ++++--
.../java/org/apache/ranger/biz/TestXUserMgr.java | 44 ++++++++++++++++++++++
3 files changed, 72 insertions(+), 4 deletions(-)
diff --git a/security-admin/src/main/java/org/apache/ranger/biz/XUserMgr.java b/security-admin/src/main/java/org/apache/ranger/biz/XUserMgr.java
index 900d30398..3e97601ab 100755
--- a/security-admin/src/main/java/org/apache/ranger/biz/XUserMgr.java
+++ b/security-admin/src/main/java/org/apache/ranger/biz/XUserMgr.java
@@ -1197,6 +1197,7 @@ public VXUser updateXUser(VXUser vXUser) {
vXUser.setPassword(hiddenPasswordString);
Long userId = vXUser.getId();
+ validateGroupMembershipChangeAccess(userId, groupIdList);
List<Long> groupUsersToRemove = new ArrayList<>();
List<XXTrxLogV2> groupUserTrxLogs = createOrDelGrpUserWithUpdatedGrpId(vXUser, groupIdList, userId, groupUsersToRemove);
@@ -3201,6 +3202,26 @@ protected void validatePassword(VXUser vXUser) {
}
}
+ private void validateGroupMembershipChangeAccess(Long userId, Collection<Long> groupIdList) {
+ if (groupIdList == null || userId == null) {
+ return;
+ }
+ UserSessionBase session = ContextUtil.getCurrentUserSession();
+ if (session == null || session.isUserAdmin()) {
+ return;
+ }
+ List<Long> existingGroupIds = daoManager.getXXGroupUser().findGroupIdListByUserId(userId);
+ Set<Long> requestedGroupIds = new HashSet<>(groupIdList);
+ Set<Long> currentGroupIds = new HashSet<>();
+ if (CollectionUtils.isNotEmpty(existingGroupIds)) {
+ currentGroupIds.addAll(existingGroupIds);
+ }
+ if (!requestedGroupIds.equals(currentGroupIds)) {
+ throw restErrorUtil.create403RESTException(
+ "Logged-in user is not permitted to modify group membership.");
+ }
+ }
+
private List<XXTrxLogV2> createOrDelGrpUserWithUpdatedGrpId(VXUser vXUser, Collection<Long> groupIdList, Long userId, List<Long> groupUsersToRemove) {
Collection<String> groupNamesSet = new HashSet<>();
List<XXTrxLogV2> trxLogList = new ArrayList<>();
diff --git a/security-admin/src/main/webapp/react-webapp/src/views/UserGroupRoleListing/users_details/UserForm.jsx b/security-admin/src/main/webapp/react-webapp/src/views/UserGroupRoleListing/users_details/UserForm.jsx
index 4b0a15ff3..cede7266b 100644
--- a/security-admin/src/main/webapp/react-webapp/src/views/UserGroupRoleListing/users_details/UserForm.jsx
+++ b/security-admin/src/main/webapp/react-webapp/src/views/UserGroupRoleListing/users_details/UserForm.jsx
@@ -37,7 +37,7 @@ import {
UserTypes
} from "Utils/XAEnums";
import { toast } from "react-toastify";
-import { InfoIcon, getUserAccessRoleList, serverError } from "Utils/XAUtils";
+import { InfoIcon, getUserAccessRoleList, isSystemAdmin, serverError } from "Utils/XAUtils";
import { getUserProfile, setUserProfile } from "Utils/appState";
import { cloneDeep, has, isEmpty, isUndefined } from "lodash";
import { SyncSourceDetails } from "Views/UserGroupRoleListing/SyncSourceDetails";
@@ -90,6 +90,7 @@ function UserForm(props) {
const isExternalOrFederatedUser =
userInfo?.userSource == UserTypes.USER_EXTERNAL.value ||
userInfo?.userSource == UserTypes.USER_FEDERATED.value;
+ const isInternalUser = userInfo?.userSource == UserTypes.USER_INTERNAL.value;
const handleSubmit = async (formData) => {
let userFormData = {};
@@ -243,9 +244,7 @@ function UserForm(props) {
loadOptions={loadOptions}
defaultOptions
isMulti
- isDisabled={
- isEditView && userInfo && isExternalOrFederatedUser ? true : false
- }
+ isDisabled={disabledGroupField()}
styles={selectInputCustomStyles}
tabSelectsValue={false}
placeholder="Select Groups"
@@ -290,6 +289,10 @@ function UserForm(props) {
return disabledUserRoleField;
};
+ const disabledGroupField = () => {
+ return !(isSystemAdmin() && isEditView && isInternalUser)
+ };
+
const userRoleListData = () => {
return getUserAccessRoleList();
};
diff --git a/security-admin/src/test/java/org/apache/ranger/biz/TestXUserMgr.java b/security-admin/src/test/java/org/apache/ranger/biz/TestXUserMgr.java
index a316b440c..e98960850 100644
--- a/security-admin/src/test/java/org/apache/ranger/biz/TestXUserMgr.java
+++ b/security-admin/src/test/java/org/apache/ranger/biz/TestXUserMgr.java
@@ -471,6 +471,50 @@ public void test05UpdateXUser() {
Assertions.assertNotNull(dbvxUser);
}
+ @Test
+ public void testUpdateXUser_KeyAdminCannotChangeGroupMembership() {
+ destroySession();
+ setupKeyAdmin();
+
+ VXUser vxUser = vxUser();
+ vxUser.setId(userId);
+ vxUser.setFirstName("test");
+ vxUser.setUserRoleList(Collections.singletonList(RangerConstants.ROLE_USER));
+
+ VXPortalUser vXPortalUser = userProfile();
+ vXPortalUser.setUserRoleList(Collections.singletonList(RangerConstants.ROLE_USER));
+
+ Mockito.when(userMgr.getUserProfileByLoginId(vxUser.getName())).thenReturn(vXPortalUser);
+ Mockito.when(xUserService.readResource(userId)).thenReturn(vxUser);
+
+ XXPortalUser xXPortalUser = xxPortalUser(vXPortalUser);
+ Mockito.when(userMgr.updateUserWithPass(Mockito.any())).thenReturn(xXPortalUser);
+ Mockito.when(xUserService.updateResource(vxUser)).thenReturn(vxUser);
+ Mockito.when(xUserService.getTransactionLog(
+ Mockito.any(VXUser.class),
+ Mockito.any(),
+ Mockito.anyInt()))
+ .thenReturn(new ArrayList<>());
+
+ VXUser loggedInUser = vxUser();
+ loggedInUser.setName(keyadminLoginID);
+ loggedInUser.setUserRoleList(Collections.singletonList(RangerConstants.ROLE_KEY_ADMIN));
+ Mockito.when(xUserService.getXUserByUserName(keyadminLoginID)).thenReturn(loggedInUser);
+
+ XXGroupUserDao xxGroupUserDao = Mockito.mock(XXGroupUserDao.class);
+ Mockito.when(daoManager.getXXGroupUser()).thenReturn(xxGroupUserDao);
+ Mockito.when(xxGroupUserDao.findGroupIdListByUserId(userId))
+ .thenReturn(Collections.emptyList());
+
+ vxUser.setGroupIdList(Collections.singletonList(105L));
+
+ Mockito.when(restErrorUtil.create403RESTException(
+ "Logged-in user is not permitted to modify group membership."))
+ .thenThrow(new WebApplicationException());
+
+ Assertions.assertThrows(WebApplicationException.class, () -> xUserMgr.updateXUser(vxUser));
+ }
+
@Test
public void test06ModifyUserVisibilitySetOne() {
setup();