Commit a3588258 authored by Matija Obreza's avatar Matija Obreza

Merge branch 'class-acloid' into 'master'

Introduced ClassAclOid as AclAwareModel

See merge request genesys-pgr/application-blocks!40
parents 4a94d934 c161f60b
......@@ -15,21 +15,19 @@
*/
package org.genesys.blocks.security.model;
import java.io.Serializable;
import com.fasterxml.jackson.databind.annotation.JsonAppend;
import org.genesys.blocks.model.EntityId;
import org.genesys.blocks.security.serialization.Permissions;
import org.genesys.blocks.security.serialization.CurrentPermissionsWriter;
import org.genesys.blocks.security.serialization.Permissions;
import org.genesys.blocks.util.JsonClassNameWriter;
import com.fasterxml.jackson.databind.annotation.JsonAppend;
/**
* Interface label for entities that require ACL security.
*/
@JsonAppend(props = { @JsonAppend.Prop(name = "_class", value = JsonClassNameWriter.class, type = String.class),
@JsonAppend.Prop(name = "_permissions", value = CurrentPermissionsWriter.class, type = Permissions.class) })
public interface AclAwareModel extends Serializable, EntityId {
public interface AclAwareModel extends EntityId {
/**
* Objects belonging to a parent entity can override this method.
......
......@@ -15,6 +15,7 @@
*/
package org.genesys.blocks.security.model;
import javax.persistence.Cacheable;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Table;
......@@ -26,6 +27,7 @@ import org.genesys.blocks.model.BasicModel;
*/
@Entity
@Table(name = "acl_class")
@Cacheable
public class AclClass extends BasicModel {
/** The Constant serialVersionUID. */
......
......@@ -17,6 +17,7 @@ package org.genesys.blocks.security.model;
import java.util.List;
import javax.persistence.Cacheable;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.DiscriminatorColumn;
......@@ -53,6 +54,7 @@ import org.hibernate.annotations.DiscriminatorOptions;
@DiscriminatorValue(value = "0")
@DiscriminatorOptions(force = false)
@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "sid")
@Cacheable
public class AclSid extends AuditedVersionedModel {
/** The Constant serialVersionUID. */
......
......@@ -33,6 +33,7 @@ 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.slf4j.Logger;
import org.slf4j.LoggerFactory;
......@@ -121,12 +122,17 @@ public class CustomAclServiceImpl implements CustomAclService {
@Override
@Transactional(propagation = Propagation.REQUIRED)
public void createOrUpdatePermissions(final AclAwareModel target) {
if ((target == null) || (target.getId() <= 0l)) {
if (target == null || (target.getId() <= 0l && !(target instanceof ClassAclOid<?>))) {
LOG.warn("No target specified for ACL permissions, bailing out!");
return;
}
final AclClass aclClass = ensureAclClass(target.getClass().getName());
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());
......@@ -416,6 +422,11 @@ public class CustomAclServiceImpl implements CustomAclService {
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());
......@@ -463,7 +474,7 @@ public class CustomAclServiceImpl implements CustomAclService {
return getPermissions(entity.getId(), entity.getClass().getName());
}
@Transactional(propagation = Propagation.REQUIRED)
@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) {
......@@ -481,7 +492,7 @@ public class CustomAclServiceImpl implements CustomAclService {
return setPermissions(objectIdentity, sid, permissions);
}
@Transactional(propagation = Propagation.REQUIRED)
@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) {
......@@ -496,33 +507,38 @@ public class CustomAclServiceImpl implements CustomAclService {
}
try {
if (permissions.isOneGranting()) {
// need to update or add permissions
final List<AclEntry> aclEntries = aclEntryPersistence.findBySidAndObjectIdentity(sid, objectIdentity);
if (aclEntries.isEmpty()) {
// add
return addPermissions(objectIdentity, sid, permissions);
} else {
// updarte
for (final AclEntry aclEntry : aclEntries) {
aclEntry.setGranting(permissions.isGranting(aclEntry.getMask()));
}
LOG.info("Saving " + aclEntries);
aclEntryPersistence.save(aclEntries);
return getObjectIdentity(objectIdentity.getId());
}
final List<AclEntry> aclEntries = aclEntryPersistence.findBySidAndObjectIdentity(sid, objectIdentity);
if (aclEntries.isEmpty()) {
// add
return addPermissions(objectIdentity, sid, permissions);
} else {
// delete existing
final List<AclEntry> aclEntries = aclEntryPersistence.findBySidAndObjectIdentity(sid, objectIdentity);
if (!aclEntries.isEmpty()) {
LOG.info("Deleting " + aclEntries);
aclEntryPersistence.delete(aclEntries);
entityManager.flush();
// update
for (final AclEntry aclEntry : aclEntries) {
aclEntry.setGranting(permissions.isGranting(aclEntry.getMask()));
}
LOG.info("Saving " + aclEntries);
aclEntryPersistence.save(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();
}
......
/*
* 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.util;
import org.genesys.blocks.security.model.AclAwareModel;
/**
* The ACL object identity for our Java classes. Mostly used to make entity
* types READ-able to EVERYONE by default.
*
* @param <T> the generic type
*/
public class ClassAclOid<T extends AclAwareModel> implements AclAwareModel {
private Class<T> clazz;
@Override
public Long getId() {
return -419l; // We use -419l for ACL OID#id for classes
}
/**
* For class.
*
* @param <T> the generic type
* @param clazz the clazz
* @return the class acl
*/
public static <T extends AclAwareModel> ClassAclOid<T> forClass(Class<T> clazz) {
ClassAclOid<T> classAcl = new ClassAclOid<T>();
classAcl.clazz = clazz;
return classAcl;
}
/**
* Gets the clazz.
*
* @return the clazz
*/
public Class<T> getClazz() {
return clazz;
}
/**
* Gets the class name.
*
* @return the class name
*/
public String getClassName() {
return clazz.getName();
}
}
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