You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ambari.apache.org by rl...@apache.org on 2017/06/15 15:06:18 UTC

[4/8] ambari git commit: AMBARI-21147. Update Database Access Layer to Support New Database Schema for Improved User Account Management (rlevas)

http://git-wip-us.apache.org/repos/asf/ambari/blob/f76c87a6/ambari-server/src/main/java/org/apache/ambari/server/security/authentication/kerberos/AmbariAuthToLocalUserDetailsService.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/security/authentication/kerberos/AmbariAuthToLocalUserDetailsService.java b/ambari-server/src/main/java/org/apache/ambari/server/security/authentication/kerberos/AmbariAuthToLocalUserDetailsService.java
index 1e4f6ea..261b94e 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/security/authentication/kerberos/AmbariAuthToLocalUserDetailsService.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/security/authentication/kerberos/AmbariAuthToLocalUserDetailsService.java
@@ -19,19 +19,21 @@
 package org.apache.ambari.server.security.authentication.kerberos;
 
 import java.io.IOException;
-import java.util.Collection;
-import java.util.Collections;
 import java.util.List;
 
 import org.apache.ambari.server.AmbariException;
 import org.apache.ambari.server.configuration.Configuration;
-import org.apache.ambari.server.security.authorization.AmbariGrantedAuthority;
-import org.apache.ambari.server.security.authorization.UserType;
+import org.apache.ambari.server.orm.entities.UserAuthenticationEntity;
+import org.apache.ambari.server.orm.entities.UserEntity;
+import org.apache.ambari.server.security.authentication.AuthenticationMethodNotAllowedException;
+import org.apache.ambari.server.security.authentication.UserNotFoundException;
+import org.apache.ambari.server.security.authorization.UserAuthenticationType;
 import org.apache.ambari.server.security.authorization.Users;
 import org.apache.commons.lang.StringUtils;
 import org.apache.hadoop.security.authentication.util.KerberosName;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
+import org.springframework.security.core.AuthenticationException;
 import org.springframework.security.core.userdetails.User;
 import org.springframework.security.core.userdetails.UserDetails;
 import org.springframework.security.core.userdetails.UserDetailsService;
@@ -47,8 +49,6 @@ public class AmbariAuthToLocalUserDetailsService implements UserDetailsService {
 
   private final Users users;
 
-  private final List<UserType> userTypeOrder;
-
   private final String authToLocalRules;
 
   /**
@@ -63,14 +63,12 @@ public class AmbariAuthToLocalUserDetailsService implements UserDetailsService {
    */
   public AmbariAuthToLocalUserDetailsService(Configuration configuration, Users users) throws AmbariException {
     String authToLocalRules = null;
-    List<UserType> orderedUserTypes = null;
 
     if (configuration != null) {
       AmbariKerberosAuthenticationProperties properties = configuration.getKerberosAuthenticationProperties();
 
       if (properties != null) {
         authToLocalRules = properties.getAuthToLocalRules();
-        orderedUserTypes = properties.getOrderedUserTypes();
       }
     }
 
@@ -78,12 +76,7 @@ public class AmbariAuthToLocalUserDetailsService implements UserDetailsService {
       authToLocalRules = "DEFAULT";
     }
 
-    if ((orderedUserTypes == null) || orderedUserTypes.isEmpty()) {
-      orderedUserTypes = Collections.singletonList(UserType.LDAP);
-    }
-
     this.users = users;
-    this.userTypeOrder = orderedUserTypes;
     this.authToLocalRules = authToLocalRules;
   }
 
@@ -107,7 +100,9 @@ public class AmbariAuthToLocalUserDetailsService implements UserDetailsService {
       }
 
       LOG.info("Translated {} to {} using auth-to-local rules during Kerberos authentication.", principal, username);
-      return createUser(username);
+      return createUser(username, principal);
+    } catch (UserNotFoundException e) {
+      throw new UsernameNotFoundException(e.getMessage(), e);
     } catch (IOException e) {
       String message = String.format("Failed to translate %s to a local username during Kerberos authentication: %s", principal, e.getLocalizedMessage());
       LOG.warn(message);
@@ -121,26 +116,83 @@ public class AmbariAuthToLocalUserDetailsService implements UserDetailsService {
    * User accounts are searched in order of preferred user type as specified in the Ambari configuration
    * ({@link Configuration#KERBEROS_AUTH_USER_TYPES}).
    *
-   * @param username a username
+   * @param username  a username
+   * @param principal the user's principal
    * @return the user details of the found user, or <code>null</code> if an appropriate user was not found
    */
-  private UserDetails createUser(String username) {
-    // Iterate over the ordered user types... when an account for the username/type combination is
-    // found, build the related AmbariUserAuthentication instance and return it.  Only the first
-    // match matters... this may be an issue and cause some ambiguity in the event multiple user
-    // types are specified in the configuration and multiple accounts for the same username, but
-    // different types (LOCAL vs LDAP, etc...).
-    for (UserType userType : userTypeOrder) {
-      org.apache.ambari.server.security.authorization.User user = users.getUser(username, userType);
-
-      if (user != null) {
-        Collection<AmbariGrantedAuthority> userAuthorities = users.getUserAuthorities(user.getUserName(), user.getUserType());
-        return new User(username, "", userAuthorities);
+  private UserDetails createUser(String username, String principal) throws AuthenticationException {
+    UserEntity userEntity = users.getUserEntity(username);
+
+    if (userEntity == null) {
+      throw new UserNotFoundException(username, String.format("Cannot find user using Kerberos ticket (%s).", principal));
+    } else if (!userEntity.getActive()) {
+      LOG.debug("User account is disabled");
+      throw new UserNotFoundException(username, "User account is disabled");
+    } else {
+
+      // Check to see if the user is allowed to authenticate using KERBEROS or LDAP
+      List<UserAuthenticationEntity> authenticationEntities = userEntity.getAuthenticationEntities();
+      boolean hasKerberos = false;
+      boolean hasLDAP = false;
+      boolean hasLocal = false;
+
+      for (UserAuthenticationEntity entity : authenticationEntities) {
+        UserAuthenticationType authenticationType = entity.getAuthenticationType();
+
+        switch (authenticationType) {
+          case KERBEROS:
+            if (principal.equalsIgnoreCase(entity.getAuthenticationKey())) {
+              LOG.trace("Found KERBEROS authentication method for {} using principal {}", username, principal);
+              hasKerberos = true;
+            }
+            break;
+
+          case LDAP:
+            hasLDAP = true;
+            break;
+
+          case LOCAL:
+            hasLocal = true;
+            break;
+
+          default:
+            break;
+        }
+
+        if (hasKerberos) {
+          break;
+        }
+      }
+
+      if (!hasKerberos) {
+        if (hasLDAP) {
+          // TODO: Determine if LDAP users can authenticate using Kerberos
+          try {
+            users.addKerberosAuthentication(userEntity, principal);
+            LOG.trace("Added KERBEROS authentication method for {} using principal {}", username, principal);
+          } catch (AmbariException e) {
+            LOG.error(String.format("Failed to add the KERBEROS authentication method for %s: %s", principal, e.getLocalizedMessage()), e);
+          }
+          hasKerberos = true;
+        }
+
+        if (!hasKerberos && hasLocal) {
+          // TODO: Determine if LOCAL users can authenticate using Kerberos
+          try {
+            users.addKerberosAuthentication(userEntity, username);
+            LOG.trace("Added KERBEROS authentication method for {} using principal {}", username, principal);
+          } catch (AmbariException e) {
+            LOG.error(String.format("Failed to add the KERBEROS authentication method for %s: %s", username, e.getLocalizedMessage()), e);
+          }
+          hasKerberos = true;
+        }
+      }
+
+      if (!hasKerberos) {
+        throw new AuthenticationMethodNotAllowedException(username, UserAuthenticationType.KERBEROS);
       }
     }
 
-    String message = String.format("Failed find user account for user with username of %s during Kerberos authentication.", username);
-    LOG.warn(message);
-    throw new UsernameNotFoundException(message);
+    return new User(username, "", users.getUserAuthorities(userEntity));
   }
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/f76c87a6/ambari-server/src/main/java/org/apache/ambari/server/security/authentication/kerberos/AmbariKerberosAuthenticationProperties.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/security/authentication/kerberos/AmbariKerberosAuthenticationProperties.java b/ambari-server/src/main/java/org/apache/ambari/server/security/authentication/kerberos/AmbariKerberosAuthenticationProperties.java
index 09422e5..3e31e0d 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/security/authentication/kerberos/AmbariKerberosAuthenticationProperties.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/security/authentication/kerberos/AmbariKerberosAuthenticationProperties.java
@@ -22,7 +22,7 @@ import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
 
-import org.apache.ambari.server.security.authorization.UserType;
+import org.apache.ambari.server.security.authorization.UserAuthenticationType;
 
 /**
  * AmbariKerberosAuthenticationProperties is a container for Kerberos authentication-related
@@ -51,10 +51,10 @@ public class AmbariKerberosAuthenticationProperties {
   private String spnegoKeytabFilePath = null;
 
   /**
-   * A list of {@link UserType}s in order of preference for use when looking up user accounts in the
+   * A list of {@link UserAuthenticationType}s in order of preference for use when looking up user accounts in the
    * Ambari database
    */
-  private List<UserType> orderedUserTypes = Collections.emptyList();
+  private List<UserAuthenticationType> orderedUserTypes = Collections.emptyList();
 
   /**
    * Auth-to-local rules to use to feed to an auth-to-local rules processor used to translate
@@ -119,11 +119,11 @@ public class AmbariKerberosAuthenticationProperties {
   }
 
   /**
-   * Sets the list of {@link UserType}s (in preference order) to use to look up uer accounts in the Ambari database.
+   * Sets the list of {@link UserAuthenticationType}s (in preference order) to use to look up uer accounts in the Ambari database.
    *
-   * @param orderedUserTypes a list of {@link UserType}s
+   * @param orderedUserTypes a list of {@link UserAuthenticationType}s
    */
-  public void setOrderedUserTypes(List<UserType> orderedUserTypes) {
+  public void setOrderedUserTypes(List<UserAuthenticationType> orderedUserTypes) {
     if (orderedUserTypes == null) {
       this.orderedUserTypes = Collections.emptyList();
     } else {
@@ -132,11 +132,11 @@ public class AmbariKerberosAuthenticationProperties {
   }
 
   /**
-   * Gets the list of {@link UserType}s (in preference order) to use to look up uer accounts in the Ambari database.
+   * Gets the list of {@link UserAuthenticationType}s (in preference order) to use to look up uer accounts in the Ambari database.
    *
-   * @return a list of {@link UserType}s
+   * @return a list of {@link UserAuthenticationType}s
    */
-  public List<UserType> getOrderedUserTypes() {
+  public List<UserAuthenticationType> getOrderedUserTypes() {
     return orderedUserTypes;
   }
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/f76c87a6/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/AmbariAuthorizationFilter.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/AmbariAuthorizationFilter.java b/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/AmbariAuthorizationFilter.java
index ce9a790..a31e951 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/AmbariAuthorizationFilter.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/AmbariAuthorizationFilter.java
@@ -300,7 +300,7 @@ public class AmbariAuthorizationFilter implements Filter {
       String username = configuration.getDefaultApiAuthenticatedUser();
 
       if (!StringUtils.isEmpty(username)) {
-        final User user = users.getUser(username, UserType.LOCAL);
+        final User user = users.getUser(username);
 
         if (user != null) {
           Principal principal = new Principal() {
@@ -311,7 +311,7 @@ public class AmbariAuthorizationFilter implements Filter {
           };
 
           defaultUser = new UsernamePasswordAuthenticationToken(principal, null,
-              users.getUserAuthorities(user.getUserName(), user.getUserType()));
+              users.getUserAuthorities(user.getUserName()));
         }
       }
     }

http://git-wip-us.apache.org/repos/asf/ambari/blob/f76c87a6/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/AmbariLdapAuthenticationProvider.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/AmbariLdapAuthenticationProvider.java b/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/AmbariLdapAuthenticationProvider.java
index b7ff297..6137b68 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/AmbariLdapAuthenticationProvider.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/AmbariLdapAuthenticationProvider.java
@@ -21,6 +21,7 @@ import java.util.List;
 
 import org.apache.ambari.server.configuration.Configuration;
 import org.apache.ambari.server.orm.dao.UserDAO;
+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.slf4j.Logger;
@@ -61,6 +62,9 @@ public class AmbariLdapAuthenticationProvider implements AuthenticationProvider
     this.userDAO = userDAO;
   }
 
+  // TODO: ************
+  // TODO: This is to be revisited for AMBARI-21219 (Update LDAP Authentication process to work with improved user management facility)
+  // TODO: ************
   @Override
   public Authentication authenticate(Authentication authentication) throws AuthenticationException {
     if (isLdapEnabled()) {
@@ -100,7 +104,6 @@ public class AmbariLdapAuthenticationProvider implements AuthenticationProvider
     } else {
       return null;
     }
-
   }
 
   @Override
@@ -196,7 +199,7 @@ public class AmbariLdapAuthenticationProvider implements AuthenticationProvider
   private Integer getUserId(Authentication authentication) {
     String userName = AuthorizationHelper.resolveLoginAliasToUserName(authentication.getName());
 
-    UserEntity userEntity = userDAO.findLdapUserByName(userName);
+    UserEntity userEntity = userDAO.findUserByName(userName);
 
     // lookup is case insensitive, so no need for string comparison
     if (userEntity == null) {
@@ -206,11 +209,19 @@ public class AmbariLdapAuthenticationProvider implements AuthenticationProvider
 
     if (!userEntity.getActive()) {
       LOG.debug("User account is disabled ('{}')", userName);
+    } else {
+      List<UserAuthenticationEntity> authenticationEntities = userEntity.getAuthenticationEntities();
+      for (UserAuthenticationEntity authenticationEntity : authenticationEntities) {
+        if (authenticationEntity.getAuthenticationType() == UserAuthenticationType.LDAP) {
+          // TODO: Ensure this is the "correct" LDAP entry..
+          return userEntity.getUserId();
+        }
+      }
 
-      throw new InvalidUsernamePasswordCombinationException();
+      LOG.debug("Failed to find LDAP authentication entry for {})", userName);
     }
 
-    return userEntity.getUserId();
+    throw new InvalidUsernamePasswordCombinationException();
   }
 
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/f76c87a6/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/AmbariLdapAuthoritiesPopulator.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/AmbariLdapAuthoritiesPopulator.java b/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/AmbariLdapAuthoritiesPopulator.java
index d38d44c..5c482a1 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/AmbariLdapAuthoritiesPopulator.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/AmbariLdapAuthoritiesPopulator.java
@@ -64,7 +64,7 @@ public class AmbariLdapAuthoritiesPopulator implements LdapAuthoritiesPopulator
 
     UserEntity user;
 
-    user = userDAO.findLdapUserByName(username);
+    user = userDAO.findUserByName(username);
     
     if (user == null) {
       log.error("Can't get authorities for user " + username + ", he is not present in local DB");

http://git-wip-us.apache.org/repos/asf/ambari/blob/f76c87a6/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/AmbariLocalUserProvider.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/AmbariLocalUserProvider.java b/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/AmbariLocalUserProvider.java
index 37d5d49..517efe4 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/AmbariLocalUserProvider.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/AmbariLocalUserProvider.java
@@ -17,9 +17,10 @@
  */
 package org.apache.ambari.server.security.authorization;
 
-import java.util.Collection;
+import java.util.List;
 
 import org.apache.ambari.server.orm.dao.UserDAO;
+import org.apache.ambari.server.orm.entities.UserAuthenticationEntity;
 import org.apache.ambari.server.orm.entities.UserEntity;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -52,47 +53,52 @@ public class AmbariLocalUserProvider extends AbstractUserDetailsAuthenticationPr
     // do nothing
   }
 
+  // TODO: ************
+  // TODO: This is to be revisited for AMBARI-21220 (Update Local Authentication process to work with improved user management facility)
+  // TODO: ************
   @Override
   public Authentication authenticate(Authentication authentication) throws AuthenticationException {
     String userName = authentication.getName().trim();
 
     LOG.info("Loading user by name: " + userName);
 
-    UserEntity userEntity = userDAO.findLocalUserByName(userName);
+    UserEntity userEntity = userDAO.findUserByName(userName);
 
     if (userEntity == null) {
-      //TODO case insensitive name comparison is a temporary solution, until users API will change to use id as PK
       LOG.info("user not found");
       throw new InvalidUsernamePasswordCombinationException();
     }
 
     if (!userEntity.getActive()) {
-      logger.debug("User account is disabled");
-
+      LOG.debug("User account is disabled");
       throw new InvalidUsernamePasswordCombinationException();
     }
 
     if (authentication.getCredentials() == null) {
-      logger.debug("Authentication failed: no credentials provided");
-
+      LOG.debug("Authentication failed: no credentials provided");
       throw new InvalidUsernamePasswordCombinationException();
     }
 
-    String password = userEntity.getUserPassword();
-    String presentedPassword = authentication.getCredentials().toString();
-
-    if (!passwordEncoder.matches(presentedPassword, password)) {
-      logger.debug("Authentication failed: password does not match stored value");
-
-      throw new InvalidUsernamePasswordCombinationException();
+    List<UserAuthenticationEntity> authenticationEntities = userEntity.getAuthenticationEntities();
+    for (UserAuthenticationEntity authenticationEntity : authenticationEntities) {
+      if (authenticationEntity.getAuthenticationType() == UserAuthenticationType.LOCAL) {
+        // This should only get invoked once...
+        String password = authenticationEntity.getAuthenticationKey();
+        String presentedPassword = authentication.getCredentials().toString();
+
+        if (passwordEncoder.matches(presentedPassword, password)) {
+          // The user was  authenticated, return the authenticated user object
+          User user = new User(userEntity);
+          Authentication auth = new AmbariUserAuthentication(password, user, users.getUserAuthorities(userEntity));
+          auth.setAuthenticated(true);
+          return auth;
+        }
+      }
     }
-    Collection<AmbariGrantedAuthority> userAuthorities =
-      users.getUserAuthorities(userEntity.getUserName(), userEntity.getUserType());
 
-    User user = new User(userEntity);
-    Authentication auth = new AmbariUserAuthentication(userEntity.getUserPassword(), user, userAuthorities);
-    auth.setAuthenticated(true);
-    return auth;
+    // The user was not authenticated, fail
+    LOG.debug("Authentication failed: password does not match stored value");
+    throw new InvalidUsernamePasswordCombinationException();
   }
 
   @Override

http://git-wip-us.apache.org/repos/asf/ambari/blob/f76c87a6/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
index 373552e..b9bcff6 100644
--- 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
@@ -17,7 +17,6 @@
  */
 package org.apache.ambari.server.security.authorization;
 
-import java.util.Collection;
 import java.util.HashSet;
 import java.util.Set;
 
@@ -51,9 +50,9 @@ public class AmbariPamAuthenticationProvider implements AuthenticationProvider {
   @Inject
   private Users users;
   @Inject
-  protected UserDAO userDAO;
+  private UserDAO userDAO;
   @Inject
-  protected GroupDAO groupDAO;
+  private GroupDAO groupDAO;
 
   private static final Logger LOG = LoggerFactory.getLogger(AmbariPamAuthenticationProvider.class);
 
@@ -64,97 +63,70 @@ public class AmbariPamAuthenticationProvider implements AuthenticationProvider {
     this.configuration = configuration;
   }
 
-  /**
-   * Performs PAM Initialization
-   *
-   * @param authentication
-   * @return authentication
-   */
-
+  // 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()){
-        PAM pam;
-        String userName = String.valueOf(authentication.getPrincipal());
-        UserEntity existingUser = userDAO.findUserByName(userName);
-        if ((existingUser != null) && (existingUser.getUserType() != UserType.PAM)) {
-          String errorMsg = String.format("%s user exists with the username %s. Cannot authenticate via PAM", existingUser.getUserType(), userName);
-          LOG.error(errorMsg);
-          return null;
-        }
-        try{
-          //Set PAM configuration file (found under /etc/pam.d)
-          String pamConfig = configuration.getPamConfigurationFile();
-          pam = new PAM(pamConfig);
-
-        } catch(PAMException ex) {
-          LOG.error("Unable to Initialize PAM." + ex.getMessage());
-          throw new AuthenticationServiceException("Unable to Initialize PAM - ", ex);
-        }
+    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;
+      return null;
     }
   }
 
-  /**
-   * Performs PAM Authentication
-   *
-   * @param pam
-   * @param authentication
-   * @return authentication
-   */
-
-  protected Authentication authenticateViaPam(PAM pam, Authentication authentication) throws AuthenticationException{
-    if(isPamEnabled()){
-      try {
-          String userName = String.valueOf(authentication.getPrincipal());
-          String passwd = String.valueOf(authentication.getCredentials());
-
-          // authenticate using PAM
-          UnixUser unixUser = pam.authenticate(userName,passwd);
-
-          //Get all the groups that user belongs to
-          //Change all group names to lower case.
-          Set<String> groups = new HashSet<>();
-
-          for(String group: unixUser.getGroups()){
-            groups.add(group.toLowerCase());
-          }
-
-          ambariPamAuthorization(userName,groups);
+  @Override
+  public boolean supports(Class<?> authentication) {
+    return UsernamePasswordAuthenticationToken.class.isAssignableFrom(authentication);
+  }
 
-          Collection<AmbariGrantedAuthority> userAuthorities =
-              users.getUserAuthorities(userName, UserType.PAM);
+  Authentication authenticateViaPam(PAM pam, Authentication authentication) {
+    String userName = String.valueOf(authentication.getPrincipal());
+    String password = String.valueOf(authentication.getCredentials());
 
-          final User user = users.getUser(userName, UserType.PAM);
- 
-          Authentication authToken = new AmbariUserAuthentication(passwd, user, userAuthorities);
-          authToken.setAuthenticated(true);
-          return authToken;   
-        } 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);
+    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);
+    }
 
-        } finally {
-          pam.dispose();
-        }
+    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;
       }
-      else {
-        return null;
-      }
-  }
+    }
 
-  @Override
-  public boolean supports(Class<?> authentication) {
-    return UsernamePasswordAuthenticationToken.class.isAssignableFrom(authentication);
+    return null;
   }
 
   /**
    * Check if PAM authentication is enabled in server properties
+   *
    * @return true if enabled
    */
   private boolean isPamEnabled() {
@@ -163,6 +135,7 @@ public class AmbariPamAuthenticationProvider implements AuthenticationProvider {
 
   /**
    * Check if PAM authentication is enabled in server properties
+   *
    * @return true if enabled
    */
   private boolean isAutoGroupCreationAllowed() {
@@ -173,56 +146,64 @@ public class AmbariPamAuthenticationProvider implements AuthenticationProvider {
   /**
    * Performs PAM authorization by creating user & group(s)
    *
-   * @param userName user name
-   * @param userGroups Collection of groups
-   * @return
+   * @param unixUser the user
    */
-  private void ambariPamAuthorization(String userName,Set<String> userGroups){
+  private UserEntity ambariPamAuthorization(UnixUser unixUser) {
+    String userName = unixUser.getUserName();
+    UserEntity userEntity = null;
+
     try {
-      User existingUser = users.getUser(userName,UserType.PAM);
+      userEntity = userDAO.findUserByName(userName);
 
-      if (existingUser == null ) {
-        users.createUser(userName, null, UserType.PAM, true, false);
+      // TODO: Ensure automatically creating users when authenticating with PAM is allowed.
+      if (userEntity == null) {
+        userEntity = users.createUser(userName, userName, userName);
+        users.addPamAuthentication(userEntity, userName);
       }
 
-      UserEntity userEntity = userDAO.findUserByNameAndType(userName, UserType.PAM);
-
-      if(isAutoGroupCreationAllowed()){
-        for(String userGroup: userGroups){
-          if(users.getGroupByNameAndType(userGroup, GroupType.PAM) == null){
-            users.createGroup(userGroup, GroupType.PAM);
-          }
-
-          final GroupEntity groupEntity = groupDAO.findGroupByNameAndType(userGroup, GroupType.PAM);
-
-          if (!isUserInGroup(userEntity, groupEntity)){
-            users.addMemberToGroup(userGroup,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<String> ambariUserGroups = getUserGroups(userName, UserType.PAM);
-
-        for(String group: ambariUserGroups){
-          if(userGroups == null || !userGroups.contains(group)){
-            users.removeMemberFromGroup(group, userName);
+        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 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()) {
+    for (MemberEntity memberEntity : userEntity.getMemberEntities()) {
       if (memberEntity.getGroup().equals(groupEntity)) {
         return true;
       }
@@ -233,17 +214,20 @@ public class AmbariPamAuthenticationProvider implements AuthenticationProvider {
   /**
    * Extracts all groups a user belongs to
    *
-   * @param userName user name
+   * @param userEntity the user
    * @return Collection of group names
    */
-  private Set<String> getUserGroups(String userName, UserType userType) {
-    UserEntity userEntity = userDAO.findUserByNameAndType(userName, userType);
-    Set<String> groups = new HashSet<>();
-    for (MemberEntity memberEntity: userEntity.getMemberEntities()) {
-      groups.add(memberEntity.getGroup().getGroupName());
+  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/f76c87a6/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/AmbariUserAuthorizationFilter.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/AmbariUserAuthorizationFilter.java b/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/AmbariUserAuthorizationFilter.java
index 95e90b3..8fbd816 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/AmbariUserAuthorizationFilter.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/AmbariUserAuthorizationFilter.java
@@ -30,6 +30,7 @@ import javax.servlet.ServletResponse;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 
+import org.apache.ambari.server.orm.entities.UserEntity;
 import org.apache.ambari.server.scheduler.ExecutionScheduleManager;
 import org.apache.ambari.server.security.authorization.internal.InternalTokenClientFilter;
 import org.apache.ambari.server.security.authorization.internal.InternalTokenStorage;
@@ -70,18 +71,18 @@ public class AmbariUserAuthorizationFilter implements Filter {
             return;
           }
           Integer userId = Integer.parseInt(userToken);
-          User user = users.getUser(userId);
-          if (user == null) {
+          UserEntity userEntity = users.getUserEntity(userId);
+          if (userEntity == null) {
             httpResponse.sendError(HttpServletResponse.SC_FORBIDDEN, "Authentication required");
             httpResponse.flushBuffer();
             return;
-          } if (!user.isActive()) {
+          } if (!userEntity.getActive()) {
             httpResponse.sendError(HttpServletResponse.SC_FORBIDDEN, "User is not active");
             httpResponse.flushBuffer();
             return;
           } else {
-            Collection<AmbariGrantedAuthority> userAuthorities =
-              users.getUserAuthorities(user.getUserName(), user.getUserType());
+            Collection<AmbariGrantedAuthority> userAuthorities = users.getUserAuthorities(userEntity);
+            User user = users.getUser(userEntity);
             AmbariUserAuthentication authentication = new AmbariUserAuthentication(token, user, userAuthorities);
             authentication.setAuthenticated(true);
             SecurityContextHolder.getContext().setAuthentication(authentication);

http://git-wip-us.apache.org/repos/asf/ambari/blob/f76c87a6/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/AuthenticationMethod.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/AuthenticationMethod.java b/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/AuthenticationMethod.java
new file mode 100644
index 0000000..5670c38
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/AuthenticationMethod.java
@@ -0,0 +1,37 @@
+/*
+ * 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;
+
+public class AuthenticationMethod {
+  private final UserAuthenticationType authenticationType;
+  private final String authenticationKey;
+
+  public AuthenticationMethod(UserAuthenticationType authenticationType, String authenticationKey) {
+    this.authenticationType = authenticationType;
+    this.authenticationKey = authenticationKey;
+  }
+
+  public UserAuthenticationType getAuthenticationType() {
+    return authenticationType;
+  }
+
+  public String getAuthenticationKey() {
+    return authenticationKey;
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/f76c87a6/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/AuthorizationHelper.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/AuthorizationHelper.java b/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/AuthorizationHelper.java
index 64d5e61..a0b6029 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/AuthorizationHelper.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/AuthorizationHelper.java
@@ -125,7 +125,7 @@ public class AuthorizationHelper {
    * @return true if authorized; otherwise false
    * @see #isAuthorized(Authentication, ResourceType, Long, Set)
    */
-  public static boolean isAuthorized(ResourceType resourceType, Long resourceId, 
+  public static boolean isAuthorized(ResourceType resourceType, Long resourceId,
                                      RoleAuthorization requiredAuthorization) {
     return isAuthorized(getAuthentication(), resourceType, resourceId, EnumSet.of(requiredAuthorization));
   }
@@ -141,7 +141,7 @@ public class AuthorizationHelper {
    * @return true if authorized; otherwise false
    * @see #isAuthorized(Authentication, ResourceType, Long, Set)
    */
-  public static boolean isAuthorized(ResourceType resourceType, Long resourceId, 
+  public static boolean isAuthorized(ResourceType resourceType, Long resourceId,
                                      Set<RoleAuthorization> requiredAuthorizations) {
     return isAuthorized(getAuthentication(), resourceType, resourceId, requiredAuthorizations);
   }

http://git-wip-us.apache.org/repos/asf/ambari/blob/f76c87a6/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/User.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/User.java b/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/User.java
index bff1fd2..a418451 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/User.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/User.java
@@ -25,8 +25,8 @@ import java.util.List;
 import org.apache.ambari.server.orm.entities.MemberEntity;
 import org.apache.ambari.server.orm.entities.PermissionEntity;
 import org.apache.ambari.server.orm.entities.PrivilegeEntity;
+import org.apache.ambari.server.orm.entities.UserAuthenticationEntity;
 import org.apache.ambari.server.orm.entities.UserEntity;
-import org.springframework.security.core.GrantedAuthority;
 
 import io.swagger.annotations.ApiModel;
 import io.swagger.annotations.ApiModelProperty;
@@ -37,32 +37,39 @@ import io.swagger.annotations.ApiModelProperty;
  */
 @ApiModel
 public class User {
-  final int userId;
-  final String userName;
-  final boolean ldapUser;
-  final UserType userType;
-  final Date createTime;
-  final boolean active;
-  final Collection<String> groups = new ArrayList<>();
-  boolean admin = false;
-  final List<GrantedAuthority> authorities = new ArrayList<>();
+  final private int userId;
+  final private String userName;
+  final private Date createTime;
+  final private boolean active;
+  final private Collection<String> groups;
+  final private Collection<AuthenticationMethod> authenticationMethods;
+  final private boolean admin;
 
   public User(UserEntity userEntity) {
     userId = userEntity.getUserId();
     userName = userEntity.getUserName();
     createTime = userEntity.getCreateTime();
-    userType = userEntity.getUserType();
-    ldapUser = userEntity.getLdapUser();
     active = userEntity.getActive();
+
+    groups = new ArrayList<>();
     for (MemberEntity memberEntity : userEntity.getMemberEntities()) {
       groups.add(memberEntity.getGroup().getGroupName());
     }
-    for (PrivilegeEntity privilegeEntity: userEntity.getPrincipal().getPrivileges()) {
+
+    authenticationMethods = new ArrayList<>();
+    List<UserAuthenticationEntity> authenticationEntities = userEntity.getAuthenticationEntities();
+    for (UserAuthenticationEntity authenticationEntity : authenticationEntities) {
+      authenticationMethods.add(new AuthenticationMethod(authenticationEntity.getAuthenticationType(), authenticationEntity.getAuthenticationKey()));
+    }
+
+    boolean admin = false;
+    for (PrivilegeEntity privilegeEntity : userEntity.getPrincipal().getPrivileges()) {
       if (privilegeEntity.getPermission().getPermissionName().equals(PermissionEntity.AMBARI_ADMINISTRATOR_PERMISSION_NAME)) {
         admin = true;
         break;
       }
     }
+    this.admin = admin;
   }
 
   @ApiModelProperty(hidden = true)
@@ -75,16 +82,6 @@ public class User {
     return userName;
   }
 
-  @ApiModelProperty(name = "Users/ldap_user")
-  public boolean isLdapUser() {
-    return ldapUser;
-  }
-
-  @ApiModelProperty(name = "Users/user_type")
-  public UserType getUserType() {
-    return userType;
-  }
-
   @ApiModelProperty(hidden = true)
   public Date getCreateTime() {
     return createTime;
@@ -105,8 +102,24 @@ public class User {
     return groups;
   }
 
+  @ApiModelProperty(name = "Users/authentication_methods")
+  public Collection<AuthenticationMethod> getAuthenticationMethods() {
+    return authenticationMethods;
+  }
+
+  @ApiModelProperty(name = "Users/ldap_user")
+  public boolean isLdapUser() {
+    for (AuthenticationMethod authenticationMethod : authenticationMethods) {
+      if (authenticationMethod.getAuthenticationType() == UserAuthenticationType.LDAP) {
+        return true;
+      }
+    }
+    return false;
+  }
+
   @Override
   public String toString() {
-    return "[" + getUserType() + "]" + userName;
+    return userName;
   }
+
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/f76c87a6/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/UserAuthenticationType.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/UserAuthenticationType.java b/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/UserAuthenticationType.java
new file mode 100644
index 0000000..ceeb7f9
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/UserAuthenticationType.java
@@ -0,0 +1,26 @@
+/*
+ * 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;
+
+public enum UserAuthenticationType {
+  LOCAL,
+  LDAP,
+  JWT,
+  PAM,
+  KERBEROS
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/f76c87a6/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/UserType.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/UserType.java b/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/UserType.java
deleted file mode 100644
index aabd368..0000000
--- a/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/UserType.java
+++ /dev/null
@@ -1,25 +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;
-
-public enum UserType {
-  LOCAL,
-  LDAP,
-  JWT,
-  PAM
-}