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

dmitriusan pushed a commit to branch branch-2.6
in repository https://gitbox.apache.org/repos/asf/ambari.git


The following commit(s) were added to refs/heads/branch-2.6 by this push:
     new 12275a4  AMBARI-25268. implement configurable password policy for 
Ambari users (dlysnichenko) (#2956)
12275a4 is described below

commit 12275a46d69f559350a757de7f0825e8c78a0ea8
Author: Lisnichenko Dmitro <[email protected]>
AuthorDate: Tue Apr 30 20:44:29 2019 +0300

    AMBARI-25268. implement configurable password policy for Ambari users 
(dlysnichenko) (#2956)
---
 .../ambari/server/configuration/Configuration.java | 15 ++++++++++
 .../server/security/authorization/Users.java       | 21 ++++++++++++++
 .../server/security/authorization/TestUsers.java   | 32 ++++++++++++++++++++++
 3 files changed, 68 insertions(+)

diff --git 
a/ambari-server/src/main/java/org/apache/ambari/server/configuration/Configuration.java
 
b/ambari-server/src/main/java/org/apache/ambari/server/configuration/Configuration.java
index 352b9ae..f553905 100644
--- 
a/ambari-server/src/main/java/org/apache/ambari/server/configuration/Configuration.java
+++ 
b/ambari-server/src/main/java/org/apache/ambari/server/configuration/Configuration.java
@@ -515,6 +515,14 @@ public class Configuration {
       "agent.ssl", "true");
 
   /**
+   * Configurable password policy for Ambari users
+   */
+  @Markdown(
+      description = "Determines Ambari user password policy. Passwords should 
match the regex")
+  public static final ConfigurationProperty<String> PASSWORD_POLICY_REGEXP = 
new ConfigurationProperty<>(
+      "security.password.policy.regexp", ".*");
+
+  /**
    * Determines whether the Ambari Agent host names should be validated against
    * a regular expression to ensure that they are well-formed.
    */
@@ -4133,6 +4141,13 @@ public class Configuration {
     return getProperty(MYSQL_JAR_NAME);
   }
 
+  /**
+   * @return Configurable password policy for Ambari users
+   */
+  public String getPasswordPolicyRegexp() {
+    return getProperty(PASSWORD_POLICY_REGEXP);
+  }
+
   public JPATableGenerationStrategy getJPATableGenerationStrategy() {
     return JPATableGenerationStrategy.fromString(
         System.getProperty(SERVER_JDBC_GENERATE_TABLES.getKey()));
diff --git 
a/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/Users.java
 
b/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/Users.java
index 0b869a5..5013987 100644
--- 
a/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/Users.java
+++ 
b/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/Users.java
@@ -26,6 +26,7 @@ import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
+import java.util.regex.Pattern;
 
 import javax.inject.Inject;
 import javax.persistence.EntityManager;
@@ -187,6 +188,7 @@ public class Users {
     if (currentUserName == null) {
       throw new AmbariException("Authentication required. Please sign in.");
     }
+    validatePassword(newPassword);
 
     UserEntity currentUserEntity = 
userDAO.findLocalUserByName(currentUserName);
 
@@ -318,6 +320,9 @@ public class Users {
       throw new AmbariException("User " + existingUser.getUserName() + " 
already exists with type "
         + existingUser.getUserType());
     }
+    if (!StringUtils.isEmpty(password)) {
+      validatePassword(password);
+    }
 
     PrincipalTypeEntity principalTypeEntity = 
principalTypeDAO.findById(PrincipalTypeEntity.USER_PRINCIPAL_TYPE);
     if (principalTypeEntity == null) {
@@ -1041,4 +1046,20 @@ public class Users {
 
     return implicitPrivileges;
   }
+
+  /**
+   * Validates that password meets configured requirements according to 
ambari.properties.
+   * @param password the password
+   * @throws  IllegalArgumentException if password does not meet the password 
policy requirements
+   */
+  public void validatePassword(String password) {
+    if (StringUtils.isEmpty(password)) {
+      throw new IllegalArgumentException("The password does not meet the 
password policy requirements");
+    }
+    String regexp = configuration.getPasswordPolicyRegexp();
+    if (!StringUtils.isEmpty(regexp) && (!Pattern.matches(regexp,password))) {
+      final String msg = "The password does not meet the Ambari user password 
policy regexp:" + regexp;
+      throw new IllegalArgumentException(msg);
+    }
+  }
 }
diff --git 
a/ambari-server/src/test/java/org/apache/ambari/server/security/authorization/TestUsers.java
 
b/ambari-server/src/test/java/org/apache/ambari/server/security/authorization/TestUsers.java
index 364664d..fb60f80 100644
--- 
a/ambari-server/src/test/java/org/apache/ambari/server/security/authorization/TestUsers.java
+++ 
b/ambari-server/src/test/java/org/apache/ambari/server/security/authorization/TestUsers.java
@@ -23,12 +23,14 @@ import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNotSame;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
 
 import java.sql.SQLException;
 import java.util.List;
 
 import org.apache.ambari.server.AmbariException;
 import org.apache.ambari.server.H2DatabaseCleaner;
+import org.apache.ambari.server.configuration.Configuration;
 import org.apache.ambari.server.orm.GuiceJpaInitializer;
 import org.apache.ambari.server.orm.InMemoryDefaultTestModule;
 import org.apache.ambari.server.orm.dao.GroupDAO;
@@ -79,6 +81,8 @@ public class TestUsers {
   protected PrincipalDAO principalDAO;
   @Inject
   protected PasswordEncoder passwordEncoder;
+  @Inject
+  protected Configuration configuration;
 
   @Before
   public void setup() throws AmbariException {
@@ -156,6 +160,34 @@ public class TestUsers {
   }
 
   @Test
+  public void testValidatePassword() throws Exception {
+    try {
+      users.validatePassword(null);
+      fail("Null password should not be allowed");
+    } catch (IllegalArgumentException e) {
+      assertEquals("The password does not meet the password policy 
requirements", e.getLocalizedMessage());
+    }
+
+    try {
+      users.validatePassword("");
+      fail("Empty password should not be allowed");
+    } catch (IllegalArgumentException e) {
+      assertEquals("The password does not meet the password policy 
requirements", e.getLocalizedMessage());
+    }
+
+    //Minimum eight characters, at least one letter and one number:
+    configuration.setProperty(Configuration.PASSWORD_POLICY_REGEXP, 
"^(?=.*[A-Za-z])(?=.*\\d)[A-Za-z\\d]{8,}$");
+    try {
+      users.validatePassword("abc123");
+      fail("Should not pass validation");
+    } catch (IllegalArgumentException e) {
+      assertEquals("The password does not meet the Ambari user password policy 
regexp:^(?=.*[A-Za-z])(?=.*\\d)[A-Za-z\\d]{8,}$", e.getLocalizedMessage());
+    }
+
+    users.validatePassword("abcd1234");
+  }
+
+  @Test
   public void testRevokeAdminPrivilege() throws Exception {
     users.createUser("old_admin", "old_admin", UserType.LOCAL, true, true);
 

Reply via email to