You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ranger.apache.org by pr...@apache.org on 2026/08/25 08:34:30 UTC

(ranger) 01/01: RANGER-5756: Make J10056 skip automatic reactivation of disabled external users (#1176)

This is an automated email from the ASF dual-hosted git repository.

pradeepagrawal8184 pushed a commit to branch RANGER-5756_210
in repository https://gitbox.apache.org/repos/asf/ranger.git

commit dfe6e2845c52ddc2e3ad14a2303b34b75c1727ef
Author: PradeeP AgrawaL <pr...@apache.org>
AuthorDate: Tue Aug 25 13:12:56 2026 +0530

    RANGER-5756: Make J10056 skip automatic reactivation of disabled external users (#1176)
---
 .../PatchForExternalUserStatusUpdate_J10056.java   | 133 +++++++++----------
 ...estPatchForExternalUserStatusUpdate_J10056.java | 143 +++++++++++++++++++++
 2 files changed, 202 insertions(+), 74 deletions(-)

diff --git a/security-admin/src/main/java/org/apache/ranger/patch/PatchForExternalUserStatusUpdate_J10056.java b/security-admin/src/main/java/org/apache/ranger/patch/PatchForExternalUserStatusUpdate_J10056.java
index f4a122b38..dcd167fdc 100644
--- a/security-admin/src/main/java/org/apache/ranger/patch/PatchForExternalUserStatusUpdate_J10056.java
+++ b/security-admin/src/main/java/org/apache/ranger/patch/PatchForExternalUserStatusUpdate_J10056.java
@@ -17,8 +17,6 @@
 
 package org.apache.ranger.patch;
 
-import java.util.List;
-
 import org.apache.commons.collections.CollectionUtils;
 import org.apache.ranger.common.RangerCommonEnums;
 import org.apache.ranger.db.RangerDaoManager;
@@ -28,81 +26,68 @@
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.beans.factory.annotation.Qualifier;
 import org.springframework.stereotype.Component;
-import org.springframework.transaction.PlatformTransactionManager;
-import org.springframework.transaction.TransactionDefinition;
-import org.springframework.transaction.TransactionStatus;
-import org.springframework.transaction.support.TransactionCallback;
-import org.springframework.transaction.support.TransactionTemplate;
+
+import java.util.List;
 
 @Component
 public class PatchForExternalUserStatusUpdate_J10056 extends BaseLoader {
+    private static final Logger logger = LoggerFactory.getLogger(PatchForExternalUserStatusUpdate_J10056.class);
+
+    @Autowired
+    private RangerDaoManager daoManager;
+
+    public static void main(String[] args) {
+        try {
+            PatchForExternalUserStatusUpdate_J10056 loader = (PatchForExternalUserStatusUpdate_J10056) CLIUtil.getBean(PatchForExternalUserStatusUpdate_J10056.class);
+
+            loader.init();
+
+            while (loader.isMoreToProcess()) {
+                loader.load();
+            }
+
+            logger.info("Load complete. Exiting!!!");
+
+            System.exit(0);
+        } catch (Exception e) {
+            logger.error("Error loading", e);
+
+            System.exit(1);
+        }
+    }
+
+    @Override
+    public void init() throws Exception {
+        // Do Nothing
+    }
+
+    @Override
+    public void printStats() {
+        // TODO Auto-generated method stub
+    }
+
+    @Override
+    public void execLoad() {
+        updateExternalUserStatus();
+    }
+
+    private void updateExternalUserStatus() {
+        XXPortalUserDao    dao           = this.daoManager.getXXPortalUser();
+        List<XXPortalUser> xXPortalUsers = dao.findByUserSourceAndStatus(RangerCommonEnums.USER_EXTERNAL, RangerCommonEnums.ACT_STATUS_DISABLED);
+
+        if (CollectionUtils.isEmpty(xXPortalUsers)) {
+            return;
+        }
+
+        // Do not bulk-reactivate external disabled users. Disabled is a valid administrative state (see XUserREST.modifyUserActiveStatus),
+        // and this patch cannot distinguish accounts left disabled by an old usersync bug from accounts disabled on purpose.
+        logger.warn("updateExternalUserStatus(): Skipping automatic reactivation of {} external disabled user(s). Re-enable affected accounts explicitly via Ranger Admin if required.", xXPortalUsers.size());
 
-	private static final Logger logger = LoggerFactory.getLogger(PatchForExternalUserStatusUpdate_J10056.class);
-
-	@Autowired
-	private RangerDaoManager daoManager;
-
-	@Autowired
-	@Qualifier(value = "transactionManager")
-	PlatformTransactionManager txManager;
-
-	public static void main(String[] args) {
-		try {
-			PatchForExternalUserStatusUpdate_J10056 loader = (PatchForExternalUserStatusUpdate_J10056) CLIUtil
-					.getBean(PatchForExternalUserStatusUpdate_J10056.class);
-			loader.init();
-			while (loader.isMoreToProcess()) {
-				loader.load();
-			}
-			logger.info("Load complete. Exiting!!!");
-			System.exit(0);
-		} catch (Exception e) {
-			logger.error("Error loading", e);
-			System.exit(1);
-		}
-	}
-
-	@Override
-	public void init() throws Exception {
-		// Do Nothing
-	}
-
-	@Override
-	public void printStats() {
-		// TODO Auto-generated method stub
-	}
-
-	@Override
-	public void execLoad() {
-		updateExternalUserStatus();
-	}
-
-	private void updateExternalUserStatus() {
-		XXPortalUserDao dao = this.daoManager.getXXPortalUser();
-		List<XXPortalUser> xXPortalUsers = dao.findByUserSourceAndStatus(RangerCommonEnums.USER_EXTERNAL,RangerCommonEnums.ACT_STATUS_DISABLED);
-
-		if(CollectionUtils.isNotEmpty(xXPortalUsers)) {
-			for (XXPortalUser xxPortalUser : xXPortalUsers) {
-				if (xxPortalUser != null) {
-					xxPortalUser.setStatus(RangerCommonEnums.ACT_STATUS_ACTIVE);
-					TransactionTemplate txTemplate = new TransactionTemplate(txManager);
-					txTemplate.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);
-					try {
-						txTemplate.execute(new TransactionCallback<Object>() {
-							@Override
-							public Object doInTransaction(TransactionStatus status) {
-								dao.update(xxPortalUser, true);
-								return null;
-							}
-						});
-					} catch (Throwable ex) {
-						logger.error("updateExternalUserStatus(): Failed to update DB for user: " + xxPortalUser.getLoginId() + " ", ex);
-						throw new RuntimeException(ex);
-					}
-				}
-			}
-		}
-	}
+        for (XXPortalUser xxPortalUser : xXPortalUsers) {
+            if (xxPortalUser != null) {
+                logger.warn("updateExternalUserStatus(): Left unchanged (loginId={})", xxPortalUser.getLoginId());
+            }
+        }
+    }
 }
diff --git a/security-admin/src/test/java/org/apache/ranger/patch/TestPatchForExternalUserStatusUpdate_J10056.java b/security-admin/src/test/java/org/apache/ranger/patch/TestPatchForExternalUserStatusUpdate_J10056.java
new file mode 100644
index 000000000..c16772d29
--- /dev/null
+++ b/security-admin/src/test/java/org/apache/ranger/patch/TestPatchForExternalUserStatusUpdate_J10056.java
@@ -0,0 +1,143 @@
+/*
+ * 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.
+ */
+
+package org.apache.ranger.patch;
+
+import org.apache.ranger.biz.ServiceDBStore;
+import org.apache.ranger.common.JSONUtil;
+import org.apache.ranger.common.RangerCommonEnums;
+import org.apache.ranger.common.RangerValidatorFactory;
+import org.apache.ranger.common.StringUtil;
+import org.apache.ranger.db.RangerDaoManager;
+import org.apache.ranger.db.XXPortalUserDao;
+import org.apache.ranger.entity.XXPortalUser;
+import org.apache.ranger.plugin.store.EmbeddedServiceDefsUtil;
+import org.apache.ranger.service.RangerPolicyService;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.MethodOrderer;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.TestMethodOrder;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.MockedStatic;
+import org.mockito.Mockito;
+import org.mockito.junit.jupiter.MockitoExtension;
+
+import java.lang.reflect.Field;
+import java.util.ArrayList;
+import java.util.Collections;
+
+/**
+ * @generated by Cursor
+ * @description <Unit Test for PatchForExternalUserStatusUpdate_J10056 class>
+ */
+@ExtendWith(MockitoExtension.class)
+@TestMethodOrder(MethodOrderer.MethodName.class)
+public class TestPatchForExternalUserStatusUpdate_J10056 {
+    private static void setIfPresent(Object target, String fieldName, Object value) {
+        try {
+            Field f = target.getClass().getDeclaredField(fieldName);
+            f.setAccessible(true);
+            f.set(target, value);
+        } catch (NoSuchFieldException ignored) {
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    @Test
+    public void testExecLoadAndPrintStats() {
+        try (MockedStatic<EmbeddedServiceDefsUtil> utilMock = Mockito.mockStatic(EmbeddedServiceDefsUtil.class)) {
+            EmbeddedServiceDefsUtil util = Mockito.mock(EmbeddedServiceDefsUtil.class);
+            utilMock.when(EmbeddedServiceDefsUtil::instance).thenReturn(util);
+
+            PatchForExternalUserStatusUpdate_J10056 patch = new PatchForExternalUserStatusUpdate_J10056();
+            ServiceDBStore svcStore = Mockito.mock(ServiceDBStore.class);
+            RangerDaoManager daoMgr = Mockito.mock(RangerDaoManager.class);
+            XXPortalUserDao xxPortalUserDao = Mockito.mock(XXPortalUserDao.class);
+            Mockito.when(daoMgr.getXXPortalUser()).thenReturn(xxPortalUserDao);
+            Mockito.when(xxPortalUserDao.findByUserSourceAndStatus(Mockito.anyInt(), Mockito.anyInt()))
+                    .thenReturn(Collections.emptyList());
+
+            setIfPresent(patch, "daoManager", daoMgr);
+            setIfPresent(patch, "svcDBStore", svcStore);
+            setIfPresent(patch, "jsonUtil", new JSONUtil());
+            setIfPresent(patch, "policyService", Mockito.mock(RangerPolicyService.class));
+            setIfPresent(patch, "stringUtil", new StringUtil());
+            setIfPresent(patch, "validatorFactory", Mockito.mock(RangerValidatorFactory.class));
+            setIfPresent(patch, "svcStore", svcStore);
+
+            patch.execLoad();
+            patch.printStats();
+        }
+    }
+
+    @Test
+    public void testExecLoad_DoesNotReactivateDisabledExternalUsers() {
+        PatchForExternalUserStatusUpdate_J10056 patch = new PatchForExternalUserStatusUpdate_J10056();
+
+        RangerDaoManager daoMgr = Mockito.mock(RangerDaoManager.class);
+        XXPortalUserDao xxPortalUserDao = Mockito.mock(XXPortalUserDao.class);
+        Mockito.when(daoMgr.getXXPortalUser()).thenReturn(xxPortalUserDao);
+
+        XXPortalUser user = new XXPortalUser();
+        user.setLoginId("u1");
+        user.setStatus(RangerCommonEnums.ACT_STATUS_DISABLED);
+        Mockito.when(xxPortalUserDao.findByUserSourceAndStatus(Mockito.anyInt(), Mockito.anyInt()))
+                .thenReturn(Collections.singletonList(user));
+
+        setIfPresent(patch, "daoManager", daoMgr);
+
+        patch.execLoad();
+
+        Assertions.assertEquals(RangerCommonEnums.ACT_STATUS_DISABLED, user.getStatus());
+        Mockito.verify(xxPortalUserDao, Mockito.never()).update(Mockito.any(XXPortalUser.class), Mockito.eq(true));
+    }
+
+    @Test
+    public void testExecLoad_NoUsers_NoAction() {
+        PatchForExternalUserStatusUpdate_J10056 patch = new PatchForExternalUserStatusUpdate_J10056();
+        RangerDaoManager daoMgr = Mockito.mock(RangerDaoManager.class);
+        XXPortalUserDao xxPortalUserDao = Mockito.mock(XXPortalUserDao.class);
+        Mockito.when(daoMgr.getXXPortalUser()).thenReturn(xxPortalUserDao);
+        Mockito.when(xxPortalUserDao.findByUserSourceAndStatus(Mockito.anyInt(), Mockito.anyInt()))
+                .thenReturn(Collections.emptyList());
+        setIfPresent(patch, "daoManager", daoMgr);
+
+        patch.execLoad();
+
+        Mockito.verify(xxPortalUserDao, Mockito.never()).update(Mockito.any(XXPortalUser.class), Mockito.eq(true));
+    }
+
+    @Test
+    public void testExecLoad_NullUserEntry_Skipped() {
+        PatchForExternalUserStatusUpdate_J10056 patch = new PatchForExternalUserStatusUpdate_J10056();
+        RangerDaoManager daoMgr = Mockito.mock(RangerDaoManager.class);
+        XXPortalUserDao xxPortalUserDao = Mockito.mock(XXPortalUserDao.class);
+        Mockito.when(daoMgr.getXXPortalUser()).thenReturn(xxPortalUserDao);
+        Mockito.when(xxPortalUserDao.findByUserSourceAndStatus(Mockito.anyInt(), Mockito.anyInt()))
+                .thenReturn(new ArrayList<XXPortalUser>() {
+                    {
+                        add(null);
+                    }
+                });
+        setIfPresent(patch, "daoManager", daoMgr);
+
+        patch.execLoad();
+
+        Mockito.verify(xxPortalUserDao, Mockito.never()).update(Mockito.any(XXPortalUser.class), Mockito.eq(true));
+    }
+}