Repository: ambari Updated Branches: refs/heads/branch-feature-AMBARI-20859 d57ebbc2d -> d6b271e6b
AMBARI-21221. Update Pam Authentication process to work with improved user management facility (rlevas) Project: http://git-wip-us.apache.org/repos/asf/ambari/repo Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/d6b271e6 Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/d6b271e6 Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/d6b271e6 Branch: refs/heads/branch-feature-AMBARI-20859 Commit: d6b271e6bbcafbe57831890c9f8aa5386a57c8c3 Parents: d57ebbc Author: Robert Levas <[email protected]> Authored: Fri Oct 20 10:03:32 2017 -0400 Committer: Robert Levas <[email protected]> Committed: Fri Oct 20 10:03:32 2017 -0400 ---------------------------------------------------------------------- ambari-server/docs/configuration/index.md | 2 +- .../server/configuration/Configuration.java | 2 +- .../ambari/server/controller/AmbariServer.java | 2 +- .../AccountDisabledException.java | 2 +- .../AmbariAuthenticationEventHandlerImpl.java | 5 +- .../AmbariAuthenticationException.java | 17 +- .../AmbariAuthenticationProvider.java | 55 ++-- .../AmbariBasicAuthenticationFilter.java | 2 +- .../AmbariLocalAuthenticationProvider.java | 52 ++-- ...lidUsernamePasswordCombinationException.java | 12 +- .../TooManyLoginFailuresException.java | 2 +- .../authentication/UserNotFoundException.java | 8 +- .../jwt/AmbariJwtAuthenticationFilter.java | 2 +- .../jwt/AmbariJwtAuthenticationProvider.java | 50 +-- .../AmbariKerberosAuthenticationFilter.java | 2 +- .../pam/AmbariPamAuthenticationProvider.java | 302 +++++++++++++++++++ .../pam/PamAuthenticationFactory.java | 21 +- .../AmbariPamAuthenticationProvider.java | 237 --------------- .../PamAuthenticationException.java | 36 --- .../server/security/authorization/Users.java | 17 +- .../AmbariPamAuthenticationProviderTest.java | 277 +++++++++++++++++ .../AmbariPamAuthenticationProviderTest.java | 177 ----------- 22 files changed, 736 insertions(+), 546 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/ambari/blob/d6b271e6/ambari-server/docs/configuration/index.md ---------------------------------------------------------------------- diff --git a/ambari-server/docs/configuration/index.md b/ambari-server/docs/configuration/index.md index 73d6fd0..514e9ed 100644 --- a/ambari-server/docs/configuration/index.md +++ b/ambari-server/docs/configuration/index.md @@ -129,7 +129,7 @@ The following are the properties which can be used to configure Ambari. | client.api.ssl.port | The port that client connections will use with the REST API when using SSL. The Ambari Web client runs on this port if SSL is enabled. |`8443` | | client.api.ssl.truststore_name | The name of the truststore used when the Ambari Server REST API is protected by SSL. |`https.keystore.p12` | | client.api.ssl.truststore_type | The type of the keystore file specified in `client.api.ssl.truststore_name`. Self-signed certificates can be `PKCS12` while CA signed certificates are `JKS` |`PKCS12` | -| client.security | The type of authentication mechanism used by Ambari.<br/><br/>The following are examples of valid values:<ul><li>`local`<li>`ldap`</ul> | | +| client.security | The type of authentication mechanism used by Ambari.<br/><br/>The following are examples of valid values:<ul><li>`local`<li>`ldap`<li>`pam`</ul> | | | client.threadpool.size.max | The size of the Jetty connection pool used for handling incoming REST API requests. This should be large enough to handle requests from both web browsers and embedded Views. |`25` | | common.services.path | The location on the Ambari Server where common service resources exist. Stack services share the common service files.<br/><br/>The following are examples of valid values:<ul><li>`/var/lib/ambari-server/resources/common-services`</ul> | | | custom.action.definitions | The location on the Ambari Server where custom actions are defined. |`/var/lib/ambari-server/resources/custom_action_definitions` | http://git-wip-us.apache.org/repos/asf/ambari/blob/d6b271e6/ambari-server/src/main/java/org/apache/ambari/server/configuration/Configuration.java ---------------------------------------------------------------------- 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 2b14b4d..205debc 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 @@ -813,7 +813,7 @@ public class Configuration { * @see ClientSecurityType */ @Markdown( - examples = { "local", "ldap" }, + examples = { "local", "ldap", "pam" }, description = "The type of authentication mechanism used by Ambari.") public static final ConfigurationProperty<String> CLIENT_SECURITY = new ConfigurationProperty<>( "client.security", null); http://git-wip-us.apache.org/repos/asf/ambari/blob/d6b271e6/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariServer.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariServer.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariServer.java index bb8e0fe..b29cfc3 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariServer.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariServer.java @@ -102,8 +102,8 @@ import org.apache.ambari.server.security.SecurityFilter; import org.apache.ambari.server.security.authentication.AmbariAuthenticationEventHandlerImpl; import org.apache.ambari.server.security.authentication.AmbariLocalAuthenticationProvider; import org.apache.ambari.server.security.authentication.jwt.AmbariJwtAuthenticationProvider; +import org.apache.ambari.server.security.authentication.pam.AmbariPamAuthenticationProvider; import org.apache.ambari.server.security.authorization.AmbariLdapAuthenticationProvider; -import org.apache.ambari.server.security.authorization.AmbariPamAuthenticationProvider; import org.apache.ambari.server.security.authorization.AmbariUserAuthorizationFilter; import org.apache.ambari.server.security.authorization.PermissionHelper; import org.apache.ambari.server.security.authorization.Users; http://git-wip-us.apache.org/repos/asf/ambari/blob/d6b271e6/ambari-server/src/main/java/org/apache/ambari/server/security/authentication/AccountDisabledException.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/security/authentication/AccountDisabledException.java b/ambari-server/src/main/java/org/apache/ambari/server/security/authentication/AccountDisabledException.java index 4a88f46..18551c3 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/security/authentication/AccountDisabledException.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/security/authentication/AccountDisabledException.java @@ -22,6 +22,6 @@ package org.apache.ambari.server.security.authentication; */ public class AccountDisabledException extends AmbariAuthenticationException { public AccountDisabledException(String username) { - super(username, "The account is disabled"); + super(username, "The account is disabled", false); } } http://git-wip-us.apache.org/repos/asf/ambari/blob/d6b271e6/ambari-server/src/main/java/org/apache/ambari/server/security/authentication/AmbariAuthenticationEventHandlerImpl.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/security/authentication/AmbariAuthenticationEventHandlerImpl.java b/ambari-server/src/main/java/org/apache/ambari/server/security/authentication/AmbariAuthenticationEventHandlerImpl.java index e651d22..8ff39e0 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/security/authentication/AmbariAuthenticationEventHandlerImpl.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/security/authentication/AmbariAuthenticationEventHandlerImpl.java @@ -97,19 +97,22 @@ public class AmbariAuthenticationEventHandlerImpl implements AmbariAuthenticatio String message; String logMessage; Integer consecutiveFailures = null; + boolean incrementFailureCount; if (cause == null) { username = null; message = "Unknown cause"; + incrementFailureCount = false; } else { username = cause.getUsername(); message = cause.getLocalizedMessage(); + incrementFailureCount = cause.isCredentialFailure(); } if (!StringUtils.isEmpty(username)) { // Only increment the authentication failure count if the authentication filter declares to // do so. - if(filter.shouldIncrementFailureCount()) { + if(incrementFailureCount && filter.shouldIncrementFailureCount()) { // Increment the user's consecutive authentication failure count. consecutiveFailures = users.incrementConsecutiveAuthenticationFailures(username); http://git-wip-us.apache.org/repos/asf/ambari/blob/d6b271e6/ambari-server/src/main/java/org/apache/ambari/server/security/authentication/AmbariAuthenticationException.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/security/authentication/AmbariAuthenticationException.java b/ambari-server/src/main/java/org/apache/ambari/server/security/authentication/AmbariAuthenticationException.java index fb18b9c..f659f19 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/security/authentication/AmbariAuthenticationException.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/security/authentication/AmbariAuthenticationException.java @@ -27,17 +27,30 @@ import org.springframework.security.core.AuthenticationException; public class AmbariAuthenticationException extends AuthenticationException { private final String username; - public AmbariAuthenticationException(String username, String message) { + /** + * A boolean value indicating whether the faulire was due to invalid credentials (<code>true</code>) or not (<code>false</code>) + * <p> + * An invalid credential failure will count towards a user's authentication failure count. + */ + private final boolean credentialFailure; + + public AmbariAuthenticationException(String username, String message, boolean credentialFailure) { super(message); this.username = username; + this.credentialFailure = credentialFailure; } - public AmbariAuthenticationException(String username, String message, Throwable throwable) { + public AmbariAuthenticationException(String username, String message, boolean credentialFailure, Throwable throwable) { super(message, throwable); this.username = username; + this.credentialFailure = credentialFailure; } public String getUsername() { return username; } + + public boolean isCredentialFailure() { + return credentialFailure; + } } http://git-wip-us.apache.org/repos/asf/ambari/blob/d6b271e6/ambari-server/src/main/java/org/apache/ambari/server/security/authentication/AmbariAuthenticationProvider.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/security/authentication/AmbariAuthenticationProvider.java b/ambari-server/src/main/java/org/apache/ambari/server/security/authentication/AmbariAuthenticationProvider.java index d3d5b88..71fa175 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/security/authentication/AmbariAuthenticationProvider.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/security/authentication/AmbariAuthenticationProvider.java @@ -37,8 +37,12 @@ import org.springframework.security.authentication.AuthenticationProvider; public abstract class AmbariAuthenticationProvider implements AuthenticationProvider { private static final Logger LOG = LoggerFactory.getLogger(AmbariAuthenticationProvider.class); - private Users users; - private Configuration configuration; + /** + * Helper object to provide logic for working with users. + */ + private final Users users; + + private final Configuration configuration; protected AmbariAuthenticationProvider(Users users, Configuration configuration) { this.users = users; @@ -46,40 +50,28 @@ public abstract class AmbariAuthenticationProvider implements AuthenticationProv } /** - * Gets the {@link UserEntity} for the user with the specified username. - * <p> - * The entity is validated such that the account is allowed to log in before returning. For example, - * if the account is not active, no user may not login as that account. + * Validates the user account such that the user is allowed to log in. * - * @param userName - * @return + * @param userEntity the user entity + * @param userName the Ambari username */ - protected UserEntity getUserEntity(String userName) { - LOG.debug("Loading user by name: {}", userName); - UserEntity userEntity = users.getUserEntity(userName); - + protected void validateLogin(UserEntity userEntity, String userName) { if (userEntity == null) { - LOG.info("User not found: {}", userName); + LOG.info("User not found"); throw new UserNotFoundException(userName); - } - - if (!userEntity.getActive()) { - LOG.info("User account is disabled: {}", userName); - throw new AccountDisabledException(userName); - } + } else { + if (!userEntity.getActive()) { + LOG.info("User account is disabled: {}", userName); + throw new AccountDisabledException(userName); + } - int maxConsecutiveFailures = configuration.getMaxAuthenticationFailures(); - if (maxConsecutiveFailures > 0 && userEntity.getConsecutiveFailures() >= maxConsecutiveFailures) { - LOG.info("User account is locked out due to too many authentication failures ({}/{}): {}", - userEntity.getConsecutiveFailures(), maxConsecutiveFailures, userName); - if (configuration.showLockedOutUserMessage()) { + int maxConsecutiveFailures = configuration.getMaxAuthenticationFailures(); + if (maxConsecutiveFailures > 0 && userEntity.getConsecutiveFailures() >= maxConsecutiveFailures) { + LOG.info("User account is locked out due to too many authentication failures ({}/{}): {}", + userEntity.getConsecutiveFailures(), maxConsecutiveFailures, userName); throw new TooManyLoginFailuresException(userName); - } else { - throw new InvalidUsernamePasswordCombinationException(userName); } } - - return userEntity; } /** @@ -103,4 +95,11 @@ public abstract class AmbariAuthenticationProvider implements AuthenticationProv return null; } + protected Users getUsers() { + return users; + } + + protected Configuration getConfiguration() { + return configuration; + } } http://git-wip-us.apache.org/repos/asf/ambari/blob/d6b271e6/ambari-server/src/main/java/org/apache/ambari/server/security/authentication/AmbariBasicAuthenticationFilter.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/security/authentication/AmbariBasicAuthenticationFilter.java b/ambari-server/src/main/java/org/apache/ambari/server/security/authentication/AmbariBasicAuthenticationFilter.java index f617a60..faa5116 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/security/authentication/AmbariBasicAuthenticationFilter.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/security/authentication/AmbariBasicAuthenticationFilter.java @@ -159,7 +159,7 @@ public class AmbariBasicAuthenticationFilter extends BasicAuthenticationFilter i LOG.warn("Error occurred during decoding authorization header.", e); } - cause = new AmbariAuthenticationException(username, authException.getMessage(), authException); + cause = new AmbariAuthenticationException(username, authException.getMessage(), false, authException); } eventHandler.onUnsuccessfulAuthentication(this, servletRequest, servletResponse, cause); http://git-wip-us.apache.org/repos/asf/ambari/blob/d6b271e6/ambari-server/src/main/java/org/apache/ambari/server/security/authentication/AmbariLocalAuthenticationProvider.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/security/authentication/AmbariLocalAuthenticationProvider.java b/ambari-server/src/main/java/org/apache/ambari/server/security/authentication/AmbariLocalAuthenticationProvider.java index 7ef6524..3ffa3e8 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/security/authentication/AmbariLocalAuthenticationProvider.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/security/authentication/AmbariLocalAuthenticationProvider.java @@ -42,49 +42,37 @@ import com.google.inject.Inject; public class AmbariLocalAuthenticationProvider extends AmbariAuthenticationProvider { private static final Logger LOG = LoggerFactory.getLogger(AmbariLocalAuthenticationProvider.class); - private Users users; private PasswordEncoder passwordEncoder; - private Configuration configuration; @Inject public AmbariLocalAuthenticationProvider(Users users, PasswordEncoder passwordEncoder, Configuration configuration) { super(users, configuration); - this.users = users; this.passwordEncoder = passwordEncoder; - this.configuration = configuration; } @Override public Authentication authenticate(Authentication authentication) throws AuthenticationException { - String userName = authentication.getName().trim(); - - UserEntity userEntity; - try { - userEntity = getUserEntity(userName); - - if (userEntity == null) { - LOG.info("User not found: {}", userName); - throw new InvalidUsernamePasswordCombinationException(userName); - } - } - catch(UserNotFoundException e) { - // Do not give away information about the existence or status of a user - throw new InvalidUsernamePasswordCombinationException(userName, e); - } - catch (AccountDisabledException | TooManyLoginFailuresException e) { - if (configuration.showLockedOutUserMessage()) { - throw e; - } else { - // Do not give away information about the existence or status of a user - throw new InvalidUsernamePasswordCombinationException(userName, e); - } + if (authentication.getName() == null) { + LOG.info("Authentication failed: no username provided"); + throw new InvalidUsernamePasswordCombinationException(""); } + String userName = authentication.getName().trim(); + if (authentication.getCredentials() == null) { LOG.info("Authentication failed: no credentials provided: {}", userName); throw new InvalidUsernamePasswordCombinationException(userName); } + Users users = getUsers(); + + UserEntity userEntity = users.getUserEntity(userName); + + if (userEntity == null) { + LOG.info("User not found: {}", userName); + throw new InvalidUsernamePasswordCombinationException(userName); + } + UserAuthenticationEntity authenticationEntity = getAuthenticationEntity(userEntity, UserAuthenticationType.LOCAL); if (authenticationEntity != null) { String password = authenticationEntity.getAuthenticationKey(); @@ -94,6 +82,18 @@ public class AmbariLocalAuthenticationProvider extends AmbariAuthenticationProvi // The user was authenticated, return the authenticated user object LOG.debug("Authentication succeeded - a matching username and password were found: {}", userName); + try { + validateLogin(userEntity, userName); + } + catch (AccountDisabledException | TooManyLoginFailuresException e) { + if (getConfiguration().showLockedOutUserMessage()) { + throw e; + } else { + // Do not give away information about the existence or status of a user + throw new InvalidUsernamePasswordCombinationException(userName, false, e); + } + } + User user = new User(userEntity); Authentication auth = new AmbariUserAuthentication(password, user, users.getUserAuthorities(userEntity)); auth.setAuthenticated(true); http://git-wip-us.apache.org/repos/asf/ambari/blob/d6b271e6/ambari-server/src/main/java/org/apache/ambari/server/security/authentication/InvalidUsernamePasswordCombinationException.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/security/authentication/InvalidUsernamePasswordCombinationException.java b/ambari-server/src/main/java/org/apache/ambari/server/security/authentication/InvalidUsernamePasswordCombinationException.java index cb1babd..640c4cc 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/security/authentication/InvalidUsernamePasswordCombinationException.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/security/authentication/InvalidUsernamePasswordCombinationException.java @@ -23,10 +23,18 @@ public class InvalidUsernamePasswordCombinationException extends AmbariAuthentic public static final String MESSAGE = "Unable to sign in. Invalid username/password combination."; public InvalidUsernamePasswordCombinationException(String username) { - super(username, MESSAGE); + super(username, MESSAGE, true); + } + + public InvalidUsernamePasswordCombinationException(String username, boolean incrementFailureCount) { + super(username, MESSAGE, incrementFailureCount); } public InvalidUsernamePasswordCombinationException(String username, Throwable t) { - super(username, MESSAGE, t); + super(username, MESSAGE, true, t); + } + + public InvalidUsernamePasswordCombinationException(String username, boolean incrementFailureCount, Throwable t) { + super(username, MESSAGE, incrementFailureCount, t); } } http://git-wip-us.apache.org/repos/asf/ambari/blob/d6b271e6/ambari-server/src/main/java/org/apache/ambari/server/security/authentication/TooManyLoginFailuresException.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/security/authentication/TooManyLoginFailuresException.java b/ambari-server/src/main/java/org/apache/ambari/server/security/authentication/TooManyLoginFailuresException.java index b172079..1a111d8 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/security/authentication/TooManyLoginFailuresException.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/security/authentication/TooManyLoginFailuresException.java @@ -22,6 +22,6 @@ package org.apache.ambari.server.security.authentication; */ public class TooManyLoginFailuresException extends AmbariAuthenticationException { public TooManyLoginFailuresException(String username) { - super(username, "Too many authentication failures"); + super(username, "Too many authentication failures", false); } } http://git-wip-us.apache.org/repos/asf/ambari/blob/d6b271e6/ambari-server/src/main/java/org/apache/ambari/server/security/authentication/UserNotFoundException.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/security/authentication/UserNotFoundException.java b/ambari-server/src/main/java/org/apache/ambari/server/security/authentication/UserNotFoundException.java index 0760d9b..683312e 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/security/authentication/UserNotFoundException.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/security/authentication/UserNotFoundException.java @@ -26,18 +26,18 @@ public class UserNotFoundException extends AmbariAuthenticationException { public static final String MESSAGE = "User does not exist."; public UserNotFoundException(String userName) { - super(userName, MESSAGE); + super(userName, MESSAGE, false); } public UserNotFoundException(String userName, Throwable cause) { - super(userName, MESSAGE, cause); + super(userName, MESSAGE, false, cause); } public UserNotFoundException(String username, String message) { - super(username, message); + super(username, message, false); } public UserNotFoundException(String username, String message, Throwable throwable) { - super(username, message, throwable); + super(username, message, false, throwable); } } http://git-wip-us.apache.org/repos/asf/ambari/blob/d6b271e6/ambari-server/src/main/java/org/apache/ambari/server/security/authentication/jwt/AmbariJwtAuthenticationFilter.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/security/authentication/jwt/AmbariJwtAuthenticationFilter.java b/ambari-server/src/main/java/org/apache/ambari/server/security/authentication/jwt/AmbariJwtAuthenticationFilter.java index dcaf3e8..72796ff 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/security/authentication/jwt/AmbariJwtAuthenticationFilter.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/security/authentication/jwt/AmbariJwtAuthenticationFilter.java @@ -235,7 +235,7 @@ public class AmbariJwtAuthenticationFilter implements AmbariAuthenticationFilter if (e instanceof AmbariAuthenticationException) { cause = (AmbariAuthenticationException) e; } else { - cause = new AmbariAuthenticationException(null, e.getMessage(), e); + cause = new AmbariAuthenticationException(null, e.getMessage(), false, e); } eventHandler.onUnsuccessfulAuthentication(this, httpServletRequest, httpServletResponse, cause); http://git-wip-us.apache.org/repos/asf/ambari/blob/d6b271e6/ambari-server/src/main/java/org/apache/ambari/server/security/authentication/jwt/AmbariJwtAuthenticationProvider.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/security/authentication/jwt/AmbariJwtAuthenticationProvider.java b/ambari-server/src/main/java/org/apache/ambari/server/security/authentication/jwt/AmbariJwtAuthenticationProvider.java index 9a5b825..672444e 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/security/authentication/jwt/AmbariJwtAuthenticationProvider.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/security/authentication/jwt/AmbariJwtAuthenticationProvider.java @@ -21,9 +21,11 @@ import org.apache.ambari.server.AmbariException; import org.apache.ambari.server.configuration.Configuration; import org.apache.ambari.server.orm.entities.UserAuthenticationEntity; import org.apache.ambari.server.orm.entities.UserEntity; +import org.apache.ambari.server.security.authentication.AccountDisabledException; import org.apache.ambari.server.security.authentication.AmbariAuthenticationException; import org.apache.ambari.server.security.authentication.AmbariAuthenticationProvider; import org.apache.ambari.server.security.authentication.AmbariUserAuthentication; +import org.apache.ambari.server.security.authentication.TooManyLoginFailuresException; import org.apache.ambari.server.security.authentication.UserNotFoundException; import org.apache.ambari.server.security.authorization.User; import org.apache.ambari.server.security.authorization.UserAuthenticationType; @@ -46,11 +48,6 @@ public class AmbariJwtAuthenticationProvider extends AmbariAuthenticationProvide private static final Logger LOG = LoggerFactory.getLogger(AmbariJwtAuthenticationProvider.class); /** - * Helper object to provide logic for working with users. - */ - private Users users; - - /** * Constructor. * * @param users the users helper @@ -59,28 +56,28 @@ public class AmbariJwtAuthenticationProvider extends AmbariAuthenticationProvide @Inject public AmbariJwtAuthenticationProvider(Users users, Configuration configuration) { super(users, configuration); - this.users = users; } @Override public Authentication authenticate(Authentication authentication) throws AuthenticationException { - String userName = authentication.getName().trim(); + if (authentication.getName() == null) { + LOG.info("Authentication failed: no username provided"); + throw new AmbariAuthenticationException(null, "Unexpected error due to missing username", false); + } - UserEntity userEntity; - try { - userEntity = getUserEntity(userName); + String userName = authentication.getName().trim(); - if (userEntity == null) { - LOG.info("User not found: {}", userName); - throw new UserNotFoundException(userName, "Cannot find user from JWT. Please, ensure LDAP is configured and users are synced."); - } - } catch (UserNotFoundException e) { - throw new UserNotFoundException(userName, "Cannot find user from JWT. Please, ensure LDAP is configured and users are synced.", e); + if (authentication.getCredentials() == null) { + LOG.info("Authentication failed: no credentials provided: {}", userName); + throw new AmbariAuthenticationException(userName, "Unexpected error due to missing JWT token", false); } - if (authentication.getCredentials() == null) { - LOG.info("Authentication failed: no token provided: {}", userName); - throw new AmbariAuthenticationException(userName, "Unexpected error due to missing JWT token"); + Users users = getUsers(); + UserEntity userEntity = users.getUserEntity(userName); + + if (userEntity == null) { + LOG.info("User not found: {}", userName); + throw new UserNotFoundException(userName, "Cannot find user from JWT. Please, ensure LDAP is configured and users are synced."); } // If the user was found and allowed to log in, make sure that user is allowed to authentcate using a JWT token. @@ -100,7 +97,7 @@ public class AmbariJwtAuthenticationProvider extends AmbariAuthenticationProvide authOK = true; } catch (AmbariException e) { LOG.error(String.format("Failed to add the JWT authentication method for %s: %s", userName, e.getLocalizedMessage()), e); - throw new AmbariAuthenticationException(userName, "Unexpected error has occurred", e); + throw new AmbariAuthenticationException(userName, "Unexpected error has occurred", false, e); } } } @@ -108,6 +105,19 @@ public class AmbariJwtAuthenticationProvider extends AmbariAuthenticationProvide if (authOK) { // The user was authenticated, return the authenticated user object LOG.debug("Authentication succeeded - a matching user was found: {}", userName); + + // Ensure the user account is allowed to log in + try { + validateLogin(userEntity, userName); + } catch (AccountDisabledException | TooManyLoginFailuresException e) { + if (getConfiguration().showLockedOutUserMessage()) { + throw e; + } else { + // Do not give away information about the existence or status of a user + throw new AmbariAuthenticationException(userName, "Unexpected error due to missing JWT token", false); + } + } + User user = new User(userEntity); Authentication auth = new AmbariUserAuthentication(authentication.getCredentials().toString(), user, users.getUserAuthorities(userEntity)); auth.setAuthenticated(true); http://git-wip-us.apache.org/repos/asf/ambari/blob/d6b271e6/ambari-server/src/main/java/org/apache/ambari/server/security/authentication/kerberos/AmbariKerberosAuthenticationFilter.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/security/authentication/kerberos/AmbariKerberosAuthenticationFilter.java b/ambari-server/src/main/java/org/apache/ambari/server/security/authentication/kerberos/AmbariKerberosAuthenticationFilter.java index 41275a5..0e59ad2 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/security/authentication/kerberos/AmbariKerberosAuthenticationFilter.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/security/authentication/kerberos/AmbariKerberosAuthenticationFilter.java @@ -95,7 +95,7 @@ public class AmbariKerberosAuthenticationFilter extends SpnegoAuthenticationProc if (e instanceof AmbariAuthenticationException) { cause = (AmbariAuthenticationException) e; } else { - cause = new AmbariAuthenticationException(null, e.getLocalizedMessage(), e); + cause = new AmbariAuthenticationException(null, e.getLocalizedMessage(), false, e); } eventHandler.onUnsuccessfulAuthentication(AmbariKerberosAuthenticationFilter.this, httpServletRequest, httpServletResponse, cause); } http://git-wip-us.apache.org/repos/asf/ambari/blob/d6b271e6/ambari-server/src/main/java/org/apache/ambari/server/security/authentication/pam/AmbariPamAuthenticationProvider.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/security/authentication/pam/AmbariPamAuthenticationProvider.java b/ambari-server/src/main/java/org/apache/ambari/server/security/authentication/pam/AmbariPamAuthenticationProvider.java new file mode 100644 index 0000000..824fbdf --- /dev/null +++ b/ambari-server/src/main/java/org/apache/ambari/server/security/authentication/pam/AmbariPamAuthenticationProvider.java @@ -0,0 +1,302 @@ +/* + * 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.ambari.server.security.authentication.pam; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashSet; +import java.util.Set; + +import org.apache.ambari.server.AmbariException; +import org.apache.ambari.server.configuration.Configuration; +import org.apache.ambari.server.orm.entities.GroupEntity; +import org.apache.ambari.server.orm.entities.MemberEntity; +import org.apache.ambari.server.orm.entities.UserAuthenticationEntity; +import org.apache.ambari.server.orm.entities.UserEntity; +import org.apache.ambari.server.security.ClientSecurityType; +import org.apache.ambari.server.security.authentication.AccountDisabledException; +import org.apache.ambari.server.security.authentication.AmbariAuthenticationException; +import org.apache.ambari.server.security.authentication.AmbariAuthenticationProvider; +import org.apache.ambari.server.security.authentication.AmbariUserAuthentication; +import org.apache.ambari.server.security.authentication.InvalidUsernamePasswordCombinationException; +import org.apache.ambari.server.security.authentication.TooManyLoginFailuresException; +import org.apache.ambari.server.security.authorization.GroupType; +import org.apache.ambari.server.security.authorization.UserAuthenticationType; +import org.apache.ambari.server.security.authorization.Users; +import org.apache.commons.lang.StringUtils; +import org.jvnet.libpam.PAM; +import org.jvnet.libpam.PAMException; +import org.jvnet.libpam.UnixUser; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.AuthenticationException; + +import com.google.inject.Inject; + +/** + * Provides PAM user authentication logic for Ambari Server + * <p> + * It is expected that PAM is properly configured in the underlying operating system for this + * authentication provider to work properly. + */ +public class AmbariPamAuthenticationProvider extends AmbariAuthenticationProvider { + + private static final Logger LOG = LoggerFactory.getLogger(AmbariPamAuthenticationProvider.class); + + private final PamAuthenticationFactory pamAuthenticationFactory; + + @Inject + public AmbariPamAuthenticationProvider(Users users, PamAuthenticationFactory pamAuthenticationFactory, Configuration configuration) { + super(users, configuration); + this.pamAuthenticationFactory = pamAuthenticationFactory; + } + + @Override + public Authentication authenticate(Authentication authentication) throws AuthenticationException { + if (isPamEnabled()) { + if (authentication.getName() == null) { + LOG.info("Authentication failed: no username provided"); + throw new InvalidUsernamePasswordCombinationException(""); + } + + String userName = authentication.getName().trim(); + + if (authentication.getCredentials() == null) { + LOG.info("Authentication failed: no credentials provided: {}", userName); + throw new InvalidUsernamePasswordCombinationException(userName); + } + + Users users = getUsers(); + + UserEntity userEntity = users.getUserEntity(userName); + String password = String.valueOf(authentication.getCredentials()); + String ambariUsername; + String localUsername; + + // Determine what the Ambari and local username values are. Most of the time these should be + // the same, however it is possible for the user names to be different in the event a user has + // multiple authentication sources. + if (userEntity == null) { + ambariUsername = userName; + localUsername = userName; + } else { + // If the user exists, the username to be used with PAM may be stored with the PAM-specific UserAuthenticationEntity + // Else, use the UserEntity#getLocalUsername value + // Else, use the UserEntity#getUserName value + UserAuthenticationEntity authenticationEntity = getAuthenticationEntity(userEntity, UserAuthenticationType.PAM); + + ambariUsername = userEntity.getUserName(); + + if (authenticationEntity == null) { + localUsername = userEntity.getLocalUsername(); + } else { + localUsername = authenticationEntity.getAuthenticationKey(); + + if (StringUtils.isEmpty(localUsername)) { + localUsername = userEntity.getLocalUsername(); + } + } + + if (StringUtils.isEmpty(localUsername)) { + localUsername = ambariUsername; + } + } + + // Perform authentication.... + UnixUser unixUser = performPAMAuthentication(ambariUsername, localUsername, password); + + if (unixUser != null) { + // Authentication was successful via PAM. Make sure that the user exists and has a PAM + // authentication entry. + if (userEntity == null) { + // TODO: Ensure automatically creating users when authenticating with PAM is allowed. + try { + userEntity = users.createUser(ambariUsername, unixUser.getUserName(), ambariUsername, true); + } catch (AmbariException e) { + LOG.error(String.format("Failed to add the user, %s: %s", ambariUsername, e.getLocalizedMessage()), e); + throw new AmbariAuthenticationException(ambariUsername, "Unexpected error has occurred", false, e); + } + } else { + // Ensure the user is allowed to login.... + try { + validateLogin(userEntity, ambariUsername); + } catch (AccountDisabledException | TooManyLoginFailuresException e) { + if (getConfiguration().showLockedOutUserMessage()) { + throw e; + } else { + // Do not give away information about the existence or status of a user + throw new InvalidUsernamePasswordCombinationException(userName, false, e); + } + } + } + + UserAuthenticationEntity authenticationEntity = getAuthenticationEntity(userEntity, UserAuthenticationType.PAM); + // TODO: Ensure automatically adding the PAM authentication method for users when authenticating is allowed. + if (authenticationEntity == null) { + try { + users.addPamAuthentication(userEntity, unixUser.getUserName()); + } catch (AmbariException e) { + LOG.error(String.format("Failed to add the PAM authentication method for %s: %s", ambariUsername, e.getLocalizedMessage()), e); + throw new AmbariAuthenticationException(ambariUsername, "Unexpected error has occurred", false, e); + } + } + + if (isAutoGroupCreationAllowed()) { + synchronizeGroups(unixUser, userEntity); + } + + Authentication authToken = new AmbariUserAuthentication(password, users.getUser(userEntity), users.getUserAuthorities(userEntity)); + authToken.setAuthenticated(true); + return authToken; + } + + + // The user was not authenticated, catch-all fail + LOG.debug(String.format("Authentication failed: password does not match stored value: %s", localUsername)); + throw new InvalidUsernamePasswordCombinationException(ambariUsername); + } else { + return null; + } + } + + /** + * Perform the OS-level PAM authentication routine. + * + * @param ambariUsername the Ambari username, used for logging and notifications + * @param localUsername the username to use for authenticating + * @param password the password to use for authenticating + * @return the resulting user object + */ + private UnixUser performPAMAuthentication(String ambariUsername, String localUsername, String password) { + PAM pam = pamAuthenticationFactory.createInstance(getConfiguration()); + + if (pam == null) { + String message = "Failed to authenticate the user using the PAM authentication method: unexpected error"; + LOG.error(message); + throw new AmbariAuthenticationException(ambariUsername, message, false); + } else { + if (LOG.isDebugEnabled() && !ambariUsername.equals(localUsername)) { + LOG.debug("Authenticating Ambari user {} using the local username {}", ambariUsername, localUsername); + } + + try { + // authenticate using PAM + return pam.authenticate(localUsername, password); + } catch (PAMException e) { + // The user was not authenticated, fail + LOG.debug(String.format("Authentication failed: password does not match stored value: %s", localUsername), e); + throw new InvalidUsernamePasswordCombinationException(ambariUsername, true, e); + } finally { + pam.dispose(); + } + } + } + + @Override + public boolean supports(Class<?> authentication) { + return UsernamePasswordAuthenticationToken.class.isAssignableFrom(authentication); + } + + /** + * Check if PAM authentication is enabled in server properties + * + * @return true if enabled + */ + private boolean isPamEnabled() { + return getConfiguration().getClientSecurityType() == ClientSecurityType.PAM; + } + + /** + * Check if PAM authentication is enabled in server properties + * + * @return true if enabled + */ + private boolean isAutoGroupCreationAllowed() { + return getConfiguration().getAutoGroupCreation().equals("true"); + } + + + /** + * Synchornizes the OS-level groups assigned to the OS-level user with the groups assigned to the + * Ambari user in Ambari + * + * @param unixUser the user + * @param userEntity the ambari user + */ + private void synchronizeGroups(UnixUser unixUser, UserEntity userEntity) { + LOG.debug("Synchronizing groups for PAM user: {}", unixUser.getUserName()); + + Users users = getUsers(); + + try { + //Get all the groups that user belongs to + //Change all group names to lower case. + Set<String> unixUserGroups = convertToLowercase(unixUser.getGroups()); + + // Add the user to the specified groups, create the group if needed... + for (String group : unixUserGroups) { + GroupEntity groupEntity = users.getGroupEntity(group, GroupType.PAM); + if (groupEntity == null) { + LOG.info("Synchronizing groups for {}, adding new PAM group: {}", userEntity.getUserName(), group); + groupEntity = users.createGroup(group, GroupType.PAM); + } + + if (!users.isUserInGroup(userEntity, groupEntity)) { + LOG.info("Synchronizing groups for {}, adding user to PAM group: {}", userEntity.getUserName(), group); + users.addMemberToGroup(groupEntity, userEntity); + } + } + + // Remove the user from any other PAM-specific group that the user may have been previously + // added to. If the user belongs to non-PAM-specific groups, do not alter those assignments. + Set<MemberEntity> memberEntities = userEntity.getMemberEntities(); + if (memberEntities != null) { + Collection<GroupEntity> groupsToRemove = new ArrayList<>(); + // Collect the groups to remove... + for (MemberEntity memberEntity : memberEntities) { + GroupEntity groupEntity = memberEntity.getGroup(); + if ((groupEntity.getGroupType() == GroupType.PAM) && !unixUserGroups.contains(groupEntity.getGroupName())) { + groupsToRemove.add(groupEntity); + } + } + + // Perform the removals... + for(GroupEntity groupEntity :groupsToRemove) { + LOG.info("Synchronizing groups for {}, removing user from PAM group: {}", userEntity.getUserName(), groupEntity.getGroupName()); + users.removeMemberFromGroup(groupEntity, userEntity); + } + } + } catch (AmbariException e) { + e.printStackTrace(); + } + } + + private Set<String> convertToLowercase(Set<String> groups) { + Set<String> lowercaseGroups = new HashSet<>(); + + if (groups != null) { + for (String group : groups) { + lowercaseGroups.add(group.toLowerCase()); + } + } + + return lowercaseGroups; + } +} http://git-wip-us.apache.org/repos/asf/ambari/blob/d6b271e6/ambari-server/src/main/java/org/apache/ambari/server/security/authentication/pam/PamAuthenticationFactory.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/security/authentication/pam/PamAuthenticationFactory.java b/ambari-server/src/main/java/org/apache/ambari/server/security/authentication/pam/PamAuthenticationFactory.java index 6f423c1..791f055 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/security/authentication/pam/PamAuthenticationFactory.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/security/authentication/pam/PamAuthenticationFactory.java @@ -20,16 +20,33 @@ package org.apache.ambari.server.security.authentication.pam; import javax.inject.Singleton; +import org.apache.ambari.server.configuration.Configuration; import org.jvnet.libpam.PAM; import org.jvnet.libpam.PAMException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.security.authentication.AuthenticationServiceException; /** * PamAuthenticationFactory returns Pam library instances. */ @Singleton public class PamAuthenticationFactory { + private static final Logger LOG = LoggerFactory.getLogger(PamAuthenticationFactory.class); - public PAM createInstance(String pamConfig) throws PAMException { - return new PAM(pamConfig); + public PAM createInstance(Configuration configuration) { + String pamConfig = (configuration == null) ? null : configuration.getPamConfigurationFile(); + return createInstance(pamConfig); + } + + public PAM createInstance(String pamConfig) { + try { + //Set PAM configuration file (found under /etc/pam.d) + return new PAM(pamConfig); + } catch (PAMException e) { + String message = String.format("Unable to Initialize PAM: %s", e.getMessage()); + LOG.error(message, e); + throw new AuthenticationServiceException(message, e); + } } } http://git-wip-us.apache.org/repos/asf/ambari/blob/d6b271e6/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/AmbariPamAuthenticationProvider.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/AmbariPamAuthenticationProvider.java b/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/AmbariPamAuthenticationProvider.java deleted file mode 100644 index a88bcab..0000000 --- a/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/AmbariPamAuthenticationProvider.java +++ /dev/null @@ -1,237 +0,0 @@ -/* - * 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.ambari.server.security.authorization; - -import java.util.HashSet; -import java.util.Set; - -import org.apache.ambari.server.AmbariException; -import org.apache.ambari.server.configuration.Configuration; -import org.apache.ambari.server.orm.dao.GroupDAO; -import org.apache.ambari.server.orm.dao.UserDAO; -import org.apache.ambari.server.orm.entities.GroupEntity; -import org.apache.ambari.server.orm.entities.MemberEntity; -import org.apache.ambari.server.orm.entities.UserEntity; -import org.apache.ambari.server.security.ClientSecurityType; -import org.apache.ambari.server.security.authentication.AmbariUserAuthentication; -import org.apache.ambari.server.security.authentication.pam.PamAuthenticationFactory; -import org.jvnet.libpam.PAM; -import org.jvnet.libpam.PAMException; -import org.jvnet.libpam.UnixUser; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.security.authentication.AuthenticationProvider; -import org.springframework.security.authentication.AuthenticationServiceException; -import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; -import org.springframework.security.core.Authentication; -import org.springframework.security.core.AuthenticationException; - -import com.google.inject.Inject; - -/** - * Provides PAM user authentication & authorization logic for Ambari Server - */ - -public class AmbariPamAuthenticationProvider implements AuthenticationProvider { - - @Inject - private Users users; - @Inject - private UserDAO userDAO; - @Inject - private GroupDAO groupDAO; - @Inject - private PamAuthenticationFactory pamAuthenticationFactory; - - private static final Logger LOG = LoggerFactory.getLogger(AmbariPamAuthenticationProvider.class); - - private final Configuration configuration; - - @Inject - public AmbariPamAuthenticationProvider(Configuration configuration) { - this.configuration = configuration; - } - - // TODO: ************ - // TODO: This is to be revisited for AMBARI-21221 (Update Pam Authentication process to work with improved user management facility) - // TODO: ************ - @Override - public Authentication authenticate(Authentication authentication) throws AuthenticationException { - if (isPamEnabled()) { - //Set PAM configuration file (found under /etc/pam.d) - String pamConfig = configuration.getPamConfigurationFile(); - PAM pam; - - try { - //Set PAM configuration file (found under /etc/pam.d) - pam = new PAM(pamConfig); - - } catch (PAMException ex) { - LOG.error("Unable to Initialize PAM: " + ex.getMessage(), ex); - throw new AuthenticationServiceException("Unable to Initialize PAM - ", ex); - } - - try { - return authenticateViaPam(pam, authentication); - } finally { - pam.dispose(); - } - } else { - return null; - } - } - - @Override - public boolean supports(Class<?> authentication) { - return UsernamePasswordAuthenticationToken.class.isAssignableFrom(authentication); - } - - Authentication authenticateViaPam(PAM pam, Authentication authentication) { - String userName = String.valueOf(authentication.getPrincipal()); - String password = String.valueOf(authentication.getCredentials()); - - UnixUser unixUser; - try { - // authenticate using PAM - unixUser = pam.authenticate(userName, password); - } catch (PAMException ex) { - LOG.error("Unable to sign in. Invalid username/password combination - " + ex.getMessage()); - Throwable t = ex.getCause(); - throw new PamAuthenticationException("Unable to sign in. Invalid username/password combination.", t); - } - - if (unixUser != null) { - UserEntity userEntity = ambariPamAuthorization(unixUser); - - if (userEntity != null) { - Authentication authToken = new AmbariUserAuthentication(password, users.getUser(userEntity), users.getUserAuthorities(userEntity)); - authToken.setAuthenticated(true); - return authToken; - } - } - - return null; - } - - /** - * Check if PAM authentication is enabled in server properties - * - * @return true if enabled - */ - private boolean isPamEnabled() { - return configuration.getClientSecurityType() == ClientSecurityType.PAM; - } - - /** - * Check if PAM authentication is enabled in server properties - * - * @return true if enabled - */ - private boolean isAutoGroupCreationAllowed() { - return configuration.getAutoGroupCreation().equals("true"); - } - - - /** - * Performs PAM authorization by creating user & group(s) - * - * @param unixUser the user - */ - private UserEntity ambariPamAuthorization(UnixUser unixUser) { - String userName = unixUser.getUserName(); - UserEntity userEntity = null; - - try { - userEntity = userDAO.findUserByName(userName); - - // TODO: Ensure automatically creating users when authenticating with PAM is allowed. - if (userEntity == null) { - userEntity = users.createUser(userName, userName, userName); - users.addPamAuthentication(userEntity, userName); - } - - if (isAutoGroupCreationAllowed()) { - //Get all the groups that user belongs to - //Change all group names to lower case. - Set<String> unixUserGroups = unixUser.getGroups(); - if (unixUserGroups != null) { - for (String group : unixUserGroups) { - // Ensure group name is lowercase - group = group.toLowerCase(); - - GroupEntity groupEntity = groupDAO.findGroupByNameAndType(group, GroupType.PAM); - if (groupEntity == null) { - groupEntity = users.createGroup(group, GroupType.PAM); - } - - if (!isUserInGroup(userEntity, groupEntity)) { - users.addMemberToGroup(groupEntity, userEntity); - } - } - } - - Set<GroupEntity> ambariUserGroups = getUserGroups(userEntity); - for (GroupEntity groupEntity : ambariUserGroups) { - if (unixUserGroups == null || !unixUserGroups.contains(groupEntity.getGroupName())) { - users.removeMemberFromGroup(groupEntity, userEntity); - } - } - } - } catch (AmbariException e) { - e.printStackTrace(); - } - - return userEntity; - } - - /** - * Performs a check if given user belongs to given group. - * - * @param userEntity user entity - * @param groupEntity group entity - * @return true if user presents in group - */ - private boolean isUserInGroup(UserEntity userEntity, GroupEntity groupEntity) { - for (MemberEntity memberEntity : userEntity.getMemberEntities()) { - if (memberEntity.getGroup().equals(groupEntity)) { - return true; - } - } - return false; - } - - /** - * Extracts all groups a user belongs to - * - * @param userEntity the user - * @return Collection of group names - */ - private Set<GroupEntity> getUserGroups(UserEntity userEntity) { - Set<GroupEntity> groups = new HashSet<>(); - if (userEntity != null) { - for (MemberEntity memberEntity : userEntity.getMemberEntities()) { - GroupEntity groupEntity = memberEntity.getGroup(); - if (groupEntity.getGroupType() == GroupType.PAM) { - groups.add(memberEntity.getGroup()); - } - } - } - - return groups; - } -} http://git-wip-us.apache.org/repos/asf/ambari/blob/d6b271e6/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/PamAuthenticationException.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/PamAuthenticationException.java b/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/PamAuthenticationException.java deleted file mode 100644 index 1588106..0000000 --- a/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/PamAuthenticationException.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * 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.ambari.server.security.authorization; - -import org.springframework.security.core.AuthenticationException; - -public class PamAuthenticationException extends AuthenticationException{ - - public PamAuthenticationException() { - this("The user authentication failed"); - } - - public PamAuthenticationException(String msg, Throwable t) { - super(msg, t); - } - - public PamAuthenticationException(String msg) { - super(msg); - } - -} http://git-wip-us.apache.org/repos/asf/ambari/blob/d6b271e6/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/Users.java ---------------------------------------------------------------------- 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 a5faea1..a268467 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 @@ -337,12 +337,23 @@ public class Users { * @param groupType group type * @return group */ - public Group getGroupByNameAndType(String groupName, GroupType groupType) { - final GroupEntity groupEntity = groupDAO.findGroupByNameAndType(groupName, groupType); + public Group getGroup(String groupName, GroupType groupType) { + final GroupEntity groupEntity = getGroupEntity(groupName, groupType); return (null == groupEntity) ? null : new Group(groupEntity); } /** + * Gets a {@link GroupEntity} by name and type. + * + * @param groupName group name + * @param groupType group type + * @return group + */ + public GroupEntity getGroupEntity(String groupName, GroupType groupType) { + return groupDAO.findGroupByNameAndType(groupName, groupType); + } + + /** * Gets group members. * * @param groupName group name @@ -640,7 +651,7 @@ public class Users { * @param groupEntity group entity * @return true if user presents in group */ - private boolean isUserInGroup(UserEntity userEntity, GroupEntity groupEntity) { + public boolean isUserInGroup(UserEntity userEntity, GroupEntity groupEntity) { for (MemberEntity memberEntity : userEntity.getMemberEntities()) { if (memberEntity.getGroup().equals(groupEntity)) { return true; http://git-wip-us.apache.org/repos/asf/ambari/blob/d6b271e6/ambari-server/src/test/java/org/apache/ambari/server/security/authentication/pam/AmbariPamAuthenticationProviderTest.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/test/java/org/apache/ambari/server/security/authentication/pam/AmbariPamAuthenticationProviderTest.java b/ambari-server/src/test/java/org/apache/ambari/server/security/authentication/pam/AmbariPamAuthenticationProviderTest.java new file mode 100644 index 0000000..6908c55 --- /dev/null +++ b/ambari-server/src/test/java/org/apache/ambari/server/security/authentication/pam/AmbariPamAuthenticationProviderTest.java @@ -0,0 +1,277 @@ +/* + * 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.ambari.server.security.authentication.pam; + +import static org.easymock.EasyMock.eq; +import static org.easymock.EasyMock.expect; +import static org.easymock.EasyMock.expectLastCall; + +import java.util.Collections; + +import javax.persistence.EntityManager; + +import org.apache.ambari.server.configuration.Configuration; +import org.apache.ambari.server.hooks.HookContextFactory; +import org.apache.ambari.server.hooks.HookService; +import org.apache.ambari.server.orm.DBAccessor; +import org.apache.ambari.server.orm.entities.PrincipalEntity; +import org.apache.ambari.server.orm.entities.UserAuthenticationEntity; +import org.apache.ambari.server.orm.entities.UserEntity; +import org.apache.ambari.server.security.ClientSecurityType; +import org.apache.ambari.server.security.authentication.AccountDisabledException; +import org.apache.ambari.server.security.authentication.AmbariUserAuthentication; +import org.apache.ambari.server.security.authentication.TooManyLoginFailuresException; +import org.apache.ambari.server.security.authorization.User; +import org.apache.ambari.server.security.authorization.UserAuthenticationType; +import org.apache.ambari.server.security.authorization.UserName; +import org.apache.ambari.server.security.authorization.Users; +import org.apache.ambari.server.state.stack.OsFamily; +import org.easymock.EasyMockSupport; +import org.junit.Before; +import org.junit.Test; +import org.jvnet.libpam.PAM; +import org.jvnet.libpam.PAMException; +import org.jvnet.libpam.UnixUser; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.AuthenticationException; +import org.springframework.security.crypto.password.PasswordEncoder; +import org.springframework.security.crypto.password.StandardPasswordEncoder; + +import com.google.inject.AbstractModule; +import com.google.inject.Guice; +import com.google.inject.Injector; + +import junit.framework.Assert; + +public class AmbariPamAuthenticationProviderTest extends EasyMockSupport { + + private static final String TEST_USER_NAME = "userName"; + private static final String TEST_USER_PASS = "userPass"; + private static final String TEST_USER_INCORRECT_PASS = "userIncorrectPass"; + + private Injector injector; + + @Before + public void setup() { + injector = Guice.createInjector(new AbstractModule() { + + @Override + protected void configure() { + bind(EntityManager.class).toInstance(createNiceMock(EntityManager.class)); + bind(DBAccessor.class).toInstance(createNiceMock(DBAccessor.class)); + bind(HookContextFactory.class).toInstance(createNiceMock(HookContextFactory.class)); + bind(HookService.class).toInstance(createNiceMock(HookService.class)); + bind(OsFamily.class).toInstance(createNiceMock(OsFamily.class)); + bind(PamAuthenticationFactory.class).toInstance(createMock(PamAuthenticationFactory.class)); + bind(PasswordEncoder.class).toInstance(new StandardPasswordEncoder()); + bind(Users.class).toInstance(createMock(Users.class)); + } + }); + + Configuration configuration = injector.getInstance(Configuration.class); + configuration.setClientSecurityType(ClientSecurityType.PAM); + configuration.setProperty(Configuration.PAM_CONFIGURATION_FILE, "ambari-pam"); + configuration.setProperty(Configuration.SHOW_LOCKED_OUT_USER_MESSAGE, "true"); + } + + @Test(expected = AuthenticationException.class) + public void testBadCredential() throws Exception { + + PAM pam = createMock(PAM.class); + expect(pam.authenticate(eq(TEST_USER_NAME), eq(TEST_USER_INCORRECT_PASS))) + .andThrow(new PAMException()) + .once(); + pam.dispose(); + expectLastCall().once(); + + PamAuthenticationFactory pamAuthenticationFactory = injector.getInstance(PamAuthenticationFactory.class); + expect(pamAuthenticationFactory.createInstance(injector.getInstance(Configuration.class))).andReturn(pam).once(); + + Users users = injector.getInstance(Users.class); + expect(users.getUserEntity(TEST_USER_NAME)).andReturn(null).once(); + + replayAll(); + + Authentication authentication = new UsernamePasswordAuthenticationToken(TEST_USER_NAME, TEST_USER_INCORRECT_PASS); + + AmbariPamAuthenticationProvider authenticationProvider = injector.getInstance(AmbariPamAuthenticationProvider.class); + authenticationProvider.authenticate(authentication); + + verifyAll(); + } + + @Test + public void testAuthenticateExistingUser() throws Exception { + + UnixUser unixUser = createNiceMock(UnixUser.class); + + PAM pam = createMock(PAM.class); + expect(pam.authenticate(eq(TEST_USER_NAME), eq(TEST_USER_PASS))).andReturn(unixUser).once(); + pam.dispose(); + expectLastCall().once(); + + PamAuthenticationFactory pamAuthenticationFactory = injector.getInstance(PamAuthenticationFactory.class); + expect(pamAuthenticationFactory.createInstance(injector.getInstance(Configuration.class))).andReturn(pam).once(); + + UserEntity userEntity = combineUserEntity(true, true, 0); + + Users users = injector.getInstance(Users.class); + expect(users.getUserEntity(TEST_USER_NAME)).andReturn(userEntity).once(); + expect(users.getUser(userEntity)).andReturn(new User(userEntity)).once(); + expect(users.getUserAuthorities(userEntity)).andReturn(null).once(); + + replayAll(); + + Authentication authentication = new UsernamePasswordAuthenticationToken(TEST_USER_NAME, TEST_USER_PASS); + AmbariPamAuthenticationProvider authenticationProvider = injector.getInstance(AmbariPamAuthenticationProvider.class); + + Authentication result = authenticationProvider.authenticate(authentication); + Assert.assertNotNull(result); + Assert.assertEquals(true, result.isAuthenticated()); + Assert.assertTrue(result instanceof AmbariUserAuthentication); + + verifyAll(); + } + + @Test(expected = AccountDisabledException.class) + public void testAuthenticateDisabledUser() throws Exception { + + UnixUser unixUser = createNiceMock(UnixUser.class); + + PAM pam = createMock(PAM.class); + expect(pam.authenticate(eq(TEST_USER_NAME), eq(TEST_USER_PASS))).andReturn(unixUser).once(); + pam.dispose(); + expectLastCall().once(); + + PamAuthenticationFactory pamAuthenticationFactory = injector.getInstance(PamAuthenticationFactory.class); + expect(pamAuthenticationFactory.createInstance(injector.getInstance(Configuration.class))).andReturn(pam).once(); + + UserEntity userEntity = combineUserEntity(true, false, 0); + + Users users = injector.getInstance(Users.class); + expect(users.getUserEntity(TEST_USER_NAME)).andReturn(userEntity).once(); + + replayAll(); + + Authentication authentication = new UsernamePasswordAuthenticationToken(TEST_USER_NAME, TEST_USER_PASS); + AmbariPamAuthenticationProvider authenticationProvider = injector.getInstance(AmbariPamAuthenticationProvider.class); + authenticationProvider.authenticate(authentication); + + verifyAll(); + } + + @Test(expected = TooManyLoginFailuresException.class) + public void testAuthenticateLockedUser() throws Exception { + + UnixUser unixUser = createNiceMock(UnixUser.class); + + PAM pam = createMock(PAM.class); + expect(pam.authenticate(eq(TEST_USER_NAME), eq(TEST_USER_PASS))).andReturn(unixUser).once(); + pam.dispose(); + expectLastCall().once(); + + PamAuthenticationFactory pamAuthenticationFactory = injector.getInstance(PamAuthenticationFactory.class); + expect(pamAuthenticationFactory.createInstance(injector.getInstance(Configuration.class))).andReturn(pam).once(); + + UserEntity userEntity = combineUserEntity(true, true, 11); + + Users users = injector.getInstance(Users.class); + expect(users.getUserEntity(TEST_USER_NAME)).andReturn(userEntity).once(); + + replayAll(); + + Authentication authentication = new UsernamePasswordAuthenticationToken(TEST_USER_NAME, TEST_USER_PASS); + AmbariPamAuthenticationProvider authenticationProvider = injector.getInstance(AmbariPamAuthenticationProvider.class); + authenticationProvider.authenticate(authentication); + + verifyAll(); + } + + @Test + public void testAuthenticateNewUser() throws Exception { + + UnixUser unixUser = createNiceMock(UnixUser.class); + expect(unixUser.getUserName()).andReturn(TEST_USER_NAME.toLowerCase()).atLeastOnce(); + + PAM pam = createMock(PAM.class); + expect(pam.authenticate(eq(TEST_USER_NAME), eq(TEST_USER_PASS))).andReturn(unixUser).once(); + pam.dispose(); + expectLastCall().once(); + + PamAuthenticationFactory pamAuthenticationFactory = injector.getInstance(PamAuthenticationFactory.class); + expect(pamAuthenticationFactory.createInstance(injector.getInstance(Configuration.class))).andReturn(pam).once(); + + UserEntity userEntity = combineUserEntity(false, true, 0); + + Users users = injector.getInstance(Users.class); + expect(users.getUserEntity(TEST_USER_NAME)).andReturn(null).once(); + expect(users.createUser(TEST_USER_NAME, TEST_USER_NAME.toLowerCase(), TEST_USER_NAME, true)).andReturn(userEntity).once(); + users.addPamAuthentication(userEntity, TEST_USER_NAME.toLowerCase()); + expectLastCall().once(); + expect(users.getUser(userEntity)).andReturn(new User(userEntity)).once(); + expect(users.getUserAuthorities(userEntity)).andReturn(null).once(); + + replayAll(); + + Authentication authentication = new UsernamePasswordAuthenticationToken(TEST_USER_NAME, TEST_USER_PASS); + AmbariPamAuthenticationProvider authenticationProvider = injector.getInstance(AmbariPamAuthenticationProvider.class); + + Authentication result = authenticationProvider.authenticate(authentication); + Assert.assertNotNull(result); + Assert.assertEquals(true, result.isAuthenticated()); + Assert.assertTrue(result instanceof AmbariUserAuthentication); + + verifyAll(); + } + + @Test + public void testDisabled() throws Exception { + + Configuration configuration = injector.getInstance(Configuration.class); + configuration.setClientSecurityType(ClientSecurityType.LOCAL); + + Authentication authentication = new UsernamePasswordAuthenticationToken(TEST_USER_NAME, TEST_USER_PASS); + + AmbariPamAuthenticationProvider authenticationProvider = injector.getInstance(AmbariPamAuthenticationProvider.class); + Authentication auth = authenticationProvider.authenticate(authentication); + Assert.assertTrue(auth == null); + } + + private UserEntity combineUserEntity(boolean addAuthentication, Boolean active, Integer consecutiveFailures) { + PrincipalEntity principalEntity = new PrincipalEntity(); + + UserEntity userEntity = new UserEntity(); + userEntity.setUserId(1); + userEntity.setUserName(UserName.fromString(TEST_USER_NAME).toString()); + userEntity.setLocalUsername(TEST_USER_NAME); + userEntity.setPrincipal(principalEntity); + userEntity.setActive(active); + userEntity.setConsecutiveFailures(consecutiveFailures); + + if(addAuthentication) { + UserAuthenticationEntity userAuthenticationEntity = new UserAuthenticationEntity(); + userAuthenticationEntity.setAuthenticationType(UserAuthenticationType.PAM); + userAuthenticationEntity.setAuthenticationKey(TEST_USER_NAME); + + userEntity.setAuthenticationEntities(Collections.singletonList(userAuthenticationEntity)); + } + return userEntity; + } + +} http://git-wip-us.apache.org/repos/asf/ambari/blob/d6b271e6/ambari-server/src/test/java/org/apache/ambari/server/security/authorization/AmbariPamAuthenticationProviderTest.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/test/java/org/apache/ambari/server/security/authorization/AmbariPamAuthenticationProviderTest.java b/ambari-server/src/test/java/org/apache/ambari/server/security/authorization/AmbariPamAuthenticationProviderTest.java deleted file mode 100644 index 38f9a9e..0000000 --- a/ambari-server/src/test/java/org/apache/ambari/server/security/authorization/AmbariPamAuthenticationProviderTest.java +++ /dev/null @@ -1,177 +0,0 @@ -/* - * 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.ambari.server.security.authorization; - -import static org.easymock.EasyMock.anyObject; -import static org.easymock.EasyMock.eq; -import static org.easymock.EasyMock.expect; -import static org.easymock.EasyMock.expectLastCall; - -import java.util.Collections; - -import javax.persistence.EntityManager; - -import org.apache.ambari.server.configuration.Configuration; -import org.apache.ambari.server.hooks.HookContextFactory; -import org.apache.ambari.server.hooks.HookService; -import org.apache.ambari.server.orm.DBAccessor; -import org.apache.ambari.server.orm.dao.MemberDAO; -import org.apache.ambari.server.orm.dao.PrivilegeDAO; -import org.apache.ambari.server.orm.dao.UserDAO; -import org.apache.ambari.server.orm.entities.PrincipalEntity; -import org.apache.ambari.server.orm.entities.UserAuthenticationEntity; -import org.apache.ambari.server.orm.entities.UserEntity; -import org.apache.ambari.server.security.ClientSecurityType; -import org.apache.ambari.server.security.authentication.AmbariUserAuthentication; -import org.apache.ambari.server.security.authentication.pam.PamAuthenticationFactory; -import org.apache.ambari.server.state.stack.OsFamily; -import org.easymock.EasyMockSupport; -import org.junit.Before; -import org.junit.Test; -import org.jvnet.libpam.PAM; -import org.jvnet.libpam.PAMException; -import org.jvnet.libpam.UnixUser; -import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; -import org.springframework.security.core.Authentication; -import org.springframework.security.core.AuthenticationException; -import org.springframework.security.crypto.password.PasswordEncoder; -import org.springframework.security.crypto.password.StandardPasswordEncoder; - -import com.google.inject.AbstractModule; -import com.google.inject.Guice; -import com.google.inject.Injector; - -import junit.framework.Assert; - -public class AmbariPamAuthenticationProviderTest extends EasyMockSupport { - - private static final String TEST_USER_NAME = "userName"; - private static final String TEST_USER_PASS = "userPass"; - private static final String TEST_USER_INCORRECT_PASS = "userIncorrectPass"; - - private Injector injector; - - @Before - public void setup() { - injector = Guice.createInjector(new AbstractModule() { - - @Override - protected void configure() { - bind(EntityManager.class).toInstance(createNiceMock(EntityManager.class)); - bind(DBAccessor.class).toInstance(createNiceMock(DBAccessor.class)); - bind(HookContextFactory.class).toInstance(createNiceMock(HookContextFactory.class)); - bind(HookService.class).toInstance(createNiceMock(HookService.class)); - bind(OsFamily.class).toInstance(createNiceMock(OsFamily.class)); - bind(UserDAO.class).toInstance(createNiceMock(UserDAO.class)); - bind(MemberDAO.class).toInstance(createNiceMock(MemberDAO.class)); - bind(PrivilegeDAO.class).toInstance(createNiceMock(PrivilegeDAO.class)); - bind(PamAuthenticationFactory.class).toInstance(createMock(PamAuthenticationFactory.class)); - bind(PasswordEncoder.class).toInstance(new StandardPasswordEncoder()); - } - }); - - Configuration configuration = injector.getInstance(Configuration.class); - configuration.setClientSecurityType(ClientSecurityType.PAM); - configuration.setProperty(Configuration.PAM_CONFIGURATION_FILE, "ambari-pam"); - } - - @Test(expected = AuthenticationException.class) - public void testBadCredential() throws Exception { - - PAM pam = createMock(PAM.class); - expect(pam.authenticate(eq(TEST_USER_NAME), eq(TEST_USER_INCORRECT_PASS))) - .andThrow(new PAMException()) - .once(); - pam.dispose(); - expectLastCall().once(); - - PamAuthenticationFactory pamAuthenticationFactory = injector.getInstance(PamAuthenticationFactory.class); - expect(pamAuthenticationFactory.createInstance(anyObject(String.class))).andReturn(pam).once(); - - replayAll(); - - Authentication authentication = new UsernamePasswordAuthenticationToken(TEST_USER_NAME, TEST_USER_INCORRECT_PASS); - - AmbariPamAuthenticationProvider authenticationProvider = injector.getInstance(AmbariPamAuthenticationProvider.class); - authenticationProvider.authenticate(authentication); - - verifyAll(); - } - - @Test - public void testAuthenticate() throws Exception { - - UnixUser unixUser = createNiceMock(UnixUser.class); - expect(unixUser.getUserName()).andReturn(TEST_USER_NAME).atLeastOnce(); - - PAM pam = createMock(PAM.class); - expect(pam.authenticate(eq(TEST_USER_NAME), eq(TEST_USER_PASS))).andReturn(unixUser).once(); - - UserEntity userEntity = combineUserEntity(); - - UserDAO userDAO = injector.getInstance(UserDAO.class); - expect(userDAO.findUserByName(TEST_USER_NAME)).andReturn(userEntity).once(); - - MemberDAO memberDAO = injector.getInstance(MemberDAO.class); - expect(memberDAO.findAllMembersByUser(userEntity)).andReturn(Collections.emptyList()).once(); - - PrivilegeDAO privilegeDAO = injector.getInstance(PrivilegeDAO.class); - expect(privilegeDAO.findAllByPrincipal(anyObject())).andReturn(Collections.emptyList()).once(); - - replayAll(); - - Authentication authentication = new UsernamePasswordAuthenticationToken(TEST_USER_NAME, TEST_USER_PASS); - AmbariPamAuthenticationProvider authenticationProvider = injector.getInstance(AmbariPamAuthenticationProvider.class); - - Authentication result = authenticationProvider.authenticateViaPam(pam, authentication); - Assert.assertNotNull(result); - Assert.assertEquals(true, result.isAuthenticated()); - Assert.assertTrue(result instanceof AmbariUserAuthentication); - - verifyAll(); - } - - @Test - public void testDisabled() throws Exception { - - Configuration configuration = injector.getInstance(Configuration.class); - configuration.setClientSecurityType(ClientSecurityType.LOCAL); - - Authentication authentication = new UsernamePasswordAuthenticationToken(TEST_USER_NAME, TEST_USER_PASS); - - AmbariPamAuthenticationProvider authenticationProvider = injector.getInstance(AmbariPamAuthenticationProvider.class); - Authentication auth = authenticationProvider.authenticate(authentication); - Assert.assertTrue(auth == null); - } - - private UserEntity combineUserEntity() { - PrincipalEntity principalEntity = new PrincipalEntity(); - - UserAuthenticationEntity userAuthenticationEntity = new UserAuthenticationEntity(); - userAuthenticationEntity.setAuthenticationType(UserAuthenticationType.PAM); - userAuthenticationEntity.setAuthenticationKey(TEST_USER_NAME); - - UserEntity userEntity = new UserEntity(); - userEntity.setUserId(1); - userEntity.setUserName(UserName.fromString(TEST_USER_NAME).toString()); - userEntity.setPrincipal(principalEntity); - userEntity.setAuthenticationEntities(Collections.singletonList(userAuthenticationEntity)); - return userEntity; - } - -}
