/* * Copyright (C) 2015 Arthur Gregorio, AG.Software * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package br.com.webbudget.domain.model.service; import br.com.webbudget.domain.misc.ex.InternalServiceError; import br.com.webbudget.domain.model.security.Grant; import br.com.webbudget.domain.model.security.Group; import br.com.webbudget.domain.model.security.GroupMembership; import br.com.webbudget.domain.model.security.Role; import br.com.webbudget.domain.model.security.User; import br.com.webbudget.infraestructure.configuration.ApplicationUtils; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import javax.enterprise.context.ApplicationScoped; import javax.faces.application.ProjectStage; import javax.inject.Inject; import javax.transaction.Transactional; import org.picketlink.idm.IdentityManagementException; import org.picketlink.idm.IdentityManager; import org.picketlink.idm.RelationshipManager; import org.picketlink.idm.credential.Password; import org.picketlink.idm.model.Account; import org.picketlink.idm.query.Condition; import org.picketlink.idm.query.IdentityQuery; import org.picketlink.idm.query.IdentityQueryBuilder; import org.picketlink.idm.query.RelationshipQuery; /** * Servico responsavel pelo gerenciamento do modelo de seguranca * * @author Arthur Gregorio * * @version 2.0.0 * @since 1.0.0, 06/10/2013 */ @ApplicationScoped public class AccountService { @Inject private IdentityManager identityManager; @Inject private RelationshipManager relationshipManager; /** * * @param user */ @Transactional public void save(User user) { // validamos os dados do usuario final User found = this.findUserByUsername(user.getUsername()); if (found != null) { throw new InternalServiceError("user.error.duplicated-username"); } // pegamos o grupo e setamos o user no membership dele final GroupMembership groupMembership = user.getGroupMembership(); // pegamos a senha antes de salvar o usuario final String unsecurePassword = user.getPassword(); // salvamos this.identityManager.add(user); // atualizamos o usuario com a senha this.identityManager.updateCredential(user, new Password(unsecurePassword)); // concedemos ao usuario o grant para o grupo que ele escolheu this.relationshipManager.add(groupMembership); } /** * * @param user */ @Transactional public void update(User user) { // limpa a senha para nao ser trocada quando em testes if (ApplicationUtils.isStageRunning(ProjectStage.SystemTest) && user.getUsername().equals("admin")) { return; } // pegamos o grupo final GroupMembership groupMembership = user.getGroupMembership(); // removemos o vinculo antigo this.listMembershipsByUser(user).forEach(membership -> { this.removeFromGroup(membership.getGroup(), user); }); // pegamos a senha antes de salvar o usuario final String unsecurePassword = user.getPassword(); // atualizamos o usuario com a senha if (unsecurePassword != null && !unsecurePassword.isEmpty()) { this.identityManager.updateCredential(user, new Password(unsecurePassword)); } else { // salvamos this.identityManager.update(user); } // concedemos ao usuario o grant para o grupo que ele escolheu this.relationshipManager.add(groupMembership); } /** * * @param user */ @Transactional public void updateProfile(User user) { // limpa a senha para nao ser trocada quando em testes if (ApplicationUtils.isStageRunning(ProjectStage.SystemTest) && user.getUsername().equals("admin")) { user.setPassword(null); } // pegamos a senha antes de salvar o usuario final String unsecurePassword = user.getPassword(); // atualizamos o usuario com a senha if (unsecurePassword != null && !unsecurePassword.isEmpty()) { this.identityManager.updateCredential(user, new Password(unsecurePassword)); } else { // salvamos this.identityManager.update(user); } } /** * * @param user */ @Transactional public void delete(User user) { // limpa a senha para nao ser trocada quando em testes if (ApplicationUtils.isStageRunning(ProjectStage.SystemTest) && user.getUsername().equals("admin")) { return; } // removemos os relacioanamentos for (GroupMembership membership : this.listMembershipsByUser(user)) { this.relationshipManager.remove(membership); } // removemos o usuario do contexto de seguranca this.identityManager.remove(user); } /** * * @param group * @param authorizations */ @Transactional public void save(Group group, List<String> authorizations) { // validamos os dados do grupo final Group found = this.findGroupByName(group.getName()); if (found != null) { throw new InternalServiceError("group.error.duplicated-group"); } // checamos se existem permissoes para este grupo if (authorizations == null || authorizations.isEmpty()) { throw new InternalServiceError("group.error.empty-authorizations"); } // cria o grupo this.identityManager.add(group); // criamos os grants para aquele grupo for (String authorization : authorizations) { final Role role = this.findRoleByName(authorization); this.relationshipManager.add(new Grant(role, group)); } } /** * * @param group * @param authorizations */ @Transactional public void update(Group group, List<String> authorizations) { // checamos se existem permissoes para este grupo if (authorizations == null || authorizations.isEmpty()) { throw new InternalServiceError("group.error.empty-authorizations"); } // removemos todos os grants atuais final List<Grant> oldGrants = this.listGrantsByGroup(group); for (Grant grant : oldGrants) { this.relationshipManager.remove(grant); } // atualiza o grupo this.identityManager.update(group); // recriamos os grants para aquele grupo for (String authorization : authorizations) { final Role role = this.findRoleByName(authorization); this.relationshipManager.add(new Grant(role, group)); } } /** * * @param group */ @Transactional public void delete(Group group) { // removemos todos os grants final List<Grant> oldGrants = this.listGrantsByGroup(group); for (Grant grant : oldGrants) { this.relationshipManager.remove(grant); } // remove o grupo this.identityManager.remove(group); } /** * * @param username * @return */ public User findUserByUsername(String username) { final IdentityQueryBuilder queryBuilder = this.identityManager.getQueryBuilder(); final List<User> users = queryBuilder.createIdentityQuery(User.class) .where(queryBuilder.equal(User.USER_NAME, username)).getResultList(); if (users.isEmpty()) { return null; } else if (users.size() == 1) { return users.get(0); } else { throw new IdentityManagementException("user.error.duplicated-usernames"); } } /** * * @param email * @return */ public User findUserByEmail(String email) { final IdentityQueryBuilder queryBuilder = this.identityManager.getQueryBuilder(); final List<User> users = queryBuilder.createIdentityQuery(User.class) .where(queryBuilder.equal(User.EMAIL, email)).getResultList(); if (users.isEmpty()) { return null; } else if (users.size() == 1) { return users.get(0); } else { throw new IdentityManagementException("user.error.duplicated-emails"); } } /** * * @param userId * @return */ public User findUserById(String userId) { return this.findUserById(userId, true); } /** * * @param userId * @param withGroup * @return */ public User findUserById(String userId, boolean withGroup) { final IdentityQueryBuilder queryBuilder = this.identityManager.getQueryBuilder(); final List<User> users = queryBuilder.createIdentityQuery(User.class) .where(queryBuilder.equal(User.ID, userId)).getResultList(); if (users.isEmpty()) { return null; } else if (users.size() == 1) { final User user = users.get(0); if (withGroup) { user.setGroupMembership(this.listMembershipsByUser(user).get(0)); } return user; } else { throw new IdentityManagementException("user.error.duplicated-usernames"); } } /** * * @param groupId * @return */ public Group findGroupById(String groupId) { final IdentityQueryBuilder queryBuilder = this.identityManager.getQueryBuilder(); final List<Group> groups = queryBuilder.createIdentityQuery(Group.class) .where(queryBuilder.equal(User.ID, groupId)).getResultList(); if (groups.isEmpty()) { return null; } else if (groups.size() == 1) { final Group group = groups.get(0); group.setGrants(this.listGrantsByGroup(group)); return group; } else { throw new IdentityManagementException("group.error.duplicated-groups"); } } /** * * @param authorization * @return */ public Role findRoleByName(String authorization) { final IdentityQueryBuilder queryBuilder = this.identityManager.getQueryBuilder(); final List<Role> roles = queryBuilder.createIdentityQuery(Role.class) .where(queryBuilder.equal(Role.AUTHORIZATION, authorization)).getResultList(); if (roles.isEmpty()) { return null; } else if (roles.size() == 1) { return roles.get(0); } else { throw new IdentityManagementException("role.error.duplicated-roles"); } } /** * * @param groupName * @return */ public Group findGroupByName(String groupName) { final IdentityQueryBuilder queryBuilder = this.identityManager.getQueryBuilder(); final List<Group> groups = queryBuilder.createIdentityQuery(Group.class) .where(queryBuilder.equal(Group.NAME, groupName)).getResultList(); if (groups.isEmpty()) { return null; } else if (groups.size() == 1) { return groups.get(0); } else { throw new IdentityManagementException("group.error.duplicated-groups"); } } /** * * @param user * @return */ public List<GroupMembership> listMembershipsByUser(User user) { final RelationshipQuery<GroupMembership> query = this.relationshipManager.createRelationshipQuery(GroupMembership.class); query.setParameter(GroupMembership.MEMBER, user); return query.getResultList(); } /** * * @param user * @return */ public List<Group> listUserGroups(User user) { final RelationshipQuery<GroupMembership> query = this.relationshipManager.createRelationshipQuery(GroupMembership.class); query.setParameter(GroupMembership.MEMBER, user); final List<Group> groups = new ArrayList<>(); query.getResultList().stream().forEach((membership) -> { groups.add(membership.getGroup()); }); return groups; } /** * * @param isBlocked * @return */ public List<User> listUsers(Boolean isBlocked) { final IdentityQueryBuilder queryBuilder = this.identityManager.getQueryBuilder(); final IdentityQuery<User> query = queryBuilder.createIdentityQuery(User.class); if (isBlocked != null) { query.where(queryBuilder.equal(User.ENABLED, !isBlocked)); } return query.getResultList(); } /** * * @param filter * @param isBlocked * @return */ public List<User> listUsersByFilter(String filter, Boolean isBlocked) { final IdentityQueryBuilder queryBuilder = this.identityManager.getQueryBuilder(); final IdentityQuery<User> query = queryBuilder.createIdentityQuery(User.class); List<Condition> conditions = new ArrayList<>(); // considera que a busca ira ou nao bucar os bloqueados if (isBlocked != null) { conditions.add(queryBuilder.equal(User.ENABLED, !isBlocked)); } // considere que os filtros devem ser setados if (filter != null && !filter.isEmpty()) { conditions = Arrays.asList( queryBuilder.like(User.USER_NAME, "%" + filter + "%"), queryBuilder.like(User.NAME, "%" + filter + "%")); } query.where(conditions.toArray(new Condition[]{})); return query.getResultList(); } /** * * @param filter * @param isBlocked * @return */ public List<Group> listGroupsByFilter(String filter, Boolean isBlocked) { final IdentityQueryBuilder queryBuilder = this.identityManager.getQueryBuilder(); final IdentityQuery<Group> query = queryBuilder.createIdentityQuery(Group.class); List<Condition> conditions = new ArrayList<>(); // considera que a busca ira ou nao bucar os bloqueados if (isBlocked != null) { conditions.add(queryBuilder.equal(User.ENABLED, !isBlocked)); } // considere que os filtros devem ser setados if (filter != null && !filter.isEmpty()) { conditions = Arrays.asList( queryBuilder.like(User.USER_NAME, "%" + filter + "%"), queryBuilder.like(User.NAME, "%" + filter + "%")); } query.where(conditions.toArray(new Condition[]{})); return query.getResultList(); } /** * * @param isBlocked * @return */ public List<Group> listGroups(Boolean isBlocked) { final IdentityQueryBuilder queryBuilder = this.identityManager.getQueryBuilder(); final IdentityQuery<Group> query = queryBuilder.createIdentityQuery(Group.class); if (isBlocked != null) { query.where(queryBuilder.equal(User.ENABLED, !isBlocked)); } return query.getResultList(); } /** * * @param user * @return */ public List<Group> listUserGroupsAndGrants(User user) { final RelationshipQuery<GroupMembership> query = this.relationshipManager.createRelationshipQuery(GroupMembership.class); query.setParameter(GroupMembership.MEMBER, user); final List<Group> groups = new ArrayList<>(); query.getResultList().stream().forEach((membership) -> { groups.add(membership.getGroup()); }); // preenchemos os grants do grupo groups.stream().forEach((group) -> { group.setGrants(this.listGrantsByGroup(group)); }); return groups; } /** * * @param group * @return */ public List<Grant> listGrantsByGroup(Group group) { final RelationshipQuery<Grant> query = this.relationshipManager .createRelationshipQuery(Grant.class); query.setParameter(Grant.ASSIGNEE, group); return query.getResultList(); } /** * * @param member * @param group * @return */ public boolean isMember(User member, Group group) { final RelationshipQuery<GroupMembership> query = this.relationshipManager.createRelationshipQuery(GroupMembership.class); query.setParameter(GroupMembership.MEMBER, member); final List<GroupMembership> memberships = query.getResultList(); return memberships.stream() .anyMatch(membership -> membership.getGroup().getId().equals(group.getId())); } /** * * @param group * @param account */ public void addToGroup(Group group, Account account) { this.relationshipManager.add(new GroupMembership(group, account)); } /** * * @param group * @param account */ public void removeFromGroup(Group group, Account account) { final RelationshipQuery<GroupMembership> query = this.relationshipManager.createRelationshipQuery(GroupMembership.class); query.setParameter(GroupMembership.GROUP, group); query.setParameter(GroupMembership.MEMBER, account); for (GroupMembership membership : query.getResultList()) { this.relationshipManager.remove(membership); } } /** * * @param user * @param role * @return */ public boolean userHasRole(User user, Role role) { final List<Group> groups = this.listUserGroups(user); boolean hasRole = false; for (Group group : groups) { if (this.groupHasRole(group, role)) { hasRole = true; break; } } return hasRole; } /** * * @param group * @param role * @return */ public boolean groupHasRole(Group group, Role role) { final RelationshipQuery<Grant> query = this.relationshipManager.createRelationshipQuery(Grant.class); query.setParameter(Grant.ASSIGNEE, group); query.setParameter(Grant.ROLE, role); return query.getResultList().stream() .anyMatch(grant -> grant.getAssignee().getId().equals(group.getId())); } /** * * @param role * @param group */ public void grantToGroup(Role role, Group group) { this.relationshipManager.add(new Grant(role, group)); } /** * * @param role * @param group */ public void revokeGroupGrant(Role role, Group group) { final RelationshipQuery<Grant> query = this.relationshipManager.createRelationshipQuery(Grant.class); query.setParameter(Grant.ASSIGNEE, group); query.setParameter(Grant.ROLE, role); for (Grant grant : query.getResultList()) { this.relationshipManager.remove(grant); } } }