This is an automated email from the ASF dual-hosted git repository.
dmitriusan pushed a commit to branch branch-2.7
in repository https://gitbox.apache.org/repos/asf/ambari.git
The following commit(s) were added to refs/heads/branch-2.7 by this push:
new 87e65b5 AMBARI-25268. implement configurable password policy for
Ambari users (dlysnichenko) (#2954)
87e65b5 is described below
commit 87e65b5f1cec08849939033c0958bbf39733c727
Author: Lisnichenko Dmitro <[email protected]>
AuthorDate: Tue Apr 30 20:43:57 2019 +0300
AMBARI-25268. implement configurable password policy for Ambari users
(dlysnichenko) (#2954)
---
.../ambari/server/configuration/Configuration.java | 15 +++++++++++++++
.../controller/internal/UserResourceProvider.java | 8 +++++++-
.../ambari/server/security/authorization/Users.java | 19 +++++++++++--------
.../server/security/authorization/TestUsers.java | 21 +++++++++++++++++----
4 files changed, 50 insertions(+), 13 deletions(-)
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 09d90e8..747236c 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
@@ -505,6 +505,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.
*/
@@ -3999,6 +4007,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/controller/internal/UserResourceProvider.java
b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/UserResourceProvider.java
index 1177b57..29f1749 100644
---
a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/UserResourceProvider.java
+++
b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/UserResourceProvider.java
@@ -379,6 +379,12 @@ public class UserResourceProvider extends
AbstractControllerResourceProvider imp
String username = request.getUsername();
String displayName =
StringUtils.defaultIfEmpty(request.getDisplayName(), username);
String localUserName =
StringUtils.defaultIfEmpty(request.getLocalUserName(), username);
+ String password = request.getPassword();
+ // Setting a user's the password here is to allow for backward
compatibility with pre-Ambari-3.0
+ // versions so that the contract for REST API V1 is maintained.
+ if (!StringUtils.isEmpty(password)) {
+ users.validatePassword(password);
+ }
UserEntity userEntity = users.createUser(username, localUserName,
displayName, request.isActive());
if (userEntity != null) {
@@ -388,7 +394,7 @@ public class UserResourceProvider extends
AbstractControllerResourceProvider imp
// Setting a user's the password here is to allow for backward
compatibility with pre-Ambari-3.0
// versions so that the contract for REST API V1 is maintained.
- if (!StringUtils.isEmpty(request.getPassword())) {
+ if (!StringUtils.isEmpty(password)) {
// This is performed as a user administrator since the
authorization check was done prior
// to executing #createResourcesAuthorized.
addOrUpdateLocalAuthenticationSource(true, userEntity,
request.getPassword(), null);
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 0974a72..3f81c52 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
@@ -28,6 +28,7 @@ import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
+import java.util.regex.Pattern;
import javax.persistence.EntityManager;
import javax.persistence.OptimisticLockException;
@@ -1746,20 +1747,22 @@ public class Users {
}
/**
- * Validates the password meets configured requirements.
+ * Validates the password meets configured requirements according
ambari.properties.
+ *
* <p>
- * In the future this may be configurable. For now just make sure the
password is not empty.
*
* @param password the password
- * @return true if the password is valid; false otherwise
+ * @throws IllegalArgumentException if password does not meet the password
policy requirements
*/
- public boolean validatePassword(String password) throws AmbariException {
- // TODO: validate the new password...
+ public void validatePassword(String password) {
if (StringUtils.isEmpty(password)) {
- throw new AmbariException("The new password does not meet the Ambari
password requirements");
+ 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);
}
-
- return true;
}
/**
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 0c1ce05..24cd6d7 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
@@ -35,6 +35,7 @@ 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.ldap.domain.AmbariLdapConfiguration;
import org.apache.ambari.server.ldap.service.AmbariLdapConfigurationProvider;
import org.apache.ambari.server.orm.GuiceJpaInitializer;
@@ -94,6 +95,8 @@ public class TestUsers {
protected PrincipalDAO principalDAO;
@Inject
protected PasswordEncoder passwordEncoder;
+ @Inject
+ protected Configuration configuration;
@Before
public void setup() throws AmbariException {
@@ -213,16 +216,26 @@ public class TestUsers {
try {
users.modifyAuthentication(foundLocalAuthenticationEntity, "user", null,
true);
fail("Null password should not be allowed");
- } catch (AmbariException e) {
- assertEquals("The new password does not meet the Ambari password
requirements", e.getLocalizedMessage());
+ } catch (IllegalArgumentException e) {
+ assertEquals("The password does not meet the password policy
requirements", e.getLocalizedMessage());
}
try {
users.modifyAuthentication(foundLocalAuthenticationEntity, "user", "",
false);
fail("Empty password should not be allowed");
- } catch (AmbariException e) {
- assertEquals("The new password does not meet the Ambari password
requirements", e.getLocalizedMessage());
+ } 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.modifyAuthentication(foundLocalAuthenticationEntity, "user",
"abc123", false);
+ 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.modifyAuthentication(foundLocalAuthenticationEntity, "user",
"abcd1234", false);
}
@Test