Commit 56db5281 authored by Matija Obreza's avatar Matija Obreza

Updated ACL service and model serialization

- Added permission checks on CustomAclService
- Sensible returns
- JSON serialization for ACL entities updated
parent b74449ff
......@@ -25,6 +25,9 @@ import javax.persistence.UniqueConstraint;
import org.genesys.blocks.model.BasicModel;
import com.fasterxml.jackson.annotation.JsonIdentityReference;
import com.fasterxml.jackson.annotation.JsonIgnore;
/**
* ACL Entry represents permissions of {@link AclSid} on a particular entity
* (through {@link AclObjectIdentity}).
......@@ -39,11 +42,13 @@ public class AclEntry extends BasicModel {
/** The acl object identity. */
@ManyToOne(fetch = FetchType.LAZY, cascade = {}, optional = false)
@JoinColumn(name = "acl_object_identity", nullable = false)
@JsonIgnore
private AclObjectIdentity aclObjectIdentity;
/** The acl sid. */
@ManyToOne(fetch = FetchType.LAZY, cascade = {}, optional = false)
@JoinColumn(name = "sid", nullable = false)
@JsonIdentityReference(alwaysAsId = false)
private AclSid aclSid;
/** The ace order. */
......
......@@ -27,10 +27,12 @@ import javax.persistence.OneToMany;
import javax.persistence.Table;
import javax.persistence.UniqueConstraint;
import com.fasterxml.jackson.annotation.JsonIgnore;
import org.genesys.blocks.model.BasicModel;
import com.fasterxml.jackson.annotation.JsonIdentityInfo;
import com.fasterxml.jackson.annotation.JsonIdentityReference;
import com.fasterxml.jackson.annotation.ObjectIdGenerators;
/**
* ACL Object Identity represents a specific ACL-aware entity (combination of
* {@link AclClass} and {#link objectIdIdentity}).
......@@ -39,6 +41,7 @@ import org.genesys.blocks.model.BasicModel;
*/
@Entity
@Table(name = "acl_object_identity", uniqueConstraints = @UniqueConstraint(columnNames = { "object_id_class", "object_id_identity" }))
@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "id")
public class AclObjectIdentity extends BasicModel {
/** The Constant serialVersionUID. */
......@@ -52,11 +55,13 @@ public class AclObjectIdentity extends BasicModel {
/** The parent object. */
@ManyToOne(fetch = FetchType.EAGER, cascade = CascadeType.PERSIST)
@JoinColumn(name = "parent_object", nullable = true)
@JsonIdentityReference(alwaysAsId = true)
private AclObjectIdentity parentObject;
/** The owner sid. */
@ManyToOne(fetch = FetchType.EAGER, cascade = {})
@JoinColumn(name = "owner_sid", nullable = true)
@JsonIdentityReference(alwaysAsId = false)
private AclSid ownerSid;
/** The object id identity. */
......@@ -68,7 +73,7 @@ public class AclObjectIdentity extends BasicModel {
private boolean entriesInheriting;
/** The acl entries. */
@JsonIgnore
// @JsonIgnore
@OneToMany(mappedBy = "aclObjectIdentity", fetch = FetchType.LAZY, cascade = CascadeType.REMOVE, orphanRemoval = true)
private List<AclEntry> aclEntries;
......
......@@ -29,7 +29,9 @@ import javax.persistence.InheritanceType;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import com.fasterxml.jackson.annotation.JsonIdentityInfo;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.ObjectIdGenerators;
import org.genesys.blocks.model.AuditedVersionedModel;
import org.hibernate.annotations.DiscriminatorOptions;
......@@ -49,6 +51,7 @@ import org.hibernate.annotations.DiscriminatorOptions;
@DiscriminatorColumn(name = "type", discriminatorType = DiscriminatorType.INTEGER)
@DiscriminatorValue(value = "0")
@DiscriminatorOptions(force = false)
@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "id")
public class AclSid extends AuditedVersionedModel {
/** The Constant serialVersionUID. */
......
......@@ -28,10 +28,10 @@ public interface AclObjectIdentityPersistence extends JpaRepository<AclObjectIde
/**
* Find by object id identity and class name.
*
* @param objectIdentityId the object identity id
* @param objectIdIdentity the object identity id
* @param aclClass the acl class
* @return the acl object identity
*/
@Query("select aoi from AclObjectIdentity aoi where aoi.objectIdIdentity = :objectIdIdentity and aoi.aclClass.aclClass = :aclClass")
AclObjectIdentity findByIdAndClassname(@Param("objectIdIdentity") long objectIdentityId, @Param("aclClass") String aclClass);
AclObjectIdentity findByObjectIdAndClassname(@Param("objectIdIdentity") long objectIdIdentity, @Param("aclClass") String aclClass);
}
......@@ -22,6 +22,8 @@ import org.genesys.blocks.security.model.AclAwareModel;
import org.genesys.blocks.security.model.AclEntry;
import org.genesys.blocks.security.model.AclObjectIdentity;
import org.genesys.blocks.security.model.AclSid;
import org.springframework.security.access.prepost.PostAuthorize;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.acls.model.Permission;
/**
......@@ -29,6 +31,14 @@ import org.springframework.security.acls.model.Permission;
*/
public interface CustomAclService {
/**
* Gets the available permissions.
*
* @param className the class name
* @return the available permissions
*/
Permission[] getAvailablePermissions(String className);
/**
* Get SID by ID
*
......@@ -36,7 +46,7 @@ public interface CustomAclService {
* @return persisted AclSid entity with specified id
*/
AclSid getSid(Long id);
/**
* Gets the sid of the specified authority
*
......@@ -48,9 +58,9 @@ public interface CustomAclService {
/**
* Adds the creator permissions.
*
* @param target the target
* @param entity the target
*/
void addCreatorPermissions(AclAwareModel target);
void addCreatorPermissions(AclAwareModel entity);
/**
* Removes the permissions on ACL model.
......@@ -67,30 +77,33 @@ public interface CustomAclService {
void removePermissionsFor(AclSid sid);
/**
* Gets the object identity.
* Get object identity by internal id
*
* @param id AclObjectIdentity id
* @return
*/
@PostAuthorize("returnObject==null or hasRole('ADMINISTRATOR') or hasPermission(#returnObject.objectIdIdentity, #returnObject.aclClass.aclClass, 'read')")
AclObjectIdentity getObjectIdentity(long id);
/**
* Gets the object identity for object of type className with specified id
*
* @param clazz the clazz
* @param id the id
* @param className the clazz
* @return the object identity
*/
AclObjectIdentity getObjectIdentity(String clazz, long id);
@PreAuthorize("returnObject==null or hasRole('ADMINISTRATOR') or hasPermission(#id, #className, 'ADMINISTRATION')")
AclObjectIdentity getObjectIdentity(long id, String className);
/**
* Gets the object identity.
* Gets the object identity of the entity
*
* @param entity the entity
* @return the object identity
*/
@PreAuthorize("hasRole('ADMINISTRATOR') or hasPermission(entity, 'ADMINISTRATION')")
AclObjectIdentity getObjectIdentity(AclAwareModel entity);
/**
* Gets the available permissions.
*
* @param className the class name
* @return the available permissions
*/
Permission[] getAvailablePermissions(String className);
/**
* Gets the permissions.
*
......@@ -98,6 +111,7 @@ public interface CustomAclService {
* @param className the class name
* @return the permissions
*/
@PreAuthorize("hasRole('ADMINISTRATOR') or hasPermission(#id, #className, 'ADMINISTRATION')")
Map<String, Map<Integer, Boolean>> getPermissions(long id, String className);
/**
......@@ -106,6 +120,7 @@ public interface CustomAclService {
* @param entity the entity
* @return the permissions
*/
@PreAuthorize("hasRole('ADMINISTRATOR') or hasPermission(entity, 'ADMINISTRATION')")
Map<String, Map<Integer, Boolean>> getPermissions(AclAwareModel entity);
/**
......@@ -114,6 +129,7 @@ public interface CustomAclService {
* @param objectIdentity the object identity
* @return the acl entries
*/
@PreAuthorize("hasRole('ADMINISTRATOR') or hasPermission(#objectIdentity.objectIdIdentity, #objectIdentity.aclClass.aclClass, 'ADMINISTRATION')")
List<AclEntry> getAclEntries(AclObjectIdentity objectIdentity);
/**
......@@ -122,10 +138,21 @@ public interface CustomAclService {
* @param entity the entity
* @param sid the sid
* @param permissionMap the permission map
* @return
*/
void updatePermissions(AclAwareModel entity, AclSid sid, Map<Integer, Boolean> permissionMap);
@PreAuthorize("hasRole('ADMINISTRATOR') or hasPermission(entity, 'ADMINISTRATION')")
List<AclEntry> updatePermissions(AclAwareModel entity, AclSid sid, Map<Integer, Boolean> permissionMap);
void updatePermissions(AclObjectIdentity objectIdentity, AclSid sid, Map<Integer, Boolean> permissionMap);
/**
* Update permissions.
*
* @param objectIdentity the object identity
* @param sid the sid
* @param permissionMap the permission map
* @return
*/
@PreAuthorize("hasRole('ADMINISTRATOR') or hasPermission(#objectIdentity.objectIdIdentity, #objectIdentity.aclClass.aclClass, 'ADMINISTRATION')")
List<AclEntry> updatePermissions(AclObjectIdentity objectIdentity, AclSid sid, Map<Integer, Boolean> permissionMap);
/**
* Gets the acl entries.
......@@ -133,6 +160,7 @@ public interface CustomAclService {
* @param entity the entity
* @return the acl entries
*/
@PreAuthorize("hasRole('ADMINISTRATOR') or hasPermission(entity, 'read')")
List<AclEntry> getAclEntries(AclAwareModel entity);
/**
......@@ -142,6 +170,7 @@ public interface CustomAclService {
* @param className the class name
* @return the sids
*/
@PreAuthorize("hasRole('ADMINISTRATOR') or hasPermission(#id, #className, 'read')")
List<AclSid> getSids(long id, String className);
/**
......@@ -150,18 +179,20 @@ public interface CustomAclService {
* @param entity the entity
* @return the sids
*/
@PreAuthorize("hasRole('ADMINISTRATOR') or hasPermission(#entity, 'read')")
List<AclSid> getSids(AclAwareModel entity);
/**
* Adds the permissions.
*
* @param objectIdIdentity the object id identity
* @param id the object id identity
* @param className the class name
* @param sid TODO
* @param permissions the permissions
* @return true, if successful
* @return list of new ACL entries
*/
boolean addPermissions(long objectIdIdentity, String className, AclSid sid, Map<Integer, Boolean> permissions);
@PreAuthorize("hasRole('ADMINISTRATOR') or hasPermission(#id, #className, 'ADMINISTRATION')")
List<AclEntry> addPermissions(long id, String className, AclSid sid, Map<Integer, Boolean> permissions);
/**
* Adds the permissions.
......@@ -169,18 +200,20 @@ public interface CustomAclService {
* @param entity the entity
* @param sid the sid
* @param permissionMap the permission map
* @return true, if successful
* @return list of new ACL entries
*/
boolean addPermissions(AclAwareModel entity, AclSid sid, Map<Integer, Boolean> permissionMap);
@PreAuthorize("hasRole('ADMINISTRATOR') or hasPermission(#entity, 'ADMINISTRATION')")
List<AclEntry> addPermissions(AclAwareModel entity, AclSid sid, Map<Integer, Boolean> permissionMap);
/**
* Ensure object identity.
*
*
* @param id the object id identity
* @param className the class name
* @param objectIdIdentity the object id identity
*
* @return the acl object identity
*/
AclObjectIdentity ensureObjectIdentity(String className, long objectIdIdentity);
AclObjectIdentity ensureObjectIdentity(long id, String className);
/**
* List IDs of the specified class for the SID with specified permissions.
......
......@@ -15,6 +15,7 @@
*/
package org.genesys.blocks.security.service.impl;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
......@@ -42,6 +43,8 @@ import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import com.google.common.collect.Lists;
/**
* The Class CustomAclServiceImpl.
*/
......@@ -140,7 +143,8 @@ public class CustomAclServiceImpl implements CustomAclService {
objectIdentity.setEntriesInheriting(false);
// save object identity
AclObjectIdentity savedAclObjectIdentity = aclObjectIdentityPersistence.findByIdAndClassname(objectIdentity.getObjectIdIdentity(), objectIdentity.getAclClass().getAclClass());
AclObjectIdentity savedAclObjectIdentity = aclObjectIdentityPersistence.findByObjectIdAndClassname(objectIdentity.getObjectIdIdentity(), objectIdentity.getAclClass()
.getAclClass());
if (savedAclObjectIdentity == null) {
savedAclObjectIdentity = aclObjectIdentityPersistence.save(objectIdentity);
final Map<Integer, Boolean> permissionsMap = new HashMap<>();
......@@ -197,26 +201,29 @@ public class CustomAclServiceImpl implements CustomAclService {
* @param permissions the permissions
* @return
*/
private boolean addPermissions(final AclSid sid, final AclObjectIdentity objectIdentity, final Map<Integer, Boolean> permissions) {
// 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(getAceOrder(objectIdentity.getId()));
aclEntry.setGranting(permissions.get(mask));
aclEntry.setAuditSuccess(true);
aclEntry.setAuditFailure(true);
// set full access for own organization
aclEntry.setMask(mask);
private List<AclEntry> addPermissions(final AclSid sid, final AclObjectIdentity objectIdentity, final Map<Integer, Boolean> permissions) {
try {
List<AclEntry> aclEntries = new ArrayList<>();
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.get(mask));
aclEntry.setAuditSuccess(true);
aclEntry.setAuditFailure(true);
// set full access for own organization
aclEntry.setMask(mask);
aclEntries.add(aclEntry);
}
// save ACL
aclEntryPersistence.save(aclEntry);
return aclEntryPersistence.save(aclEntries);
} finally {
clearAclCache();
}
clearAclCache();
return true;
}
private void clearAclCache() {
......@@ -264,8 +271,20 @@ public class CustomAclServiceImpl implements CustomAclService {
*/
@Override
@Transactional(readOnly = true)
public AclObjectIdentity getObjectIdentity(final String className, final long id) {
return aclObjectIdentityPersistence.findByIdAndClassname(id, className);
public AclObjectIdentity getObjectIdentity(final long id) {
return aclObjectIdentityPersistence.findOne(id);
}
/*
* (non-Javadoc)
* @see
* org.genesys.blocks.security.service.CustomAclService#getObjectIdentity(java.
* lang.String, long)
*/
@Override
@Transactional(readOnly = true)
public AclObjectIdentity getObjectIdentity(final long id, final String className) {
return aclObjectIdentityPersistence.findByObjectIdAndClassname(id, className);
}
/*
......@@ -280,7 +299,7 @@ public class CustomAclServiceImpl implements CustomAclService {
if (entity == null) {
LOG.error("getObjectIdentity: Entity is null");
}
final AclObjectIdentity oid = aclObjectIdentityPersistence.findByIdAndClassname(entity.getId(), entity.getClass().getName());
final AclObjectIdentity oid = aclObjectIdentityPersistence.findByObjectIdAndClassname(entity.getId(), entity.getClass().getName());
if (oid == null) {
LOG.warn("ACL object identity not found for class={} id={}", entity.getClass().getName(), entity.getId());
}
......@@ -313,7 +332,7 @@ public class CustomAclServiceImpl implements CustomAclService {
public Map<String, Map<Integer, Boolean>> getPermissions(final long id, final String className) {
final Map<String, Map<Integer, Boolean>> perm = new HashMap<>();
final List<AclEntry> aclEntries = getAclEntries(getObjectIdentity(className, id));
final List<AclEntry> aclEntries = getAclEntries(getObjectIdentity(id, className));
for (final AclEntry aclEntry : aclEntries) {
Map<Integer, Boolean> granted = perm.get(aclEntry.getAclSid().getSid());
if (granted == null) {
......@@ -339,29 +358,32 @@ public class CustomAclServiceImpl implements CustomAclService {
@Override
@PreAuthorize("hasRole('ADMINISTRATOR') or hasPermission(#entity, 'ADMINISTRATION')")
public void updatePermissions(final AclAwareModel entity, final AclSid sid, final Map<Integer, Boolean> permissions) {
public List<AclEntry> updatePermissions(final AclAwareModel entity, final AclSid sid, final Map<Integer, Boolean> permissions) {
final AclObjectIdentity objectIdentity = getObjectIdentity(entity);
updatePermissions(objectIdentity, sid, permissions);
return updatePermissions(objectIdentity, sid, permissions);
}
@Override
@PreAuthorize("hasRole('ADMINISTRATOR') or hasPermission(#objectIdentity.objectIdIdentity, #objectIdentity.aclClass.aclClass, 'ADMINISTRATION')")
public void updatePermissions(AclObjectIdentity objectIdentity, AclSid sid, Map<Integer, Boolean> permissions) {
boolean oneGranting = false;
final List<AclEntry> aclEntries = aclEntryPersistence.findBySidAndObjectIdentity(sid, objectIdentity);
for (final AclEntry aclEntry : aclEntries) {
aclEntry.setGranting(permissions.get((int) aclEntry.getMask()));
oneGranting |= aclEntry.isGranting();
}
if (oneGranting) {
LOG.info("Saving " + aclEntries);
aclEntryPersistence.save(aclEntries);
} else {
LOG.info("Deleting " + aclEntries);
aclEntryPersistence.delete(aclEntries);
public List<AclEntry> updatePermissions(AclObjectIdentity objectIdentity, AclSid sid, Map<Integer, Boolean> permissions) {
try {
boolean oneGranting = false;
final List<AclEntry> aclEntries = aclEntryPersistence.findBySidAndObjectIdentity(sid, objectIdentity);
for (final AclEntry aclEntry : aclEntries) {
aclEntry.setGranting(permissions.get((int) aclEntry.getMask()));
oneGranting |= aclEntry.isGranting();
}
if (oneGranting) {
LOG.info("Saving " + aclEntries);
return aclEntryPersistence.save(aclEntries);
} else {
LOG.info("Deleting " + aclEntries);
aclEntryPersistence.delete(aclEntries);
return Lists.newArrayList();
}
} finally {
clearAclCache();
}
clearAclCache();
}
/*
......@@ -371,7 +393,6 @@ public class CustomAclServiceImpl implements CustomAclService {
*/
@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);
}
......@@ -395,7 +416,7 @@ public class CustomAclServiceImpl implements CustomAclService {
@Override
@Transactional(readOnly = true)
public List<AclSid> getSids(final long id, final String className) {
return aclEntryPersistence.getSids(getObjectIdentity(className, id));
return aclEntryPersistence.getSids(getObjectIdentity(id, className));
}
/*
......@@ -412,7 +433,7 @@ public class CustomAclServiceImpl implements CustomAclService {
}
@Override
public boolean addPermissions(AclAwareModel entity, AclSid sid, Map<Integer, Boolean> permissions) {
public List<AclEntry> addPermissions(AclAwareModel entity, AclSid sid, Map<Integer, Boolean> permissions) {
return addPermissions(sid, getObjectIdentity(entity), permissions);
}
......@@ -424,8 +445,8 @@ public class CustomAclServiceImpl implements CustomAclService {
*/
@Override
@PreAuthorize("hasRole('ADMINISTRATOR') or hasPermission(#objectIdIdentity, #className, 'ADMINISTRATION')")
public boolean addPermissions(final long objectIdIdentity, final String className, AclSid sid, final Map<Integer, Boolean> permissions) {
final AclObjectIdentity oid = ensureObjectIdentity(className, objectIdIdentity);
public List<AclEntry> addPermissions(final long objectIdIdentity, final String className, AclSid sid, final Map<Integer, Boolean> permissions) {
final AclObjectIdentity oid = ensureObjectIdentity(objectIdIdentity, className);
return addPermissions(sid, oid, permissions);
}
......@@ -455,8 +476,8 @@ public class CustomAclServiceImpl implements CustomAclService {
*/
@Override
@Transactional
public AclObjectIdentity ensureObjectIdentity(final String className, final long objectIdIdentity) {
AclObjectIdentity aoi = aclObjectIdentityPersistence.findByIdAndClassname(objectIdIdentity, className);
public AclObjectIdentity ensureObjectIdentity(final long objectIdIdentity, final String className) {
AclObjectIdentity aoi = aclObjectIdentityPersistence.findByObjectIdAndClassname(objectIdIdentity, className);
if (aoi == null) {
aoi = new AclObjectIdentity();
aoi.setObjectIdIdentity(objectIdIdentity);
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment