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

mehul 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 9e12688  RANGER-2805 : fixed for creating role with non-existing 
group/user failing due to concurrent threads
9e12688 is described below

commit 9e1268863d82d5c63a899375d5aa06fdec6a7d53
Author: Dineshkumar Yadav <[email protected]>
AuthorDate: Thu Apr 23 15:44:22 2020 +0530

    RANGER-2805 : fixed for creating role with non-existing group/user failing 
due to concurrent threads
    
    Signed-off-by: Mehul Parikh <[email protected]>
---
 .../java/org/apache/ranger/biz/RoleRefUpdater.java | 248 +++++++++++++++++++--
 1 file changed, 227 insertions(+), 21 deletions(-)

diff --git 
a/security-admin/src/main/java/org/apache/ranger/biz/RoleRefUpdater.java 
b/security-admin/src/main/java/org/apache/ranger/biz/RoleRefUpdater.java
index bb68e32..ff8e2ba 100644
--- a/security-admin/src/main/java/org/apache/ranger/biz/RoleRefUpdater.java
+++ b/security-admin/src/main/java/org/apache/ranger/biz/RoleRefUpdater.java
@@ -20,6 +20,7 @@
 package org.apache.ranger.biz;
 
 import java.util.HashSet;
+import java.util.List;
 import java.util.Set;
 
 import org.apache.commons.collections.CollectionUtils;
@@ -29,6 +30,7 @@ import org.apache.commons.logging.LogFactory;
 import org.apache.ranger.common.MessageEnums;
 import org.apache.ranger.common.RESTErrorUtil;
 import org.apache.ranger.common.RangerCommonEnums;
+import org.apache.ranger.common.db.RangerTransactionSynchronizationAdapter;
 import org.apache.ranger.db.RangerDaoManager;
 import org.apache.ranger.db.XXRoleRefGroupDao;
 import org.apache.ranger.db.XXRoleRefRoleDao;
@@ -38,13 +40,14 @@ import org.apache.ranger.entity.XXRole;
 import org.apache.ranger.entity.XXRoleRefGroup;
 import org.apache.ranger.entity.XXRoleRefRole;
 import org.apache.ranger.entity.XXRoleRefUser;
+import org.apache.ranger.entity.XXTrxLog;
 import org.apache.ranger.entity.XXUser;
 import org.apache.ranger.plugin.model.RangerRole;
 import org.apache.ranger.service.RangerAuditFields;
+import org.apache.ranger.service.RangerTransactionService;
 import org.apache.ranger.service.XGroupService;
 import org.apache.ranger.service.XUserService;
 import org.apache.ranger.view.VXGroup;
-import org.apache.ranger.view.VXUser;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Component;
 
@@ -71,6 +74,15 @@ public class RoleRefUpdater {
     @Autowired
     XGroupService xGroupService;
 
+    @Autowired
+    RangerTransactionSynchronizationAdapter 
rangerTransactionSynchronizationAdapter;
+
+       @Autowired
+       RangerTransactionService transactionService;
+
+       @Autowired
+       RangerBizUtil xaBizUtil;
+
        public void createNewRoleMappingForRefTable(RangerRole rangerRole, 
Boolean createNonExistUserGroup) throws Exception {
                if (rangerRole == null) {
                        return;
@@ -99,29 +111,40 @@ public class RoleRefUpdater {
                                if (StringUtils.isBlank(roleUser)) {
                                        continue;
                                }
-                               VXUser vXUser = null;
+                               Long userId = null;
                                XXUser xUser = 
daoMgr.getXXUser().findByUserName(roleUser);
 
                                if (xUser == null) {
                                        if (createNonExistUserGroup) {
                                                LOG.warn("User specified in 
role does not exist in ranger admin, creating new user, User = "
                                                                + roleUser);
-                                               vXUser = 
xUserMgr.createExternalUser(roleUser);
+                                               // Schedule another transaction 
and let this transaction complete (and commit) successfully!
+                                               final RoleUserCreateContext 
roleUserCreateContext = new RoleUserCreateContext(roleUser, roleId);
+                                               Runnable CreateAndAssociateUser 
= new Runnable () {
+                                                       @Override
+                                                       public void run() {
+                                                               Runnable 
realTask = new Runnable () {
+                                                                       
@Override
+                                                                       public 
void run() {
+                                                                               
doCreateAndAssociateRoleUser(roleUserCreateContext);
+                                                                       }
+                                                               };
+                                                               
transactionService.scheduleToExecuteInOwnTransaction(realTask, 0L);
+                                                       }
+                        };
+                                               
rangerTransactionSynchronizationAdapter.executeOnTransactionCommit(CreateAndAssociateUser);
+
                                        } else {
                                                throw 
restErrorUtil.createRESTException("user with name: " + roleUser + " does not 
exist ",
                                                                
MessageEnums.INVALID_INPUT_DATA);
                                        }
                                }else {
-                                        vXUser = 
xUserService.populateViewBean(xUser);
+                                       userId = xUser.getId();
                                }
 
-                               XXRoleRefUser xRoleRefUser = 
rangerAuditFields.populateAuditFieldsForCreate(new XXRoleRefUser());
-
-                               xRoleRefUser.setRoleId(roleId);
-                               xRoleRefUser.setUserId(vXUser.getId());
-                               xRoleRefUser.setUserName(roleUser);
-                               xRoleRefUser.setUserType(0);
-                               daoMgr.getXXRoleRefUser().create(xRoleRefUser);
+                               if(null != userId) {
+                                       
userRoleAssociation(roleId,userId,roleUser);
+                               }
                        }
                }
 
@@ -131,7 +154,7 @@ public class RoleRefUpdater {
                                if (StringUtils.isBlank(roleGroup)) {
                                        continue;
                                }
-                               VXGroup vXGroup = null;
+                               Long groupId = null;
                                XXGroup xGroup = 
daoMgr.getXXGroup().findByGroupName(roleGroup);
 
                                if (xGroup == null) {
@@ -140,23 +163,36 @@ public class RoleRefUpdater {
                                                                + roleGroup);
                                                VXGroup vxGroupNew = new 
VXGroup();
                                                vxGroupNew.setName(roleGroup);
+                                               
vxGroupNew.setDescription(roleGroup);
                                                
vxGroupNew.setGroupSource(RangerCommonEnums.GROUP_EXTERNAL);
-                                               vXGroup = 
xUserMgr.createXGroup(vxGroupNew);
+                                               // Schedule another transaction 
and let this transaction complete (and commit) successfully!
+                                               final RoleGroupCreateContext 
roleGroupCreateContext = new RoleGroupCreateContext(vxGroupNew, roleId);
+
+                                               Runnable 
createAndAssociateRoleGroup = new Runnable() {
+                            @Override
+                            public void run() {
+                                Runnable realTask = new Runnable() {
+                                    @Override
+                                    public void run() {
+                                        
doCreateAndAssociateRoleGroup(roleGroupCreateContext);
+                                    }
+                                };
+                                
transactionService.scheduleToExecuteInOwnTransaction(realTask, 0L);
+                            }
+                        };
+                                               
rangerTransactionSynchronizationAdapter.executeOnTransactionCommit(createAndAssociateRoleGroup);
+
                                        } else {
                                                throw 
restErrorUtil.createRESTException("group with name: " + roleGroup + " does not 
exist ",
                                                                
MessageEnums.INVALID_INPUT_DATA);
                                        }
                                }else {
-                                       vXGroup = 
xGroupService.populateViewBean(xGroup);
+                                       groupId = xGroup.getId();
                                }
 
-                               XXRoleRefGroup xRoleRefGroup = 
rangerAuditFields.populateAuditFieldsForCreate(new XXRoleRefGroup());
-
-                               xRoleRefGroup.setRoleId(roleId);
-                               xRoleRefGroup.setGroupId(vXGroup.getId());
-                               xRoleRefGroup.setGroupName(roleGroup);
-                               xRoleRefGroup.setGroupType(0);
-                               
daoMgr.getXXRoleRefGroup().create(xRoleRefGroup);
+                               if(null != groupId) {
+                                       groupRoleAssociation(roleId, groupId, 
roleGroup);
+                               }
                        }
                }
 
@@ -210,4 +246,174 @@ public class RoleRefUpdater {
                }
                return true;
        }
+
+       public void groupRoleAssociation(Long roleId, Long groupId, String 
groupName) {
+               if(LOG.isDebugEnabled()) {
+                       LOG.debug("===> groupRoleAssociation()");
+               }
+
+               XXRoleRefGroup xRoleRefGroup = 
rangerAuditFields.populateAuditFieldsForCreate(new XXRoleRefGroup());
+               xRoleRefGroup.setRoleId(roleId);
+               xRoleRefGroup.setGroupId(groupId);
+               xRoleRefGroup.setGroupName(groupName);
+               xRoleRefGroup.setGroupType(0);
+               daoMgr.getXXRoleRefGroup().create(xRoleRefGroup);
+       }
+
+       private static final class RoleGroupCreateContext {
+               final VXGroup group;
+               final Long roleId;
+
+               RoleGroupCreateContext(VXGroup group, Long roleId) {
+                       this.group = group;
+                       this.roleId = roleId;
+               }
+
+               @Override
+               public String toString() {
+                       return "{group=" + group + ", roleId=" + roleId + "}";
+               }
+       }
+
+       void doCreateAndAssociateRoleGroup(final RoleGroupCreateContext 
context) {
+               if (LOG.isDebugEnabled()) {
+                       LOG.debug("===> doCreateAndAssociateRoleGroup()");
+               }
+               XXGroup xGroup = 
daoMgr.getXXGroup().findByGroupName(context.group.getName());
+
+               if (xGroup != null) {
+                       groupRoleAssociation(context.roleId, xGroup.getId(), 
context.group.getName());
+               } else {
+                       try {
+                               // Create group
+                               VXGroup vXGroup = 
xGroupService.createXGroupWithOutLogin(context.group);
+                               if (null != vXGroup) {
+                                       List<XXTrxLog> trxLogList = 
xGroupService.getTransactionLog(vXGroup, "create");
+                                       xaBizUtil.createTrxLog(trxLogList);
+                               }
+                       } catch (Exception exception) {
+                               LOG.error("Failed to create Group or to 
associate group and role, RoleGroupContext:[" + context + "]",
+                                               exception);
+                       } finally {
+                               // This transaction may still fail at commit 
time because another transaction
+                               // has already created the group
+                               // So, associate the group to role in a 
different transaction
+                               Runnable associateRoleGroup = new Runnable() {
+                    @Override
+                                       public void run() {
+                                               Runnable realTask = new 
Runnable() {
+                                                       @Override
+                                                       public void run() {
+                                                               
doAssociateRoleGroup(context);
+                                                       }
+                                               };
+                                               
transactionService.scheduleToExecuteInOwnTransaction(realTask, 0L);
+                                       }
+                };
+                               
rangerTransactionSynchronizationAdapter.executeOnTransactionCompletion(associateRoleGroup);
+                       }
+               }
+       }
+
+       void doAssociateRoleGroup(final RoleGroupCreateContext context) {
+               if(LOG.isDebugEnabled()) {
+                       LOG.debug("===> doAssociateRoleGroup()");
+               }
+               XXGroup xGroup = 
daoMgr.getXXGroup().findByGroupName(context.group.getName());
+
+               if (xGroup == null) {
+                       LOG.error("No Group created!! Irrecoverable error! 
RoleGroupContext:[" + context + "]");
+               } else {
+                       try {
+                               groupRoleAssociation(context.roleId, 
xGroup.getId(), context.group.getName());
+                       } catch (Exception exception) {
+                               LOG.error("Failed to associate group and role, 
RoleGroupContext:[" + context + "]", exception);
+                       }
+               }
+       }
+
+       private static final class RoleUserCreateContext {
+               final String userName;
+               final Long roleId;
+
+               RoleUserCreateContext(String userName, Long roleId) {
+                       this.userName = userName;
+                       this.roleId = roleId;
+               }
+
+               @Override
+               public String toString() {
+                       return "{userName=" + userName + ", roleId=" + roleId + 
"}";
+               }
+       }
+
+       public void userRoleAssociation(Long roleId, Long userId, String 
userName) {
+               if(LOG.isDebugEnabled()) {
+                       LOG.debug("===> userRoleAssociation()");
+               }
+               XXRoleRefUser xRoleRefUser = 
rangerAuditFields.populateAuditFieldsForCreate(new XXRoleRefUser());
+               xRoleRefUser.setRoleId(roleId);
+               xRoleRefUser.setUserId(userId);
+               xRoleRefUser.setUserName(userName);
+               xRoleRefUser.setUserType(0);
+               daoMgr.getXXRoleRefUser().create(xRoleRefUser);
+               if(LOG.isDebugEnabled()) {
+                       LOG.debug("<=== userRoleAssociation()");
+               }
+       }
+
+       void doCreateAndAssociateRoleUser(final RoleUserCreateContext context) {
+               if (LOG.isDebugEnabled()) {
+                       LOG.debug("===> doCreateAndAssociateRoleUser()");
+               }
+               XXUser xUser = 
daoMgr.getXXUser().findByUserName(context.userName);
+
+               if (xUser != null) {
+                       userRoleAssociation(context.roleId, xUser.getId(), 
context.userName);
+               } else {
+                       try {
+                               // Create External user
+                               
xUserMgr.createServiceConfigUser(context.userName);
+                       } catch (Exception exception) {
+                               LOG.error("Failed to create User or to 
associate user and role, RoleUserContext:[" + context + "]",
+                                               exception);
+                       } finally {
+                               // This transaction may still fail at commit 
time because another transaction
+                               // has already created the user
+                               // So, associate the user to role in a 
different transaction
+                               Runnable associateRoleUser = new Runnable() {
+                                       @Override
+                                       public void run() {
+                                               Runnable realTask = new 
Runnable() {
+                                                       @Override
+                                                       public void run() {
+                                                               
doAssociateRoleUser(context);
+                                                       }
+                                               };
+                                               
transactionService.scheduleToExecuteInOwnTransaction(realTask, 0L);
+                                       }
+                };
+                               
rangerTransactionSynchronizationAdapter.executeOnTransactionCompletion(associateRoleUser);
+                       }
+               }
+
+       }
+
+       void doAssociateRoleUser(final RoleUserCreateContext context) {
+               if(LOG.isDebugEnabled()) {
+                       LOG.debug("===> doAssociateRoleUser()");
+               }
+               XXUser xUser = 
daoMgr.getXXUser().findByUserName(context.userName);
+
+               if (xUser == null) {
+                       LOG.error("No User created!! Irrecoverable error! 
RoleUserContext:[" + context + "]");
+               } else {
+                       try {
+                               userRoleAssociation(context.roleId, 
xUser.getId(), context.userName);
+                       } catch (Exception exception) {
+                               LOG.error("Failed to associate user and role, 
RoleUserContext:[" + context + "]", exception);
+                       }
+               }
+       }
+
 }

Reply via email to