package org.bubblecloud.ilves.security;
import org.bubblecloud.ilves.cache.PrivilegeCache;
import org.bubblecloud.ilves.exception.SiteException;
import org.bubblecloud.ilves.model.*;
import javax.persistence.EntityManager;
import javax.persistence.TypedQuery;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import java.util.List;
/**
* Created by tlaukkan on 12/14/2014.
*/
public class SecurityService {
public static void addCustomer(final SecurityContext context, final Customer customer, final User user) {
addCustomer(context, customer);
UserDao.addGroupMember(context.getEntityManager(), customer.getAdminGroup(), user);
UserDao.addGroupMember(context.getEntityManager(), customer.getMemberGroup(), user);
}
/**
* Adds new customer to database.
* @param context the processing context
* @param customer the customer
*/
public static void addCustomer(final SecurityContext context, final Customer customer) {
final Company company = context.getObject(Company.class);
if (company.isSelfRegistration()) {
requireRole("add-customer", context, DefaultRoles.ADMINISTRATOR, DefaultRoles.ANONYMOUS);
} else {
requireRole("add-customer", context, DefaultRoles.ADMINISTRATOR);
}
CustomerDao.addCustomer(context.getEntityManager(), customer);
AuditService.log(context, "add", "customer", customer.getCustomerId(), customer.toString());
}
/**
* Updates new customer to database.
* @param context the processing context
* @param customer the customer
*/
public static void updateCustomer(final SecurityContext context, final Customer customer) {
requirePrivilege(DefaultPrivileges.ADMINISTER, "customer", customer.getCustomerId(), customer.toString(), context, DefaultRoles.ADMINISTRATOR);
CustomerDao.updateCustomer(context.getEntityManager(), customer);
AuditService.log(context, "update", "customer", customer.getCustomerId(), customer.toString());
}
/**
* Removes customer from database.
* @param context the processing context
* @param customer the customer
*/
public static void removeCustomer(final SecurityContext context, final Customer customer) {
requireRole("remove-customer", context, DefaultRoles.ADMINISTRATOR);
CustomerDao.removeCustomer(context.getEntityManager(), customer);
AuditService.log(context, "remove", "customer", customer.getCustomerId(), customer.toString());
}
/**
* Adds new userDirectory to database.
* @param context the processing context
* @param userDirectory the userDirectory
*/
public static void addUserDirectory(final SecurityContext context, final UserDirectory userDirectory) {
requireRole("add-user-directory", context, DefaultRoles.ADMINISTRATOR);
UserDirectoryDao.addUserDirectory(context.getEntityManager(), userDirectory);
AuditService.log(context, "add", "user-directory", userDirectory.getUserDirectoryId(), userDirectory.getAddress());
}
/**
* Updates new userDirectory to database.
* @param context the processing context
* @param userDirectory the userDirectory
*/
public static void updateUserDirectory(final SecurityContext context, final UserDirectory userDirectory) {
requireRole("update-user-directory", context, DefaultRoles.ADMINISTRATOR);
UserDirectoryDao.updateUserDirectory(context.getEntityManager(), userDirectory);
AuditService.log(context, "update", "user-directory", userDirectory.getUserDirectoryId(), userDirectory.getAddress());
}
/**
* Removes userDirectory from database.
* @param context the processing context
* @param userDirectory the userDirectory
*/
public static void removeUserDirectory(final SecurityContext context, final UserDirectory userDirectory) {
requireRole("remove-user-directory", context, DefaultRoles.ADMINISTRATOR);
UserDirectoryDao.removeUserDirectory(context.getEntityManager(), userDirectory);
AuditService.log(context, "remove", "user-directory", userDirectory.getUserDirectoryId(), userDirectory.getAddress());
}
/**
* Adds new company to database.
* @param context the processing context
* @param company the company
*/
public static void addCompany(final SecurityContext context, final Company company) {
requireRole("add-company", context, DefaultRoles.ADMINISTRATOR);
CompanyDao.addCompany(context.getEntityManager(), company);
AuditService.log(context, "add", "company", company.getCompanyId(), company.getCompanyName());
}
/**
* Updates new company to database.
* @param context the processing context
* @param company the company
*/
public static void updateCompany(final SecurityContext context, final Company company) {
requireRole("update-company", context, DefaultRoles.ADMINISTRATOR);
CompanyDao.updateCompany(context.getEntityManager(), company);
AuditService.log(context, "update", "company", company.getCompanyId(), company.getCompanyName());
}
/**
* Removes company from database.
* @param context the processing context
* @param company the company
*/
public static void removeCompany(final SecurityContext context, final Company company) {
requireRole("remove-company", context, DefaultRoles.ADMINISTRATOR);
CompanyDao.removeCompany(context.getEntityManager(), company);
AuditService.log(context, "remove", "company", company.getCompanyId(), company.getCompanyName());
}
/**
* Adds user to database.
* @param context the processing context
* @param user the user
* @param defaultGroup the default group
*/
public static final void addUser(final SecurityContext context, final User user, final Group defaultGroup) {
final Company company = context.getObject(Company.class);
if (company.isSelfRegistration()) {
requireRole("add-user", context, DefaultRoles.ADMINISTRATOR, DefaultRoles.ANONYMOUS);
} else {
requireRole("add-user", context, DefaultRoles.ADMINISTRATOR);
}
UserDao.addUser(context.getEntityManager(), user, defaultGroup);
AuditService.log(context, "add", "user", user.getUserId(), user.getEmailAddress());
}
/**
* Updates user to database.
* @param context the processing context
* @param user the user
*/
public static final void updateUser(final SecurityContext context, final User user) {
if (user.getUserId().equals(context.getUserId())) {
requireRole("update-user", context, DefaultRoles.ADMINISTRATOR, DefaultRoles.USER);
} else {
requireRole("update-user", context, DefaultRoles.ADMINISTRATOR);
}
UserDao.updateUser(context.getEntityManager(), user);
AuditService.log(context, "update", "user", user.getUserId(), user.getEmailAddress());
}
/**
* Removes user from database.
* @param context the processing context
* @param user the user
*/
public static final void removeUser(final SecurityContext context, final User user) {
requireRole("remove-user", context, DefaultRoles.ADMINISTRATOR);
UserDao.removeUser(context.getEntityManager(), user);
AuditService.log(context, "remove", "user", user.getUserId(), user.getEmailAddress());
}
/**
* Adds new group to database.
* @param context the processing context
* @param group the group
*/
public static void addGroup(final SecurityContext context, final Group group) {
requireRole("add-group", context, DefaultRoles.ADMINISTRATOR);
UserDao.addGroup(context.getEntityManager(), group);
AuditService.log(context, "add", "group", group.getGroupId(), group.getName());
}
/**
* Updates new group to database.
* @param context the processing context
* @param group the group
*/
public static void updateGroup(final SecurityContext context, final Group group) {
requireRole("update-group", context, DefaultRoles.ADMINISTRATOR);
UserDao.updateGroup(context.getEntityManager(), group);
AuditService.log(context, "update", "group", group.getGroupId(), group.getName());
}
/**
* Removes group from database.
* @param context the processing context
* @param group the group
*/
public static void removeGroup(final SecurityContext context, final Group group) {
requireRole("remove-group", context, DefaultRoles.ADMINISTRATOR);
UserDao.removeGroup(context.getEntityManager(), group);
AuditService.log(context, "remove", "group", group.getGroupId(), group.getName());
}
/**
* Adds new group member to database.
* @param context the processing context
* @param group the group
* @param user the user
*/
public static void addGroupMember(final SecurityContext context, final Group group, final User user) {
requirePrivilege(DefaultPrivileges.ADMINISTER, "group", group.getGroupId(), group.getName(), context, DefaultRoles.ADMINISTRATOR);
UserDao.addGroupMember(context.getEntityManager(), group, user);
AuditService.log(context, group.getName() + " member add", "user", user.getUserId(), user.getEmailAddress());
}
/**
* Removes group member from database.
* @param context the processing context
* @param group the group
* @param user the user
*/
public static void removeGroupMember(final SecurityContext context, final Group group, final User user) {
requirePrivilege(DefaultPrivileges.ADMINISTER, "group", group.getGroupId(), group.getName(), context, DefaultRoles.ADMINISTRATOR);
UserDao.removeGroupMember(context.getEntityManager(), group, user);
AuditService.log(context, group.getName() + " member remove", "user", user.getUserId(), user.getEmailAddress());
}
/**
* Adds new user privilege to database.
* @param context the processing context
* @param user the user
* @param privilegeKey the privilegeKey
* @param dataType the data type
* @param dataId the data ID
* @param dataLabel the data label
*/
public static void addUserPrivilege(final SecurityContext context, final User user, final String privilegeKey,
final String dataType, final String dataId, final String dataLabel) {
requirePrivilege(DefaultPrivileges.ADMINISTER, dataType, dataId, dataLabel, context, DefaultRoles.ADMINISTRATOR);
UserDao.addUserPrivilege(context.getEntityManager(), user, privilegeKey, dataId);
AuditService.log(context, user.getEmailAddress() + " had " + privilegeKey + " granted", dataType, dataId, dataLabel);
}
/**
* Adds new group privilege to database.
* @param context the processing context
* @param group the group
* @param privilegeKey the privilegeKey
* @param dataType the data type
* @param dataId the data ID
* @param dataLabel the data label
*/
public static void addGroupPrivilege(final SecurityContext context,
final Group group, final String privilegeKey,
final String dataType, final String dataId, final String dataLabel) {
requirePrivilege(DefaultPrivileges.ADMINISTER, dataType, dataId, dataLabel, context, DefaultRoles.ADMINISTRATOR);
UserDao.addGroupPrivilege(context.getEntityManager(), group, privilegeKey, dataId);
AuditService.log(context, group.getName() + " had " + privilegeKey + " granted", dataType, dataId, dataLabel);
}
/**
* Removes user privilege from database.
* @param context the processing context
* @param user the user
* @param privilegeKey the privilegeKey
* @param dataType the data type
* @param dataId the data ID
* @param dataLabel the data label
*/
public static void removeUserPrivilege(final SecurityContext context,
final User user, final String privilegeKey,
final String dataType, final String dataId, final String dataLabel) {
requirePrivilege(DefaultPrivileges.ADMINISTER, dataType, dataId, dataLabel, context, DefaultRoles.ADMINISTRATOR);
UserDao.removeUserPrivilege(context.getEntityManager(), user, privilegeKey, dataId);
AuditService.log(context, user.getEmailAddress() + " had " + privilegeKey + " revoked", dataType, dataId, dataLabel);
}
/**
* Removes group privilege from database.
* @param context the processing context
* @param group the group
* @param privilegeKey the privilegeKey
* @param dataType the data type
* @param dataId the data ID
* @param dataLabel the data label
*/
public static void removeGroupPrivilege(final SecurityContext context,
final Group group, final String privilegeKey,
final String dataType, final String dataId, final String dataLabel) {
requirePrivilege(DefaultPrivileges.ADMINISTER, dataType, dataId, dataLabel, context, DefaultRoles.ADMINISTRATOR);
UserDao.removeGroupPrivilege(context.getEntityManager(), group, privilegeKey, dataId);
AuditService.log(context, group.getName() + " had " + privilegeKey + " revoked", dataType, dataId, dataLabel);
}
/**
* Require privilege to given data or one of the listed roles.
* @param key the privilege key
* @param dataType the data type
* @param dataId the data ID
* @param dataLabel the data label
* @param context the processing context
* @param roles the privileged roles
*/
private static synchronized void requirePrivilege(final String key,
final String dataType, final String dataId, final String dataLabel,
final SecurityContext context, final String... roles) {
for (final String role : roles) {
if (context.getRoles().contains(role)) {
AuditService.log(context, key + " access granted based on role " + role);
return;
}
}
if (!hasPrivilege(key, dataId, context)) {
AuditService.log(context, key + " access denied", dataType, dataId, dataLabel);
throw new SiteException("Access denied.");
}
AuditService.log(context, key + " access granted based on privilege", dataType, dataId, dataLabel);
}
/**
* Require one of the following roles for privilege identified by privilege key.
* @param key the privilege key
* @param context the processing context
* @param roles the roles
*/
public static final void requireRole(final String key,
final SecurityContext context, final String... roles) {
for (final String role : roles) {
if (context.getRoles().contains(role)) {
AuditService.log(context, key + " access granted based on role " + role);
return;
}
}
AuditService.log(context, key + " access denied");
throw new SiteException("Access denied.");
}
/**
* Check if processing context has privilege to access given data.
* @param key the privilege key
* @param context the processing context
* @param dataId the data ID
* @return true if privilege exists on given data.
*/
private static synchronized boolean hasPrivilege(final String key, final String dataId, final SecurityContext context) {
final EntityManager entityManager = context.getEntityManager();
final Company company = context.getObject(Company.class);
if (context.getUserId() != null && context.getObject(PrivilegeCache.USER_FOR_PRIVILEGE_CHECK) == null) {
context.putObject(PrivilegeCache.USER_FOR_PRIVILEGE_CHECK, entityManager.getReference(User.class, context.getUserId()));
}
final User user = context.getObject(PrivilegeCache.USER_FOR_PRIVILEGE_CHECK);
if (context.getObject(PrivilegeCache.USER_GROUPS_FOR_PRIVILEGE_CHECK) == null) {
context.putObject(PrivilegeCache.USER_GROUPS_FOR_PRIVILEGE_CHECK, UserDao.getUserGroups(entityManager, company, user));;
}
final List<Group> groups = context.getObject(PrivilegeCache.USER_GROUPS_FOR_PRIVILEGE_CHECK);
if (!PrivilegeCache.hasPrivilege(entityManager, company, user, groups, key, dataId)) {
return false;
} else {
return true;
}
}
public static void addUserSession(final EntityManager entityManager, final UserSession userSession) {
entityManager.getTransaction().begin();
try {
entityManager.persist(userSession);
entityManager.getTransaction().commit();
} catch (final Exception e) {
if (entityManager.getTransaction().isActive()) {
entityManager.getTransaction().rollback();
}
throw new RuntimeException("Unable to persist user session.", e);
}
}
public static void removeUserSession(final EntityManager entityManager, final UserSession userSession) {
entityManager.getTransaction().begin();
try {
entityManager.remove(userSession);
entityManager.getTransaction().commit();
} catch (final Exception e) {
if (entityManager.getTransaction().isActive()) {
entityManager.getTransaction().rollback();
}
throw new RuntimeException("Unable to persist user session.", e);
}
}
/**
* Gets user session.
* @param entityManager the entity manager
* @param sessionIdHash the session ID hash
* @return user session or null
*/
public static UserSession getUserSessionByIdHash(final EntityManager entityManager, final String sessionIdHash) {
final CriteriaBuilder queryBuilder = entityManager.getCriteriaBuilder();
final CriteriaQuery<UserSession> criteriaQuery = queryBuilder.createQuery(UserSession.class);
final Root<UserSession> root = criteriaQuery.from(UserSession.class);
final Predicate condition = queryBuilder.equal(root.get("sessionIdHash"), sessionIdHash);
criteriaQuery.where(condition);
final TypedQuery<UserSession> typedQuery = entityManager.createQuery(criteriaQuery);
final List<UserSession> resultList = typedQuery.getResultList();
if (resultList.size() > 0) {
return resultList.get(0);
} else {
return null;
}
}
/**
* Gets user session.
* @param entityManager the entity manager
* @param loginTransactionIdHash the login transaction ID hash
* @return user session or null
*/
public static UserSession getUserSessionByAccessTokenHash(final EntityManager entityManager, final String loginTransactionIdHash) {
final CriteriaBuilder queryBuilder = entityManager.getCriteriaBuilder();
final CriteriaQuery<UserSession> criteriaQuery = queryBuilder.createQuery(UserSession.class);
final Root<UserSession> root = criteriaQuery.from(UserSession.class);
final Predicate condition = queryBuilder.equal(root.get("loginTransactionIdHash"), loginTransactionIdHash);
criteriaQuery.where(condition);
final TypedQuery<UserSession> typedQuery = entityManager.createQuery(criteriaQuery);
final List<UserSession> resultList = typedQuery.getResultList();
if (resultList.size() > 0) {
return resultList.get(0);
} else {
return null;
}
}
}