CCM NG: Permissions are now written recursivly
git-svn-id: https://svn.libreccm.org/ccm/ccm_ng@4534 8810af33-2d31-482b-a856-94f89814c4df
Former-commit-id: a8c85aaca9
pull/2/head
parent
e1b54a5347
commit
c0315684c7
|
|
@ -19,7 +19,9 @@
|
|||
package org.librecms.contentsection;
|
||||
|
||||
import org.hibernate.envers.Audited;
|
||||
import org.libreccm.core.CcmObject;
|
||||
import org.libreccm.core.Identifiable;
|
||||
import org.libreccm.security.Relation;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Objects;
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@ import java.util.Objects;
|
|||
|
||||
import static org.libreccm.core.CoreConstants.DB_SCHEMA;
|
||||
|
||||
import org.libreccm.security.RecursivePermissions;
|
||||
import org.libreccm.security.Relation;
|
||||
|
||||
/**
|
||||
* Association class describing the association between a category and an
|
||||
|
|
@ -70,7 +70,7 @@ import org.libreccm.security.RecursivePermissions;
|
|||
+ "WHERE c.category = :category "
|
||||
+ "AND c.index = TRUE")
|
||||
})
|
||||
public class Categorization implements Serializable, Portable {
|
||||
public class Categorization implements Serializable, Relation, Portable {
|
||||
|
||||
private static final long serialVersionUID = 201504301320L;
|
||||
|
||||
|
|
@ -93,7 +93,6 @@ public class Categorization implements Serializable, Portable {
|
|||
/**
|
||||
* The categorised object.
|
||||
*/
|
||||
@RecursivePermissions
|
||||
@ManyToOne
|
||||
@JoinColumn(name = "OBJECT_ID")
|
||||
@JsonBackReference(value = "object-categorization")
|
||||
|
|
@ -145,6 +144,11 @@ public class Categorization implements Serializable, Portable {
|
|||
return category;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CcmObject getOwner() {
|
||||
return getCategory();
|
||||
}
|
||||
|
||||
protected void setCategory(final Category category) {
|
||||
this.category = category;
|
||||
}
|
||||
|
|
@ -153,6 +157,11 @@ public class Categorization implements Serializable, Portable {
|
|||
return categorizedObject;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CcmObject getRelatedObject() {
|
||||
return getCategorizedObject();
|
||||
}
|
||||
|
||||
protected void setCategorizedObject(final CcmObject categorizedObject) {
|
||||
this.categorizedObject = categorizedObject;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -162,7 +162,7 @@ public class Permission implements Serializable, Portable {
|
|||
*/
|
||||
@OneToOne
|
||||
@JoinColumn(name = "INHERITED_FROM_ID")
|
||||
private CcmObject inheritedForm;
|
||||
private CcmObject inheritedFrom;
|
||||
|
||||
protected Permission() {
|
||||
//Nothing
|
||||
|
|
@ -236,12 +236,12 @@ public class Permission implements Serializable, Portable {
|
|||
this.inherited = inherited;
|
||||
}
|
||||
|
||||
public CcmObject getInheritedForm() {
|
||||
return inheritedForm;
|
||||
public CcmObject getInheritedFrom() {
|
||||
return inheritedFrom;
|
||||
}
|
||||
|
||||
protected void setInheritedForm(CcmObject inheritedForm) {
|
||||
this.inheritedForm = inheritedForm;
|
||||
protected void setInheritedFrom(CcmObject inheritedFrom) {
|
||||
this.inheritedFrom = inheritedFrom;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -18,6 +18,8 @@
|
|||
*/
|
||||
package org.libreccm.security;
|
||||
|
||||
import com.arsdigita.util.UncheckedWrapperException;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
|
@ -31,6 +33,7 @@ import org.libreccm.core.CoreConstants;
|
|||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import javax.enterprise.context.RequestScoped;
|
||||
|
|
@ -101,6 +104,69 @@ public class PermissionManager {
|
|||
permission.setObject(object);
|
||||
|
||||
entityManager.persist(permission);
|
||||
|
||||
grantRecursive(privilege, grantee, object, object.getClass());
|
||||
}
|
||||
}
|
||||
|
||||
private void grantRecursive(final String privilege,
|
||||
final Role grantee,
|
||||
final CcmObject object,
|
||||
final Class<?> clazz) {
|
||||
final Field[] fields = clazz.getDeclaredFields();
|
||||
Arrays.stream(fields)
|
||||
.filter(field -> field.isAnnotationPresent(
|
||||
RecursivePermissions.class))
|
||||
.forEach(field -> {
|
||||
field.setAccessible(true);
|
||||
grantRecursive(privilege, grantee, field, object);
|
||||
});
|
||||
|
||||
if (clazz.getSuperclass() != null) {
|
||||
grantRecursive(privilege, grantee, object, clazz.getSuperclass());
|
||||
}
|
||||
}
|
||||
|
||||
private void grantRecursive(final String privilege,
|
||||
final Role grantee,
|
||||
final Field field,
|
||||
final CcmObject owner) {
|
||||
final Object value;
|
||||
try {
|
||||
value = field.get(owner);
|
||||
} catch (IllegalAccessException ex) {
|
||||
throw new UncheckedWrapperException(ex);
|
||||
}
|
||||
|
||||
if (value == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (field.getType().equals(Collection.class)) {
|
||||
final Collection<?> collection = (Collection<?>) value;
|
||||
collection.stream()
|
||||
.filter(obj -> obj instanceof CcmObject)
|
||||
.map(obj -> (CcmObject) obj)
|
||||
.forEach(obj -> grantPrivilege(privilege, grantee, obj));
|
||||
collection.stream()
|
||||
.filter(obj -> obj instanceof Relation)
|
||||
.map(obj -> (Relation) obj)
|
||||
.filter(relation -> relation.getRelatedObject() != null)
|
||||
.map(relation -> relation.getRelatedObject())
|
||||
.forEach(obj -> grantPrivilege(privilege, grantee, obj));
|
||||
} else if (field.getType().equals(CcmObject.class)) {
|
||||
grantPrivilege(privilege, grantee, (CcmObject) value);
|
||||
} else if (field.getType().equals(Relation.class)) {
|
||||
final Relation relation = (Relation) value;
|
||||
if (relation.getRelatedObject() != null) {
|
||||
grantPrivilege(privilege, grantee, relation.getRelatedObject());
|
||||
}
|
||||
} else {
|
||||
throw new IllegalArgumentException(String.format(
|
||||
"Found a field annotated with \"%s\" but the field is not a "
|
||||
+ "collection nor a CcmObject nore a Relation object. This "
|
||||
+ "is not supported.",
|
||||
RecursivePermissions.class));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -166,15 +232,26 @@ public class PermissionManager {
|
|||
}
|
||||
|
||||
if (existsPermission(privilege, grantee, object)) {
|
||||
final Query query = entityManager.createQuery(
|
||||
final Query deleteQuery = entityManager.createQuery(
|
||||
"DELETE FROM Permission p "
|
||||
+ "WHERE p.grantedPrivilege = :privilege "
|
||||
+ "AND p.grantee = :grantee "
|
||||
+ "AND p.object = :object");
|
||||
query.setParameter(QUERY_PARAM_PRIVILEGE, privilege);
|
||||
query.setParameter(QUERY_PARAM_GRANTEE, grantee);
|
||||
query.setParameter(QUERY_PARAM_OBJECT, object);
|
||||
query.executeUpdate();
|
||||
deleteQuery.setParameter(QUERY_PARAM_PRIVILEGE, privilege);
|
||||
deleteQuery.setParameter(QUERY_PARAM_GRANTEE, grantee);
|
||||
deleteQuery.setParameter(QUERY_PARAM_OBJECT, object);
|
||||
deleteQuery.executeUpdate();
|
||||
|
||||
final Query deleteInheritedQuery = entityManager.createQuery(
|
||||
"DELETE FROM Permission p "
|
||||
+ "WHERE p.grantedPrivilege = :privilege "
|
||||
+ "AND p.grantee = :grantee "
|
||||
+ "AND p.inheritedFrom = :object "
|
||||
+ "AND p.inherited = true");
|
||||
deleteInheritedQuery.setParameter(QUERY_PARAM_PRIVILEGE, privilege);
|
||||
deleteInheritedQuery.setParameter(QUERY_PARAM_GRANTEE, grantee);
|
||||
deleteInheritedQuery.setParameter("p.inheritedFrom", object);
|
||||
deleteQuery.executeUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,46 @@
|
|||
/*
|
||||
* Copyright (C) 2017 LibreCCM Foundation.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
* MA 02110-1301 USA
|
||||
*/
|
||||
package org.libreccm.security;
|
||||
|
||||
import org.libreccm.core.CcmObject;
|
||||
import org.libreccm.security.RecursivePermissions;
|
||||
|
||||
/**
|
||||
* If N:M or relation with attributes is annotated with {@link RecursivePermissions} and the
|
||||
* relation object is not a {@link CcmObject} the relation object must
|
||||
* implement this interface.
|
||||
*
|
||||
* An example are {@link Category#objects} and {@link Categorization}.
|
||||
*
|
||||
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
|
||||
*/
|
||||
public interface Relation {
|
||||
|
||||
/**
|
||||
* Get the owning object of the relation.
|
||||
* @return
|
||||
*/
|
||||
CcmObject getOwner();
|
||||
/**
|
||||
* Get the related object of the relation.
|
||||
* @return
|
||||
*/
|
||||
CcmObject getRelatedObject();
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
alter table CCM_CORE.PERMISSIONS
|
||||
add column INHERITED boolean;
|
||||
|
||||
alter table CCM_CORE.PERMISSIONS
|
||||
add column INHERITED_FROM_ID int8;
|
||||
|
||||
alter table CCM_CORE.PERMISSIONS
|
||||
add constraint FKc1x3h1p3o20qiwmonpmva7t5i
|
||||
foreign key (INHERITED_FROM_ID)
|
||||
references CCM_CORE.CCM_OBJECTS;
|
||||
|
|
@ -21,6 +21,7 @@ package org.libreccm.portation;
|
|||
import org.libreccm.categorization.CategorizationMarshaller;
|
||||
import org.libreccm.categorization.Category;
|
||||
import org.libreccm.categorization.CategoryMarshaller;
|
||||
import org.libreccm.security.Group;
|
||||
import org.libreccm.security.GroupMarshaller;
|
||||
import org.libreccm.security.GroupMembershipMarshaller;
|
||||
import org.libreccm.security.PermissionMarshaller;
|
||||
|
|
@ -34,6 +35,7 @@ import org.libreccm.workflow.WorkflowTemplateMarshaller;
|
|||
|
||||
import javax.enterprise.context.RequestScoped;
|
||||
import javax.inject.Inject;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
|
|
@ -57,6 +59,7 @@ class ImportHelper {
|
|||
@Inject
|
||||
private UserMarshaller userMarshaller;
|
||||
@Inject
|
||||
@Marshals(Group.class)
|
||||
private GroupMarshaller groupMarshaller;
|
||||
@Inject
|
||||
private GroupMembershipMarshaller groupMembershipMarshaller;
|
||||
|
|
|
|||
|
|
@ -229,7 +229,12 @@ public class PermissionManagerTest {
|
|||
excludeColumns = {"permission_id"})
|
||||
@InSequence(211)
|
||||
public void grantPermissionRecursively() {
|
||||
fail();
|
||||
final Role role1 = roleRepository.findByName("role1");
|
||||
final CcmObject category1 = ccmObjectRepository.findById(-20001L);
|
||||
|
||||
shiro.getSystemUser().execute(() -> {
|
||||
permissionManager.grantPrivilege("privilege4", role1, category1);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -246,7 +251,12 @@ public class PermissionManagerTest {
|
|||
excludeColumns = {"permission_id"})
|
||||
@InSequence(212)
|
||||
public void grantInheritedPermission() {
|
||||
fail();
|
||||
final Role role1 = roleRepository.findByName("role1");
|
||||
final CcmObject category2 = ccmObjectRepository.findById(-20001L);
|
||||
|
||||
shiro.getSystemUser().execute(() -> {
|
||||
permissionManager.grantPrivilege("privilege4", role1, category2);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -480,7 +490,12 @@ public class PermissionManagerTest {
|
|||
+ "after-revoke-recursivly.yml")
|
||||
@InSequence(311)
|
||||
public void revokePermissionRecursivly() {
|
||||
fail();
|
||||
final Role role1 = roleRepository.findByName("role1");
|
||||
final CcmObject category1 = ccmObjectRepository.findById(-20001L);
|
||||
|
||||
shiro.getSystemUser().execute(() -> {
|
||||
permissionManager.revokePrivilege("privilege4", role1, category1);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
Loading…
Reference in New Issue