/*
* 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.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.inject.Inject;
import javax.persistence.EntityManager;
import org.apache.ambari.server.AmbariException;
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.dao.GroupDAO;
import org.apache.ambari.server.orm.dao.MemberDAO;
import org.apache.ambari.server.orm.dao.PermissionDAO;
import org.apache.ambari.server.orm.dao.PrincipalDAO;
import org.apache.ambari.server.orm.dao.PrincipalTypeDAO;
import org.apache.ambari.server.orm.dao.PrivilegeDAO;
import org.apache.ambari.server.orm.dao.ResourceDAO;
import org.apache.ambari.server.orm.dao.ResourceTypeDAO;
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.PermissionEntity;
import org.apache.ambari.server.orm.entities.PrincipalEntity;
import org.apache.ambari.server.orm.entities.PrincipalTypeEntity;
import org.apache.ambari.server.orm.entities.PrivilegeEntity;
import org.apache.ambari.server.orm.entities.ResourceTypeEntity;
import org.apache.ambari.server.orm.entities.UserEntity;
import org.apache.ambari.server.security.ldap.LdapBatchDto;
import org.apache.ambari.server.security.ldap.LdapUserGroupMemberDto;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.crypto.password.PasswordEncoder;
import com.google.inject.Provider;
import com.google.inject.Singleton;
import com.google.inject.persist.Transactional;
/**
* Provides high-level access to Users and Roles in database
*/
@Singleton
public class Users {
private static final Logger LOG = LoggerFactory.getLogger(Users.class);
@Inject
Provider<EntityManager> entityManagerProvider;
@Inject
protected UserDAO userDAO;
@Inject
protected GroupDAO groupDAO;
@Inject
protected MemberDAO memberDAO;
@Inject
protected PrincipalDAO principalDAO;
@Inject
protected PermissionDAO permissionDAO;
@Inject
protected PrivilegeDAO privilegeDAO;
@Inject
protected ResourceDAO resourceDAO;
@Inject
protected ResourceTypeDAO resourceTypeDAO;
@Inject
protected PrincipalTypeDAO principalTypeDAO;
@Inject
protected PasswordEncoder passwordEncoder;
@Inject
protected Configuration configuration;
@Inject
private AmbariLdapAuthenticationProvider ldapAuthenticationProvider;
@Inject
private Provider<HookService> hookServiceProvider;
@Inject
private HookContextFactory hookContextFactory;
public List<User> getAllUsers() {
List<UserEntity> userEntities = userDAO.findAll();
List<User> users = new ArrayList<>(userEntities.size());
for (UserEntity userEntity : userEntities) {
users.add(new User(userEntity));
}
return users;
}
/**
* This method works incorrectly, userName is not unique if users have different types
*
* @return One user. Priority is LOCAL -> LDAP -> JWT -> PAM
*/
@Deprecated
public User getAnyUser(String userName) {
UserEntity userEntity = userDAO.findSingleUserByName(userName);
return (null == userEntity) ? null : new User(userEntity);
}
public User getUser(String userName, UserType userType) {
UserEntity userEntity = userDAO.findUserByNameAndType(userName, userType);
return (null == userEntity) ? null : new User(userEntity);
}
public User getUser(Integer userId) {
UserEntity userEntity = userDAO.findByPK(userId);
return (null == userEntity) ? null : new User(userEntity);
}
/**
* Retrieves User then userName is unique in users DB. Will return null if there no user with provided userName or
* there are some users with provided userName but with different types.
*
* <p>User names in the future will likely be unique hence the deprecation.</p>
*
* @param userName
* @return User if userName is unique in DB, null otherwise
*/
@Deprecated
public User getUserIfUnique(String userName) {
List<UserEntity> userEntities = new ArrayList<>();
UserEntity userEntity = userDAO.findUserByNameAndType(userName, UserType.LOCAL);
if (userEntity != null) {
userEntities.add(userEntity);
}
userEntity = userDAO.findUserByNameAndType(userName, UserType.LDAP);
if (userEntity != null) {
userEntities.add(userEntity);
}
userEntity = userDAO.findUserByNameAndType(userName, UserType.JWT);
if (userEntity != null) {
userEntities.add(userEntity);
}
return (userEntities.isEmpty() || userEntities.size() > 1) ? null : new User(userEntities.get(0));
}
/**
* Modifies password of local user
*
* @throws AmbariException
*/
public synchronized void modifyPassword(String userName, String currentUserPassword, String newPassword) throws AmbariException {
SecurityContext securityContext = SecurityContextHolder.getContext();
String currentUserName = securityContext.getAuthentication().getName();
if (currentUserName == null) {
throw new AmbariException("Authentication required. Please sign in.");
}
UserEntity currentUserEntity = userDAO.findLocalUserByName(currentUserName);
//Authenticate LDAP user
boolean isLdapUser = false;
if (currentUserEntity == null) {
currentUserEntity = userDAO.findLdapUserByName(currentUserName);
try {
ldapAuthenticationProvider.authenticate(
new UsernamePasswordAuthenticationToken(currentUserName, currentUserPassword));
isLdapUser = true;
} catch (InvalidUsernamePasswordCombinationException ex) {
throw new AmbariException(ex.getMessage());
}
}
boolean isCurrentUserAdmin = false;
for (PrivilegeEntity privilegeEntity : currentUserEntity.getPrincipal().getPrivileges()) {
if (privilegeEntity.getPermission().getPermissionName().equals(PermissionEntity.AMBARI_ADMINISTRATOR_PERMISSION_NAME)) {
isCurrentUserAdmin = true;
break;
}
}
UserEntity userEntity = userDAO.findLocalUserByName(userName);
if ((userEntity != null) && (currentUserEntity != null)) {
if (!isCurrentUserAdmin && !userName.equals(currentUserName)) {
throw new AmbariException("You can't change password of another user");
}
if ((isLdapUser && isCurrentUserAdmin) || (StringUtils.isNotEmpty(currentUserPassword) &&
passwordEncoder.matches(currentUserPassword, currentUserEntity.getUserPassword()))) {
userEntity.setUserPassword(passwordEncoder.encode(newPassword));
userDAO.merge(userEntity);
} else {
throw new AmbariException("Wrong current password provided");
}
} else {
userEntity = userDAO.findLdapUserByName(userName);
if (userEntity != null) {
throw new AmbariException("Password of LDAP user cannot be modified");
} else {
throw new AmbariException("User " + userName + " not found");
}
}
}
/**
* Enables/disables user.
*
* @param userName user name
* @throws AmbariException if user does not exist
*/
public synchronized void setUserActive(String userName, boolean active) throws AmbariException {
UserEntity userEntity = userDAO.findUserByName(userName);
if (userEntity != null) {
userEntity.setActive(active);
userDAO.merge(userEntity);
} else {
throw new AmbariException("User " + userName + " doesn't exist");
}
}
/**
* Converts user to LDAP user.
*
* @param userName user name
* @throws AmbariException if user does not exist
*/
public synchronized void setUserLdap(String userName) throws AmbariException {
UserEntity userEntity = userDAO.findUserByName(userName);
if (userEntity != null) {
userEntity.setLdapUser(true);
userDAO.merge(userEntity);
} else {
throw new AmbariException("User " + userName + " doesn't exist");
}
}
/**
* Converts group to LDAP group.
*
* @param groupName group name
* @throws AmbariException if group does not exist
*/
public synchronized void setGroupLdap(String groupName) throws AmbariException {
GroupEntity groupEntity = groupDAO.findGroupByName(groupName);
if (groupEntity != null) {
groupEntity.setGroupType(GroupType.LDAP);
groupDAO.merge(groupEntity);
} else {
throw new AmbariException("Group " + groupName + " doesn't exist");
}
}
/**
* Creates new local user with provided userName and password.
*
* @param userName user name
* @param password password
* @throws AmbariException if user already exists
*/
public void createUser(String userName, String password) throws AmbariException {
createUser(userName, password, UserType.LOCAL, true, false);
}
/**
* Creates new user with provided userName and password.
*
* @param userName user name
* @param password password
* @param userType user type
* @param active is user active
* @param admin is user admin
* @throws AmbariException if user already exists
*/
public synchronized void createUser(String userName, String password, UserType userType, Boolean active, Boolean
admin) throws AmbariException {
// if user type is not provided, assume LOCAL since the default
// value of user_type in the users table is LOCAL
if (userType == null) {
throw new AmbariException("UserType not specified.");
}
User existingUser = getAnyUser(userName);
if (existingUser != null) {
throw new AmbariException("User " + existingUser.getUserName() + " already exists with type "
+ existingUser.getUserType());
}
PrincipalTypeEntity principalTypeEntity = principalTypeDAO.findById(PrincipalTypeEntity.USER_PRINCIPAL_TYPE);
if (principalTypeEntity == null) {
principalTypeEntity = new PrincipalTypeEntity();
principalTypeEntity.setId(PrincipalTypeEntity.USER_PRINCIPAL_TYPE);
principalTypeEntity.setName(PrincipalTypeEntity.USER_PRINCIPAL_TYPE_NAME);
principalTypeDAO.create(principalTypeEntity);
}
PrincipalEntity principalEntity = new PrincipalEntity();
principalEntity.setPrincipalType(principalTypeEntity);
principalDAO.create(principalEntity);
UserEntity userEntity = new UserEntity();
userEntity.setUserName(UserName.fromString(userName));
if (userType == UserType.LOCAL) {
//passwords should be stored for local users only
userEntity.setUserPassword(passwordEncoder.encode(password));
}
userEntity.setPrincipal(principalEntity);
if (active != null) {
userEntity.setActive(active);
}
userEntity.setUserType(userType);
if (userType == UserType.LDAP) {
userEntity.setLdapUser(true);
}
userDAO.create(userEntity);
if (admin != null && admin) {
grantAdminPrivilege(userEntity.getUserId());
}
// execute user initialization hook if required ()
hookServiceProvider.get().execute(hookContextFactory.createUserHookContext(userName));
}
public synchronized void removeUser(User user) throws AmbariException {
UserEntity userEntity = userDAO.findByPK(user.getUserId());
if (userEntity != null) {
if (!isUserCanBeRemoved(userEntity)) {
throw new AmbariException("Could not remove user " + userEntity.getUserName() +
". System should have at least one administrator.");
}
userDAO.remove(userEntity);
} else {
throw new AmbariException("User " + user + " doesn't exist");
}
}
/**
* Gets group by given name.
*
* @param groupName group name
* @return group
*/
public Group getGroup(String groupName) {
final GroupEntity groupEntity = groupDAO.findGroupByName(groupName);
return (null == groupEntity) ? null : new Group(groupEntity);
}
/**
* Gets group by given name & type.
*
* @param groupName group name
* @param groupType group type
* @return group
*/
public Group getGroupByNameAndType(String groupName, GroupType groupType) {
final GroupEntity groupEntity = groupDAO.findGroupByNameAndType(groupName, groupType);
return (null == groupEntity) ? null : new Group(groupEntity);
}
/**
* Gets group members.
*
* @param groupName group name
* @return list of members
*/
public Collection<User> getGroupMembers(String groupName) {
final GroupEntity groupEntity = groupDAO.findGroupByName(groupName);
if (groupEntity == null) {
return null;
} else {
final Set<User> users = new HashSet<>();
for (MemberEntity memberEntity : groupEntity.getMemberEntities()) {
if (memberEntity.getUser() != null) {
users.add(new User(memberEntity.getUser()));
} else {
LOG.error("Wrong state, not found user for member '{}' (group: '{}')",
memberEntity.getMemberId(), memberEntity.getGroup().getGroupName());
}
}
return users;
}
}
/**
* Creates new group with provided name & type
*/
@Transactional
public synchronized void createGroup(String groupName, GroupType groupType) {
// create an admin principal to represent this group
PrincipalTypeEntity principalTypeEntity = principalTypeDAO.findById(PrincipalTypeEntity.GROUP_PRINCIPAL_TYPE);
if (principalTypeEntity == null) {
principalTypeEntity = new PrincipalTypeEntity();
principalTypeEntity.setId(PrincipalTypeEntity.GROUP_PRINCIPAL_TYPE);
principalTypeEntity.setName(PrincipalTypeEntity.GROUP_PRINCIPAL_TYPE_NAME);
principalTypeDAO.create(principalTypeEntity);
}
PrincipalEntity principalEntity = new PrincipalEntity();
principalEntity.setPrincipalType(principalTypeEntity);
principalDAO.create(principalEntity);
final GroupEntity groupEntity = new GroupEntity();
groupEntity.setGroupName(groupName);
groupEntity.setPrincipal(principalEntity);
groupEntity.setGroupType(groupType);
groupDAO.create(groupEntity);
}
/**
* Gets all groups.
*
* @return list of groups
*/
public List<Group> getAllGroups() {
final List<GroupEntity> groupEntities = groupDAO.findAll();
final List<Group> groups = new ArrayList<>(groupEntities.size());
for (GroupEntity groupEntity : groupEntities) {
groups.add(new Group(groupEntity));
}
return groups;
}
/**
* Gets all members of a group specified.
*
* @param groupName group name
* @return list of user names
*/
public List<String> getAllMembers(String groupName) throws AmbariException {
final List<String> members = new ArrayList<>();
final GroupEntity groupEntity = groupDAO.findGroupByName(groupName);
if (groupEntity == null) {
throw new AmbariException("Group " + groupName + " doesn't exist");
}
for (MemberEntity member : groupEntity.getMemberEntities()) {
members.add(member.getUser().getUserName());
}
return members;
}
@Transactional
public synchronized void removeGroup(Group group) throws AmbariException {
final GroupEntity groupEntity = groupDAO.findByPK(group.getGroupId());
if (groupEntity != null) {
groupDAO.remove(groupEntity);
} else {
throw new AmbariException("Group " + group + " doesn't exist");
}
}
/**
* Grants AMBARI.ADMINISTRATOR privilege to provided user.
*
* @param userId user id
*/
public synchronized void grantAdminPrivilege(Integer userId) {
final UserEntity user = userDAO.findByPK(userId);
final PrivilegeEntity adminPrivilege = new PrivilegeEntity();
adminPrivilege.setPermission(permissionDAO.findAmbariAdminPermission());
adminPrivilege.setPrincipal(user.getPrincipal());
adminPrivilege.setResource(resourceDAO.findAmbariResource());
if (!user.getPrincipal().getPrivileges().contains(adminPrivilege)) {
privilegeDAO.create(adminPrivilege);
user.getPrincipal().getPrivileges().add(adminPrivilege);
principalDAO.merge(user.getPrincipal()); //explicit merge for Derby support
userDAO.merge(user);
}
}
/**
* Grants privilege to provided group.
*
* @param groupId group id
* @param resourceId resource id
* @param resourceType resource type
* @param permissionName permission name
*/
public synchronized void grantPrivilegeToGroup(Integer groupId, Long resourceId, ResourceType resourceType, String permissionName) {
final GroupEntity group = groupDAO.findByPK(groupId);
final PrivilegeEntity privilege = new PrivilegeEntity();
ResourceTypeEntity resourceTypeEntity = new ResourceTypeEntity();
resourceTypeEntity.setId(resourceType.getId());
resourceTypeEntity.setName(resourceType.name());
privilege.setPermission(permissionDAO.findPermissionByNameAndType(permissionName,resourceTypeEntity));
privilege.setPrincipal(group.getPrincipal());
privilege.setResource(resourceDAO.findById(resourceId));
if (!group.getPrincipal().getPrivileges().contains(privilege)) {
privilegeDAO.create(privilege);
group.getPrincipal().getPrivileges().add(privilege);
principalDAO.merge(group.getPrincipal()); //explicit merge for Derby support
groupDAO.merge(group);
privilegeDAO.merge(privilege);
}
}
/**
* Revokes AMBARI.ADMINISTRATOR privilege from provided user.
*
* @param userId user id
*/
public synchronized void revokeAdminPrivilege(Integer userId) {
final UserEntity user = userDAO.findByPK(userId);
for (PrivilegeEntity privilege : user.getPrincipal().getPrivileges()) {
if (privilege.getPermission().getPermissionName().equals(PermissionEntity.AMBARI_ADMINISTRATOR_PERMISSION_NAME)) {
user.getPrincipal().getPrivileges().remove(privilege);
principalDAO.merge(user.getPrincipal()); //explicit merge for Derby support
userDAO.merge(user);
privilegeDAO.remove(privilege);
break;
}
}
}
@Transactional
public synchronized void addMemberToGroup(String groupName, String userName)
throws AmbariException {
final GroupEntity groupEntity = groupDAO.findGroupByName(groupName);
if (groupEntity == null) {
throw new AmbariException("Group " + groupName + " doesn't exist");
}
UserEntity userEntity = userDAO.findUserByName(userName);
if (userEntity == null) {
throw new AmbariException("User " + userName + " doesn't exist");
}
if (isUserInGroup(userEntity, groupEntity)) {
throw new AmbariException("User " + userName + " is already present in group " + groupName);
} else {
final MemberEntity memberEntity = new MemberEntity();
memberEntity.setGroup(groupEntity);
memberEntity.setUser(userEntity);
userEntity.getMemberEntities().add(memberEntity);
groupEntity.getMemberEntities().add(memberEntity);
memberDAO.create(memberEntity);
userDAO.merge(userEntity);
groupDAO.merge(groupEntity);
}
}
@Transactional
public synchronized void removeMemberFromGroup(String groupName, String userName)
throws AmbariException {
final GroupEntity groupEntity = groupDAO.findGroupByName(groupName);
if (groupEntity == null) {
throw new AmbariException("Group " + groupName + " doesn't exist");
}
UserEntity userEntity = userDAO.findUserByName(userName);
if (userEntity == null) {
throw new AmbariException("User " + userName + " doesn't exist");
}
if (isUserInGroup(userEntity, groupEntity)) {
MemberEntity memberEntity = null;
for (MemberEntity entity : userEntity.getMemberEntities()) {
if (entity.getGroup().equals(groupEntity)) {
memberEntity = entity;
break;
}
}
userEntity.getMemberEntities().remove(memberEntity);
groupEntity.getMemberEntities().remove(memberEntity);
userDAO.merge(userEntity);
groupDAO.merge(groupEntity);
memberDAO.remove(memberEntity);
} else {
throw new AmbariException("User " + userName + " is not present in group " + groupName);
}
}
/**
* Performs a check if the user can be removed. Do not allow removing all admins from database.
*
* @param userEntity user to be checked
* @return true if user can be removed
*/
public synchronized boolean isUserCanBeRemoved(UserEntity userEntity) {
List<PrincipalEntity> adminPrincipals = principalDAO.findByPermissionId(PermissionEntity.AMBARI_ADMINISTRATOR_PERMISSION);
Set<UserEntity> userEntitysSet = new HashSet<>(userDAO.findUsersByPrincipal(adminPrincipals));
return (userEntitysSet.contains(userEntity) && userEntitysSet.size() < 2) ? false : true;
}
/**
* 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;
}
/**
* Executes batch queries to database to insert large amounts of LDAP data.
*
* @param batchInfo DTO with batch information
*/
public void processLdapSync(LdapBatchDto batchInfo) {
final Map<String, UserEntity> allUsers = new HashMap<>();
final Map<String, GroupEntity> allGroups = new HashMap<>();
// prefetch all user and group data to avoid heavy queries in membership creation
for (UserEntity userEntity : userDAO.findAll()) {
allUsers.put(userEntity.getUserName(), userEntity);
}
for (GroupEntity groupEntity : groupDAO.findAll()) {
allGroups.put(groupEntity.getGroupName(), groupEntity);
}
final PrincipalTypeEntity userPrincipalType = principalTypeDAO
.ensurePrincipalTypeCreated(PrincipalTypeEntity.USER_PRINCIPAL_TYPE);
final PrincipalTypeEntity groupPrincipalType = principalTypeDAO
.ensurePrincipalTypeCreated(PrincipalTypeEntity.GROUP_PRINCIPAL_TYPE);
// remove users
final Set<UserEntity> usersToRemove = new HashSet<>();
for (String userName : batchInfo.getUsersToBeRemoved()) {
UserEntity userEntity = userDAO.findUserByName(userName);
if (userEntity == null) {
continue;
}
allUsers.remove(userEntity.getUserName());
usersToRemove.add(userEntity);
}
userDAO.remove(usersToRemove);
// remove groups
final Set<GroupEntity> groupsToRemove = new HashSet<>();
for (String groupName : batchInfo.getGroupsToBeRemoved()) {
final GroupEntity groupEntity = groupDAO.findGroupByName(groupName);
allGroups.remove(groupEntity.getGroupName());
groupsToRemove.add(groupEntity);
}
groupDAO.remove(groupsToRemove);
// update users
final Set<UserEntity> usersToBecomeLdap = new HashSet<>();
for (String userName : batchInfo.getUsersToBecomeLdap()) {
UserEntity userEntity = userDAO.findLocalUserByName(userName);
if (userEntity == null) {
userEntity = userDAO.findLdapUserByName(userName);
if (userEntity == null) {
continue;
}
}
userEntity.setLdapUser(true);
allUsers.put(userEntity.getUserName(), userEntity);
usersToBecomeLdap.add(userEntity);
}
userDAO.merge(usersToBecomeLdap);
// update groups
final Set<GroupEntity> groupsToBecomeLdap = new HashSet<>();
for (String groupName : batchInfo.getGroupsToBecomeLdap()) {
final GroupEntity groupEntity = groupDAO.findGroupByName(groupName);
groupEntity.setGroupType(GroupType.LDAP);
allGroups.put(groupEntity.getGroupName(), groupEntity);
groupsToBecomeLdap.add(groupEntity);
}
groupDAO.merge(groupsToBecomeLdap);
// prepare create principals
final List<PrincipalEntity> principalsToCreate = new ArrayList<>();
// prepare create users
final Set<UserEntity> usersToCreate = new HashSet<>();
for (String userName : batchInfo.getUsersToBeCreated()) {
final PrincipalEntity principalEntity = new PrincipalEntity();
principalEntity.setPrincipalType(userPrincipalType);
principalsToCreate.add(principalEntity);
final UserEntity userEntity = new UserEntity();
userEntity.setUserName(UserName.fromString(userName));
userEntity.setUserPassword("");
userEntity.setPrincipal(principalEntity);
userEntity.setLdapUser(true);
allUsers.put(userEntity.getUserName(), userEntity);
usersToCreate.add(userEntity);
}
// prepare create groups
final Set<GroupEntity> groupsToCreate = new HashSet<>();
for (String groupName : batchInfo.getGroupsToBeCreated()) {
final PrincipalEntity principalEntity = new PrincipalEntity();
principalEntity.setPrincipalType(groupPrincipalType);
principalsToCreate.add(principalEntity);
final GroupEntity groupEntity = new GroupEntity();
groupEntity.setGroupName(groupName);
groupEntity.setPrincipal(principalEntity);
groupEntity.setGroupType(GroupType.LDAP);
allGroups.put(groupEntity.getGroupName(), groupEntity);
groupsToCreate.add(groupEntity);
}
// create users and groups
principalDAO.create(principalsToCreate);
userDAO.create(usersToCreate);
groupDAO.create(groupsToCreate);
// create membership
final Set<MemberEntity> membersToCreate = new HashSet<>();
final Set<GroupEntity> groupsToUpdate = new HashSet<>();
for (LdapUserGroupMemberDto member : batchInfo.getMembershipToAdd()) {
final MemberEntity memberEntity = new MemberEntity();
final GroupEntity groupEntity = allGroups.get(member.getGroupName());
memberEntity.setGroup(groupEntity);
memberEntity.setUser(allUsers.get(member.getUserName()));
groupEntity.getMemberEntities().add(memberEntity);
groupsToUpdate.add(groupEntity);
membersToCreate.add(memberEntity);
}
memberDAO.create(membersToCreate);
groupDAO.merge(groupsToUpdate); // needed for Derby DB as it doesn't fetch newly added members automatically
// remove membership
final Set<MemberEntity> membersToRemove = new HashSet<>();
for (LdapUserGroupMemberDto member : batchInfo.getMembershipToRemove()) {
MemberEntity memberEntity = memberDAO.findByUserAndGroup(member.getUserName(), member.getGroupName());
if (memberEntity != null) {
membersToRemove.add(memberEntity);
}
}
memberDAO.remove(membersToRemove);
// clear cached entities
entityManagerProvider.get().getEntityManagerFactory().getCache().evictAll();
if (!usersToCreate.isEmpty()) {
// entry point in the hook logic
hookServiceProvider.get().execute(hookContextFactory.createBatchUserHookContext(getUsersToGroupMap(usersToCreate)));
}
}
/**
* Assembles a map where the keys are usernames and values are Lists with groups associated with users.
*
* @param usersToCreate a list with user entities
* @return the a populated map instance
*/
private Map<String, Set<String>> getUsersToGroupMap(Set<UserEntity> usersToCreate) {
Map<String, Set<String>> usersToGroups = new HashMap<>();
for (UserEntity userEntity : usersToCreate) {
// make sure user entities are refreshed so that membership is updated
userEntity = userDAO.findByPK(userEntity.getUserId());
usersToGroups.put(userEntity.getUserName(), new HashSet<String>());
for (MemberEntity memberEntity : userEntity.getMemberEntities()) {
usersToGroups.get(userEntity.getUserName()).add(memberEntity.getGroup().getGroupName());
}
}
return usersToGroups;
}
/**
* Gets the explicit and implicit privileges for the given user.
* <p>
* The explicit privileges are the privileges that have be explicitly set by assigning roles to
* a user. For example the Cluster Operator role on a given cluster gives that the ability to
* start and stop services in that cluster, among other privileges for that particular cluster.
* <p>
* The implicit privileges are the privileges that have been given to the roles themselves which
* in turn are granted to the users that have been assigned those roles. For example if the
* Cluster User role for a given cluster has been given View User access on a specified File View
* instance, then all users who have the Cluster User role for that cluster will implicitly be
* granted View User access on that File View instance.
*
* @param userEntity the relevant user
* @return the collection of implicit and explicit privileges
*/
public Collection<PrivilegeEntity> getUserPrivileges(UserEntity userEntity) {
if (userEntity == null) {
return Collections.emptyList();
}
// get all of the privileges for the user
List<PrincipalEntity> principalEntities = new LinkedList<>();
principalEntities.add(userEntity.getPrincipal());
List<MemberEntity> memberEntities = memberDAO.findAllMembersByUser(userEntity);
for (MemberEntity memberEntity : memberEntities) {
principalEntities.add(memberEntity.getGroup().getPrincipal());
}
List<PrivilegeEntity> explicitPrivilegeEntities = privilegeDAO.findAllByPrincipal(principalEntities);
List<PrivilegeEntity> implicitPrivilegeEntities = getImplicitPrivileges(explicitPrivilegeEntities);
List<PrivilegeEntity> privilegeEntities;
if (implicitPrivilegeEntities.isEmpty()) {
privilegeEntities = explicitPrivilegeEntities;
} else {
privilegeEntities = new LinkedList<>();
privilegeEntities.addAll(explicitPrivilegeEntities);
privilegeEntities.addAll(implicitPrivilegeEntities);
}
return privilegeEntities;
}
/**
* Gets the explicit and implicit privileges for the given group.
* <p>
* The explicit privileges are the privileges that have be explicitly set by assigning roles to
* a group. For example the Cluster Operator role on a given cluster gives that the ability to
* start and stop services in that cluster, among other privileges for that particular cluster.
* <p>
* The implicit privileges are the privileges that have been given to the roles themselves which
* in turn are granted to the groups that have been assigned those roles. For example if the
* Cluster User role for a given cluster has been given View User access on a specified File View
* instance, then all groups that have the Cluster User role for that cluster will implicitly be
* granted View User access on that File View instance.
*
* @param groupEntity the relevant group
* @return the collection of implicit and explicit privileges
*/
public Collection<PrivilegeEntity> getGroupPrivileges(GroupEntity groupEntity) {
if (groupEntity == null) {
return Collections.emptyList();
}
// get all of the privileges for the group
List<PrincipalEntity> principalEntities = new LinkedList<>();
principalEntities.add(groupEntity.getPrincipal());
List<PrivilegeEntity> explicitPrivilegeEntities = privilegeDAO.findAllByPrincipal(principalEntities);
List<PrivilegeEntity> implicitPrivilegeEntities = getImplicitPrivileges(explicitPrivilegeEntities);
List<PrivilegeEntity> privilegeEntities;
if (implicitPrivilegeEntities.isEmpty()) {
privilegeEntities = explicitPrivilegeEntities;
} else {
privilegeEntities = new LinkedList<>();
privilegeEntities.addAll(explicitPrivilegeEntities);
privilegeEntities.addAll(implicitPrivilegeEntities);
}
return privilegeEntities;
}
/**
* Gets the explicit and implicit authorities for the given user.
* <p>
* The explicit authorities are the authorities that have be explicitly set by assigning roles to
* a user. For example the Cluster Operator role on a given cluster gives that the ability to
* start and stop services in that cluster, among other privileges for that particular cluster.
* <p>
* The implicit authorities are the authorities that have been given to the roles themselves which
* in turn are granted to the users that have been assigned those roles. For example if the
* Cluster User role for a given cluster has been given View User access on a specified File View
* instance, then all users who have the Cluster User role for that cluster will implicitly be
* granted View User access on that File View instance.
*
* @param userName the username for the relevant user
* @param userType the user type for the relevant user
* @return the users collection of implicit and explicit granted authorities
*/
public Collection<AmbariGrantedAuthority> getUserAuthorities(String userName, UserType userType) {
UserEntity userEntity = userDAO.findUserByNameAndType(userName, userType);
if (userEntity == null) {
return Collections.emptyList();
}
Collection<PrivilegeEntity> privilegeEntities = getUserPrivileges(userEntity);
Set<AmbariGrantedAuthority> authorities = new HashSet<>(privilegeEntities.size());
for (PrivilegeEntity privilegeEntity : privilegeEntities) {
authorities.add(new AmbariGrantedAuthority(privilegeEntity));
}
return authorities;
}
/**
* Gets the implicit privileges based on the set of roles found in a collection of privileges.
* <p>
* The implicit privileges are the privileges that have been given to the roles themselves which
* in turn are granted to the groups that have been assigned those roles. For example if the
* Cluster User role for a given cluster has been given View User access on a specified File View
* instance, then all groups that have the Cluster User role for that cluster will implicitly be
* granted View User access on that File View instance.
*
* @param privilegeEntities the relevant privileges
* @return the collection explicit privileges
*/
private List<PrivilegeEntity> getImplicitPrivileges(List<PrivilegeEntity> privilegeEntities) {
if ((privilegeEntities == null) || privilegeEntities.isEmpty()) {
return Collections.emptyList();
}
List<PrivilegeEntity> implicitPrivileges = new LinkedList<>();
// A list of principals representing roles/permissions. This collection of roles will be used to
// find additional inherited privileges based on the assigned roles.
// For example a File View instance may be set to be accessible to all authenticated user with
// the Cluster User role.
List<PrincipalEntity> rolePrincipals = new ArrayList<>();
for (PrivilegeEntity privilegeEntity : privilegeEntities) {
// Add the principal representing the role associated with this PrivilegeEntity to the collection
// of roles.
PrincipalEntity rolePrincipal = privilegeEntity.getPermission().getPrincipal();
if (rolePrincipal != null) {
rolePrincipals.add(rolePrincipal);
}
}
// If the collections of assigned roles is not empty find the inherited priviliges.
if (!rolePrincipals.isEmpty()) {
// For each "role" see if any privileges have been granted...
implicitPrivileges.addAll(privilegeDAO.findAllByPrincipal(rolePrincipals));
}
return implicitPrivileges;
}
}