From 3ab51a59c0b5fc043d1f91e54fdf25d647ea8fce Mon Sep 17 00:00:00 2001 From: "nikolce.mihajlovski" Date: Mon, 5 Jan 2015 01:03:36 +0100 Subject: [PATCH] Implemented permission-based "delete" button visibility in generic view screen. --- .../rapidoid/app/ViewEntityScreenGeneric.java | 9 ++- .../rapidoid/demo/taskplanner/model/Task.java | 2 +- .../java/org/rapidoid/widget/FormWidget.java | 2 +- .../java/org/rapidoid/security/Secure.java | 62 ++++++++++++++++++- .../security/SecurityTestCommons.java | 2 +- .../main/java/org/rapidoid/util/Metadata.java | 5 ++ 6 files changed, 77 insertions(+), 5 deletions(-) diff --git a/rapidoid-app/src/main/java/org/rapidoid/app/ViewEntityScreenGeneric.java b/rapidoid-app/src/main/java/org/rapidoid/app/ViewEntityScreenGeneric.java index 9c41fa2773..aaab09b13a 100644 --- a/rapidoid-app/src/main/java/org/rapidoid/app/ViewEntityScreenGeneric.java +++ b/rapidoid-app/src/main/java/org/rapidoid/app/ViewEntityScreenGeneric.java @@ -24,6 +24,7 @@ import org.rapidoid.db.DB; import org.rapidoid.html.Tag; import org.rapidoid.http.HttpExchange; +import org.rapidoid.security.Secure; import org.rapidoid.util.U; import org.rapidoid.widget.FormWidget; @@ -43,7 +44,13 @@ public Object content(HttpExchange x) { return x.notFound(); } - FormWidget details = show(entity).buttons(EDIT, BACK, DELETE); + FormWidget details = show(entity); + + if (Secure.getObjectPermissions(x.username(), entity).delete) { + details = details.buttons(EDIT, BACK, DELETE); + } else { + details = details.buttons(EDIT, BACK); + } return row(caption, details); } diff --git a/rapidoid-demo/src/main/java/org/rapidoid/demo/taskplanner/model/Task.java b/rapidoid-demo/src/main/java/org/rapidoid/demo/taskplanner/model/Task.java index e48ee06cae..0505d511de 100644 --- a/rapidoid-demo/src/main/java/org/rapidoid/demo/taskplanner/model/Task.java +++ b/rapidoid-demo/src/main/java/org/rapidoid/demo/taskplanner/model/Task.java @@ -37,7 +37,7 @@ @CanRead(CommonRoles.LOGGED_IN) @CanChange({ CommonRoles.OWNER }) @CanInsert(CommonRoles.LOGGED_IN) -@CanDelete(CommonRoles.OWNER) +@CanDelete({ CommonRoles.OWNER, CommonRoles.ADMIN }) public class Task extends Entity { @CanChange({ MODERATOR, OWNER }) diff --git a/rapidoid-pages/src/main/java/org/rapidoid/widget/FormWidget.java b/rapidoid-pages/src/main/java/org/rapidoid/widget/FormWidget.java index 6a293df62d..6296ee13a0 100644 --- a/rapidoid-pages/src/main/java/org/rapidoid/widget/FormWidget.java +++ b/rapidoid-pages/src/main/java/org/rapidoid/widget/FormWidget.java @@ -252,7 +252,7 @@ protected void initPermissions() { for (int i = 0; i < fieldNames.length; i++) { if (permissions[i] == null) { - permissions[i] = Secure.getDataPermissions(exchange().username(), targetClass, target, + permissions[i] = Secure.getPropertyPermissions(exchange().username(), targetClass, target, fieldNames[i]); } } diff --git a/rapidoid-security/src/main/java/org/rapidoid/security/Secure.java b/rapidoid-security/src/main/java/org/rapidoid/security/Secure.java index 66cd003cb6..eb6cb6e938 100644 --- a/rapidoid-security/src/main/java/org/rapidoid/security/Secure.java +++ b/rapidoid-security/src/main/java/org/rapidoid/security/Secure.java @@ -98,7 +98,8 @@ public static boolean hasAnyRole(String username, String[] roles, Class clazz return false; } - public static DataPermissions getDataPermissions(String username, Class clazz, Object target, String propertyName) { + public static DataPermissions getPropertyPermissions(String username, Class clazz, Object target, + String propertyName) { U.notNull(clazz, "class"); if (Collection.class.isAssignableFrom(clazz) || Map.class.isAssignableFrom(clazz) @@ -127,6 +128,65 @@ public static DataPermissions getDataPermissions(String username, Class clazz return DataPermissions.from(read, insert, change, delete); } + public static DataPermissions getClassPermissions(String username, Class clazz) { + U.notNull(clazz, "class"); + + if (Collection.class.isAssignableFrom(clazz) || Map.class.isAssignableFrom(clazz) + || Object[].class.isAssignableFrom(clazz)) { + return DataPermissions.ALL; + } + + if (!hasRoleBasedAccess(username, clazz, null)) { + return DataPermissions.NONE; + } + + CanRead canRead = Metadata.classAnnotation(clazz, CanRead.class); + CanInsert canInsert = Metadata.classAnnotation(clazz, CanInsert.class); + CanChange canChange = Metadata.classAnnotation(clazz, CanChange.class); + CanDelete canDelete = Metadata.classAnnotation(clazz, CanDelete.class); + + if (canRead == null && canInsert == null && canChange == null && canDelete == null) { + return DataPermissions.ALL; + } + + boolean read = canRead != null && hasAnyRole(username, canRead.value(), clazz, null); + boolean insert = canInsert != null && hasAnyRole(username, canInsert.value(), clazz, null); + boolean change = canChange != null && hasAnyRole(username, canChange.value(), clazz, null); + boolean delete = canDelete != null && hasAnyRole(username, canDelete.value(), clazz, null); + + return DataPermissions.from(read, insert, change, delete); + } + + public static DataPermissions getObjectPermissions(String username, Object target) { + U.notNull(target, "target"); + Class clazz = target.getClass(); + + if (Collection.class.isAssignableFrom(clazz) || Map.class.isAssignableFrom(clazz) + || Object[].class.isAssignableFrom(clazz)) { + return DataPermissions.ALL; + } + + if (!hasRoleBasedAccess(username, clazz, null)) { + return DataPermissions.NONE; + } + + CanRead canRead = Metadata.classAnnotation(clazz, CanRead.class); + CanInsert canInsert = Metadata.classAnnotation(clazz, CanInsert.class); + CanChange canChange = Metadata.classAnnotation(clazz, CanChange.class); + CanDelete canDelete = Metadata.classAnnotation(clazz, CanDelete.class); + + if (canRead == null && canInsert == null && canChange == null && canDelete == null) { + return DataPermissions.ALL; + } + + boolean read = canRead != null && hasAnyRole(username, canRead.value(), clazz, target); + boolean insert = canInsert != null && hasAnyRole(username, canInsert.value(), clazz, target); + boolean change = canChange != null && hasAnyRole(username, canChange.value(), clazz, target); + boolean delete = canDelete != null && hasAnyRole(username, canDelete.value(), clazz, target); + + return DataPermissions.from(read, insert, change, delete); + } + public static List getUserRoles(String username) { return security.getUserRoles(username); } diff --git a/rapidoid-security/src/test/java/org/rapidoid/security/SecurityTestCommons.java b/rapidoid-security/src/test/java/org/rapidoid/security/SecurityTestCommons.java index c690e8647e..937bae594f 100644 --- a/rapidoid-security/src/test/java/org/rapidoid/security/SecurityTestCommons.java +++ b/rapidoid-security/src/test/java/org/rapidoid/security/SecurityTestCommons.java @@ -28,7 +28,7 @@ public abstract class SecurityTestCommons extends TestCommons implements CommonR protected void checkPermissions(String username, Class clazz, Object target, String propertyName, boolean canRead, boolean canChange) { - DataPermissions perms = Secure.getDataPermissions(username, clazz, target, propertyName); + DataPermissions perms = Secure.getPropertyPermissions(username, clazz, target, propertyName); eq(perms.read, canRead); eq(perms.change, canChange); diff --git a/rapidoid-utils/src/main/java/org/rapidoid/util/Metadata.java b/rapidoid-utils/src/main/java/org/rapidoid/util/Metadata.java index 413bf68b9e..86c28c569b 100644 --- a/rapidoid-utils/src/main/java/org/rapidoid/util/Metadata.java +++ b/rapidoid-utils/src/main/java/org/rapidoid/util/Metadata.java @@ -36,6 +36,11 @@ public static Map, Annotation> classAnnotations(Class clazz) { return annotations; } + @SuppressWarnings("unchecked") + public static T classAnnotation(Class clazz, Class annotationClass) { + return (T) classAnnotations(clazz).get(annotationClass); + } + public static Map, Annotation> fieldAnnotations(Class clazz, String fieldName) { Field field = Cls.getField(clazz, fieldName);