CustomAclServiceImpl.java
/*
* Copyright 2018 Global Crop Diversity Trust
*
* Licensed 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.genesys.blocks.security.service.impl;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import javax.persistence.EntityManager;
import org.genesys.blocks.security.SecurityContextUtil;
import org.genesys.blocks.security.model.AclAwareModel;
import org.genesys.blocks.security.model.AclClass;
import org.genesys.blocks.security.model.AclEntry;
import org.genesys.blocks.security.model.AclObjectIdentity;
import org.genesys.blocks.security.model.AclSid;
import org.genesys.blocks.security.persistence.AclClassPersistence;
import org.genesys.blocks.security.persistence.AclEntryPersistence;
import org.genesys.blocks.security.persistence.AclObjectIdentityPersistence;
import org.genesys.blocks.security.persistence.AclSidPersistence;
import org.genesys.blocks.security.serialization.Permissions;
import org.genesys.blocks.security.serialization.SidPermissions;
import org.genesys.blocks.security.service.CustomAclService;
import org.genesys.blocks.util.ClassAclOid;
import org.hibernate.proxy.HibernateProxyHelper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.Cache;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.security.access.prepost.PostAuthorize;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.acls.domain.BasePermission;
import org.springframework.security.acls.model.Permission;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import lombok.extern.slf4j.Slf4j;
/**
* The Class CustomAclServiceImpl.
*/
@Service
@Transactional
@Slf4j
public class CustomAclServiceImpl implements CustomAclService {
/**
* The name of the cache holding SID id-to-name mappings.
*/
public static final String CACHE_SID_NAMES = "aclSidNames";
/** The base permissions. */
private static Permission[] basePermissions;
/** The acl object identity persistence. */
@Autowired
private AclObjectIdentityPersistence aclObjectIdentityPersistence;
/** The acl class persistence. */
@Autowired
private AclClassPersistence aclClassPersistence;
/** The acl entry persistence. */
@Autowired
private AclEntryPersistence aclEntryPersistence;
/** The cache manager. */
@Autowired(required = false)
private CacheManager cacheManager;
/** The acl sid persistence. */
@Autowired
private AclSidPersistence aclSidPersistence;
/** The entity manager. */
@Autowired
private EntityManager entityManager;
static {
basePermissions = new Permission[] { BasePermission.CREATE, BasePermission.READ, BasePermission.WRITE, BasePermission.DELETE, BasePermission.ADMINISTRATION };
}
@Override
@Transactional(readOnly = true)
public AclSid getSid(Long id) {
return aclSidPersistence.findById(id).orElse(null);
}
@Override
@Transactional(readOnly = true)
@Cacheable(cacheNames = { CACHE_SID_NAMES }, key = "#id", unless = "#result == null")
public String getSidName(long id) {
AclSid sid = aclSidPersistence.findById(id).orElse(null);
return sid == null ? null : sid.getSid();
}
@Override
@Transactional(readOnly = true, propagation = Propagation.REQUIRES_NEW, isolation = Isolation.READ_UNCOMMITTED)
@Cacheable(cacheNames = { CACHE_SID_NAMES }, key = "#sid", unless = "#result == null")
public Long getSidId(String sid) {
return aclSidPersistence.getSidId(sid);
}
@Override
public AclSid getAuthoritySid(String authority) {
return aclSidPersistence.findBySidAndPrincipal(authority, false);
}
@Override
@Transactional(propagation = Propagation.REQUIRED)
public AclSid ensureAuthoritySid(String authority) {
return ensureSidForAuthority(authority);
}
@Override
@Transactional(propagation = Propagation.REQUIRED)
public AclSid removeAuthoritySid(String authority) {
AclSid authoritySid = aclSidPersistence.findBySidAndPrincipal(authority, false);
if (authoritySid == null) {
log.warn("ACL SID for authority {} does not exist", authority);
return null;
}
// Remove ACL entries
removePermissionsFor(authoritySid);
aclSidPersistence.delete(authoritySid);
return authoritySid;
}
@Override
@Transactional(propagation = Propagation.REQUIRED)
public AclObjectIdentity createOrUpdatePermissions(final AclAwareModel target, AclSid ownerSid) {
if (target == null || (target.getId() <= 0l && !(target instanceof ClassAclOid<?>))) {
log.warn("No target specified for ACL permissions, bailing out!");
return null;
}
String className = target.getClass().getName();
if (target instanceof ClassAclOid<?>) {
className = ((ClassAclOid<?>) target).getClassName();
}
final AclClass aclClass = ensureAclClass(className);
// save object identity
AclObjectIdentity objectIdentity = aclObjectIdentityPersistence.findByObjectIdAndClassname(target.getId(), aclClass.getAclClass());
if (objectIdentity == null) {
objectIdentity = new AclObjectIdentity();
if (ownerSid == null) {
log.warn("No SID in security context, not assigning creator permissions");
} else if (ownerSid.isNew()) {
log.warn("Owner SID not persisted, not assigning creator permissions");
} else {
objectIdentity.setOwnerSid(ownerSid);
}
log.debug("Inserting owner ACL entries for owner={} class={} id={}", ownerSid, target.getClass().getName(), target.getId());
objectIdentity.setObjectIdIdentity(target.getId());
objectIdentity.setAclClass(aclClass);
AclObjectIdentity parentObject = target.aclParentObjectIdentity();
if (parentObject == null && target.aclParentObject() != null) {
// get OID of parent business entity
parentObject = getObjectIdentity(target.aclParentObject());
}
if (parentObject != null) {
objectIdentity.setParentObject(parentObject);
}
objectIdentity.setEntriesInheriting(true);
objectIdentity = aclObjectIdentityPersistence.save(objectIdentity);
if (objectIdentity.getOwnerSid() != null) {
// Grant permissions to owner
final Permissions permissions = new Permissions().grantAll();
addPermissions(objectIdentity, objectIdentity.getOwnerSid(), permissions);
}
} else {
// update permissions
log.debug("Updating ACL parent object for class={} id={}", target.getClass().getName(), target.getId());
if (objectIdentity.getOwnerSid() == null) {
if (ownerSid != null && ! ownerSid.isNew()) {
objectIdentity.setOwnerSid(ownerSid);
// Grant permissions to owner
final Permissions permissions = new Permissions().grantAll();
addPermissions(objectIdentity, objectIdentity.getOwnerSid(), permissions);
} else {
log.debug("Owner SID not persisted or is null.");
}
}
AclObjectIdentity parentObject = target.aclParentObjectIdentity();
if (parentObject == null && target.aclParentObject() != null) {
// get OID of parent business entity
parentObject = getObjectIdentity(target.aclParentObject());
}
if (parentObject != null) {
log.trace("Updating ACL parent to {}", parentObject);
objectIdentity.setParentObject(parentObject);
objectIdentity.setEntriesInheriting(true);
} else {
log.trace("Clearing ACL parent");
objectIdentity.setParentObject(null);
// objectIdentity.setEntriesInheriting(false);
}
objectIdentity = aclObjectIdentityPersistence.save(objectIdentity);
}
clearAclCache();
return objectIdentity;
}
@Override
@Transactional(propagation = Propagation.REQUIRED)
public AclObjectIdentity createOrUpdatePermissions(final AclAwareModel target) {
if (target == null || (target.getId() <= 0l && !(target instanceof ClassAclOid<?>))) {
log.warn("No target specified for ACL permissions, bailing out!");
return null;
}
final AclSid ownerSid = SecurityContextUtil.getCurrentUser();
return createOrUpdatePermissions(target, ownerSid);
}
@Override
@PreAuthorize("hasRole('ADMINISTRATOR')")
public AclObjectIdentity updateInheriting(final long objectIdIdentity, final boolean entriesInheriting) {
final AclObjectIdentity objectIdentity = aclObjectIdentityPersistence.findById(objectIdIdentity).orElse(null);
if (objectIdentity == null) {
log.warn("ACL object identity not found by id={}", objectIdIdentity);
return null;
}
if (objectIdentity.isEntriesInheriting() == entriesInheriting) {
return objectIdentity;
} else {
try {
log.info("Updating inheriting status for OID={} to {}", objectIdentity, entriesInheriting);
objectIdentity.setEntriesInheriting(entriesInheriting);
return aclObjectIdentityPersistence.save(objectIdentity);
} finally {
clearAclCache();
}
}
}
@Override
@PreAuthorize("hasRole('ADMINISTRATOR')")
public AclObjectIdentity setAclParent(AclAwareModel target, AclAwareModel parent) {
final AclObjectIdentity objectIdentity = getObjectIdentity(target);
final AclObjectIdentity parentIdentity = parent == null ? null : getObjectIdentity(parent);
return updateAclParentObject(objectIdentity, parentIdentity);
}
@Override
@PreAuthorize("hasRole('ADMINISTRATOR')")
public AclObjectIdentity updateParentObject(final long objectIdIdentity, final long parentObjectId) {
final AclObjectIdentity objectIdentity = aclObjectIdentityPersistence.findById(objectIdIdentity).orElse(null);
if (objectIdentity == null) {
log.warn("ACL object identity not found by id={}", objectIdIdentity);
return null;
}
final AclObjectIdentity parentIdentity = aclObjectIdentityPersistence.findById(parentObjectId).orElse(null);
if (parentIdentity == null) {
log.warn("ACL object identity not found by id={}", objectIdIdentity);
return null;
}
return updateAclParentObject(objectIdentity, parentIdentity);
}
private AclObjectIdentity updateAclParentObject(final AclObjectIdentity objectIdentity, final AclObjectIdentity parentObject) {
try {
log.trace("Updating ACL parent to {}", parentObject);
objectIdentity.setParentObject(parentObject);
objectIdentity.setEntriesInheriting(parentObject != null);
return aclObjectIdentityPersistence.save(objectIdentity);
} finally {
clearAclCache();
}
}
/**
* Remove ACL data for AclAwareModel: deletes {@link AclObjectIdentity} and
* associated {@link AclEntry} list. If target happens to be {@link AclSid},
* permissions granted to the SID are removed.
*/
@Override
@Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.READ_UNCOMMITTED)
public void removeAclAwareModel(final AclAwareModel target) {
log.debug("Deleting ACL data for {}", target);
if (target instanceof AclSid) {
log.info("Deleting permissions for {}", target);
removePermissionsFor((AclSid) target);
}
final AclObjectIdentity aclObjectIdentity = getObjectIdentity(target);
if (aclObjectIdentity != null) {
log.debug("OID {}#{} of {}", aclObjectIdentity.getAclClass().getAclClass(), aclObjectIdentity.getObjectIdIdentity(), target);
for (AclObjectIdentity child : aclObjectIdentityPersistence.findByParentObject(aclObjectIdentity)) {
log.debug("Has child {}#{}", child.getAclClass().getAclClass(), child.getObjectIdIdentity());
}
log.info("Deleting ACL data of {}", target);
final List<AclEntry> aclEntries = aclEntryPersistence.findByObjectIdentity(aclObjectIdentity);
if (aclEntries != null) {
aclEntryPersistence.deleteAll(aclEntries);
}
aclObjectIdentityPersistence.delete(aclObjectIdentity);
}
clearAclCache();
}
/*
* (non-Javadoc)
* @see
* org.genesys.blocks.security.service.CustomAclService#removePermissions(org.
* genesys.blocks.security.model.AclAwareModel)
*/
@Override
@Transactional(propagation = Propagation.REQUIRED)
public void removePermissionsFor(final AclSid sid) {
int count = aclEntryPersistence.deleteForSid(sid);
log.debug("Deleting {} permision entries granted to {}", count, sid);
if (count > 0) {
clearAclCache();
}
}
/**
* Adds the permissions.
*
* @param objectIdentity the object identity
* @param sid the sid
* @param permissions the permissions
* @return the list
*/
private AclObjectIdentity addPermissions(final AclObjectIdentity objectIdentity, final AclSid sid, final Permissions permissions) {
if (objectIdentity == null) {
throw new NullPointerException("AclObjectIdentity must be provided, was null.");
}
if (sid == null) {
throw new NullPointerException("AclSid must be provided, was null.");
}
if (permissions == null) {
throw new NullPointerException("Permissions must be provided, was null.");
}
try {
List<AclEntry> aclEntries = new ArrayList<>(10);
long nextAceOrder = getAceOrder(objectIdentity.getId());
// create Acl Entry
for (final Permission permission : basePermissions) {
final int mask = permission.getMask();
final AclEntry aclEntry = new AclEntry();
aclEntry.setAclObjectIdentity(objectIdentity);
aclEntry.setAclSid(sid);
aclEntry.setAceOrder(nextAceOrder++);
aclEntry.setGranting(permissions.isGranting(mask));
aclEntry.setAuditSuccess(true);
aclEntry.setAuditFailure(true);
// set full access for own organization
aclEntry.setMask(mask);
aclEntries.add(aclEntry);
}
// save ACL
aclEntryPersistence.saveAll(aclEntries);
return getObjectIdentity(objectIdentity.getId());
} finally {
clearAclCache();
}
}
private void clearAclCache() {
if (cacheManager!=null) {
final Cache aclCache = cacheManager.getCache("aclCache");
if (aclCache != null)
aclCache.clear();
}
}
/**
* Generates next ace_order value (to avoid DuplicateIndex exception :
* acl_object_identity + ace_order is unique index).
*
* @param aclObjectEntityId - id of acl_object_identity table
* @return - ace_order value
*/
private Long getAceOrder(final long aclObjectEntityId) {
final Long maxAceOrder = aclEntryPersistence.getMaxAceOrderForObjectEntity(aclObjectEntityId);
return maxAceOrder != null ? maxAceOrder + 1 : 1;
}
/**
* Ensure acl class.
*
* @param className the class name
* @return the acl class
*/
private AclClass ensureAclClass(final String className) {
AclClass aclClass = aclClassPersistence.findByAclClass(className);
if (aclClass == null) {
log.debug("Registering missing AclClass '{}'", className);
aclClass = new AclClass();
aclClass.setAclClass(className);
return aclClassPersistence.save(aclClass);
}
return aclClass;
}
@Override
@Transactional(readOnly = true)
public AclObjectIdentityExt loadObjectIdentityExt(AclObjectIdentity objectIdentity) {
if (objectIdentity != null) {
objectIdentity = getObjectIdentity(objectIdentity.getId());
AclObjectIdentityExt _aclObjectIdentity = new AclObjectIdentityExt(objectIdentity);
// lazy load SIDs for AclEntries
if (objectIdentity.getAclEntries() != null) {
objectIdentity.getAclEntries().forEach(entry -> entry.getAclSid().getId());
}
List<AclEntry> inheritedEntries = inherited(objectIdentity.getParentObject(), new ArrayList<>(), new HashSet<>());
_aclObjectIdentity.inherited.addAll(inheritedEntries);
// lazy load for JSON
_aclObjectIdentity.inherited.forEach(entry -> entry.getAclSid().getId());
return _aclObjectIdentity;
}
return null;
}
private List<AclEntry> inherited(AclObjectIdentity objectIdentity, List<AclEntry> aclEntries, Set<AclObjectIdentity> handled) {
if (objectIdentity == null || handled.contains(objectIdentity)) {
return aclEntries;
}
// lazy load SIDs for AclEntries
objectIdentity.getAclEntries().forEach(entry -> entry.getAclSid().getId());
aclEntries.addAll(objectIdentity.getAclEntries());
handled.add(objectIdentity);
if (objectIdentity.getParentObject() != null) {
inherited(objectIdentity.getParentObject(), aclEntries, handled);
}
return aclEntries;
}
/*
* (non-Javadoc)
* @see
* org.genesys.blocks.security.service.CustomAclService#getObjectIdentity(java.
* lang.String, long)
*/
@Override
@Transactional(readOnly = true)
@PostAuthorize("returnObject==null or hasRole('ADMINISTRATOR') or hasPermission(returnObject.objectIdIdentity, returnObject.aclClass.aclClass, 'READ')")
public AclObjectIdentity getObjectIdentity(final long id) {
return aclObjectIdentityPersistence.findById(id).orElse(null);
}
/*
* (non-Javadoc)
* @see
* org.genesys.blocks.security.service.CustomAclService#getObjectIdentity(java.
* lang.String, long)
*/
@Override
@Transactional(readOnly = true)
@PreAuthorize("hasRole('ADMINISTRATOR') or hasPermission(#id, #className, 'ADMINISTRATION')")
public AclObjectIdentity getObjectIdentity(final long id, final String className) {
return aclObjectIdentityPersistence.findByObjectIdAndClassname(id, className);
}
/*
* (non-Javadoc)
* @see
* org.genesys.blocks.security.service.CustomAclService#getObjectIdentity(org.
* genesys.blocks.security.model.AclAwareModel)
*/
@Override
@Transactional(readOnly = true)
@PreAuthorize("hasRole('ADMINISTRATOR') or hasPermission(#entity, 'ADMINISTRATION')")
public AclObjectIdentity getObjectIdentity(final AclAwareModel entity) {
if (entity == null) {
log.trace("getObjectIdentity: Entity is null");
return null;
}
String className = HibernateProxyHelper.getClassWithoutInitializingProxy(entity).getName();
if (entity instanceof ClassAclOid<?>) {
className = ((ClassAclOid<?>) entity).getClassName();
}
final AclObjectIdentity oid = aclObjectIdentityPersistence.findByObjectIdAndClassname(entity.getId(), className);
if (oid == null) {
log.warn("ACL object identity not found for class={} id={}", className, entity.getId());
}
return oid;
}
/*
* (non-Javadoc)
* @see
* org.genesys.blocks.security.service.CustomAclService#getAvailablePermissions(
* java.lang.String)
*/
@Override
@Transactional(readOnly = true)
public Permission[] getAvailablePermissions(final String className) {
// Do not remove parameter. We may change available permissions based on
// parameter type!
return basePermissions;
}
/*
* (non-Javadoc)
* @see
* org.genesys.blocks.security.service.CustomAclService#getPermissions(long,
* java.lang.String)
*/
@Transactional(readOnly = true)
@Override
@PreAuthorize("hasRole('ADMINISTRATOR') or hasPermission(#id, #className, 'ADMINISTRATION')")
public List<SidPermissions> getPermissions(final long id, final String className) {
final List<AclEntry> aclEntries = getAclEntries(getObjectIdentity(id, className));
return SidPermissions.fromEntries(aclEntries);
}
/*
* (non-Javadoc)
* @see org.genesys.blocks.security.service.CustomAclService#getPermissions(org.
* genesys.blocks.security.model.AclAwareModel)
*/
@Transactional(readOnly = true)
@Override
@PreAuthorize("hasRole('ADMINISTRATOR') or hasPermission(#entity, 'ADMINISTRATION')")
public List<SidPermissions> getPermissions(final AclAwareModel entity) {
return getPermissions(entity.getId(), entity.getClass().getName());
}
@Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.READ_UNCOMMITTED)
@Override
@PreAuthorize("hasRole('ADMINISTRATOR') or hasPermission(#entity, 'ADMINISTRATION')")
public AclObjectIdentity setPermissions(final AclAwareModel entity, final AclSid sid, final Permissions permissions) {
if (entity == null) {
throw new NullPointerException("AclAwareModel must be provided, was null.");
}
if (sid == null) {
throw new NullPointerException("AclSid must be provided, was null.");
}
if (permissions == null) {
throw new NullPointerException("Permissions must be provided, was null.");
}
final AclObjectIdentity objectIdentity = ensureObjectIdentity(entity);
return setPermissions(objectIdentity, sid, permissions);
}
private AclObjectIdentity ensureObjectIdentity(final AclAwareModel entity) {
String className = entity.getClass().getName();
if (entity instanceof ClassAclOid<?>) {
className = ((ClassAclOid<?>) entity).getClassName();
}
final AclObjectIdentity objectIdentity = ensureObjectIdentity(entity.getId(), className);
return objectIdentity;
}
@Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.READ_UNCOMMITTED)
@Override
@PreAuthorize("hasRole('ADMINISTRATOR') or hasPermission(#objectIdentity.objectIdIdentity, #objectIdentity.aclClass.aclClass, 'ADMINISTRATION')")
public AclObjectIdentity setPermissions(AclObjectIdentity objectIdentity, AclSid sid, final Permissions permissions) {
if (objectIdentity == null) {
throw new NullPointerException("AclObjectIdentity must be provided, was null.");
}
assert objectIdentity.getId() != null;
if (sid == null) {
throw new NullPointerException("AclSid must be provided, was null.");
}
if (permissions == null) {
throw new NullPointerException("Permissions must be provided, was null.");
}
try {
final List<AclEntry> aclEntries = aclEntryPersistence.findBySidAndObjectIdentity(sid, objectIdentity);
if (aclEntries.isEmpty()) {
// add
return addPermissions(objectIdentity, sid, permissions);
} else {
// update
for (final AclEntry aclEntry : aclEntries) {
aclEntry.setGranting(permissions.isGranting(aclEntry.getMask()));
}
log.info("Saving {}", aclEntries);
aclEntryPersistence.saveAll(aclEntries);
return getObjectIdentity(objectIdentity.getId());
}
// // This is the original code, one that cleared permissions when none were granted
// // It didn't take into account inherited permissions.
// if (permissions.isOneGranting()) {
// need to update or add permissions
// ...
// } else {
// // delete existing
// final List<AclEntry> aclEntries =
// aclEntryPersistence.findBySidAndObjectIdentity(sid, objectIdentity);
// if (!aclEntries.isEmpty()) {
// log.info("Deleting " + aclEntries);
// aclEntryPersistence.delete(aclEntries);
// entityManager.flush();
// }
// return getObjectIdentity(objectIdentity.getId());
// }
} finally {
clearAclCache();
}
}
/* (non-Javadoc)
* @see org.genesys.blocks.security.service.CustomAclService#removePermissions(org.genesys.blocks.security.model.AclObjectIdentity, org.genesys.blocks.security.model.AclSid)
*/
@Override
@Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.READ_UNCOMMITTED)
public AclObjectIdentity removePermissions(AclObjectIdentity objectIdentity, AclSid sid) {
if (objectIdentity == null) {
throw new NullPointerException("AclObjectIdentity must be provided, was null.");
}
if (sid == null) {
throw new NullPointerException("AclSid must be provided, was null.");
}
try {
final List<AclEntry> aclEntries = aclEntryPersistence.findBySidAndObjectIdentity(sid, objectIdentity);
// delete ACL entries for sid
log.debug("Deleting {} AclEntries for {}", aclEntries.size(), sid);
aclEntryPersistence.deleteAll(aclEntries);
return getObjectIdentity(objectIdentity.getId());
} finally {
clearAclCache();
}
}
/*
* (non-Javadoc)
* @see org.genesys.blocks.security.service.CustomAclService#getAclEntries(org.
* genesys.blocks.security.model.AclObjectIdentity)
*/
@Override
@Transactional(readOnly = true)
@PreAuthorize("hasRole('ADMINISTRATOR') or hasPermission(#objectIdentity.objectIdIdentity, #objectIdentity.aclClass.aclClass, 'ADMINISTRATION')")
public List<AclEntry> getAclEntries(final AclObjectIdentity objectIdentity) {
return aclEntryPersistence.findByObjectIdentity(objectIdentity);
}
/*
* (non-Javadoc)
* @see org.genesys.blocks.security.service.CustomAclService#getAclEntries(org.
* genesys.blocks.security.model.AclAwareModel)
*/
@Override
@Transactional(readOnly = true)
@PreAuthorize("hasRole('ADMINISTRATOR') or hasPermission(#entity, 'ADMINISTRATION')")
public List<AclEntry> getAclEntries(final AclAwareModel entity) {
return aclEntryPersistence.findByObjectIdentity(getObjectIdentity(entity));
}
/*
* (non-Javadoc)
* @see org.genesys.blocks.security.service.CustomAclService#getSids(long,
* java.lang.String)
*/
@Override
@Transactional(readOnly = true)
@PreAuthorize("hasRole('ADMINISTRATOR') or hasPermission(#id, #className, 'ADMINISTRATION')")
public List<AclSid> getSids(final long id, final String className) {
return aclEntryPersistence.getSids(getObjectIdentity(id, className));
}
/*
* (non-Javadoc)
* @see
* org.genesys.blocks.security.service.CustomAclService#getSids(org.genesys.
* blocks.security.model.AclAwareModel)
*/
@Override
@Transactional(readOnly = true)
@PreAuthorize("hasRole('ADMINISTRATOR') or hasPermission(#entity, 'ADMINISTRATION')")
public List<AclSid> getSids(final AclAwareModel entity) {
return aclEntryPersistence.getSids(getObjectIdentity(entity));
}
/**
* Ensure ACL SID entry for the specified authority name (role)
*/
private AclSid ensureSidForAuthority(String authority) {
AclSid roleSid = aclSidPersistence.findBySidAndPrincipal(authority, false);
if (roleSid == null) {
log.warn("Creating AclSid for role '{}'", authority);
roleSid = new AclSid();
roleSid.setPrincipal(false);
roleSid.setSid(authority);
return aclSidPersistence.save(roleSid);
}
return roleSid;
}
/*
* (non-Javadoc)
* @see org.genesys.blocks.security.service.CustomAclService#listAuthoritySids()
*/
@Override
@Transactional(readOnly = true)
public List<AclSid> listAuthoritySids() {
return aclSidPersistence.listAuthoritySids();
}
/*
* (non-Javadoc)
* @see
* org.genesys.blocks.security.service.CustomAclService#ensureObjectIdentity(
* java.lang.String, long)
*/
@Override
@Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.READ_UNCOMMITTED)
public AclObjectIdentity ensureObjectIdentity(final long objectIdIdentity, final String className) {
AclObjectIdentity aoi = aclObjectIdentityPersistence.findByObjectIdAndClassname(objectIdIdentity, className);
if (aoi == null) {
aoi = new AclObjectIdentity();
aoi.setObjectIdIdentity(objectIdIdentity);
aoi.setAclClass(ensureAclClass(className));
final AclSid ownerSid = SecurityContextUtil.getCurrentUser();
aoi.setOwnerSid(ownerSid);
aoi = aclObjectIdentityPersistence.save(aoi);
}
return aoi;
}
/*
* (non-Javadoc)
* @see
* org.genesys.blocks.security.service.CustomAclService#listIdentitiesForSid(
* java.lang.Class, org.springframework.security.core.userdetails.UserDetails,
* org.springframework.security.acls.model.Permission)
*/
@Override
@Transactional(readOnly = true)
public List<Long> listObjectIdentityIdsForSid(final Class<? extends AclAwareModel> clazz, final AclSid sid, final Permission permission) {
return aclEntryPersistence.findObjectIdentitiesForSidAndAclClassAndMask(sid, clazz.getName(), permission.getMask());
}
/*
* (non-Javadoc)
* @see
* org.genesys.blocks.security.service.CustomAclService#makePubliclyReadable(org
* .genesys.blocks.security.model.AclAwareModel, boolean)
*/
@Override
@Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.READ_UNCOMMITTED)
@PreAuthorize("hasRole('ADMINISTRATOR') or hasPermission(#entity, 'ADMINISTRATION')")
public void makePubliclyReadable(AclAwareModel entity, boolean publiclyReadable) {
AclSid roleEveryone = ensureAuthoritySid("ROLE_EVERYONE");
if (!publiclyReadable) {
final AclObjectIdentity objectIdentity = ensureObjectIdentity(entity);
removePermissions(objectIdentity, roleEveryone);
} else {
Permissions readPermissions = new Permissions().grantNone();
readPermissions.read = publiclyReadable;
setPermissions(entity, roleEveryone, readPermissions);
}
}
@Override
@Transactional
public void cleanupAcl() {
List<AclObjectIdentity> OIDs = aclObjectIdentityPersistence.findAll();
log.warn("Cleaning ACL for {} OIDs", OIDs.size());
for (AclObjectIdentity OID : OIDs) {
try {
Class<?> clazz = Class.forName(OID.getAclClass().getAclClass());
Object entity = entityManager.find(clazz, OID.getObjectIdIdentity());
if (entity == null) {
log.info("{} with OID={} no longer exists, clearing ACL", clazz.getName(), OID.getObjectIdIdentity());
final List<AclEntry> aclEntries = aclEntryPersistence.findByObjectIdentity(OID);
if (aclEntries != null) {
aclEntryPersistence.deleteAll(aclEntries);
}
aclObjectIdentityPersistence.resetChildrenOfOID(OID);
aclObjectIdentityPersistence.delete(OID);
}
} catch (ClassNotFoundException e) {
log.info("{} for OID={} no longer exists, clearing ACL", OID.getAclClass().getAclClass(), OID.getObjectIdIdentity());
final List<AclEntry> aclEntries = aclEntryPersistence.findByObjectIdentity(OID);
if (aclEntries != null) {
aclEntryPersistence.deleteAll(aclEntries);
}
aclObjectIdentityPersistence.resetChildrenOfOID(OID);
aclObjectIdentityPersistence.delete(OID);
}
}
log.warn("Done cleaning ACL for {} OIDs", OIDs.size());
List<AclClass> aclClasses = aclClassPersistence.findAll();
log.warn("Cleaning ACL for {} ACL classes", aclClasses.size());
for (AclClass aclClass : aclClasses) {
try {
Class.forName(aclClass.getAclClass());
} catch (ClassNotFoundException e) {
log.info("{} no longer exists, clearing ACL", aclClass.getAclClass());
aclClassPersistence.delete(aclClass);
}
}
log.warn("Done cleaning ACL for {} ACL classes", aclClasses.size());
}
}