This is an automated email from the ASF dual-hosted git repository.
rmani 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 f056eae1f RANGER-5008:Handle creation of federated user in Ranger
f056eae1f is described below
commit f056eae1fda73c17e4c5332160144829eb7be949
Author: Ramesh Mani <[email protected]>
AuthorDate: Sun Dec 8 19:54:39 2024 -0800
RANGER-5008:Handle creation of federated user in Ranger
---
.../apache/ranger/plugin/util/PasswordUtils.java | 118 +++++++++++++++++++++
.../main/java/org/apache/ranger/biz/UserMgr.java | 7 +-
.../main/java/org/apache/ranger/biz/XUserMgr.java | 16 +++
.../java/org/apache/ranger/biz/TestXUserMgr.java | 80 ++++++++++++++
4 files changed, 218 insertions(+), 3 deletions(-)
diff --git
a/agents-common/src/main/java/org/apache/ranger/plugin/util/PasswordUtils.java
b/agents-common/src/main/java/org/apache/ranger/plugin/util/PasswordUtils.java
index 546412b53..6cd4ee044 100644
---
a/agents-common/src/main/java/org/apache/ranger/plugin/util/PasswordUtils.java
+++
b/agents-common/src/main/java/org/apache/ranger/plugin/util/PasswordUtils.java
@@ -19,6 +19,8 @@ package org.apache.ranger.plugin.util;
import java.io.IOException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
+import java.util.ArrayList;
+import java.util.List;
import java.util.Map;
import javax.crypto.Cipher;
@@ -229,4 +231,120 @@ public class PasswordUtils {
}
return decryptedPwd;
}
+
+ /* Password Generator */
+ public static final class PasswordGenerator {
+ private static final String LOWER =
"abcdefghijklmnopqrstuvwxyz";
+ private static final String UPPER =
"ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+ private static final String DIGITS = "0123456789";
+ private static final String SYMBOLS = "!@#$%&*()_+-=[]|,./?><";
+ private final boolean useLower;
+ private final boolean useUpper;
+ private final boolean useDigits;
+ private final boolean useSymbols;
+
+ private PasswordGenerator(PasswordGeneratorBuilder builder) {
+ this.useLower = builder.useLower;
+ this.useUpper = builder.useUpper;
+ this.useDigits = builder.useDigits;
+ this.useSymbols = builder.useSymbols;
+ }
+
+ public static class PasswordGeneratorBuilder {
+ private boolean useLower;
+ private boolean useUpper;
+ private boolean useDigits;
+ private boolean useSymbols;
+
+ public PasswordGeneratorBuilder() {
+ this.useLower = false;
+ this.useUpper = false;
+ this.useDigits = false;
+ this.useSymbols = false;
+ }
+
+ /**
+ * @param useLower true in case you would like to
include lowercase
+ * characters (abc...xyz). Default
false.
+ * @return the builder for chaining.
+ */
+ public PasswordGeneratorBuilder useLower(boolean
useLower) {
+ this.useLower = useLower;
+ return this;
+ }
+
+ /**
+ * @param useUpper true in case you would like to
include uppercase
+ * characters (ABC...XYZ). Default
false.
+ * @return the builder for chaining.
+ */
+ public PasswordGeneratorBuilder useUpper(boolean
useUpper) {
+ this.useUpper = useUpper;
+ return this;
+ }
+
+ /**
+ * @param useDigits true in case you would like to
include digit
+ * characters (123...). Default false.
+ * @return the builder for chaining.
+ */
+ public PasswordGeneratorBuilder useDigits(boolean
useDigits) {
+ this.useDigits = useDigits;
+ return this;
+ }
+
+ /**
+ * @param useSymbols true in case you would like to
include
+ * punctuation characters (!@#...).
Default false.
+ * @return the builder for chaining.
+ */
+ public PasswordGeneratorBuilder useSymbols(boolean
useSymbols) {
+ this.useSymbols = useSymbols;
+ return this;
+ }
+
+ /**
+ * Get an object to use.
+ *
+ * @return the {@link PasswordGenerator}
+ * object.
+ */
+ public PasswordGenerator build() {
+ return new PasswordGenerator(this);
+ }
+ }
+
+ /**
+ * @param length the length of the password you would like to
generate.
+ * @return a password that uses the categories you define when
constructing
+ * the object with a probability.
+ */
+ public String generate(int length) {
+ StringBuilder password = new StringBuilder(length);
+ SecureRandom secureRandom = new SecureRandom();
+
+ List<String> charCategories = new ArrayList<>(4);
+ if (useLower) {
+ charCategories.add(LOWER);
+ }
+ if (useUpper) {
+ charCategories.add(UPPER);
+ }
+ if (useDigits) {
+ charCategories.add(DIGITS);
+ }
+ if (useSymbols) {
+ charCategories.add(SYMBOLS);
+ }
+
+ // Build the password.
+ for (int i = 0; i < length; i++) {
+ int idxCatagory = (i <
charCategories.size()) ? i : secureRandom.nextInt(charCategories.size());
+ String charCategory =
charCategories.get(idxCatagory);
+ int position =
secureRandom.nextInt(charCategory.length());
+ password.append(charCategory.charAt(position));
+ }
+ return new String(password);
+ }
+ }
}
diff --git a/security-admin/src/main/java/org/apache/ranger/biz/UserMgr.java
b/security-admin/src/main/java/org/apache/ranger/biz/UserMgr.java
index 07119dee3..f19c04994 100644
--- a/security-admin/src/main/java/org/apache/ranger/biz/UserMgr.java
+++ b/security-admin/src/main/java/org/apache/ranger/biz/UserMgr.java
@@ -1068,9 +1068,10 @@ public class UserMgr {
}
public VXPortalUser createDefaultAccountUser(VXPortalUser userProfile) {
- if (userProfile.getPassword() == null
- || userProfile.getPassword().trim().isEmpty()) {
-
userProfile.setUserSource(RangerCommonEnums.USER_EXTERNAL);
+ if (userProfile.getUserSource() !=
RangerCommonEnums.USER_FEDERATED) {
+ if (StringUtils.isBlank(userProfile.getPassword())) {
+
userProfile.setUserSource(RangerCommonEnums.USER_EXTERNAL);
+ }
}
// access control
checkAdminAccess();
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 cec829361..035070474 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
@@ -50,6 +50,7 @@ import org.apache.ranger.plugin.model.RangerPrincipal;
import org.apache.ranger.plugin.model.UserInfo;
import org.apache.ranger.plugin.store.EmbeddedServiceDefsUtil;
import org.apache.ranger.plugin.util.RangerUserStore;
+import org.apache.ranger.plugin.util.PasswordUtils.PasswordGenerator;
import org.apache.ranger.service.*;
import org.apache.ranger.ugsyncutil.model.GroupUserInfo;
import org.apache.ranger.ugsyncutil.model.UsersGroupRoleAssignments;
@@ -110,6 +111,7 @@ public class XUserMgr extends XUserMgrBase {
private static final String USER = "User";
private static final String GROUP = "Group";
private static final int MAX_DB_TRANSACTION_RETRIES = 5;
+ private static final int PASSWORD_LENGTH = 16;
@Autowired
RangerBizUtil msBizUtil;
@@ -187,6 +189,20 @@ public class XUserMgr extends XUserMgrBase {
public VXUser createXUser(VXUser vXUser) {
checkAdminAccess();
xaBizUtil.blockAuditorRoleUser();
+
+ if (vXUser.getUserSource() == RangerCommonEnums.USER_FEDERATED)
{
+ if (StringUtils.isEmpty(vXUser.getPassword())) {
+ PasswordGenerator passwordGenerator = new
PasswordGenerator.PasswordGeneratorBuilder()
+ .useLower(true)
+ .useUpper(true)
+ .useDigits(true)
+ .useSymbols(true)
+ .build();
+ String passWd =
passwordGenerator.generate(PASSWORD_LENGTH);
+ vXUser.setPassword(passWd);
+ }
+ }
+
validatePassword(vXUser);
String userName = vXUser.getName();
String firstName = vXUser.getFirstName();
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 647891ef3..2da5d3cd8 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
@@ -278,6 +278,23 @@ public class TestXUserMgr {
return vxUser;
}
+ private VXUser vxUserFederated() {
+ Collection<String> userRoleList = new ArrayList<String>();
+ userRoleList.add("ROLE_USER");
+ Collection<String> groupNameList = new ArrayList<String>();
+ groupNameList.add(groupName);
+ VXUser vxUser = new VXUser();
+ vxUser.setId(userId);
+ vxUser.setDescription("group test working");
+ vxUser.setName(userLoginID);
+ vxUser.setUserRoleList(userRoleList);
+ vxUser.setGroupNameList(groupNameList);
+ vxUser.setPassword(null);
+ vxUser.setEmailAddress("[email protected]");
+ vxUser.setUserSource(RangerCommonEnums.USER_FEDERATED);
+ return vxUser;
+ }
+
private XXUser xxUser(VXUser vxUser) {
XXUser xXUser = new XXUser();
xXUser.setId(userId);
@@ -4655,4 +4672,67 @@ public class TestXUserMgr {
Assert.assertNotNull(createdXUser);
Assert.assertEquals(createdXUser.getName(), vXUser.getName());
}
+
+ @Test
+ public void test01CreateXUser_federated() {
+ destroySession();
+ setup();
+ VXUser vxUser = vxUserFederated();
+ vxUser.setFirstName("user12");
+ vxUser.setLastName("test12");
+ Collection<Long> groupIdList = new ArrayList<Long>();
+ groupIdList.add(userId);
+ vxUser.setGroupIdList(groupIdList);
+ VXGroup vxGroup = vxGroup();
+ vxGroup.setName("user12Grp");
+ VXGroupUser vXGroupUser = new VXGroupUser();
+ vXGroupUser.setParentGroupId(userId);
+ vXGroupUser.setUserId(userId);
+ vXGroupUser.setName(vxGroup.getName());
+
Mockito.when(xGroupService.readResource(userId)).thenReturn(vxGroup);
+ Mockito.when(xGroupUserService.createResource((VXGroupUser)
Mockito.any())).thenReturn(vXGroupUser);
+ ArrayList<String> userRoleListVXPortaUser = getRoleList();
+ VXPortalUser vXPortalUser = new VXPortalUser();
+ vXPortalUser.setUserRoleList(userRoleListVXPortaUser);
+
Mockito.when(xUserService.createResource(vxUser)).thenReturn(vxUser);
+ XXModuleDefDao value = Mockito.mock(XXModuleDefDao.class);
+ Mockito.when(daoManager.getXXModuleDef()).thenReturn(value);
+ Mockito.when(userMgr.createDefaultAccountUser((VXPortalUser)
Mockito.any())).thenReturn(vXPortalUser);
+
Mockito.when(stringUtil.validateEmail("[email protected]")).thenReturn(true);
+ VXUser dbUser = xUserMgr.createXUser(vxUser);
+ Assert.assertNotNull(dbUser);
+ userId = dbUser.getId();
+ Assert.assertEquals(userId, dbUser.getId());
+ Assert.assertEquals(dbUser.getDescription(),
vxUser.getDescription());
+ Assert.assertEquals(dbUser.getName(), vxUser.getName());
+ Assert.assertEquals(dbUser.getUserRoleList(),
vxUser.getUserRoleList());
+ Assert.assertEquals(dbUser.getGroupNameList(),
+ vxUser.getGroupNameList());
+ Assert.assertNotNull(dbUser.getPassword());
+ Assert.assertEquals(dbUser.getUserSource(),
RangerCommonEnums.USER_FEDERATED);
+ Mockito.verify(xUserService).createResource(vxUser);
+
Mockito.when(xUserService.readResourceWithOutLogin(userId)).thenReturn(vxUser);
+
+ VXUser loggedInUser = vxUser();
+ List<String> loggedInUserRole = new ArrayList<String>();
+ loggedInUserRole.add(RangerConstants.ROLE_ADMIN);
+ loggedInUser.setId(8L);
+ loggedInUser.setName("testuser");
+ loggedInUser.setUserRoleList(loggedInUserRole);
+
Mockito.when(xUserService.getXUserByUserName("admin")).thenReturn(loggedInUser);
+
Mockito.when(restErrorUtil.createRESTException(HttpServletResponse.SC_FORBIDDEN,
"Logged-In user is not allowed to access requested user data",
true)).thenThrow(new WebApplicationException());
+ thrown.expect(WebApplicationException.class);
+ VXUser dbvxUser = xUserMgr.getXUser(userId);
+ Mockito.verify(userMgr).createDefaultAccountUser((VXPortalUser)
Mockito.any());
+ Assert.assertNotNull(dbvxUser);
+ Assert.assertEquals(userId, dbvxUser.getId());
+ Assert.assertEquals(dbvxUser.getDescription(),
vxUser.getDescription());
+ Assert.assertEquals(dbvxUser.getName(), vxUser.getName());
+
Assert.assertEquals(dbvxUser.getUserRoleList(),vxUser.getUserRoleList());
+
Assert.assertEquals(dbvxUser.getGroupIdList(),vxUser.getGroupIdList());
+
Assert.assertEquals(dbvxUser.getGroupNameList(),vxUser.getGroupNameList());
+ Assert.assertNotNull(dbvxUser.getPassword());
+ Assert.assertEquals(dbvxUser.getUserSource(),
RangerCommonEnums.USER_FEDERATED);
+ Mockito.verify(xUserService).readResourceWithOutLogin(userId);
+ }
}