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 -}
