From 8958fc14a5a6faaee0234dcac3c5ef0d4c04dee1 Mon Sep 17 00:00:00 2001 From: Alex Heneveld Date: Fri, 27 Jun 2014 14:29:00 +0100 Subject: [PATCH 1/2] more support for entitlements --- .../entitlement/EntitlementManager.java | 8 ++- .../EntitlementManagerAdapter.java | 51 +++++++++++++++++++ .../management/entitlement/Entitlements.java | 48 ++++++++++++++--- .../main/java/brooklyn/util/guava/Maybe.java | 2 +- .../java/brooklyn/util/time/Duration.java | 6 +++ 5 files changed, 105 insertions(+), 10 deletions(-) create mode 100644 core/src/main/java/brooklyn/management/entitlement/EntitlementManagerAdapter.java diff --git a/api/src/main/java/brooklyn/management/entitlement/EntitlementManager.java b/api/src/main/java/brooklyn/management/entitlement/EntitlementManager.java index d9312d0650..3035344d57 100644 --- a/api/src/main/java/brooklyn/management/entitlement/EntitlementManager.java +++ b/api/src/main/java/brooklyn/management/entitlement/EntitlementManager.java @@ -7,7 +7,13 @@ * Entitlement lookup relies on: *
  • an "entitlement context", consisting of at minimum a string identifier of the user/actor for which entitlement is being requested *
  • an "entitlement class", representing the category of activity for which entitlement is being requested - *
  • an "entitlement class argument", representing the specifics of the activity for which entitlement is being requested + *
  • an "entitlement class argument", representing the specifics of the activity for which entitlement is being requested + *

    + * Instances of this class typically have a 1-arg constructor taking a BrooklynProperties object + * (configuration injected by the Brooklyn framework) + * or a 0-arg constructor (if no external configuration is needed). + *

    + * Instantiation is done e.g. by Entitlements.newManager. */ public interface EntitlementManager { diff --git a/core/src/main/java/brooklyn/management/entitlement/EntitlementManagerAdapter.java b/core/src/main/java/brooklyn/management/entitlement/EntitlementManagerAdapter.java new file mode 100644 index 0000000000..7b4196d339 --- /dev/null +++ b/core/src/main/java/brooklyn/management/entitlement/EntitlementManagerAdapter.java @@ -0,0 +1,51 @@ +package brooklyn.management.entitlement; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import brooklyn.entity.Entity; +import brooklyn.management.entitlement.Entitlements.EntityAndItem; + +public abstract class EntitlementManagerAdapter implements EntitlementManager { + + private static final Logger log = LoggerFactory.getLogger(EntitlementManagerAdapter.class); + + @SuppressWarnings("unchecked") + @Override + public boolean isEntitled(EntitlementContext context, EntitlementClass entitlementClass, T entitlementClassArgument) { + if (log.isTraceEnabled()) { + log.trace("Checking entitlement of "+context+" to "+entitlementClass+" "+entitlementClassArgument); + } + + if (isEntitledToRoot( context )) return true; + + switch (Entitlements.EntitlementClassesEnum.of(entitlementClass)) { + case ENTITLEMENT_SEE_ENTITY: + return isEntitledToSeeEntity( context, (Entity)entitlementClassArgument ); + + case ENTITLEMENT_SEE_SENSOR: + return isEntitledToSeeSensor( context, (EntityAndItem)entitlementClassArgument ); + + case ENTITLEMENT_INVOKE_EFFECTOR: + return isEntitledToInvokeEffector( context, (EntityAndItem)entitlementClassArgument ); + + case ENTITLEMENT_DEPLOY_APPLICATION: + return isEntitledToDeploy( context, entitlementClassArgument ); + + case ENTITLEMENT_SEE_ALL_SERVER_INFO: + return isEntitledToSeeAllServerInfo( context ); + + default: + log.warn("Unsupported permission type: "+entitlementClass+" / "+entitlementClassArgument); + return false; + } + } + + protected abstract boolean isEntitledToSeeSensor(EntitlementContext context, EntityAndItem sensorInfo); + protected abstract boolean isEntitledToSeeEntity(EntitlementContext context, Entity entity); + protected abstract boolean isEntitledToInvokeEffector(EntitlementContext context, EntityAndItem effectorInfo); + protected abstract boolean isEntitledToDeploy(EntitlementContext context, Object app); + protected abstract boolean isEntitledToSeeAllServerInfo(EntitlementContext context); + protected abstract boolean isEntitledToRoot(EntitlementContext context); + +} diff --git a/core/src/main/java/brooklyn/management/entitlement/Entitlements.java b/core/src/main/java/brooklyn/management/entitlement/Entitlements.java index 684b0c6b78..6e3fe71e2b 100644 --- a/core/src/main/java/brooklyn/management/entitlement/Entitlements.java +++ b/core/src/main/java/brooklyn/management/entitlement/Entitlements.java @@ -15,10 +15,6 @@ */ package brooklyn.management.entitlement; -import com.google.common.base.Objects; -import com.google.common.base.Predicate; -import com.google.common.base.Predicates; -import com.google.common.reflect.TypeToken; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -31,6 +27,11 @@ import brooklyn.util.exceptions.Exceptions; import brooklyn.util.text.Strings; +import com.google.common.base.Objects; +import com.google.common.base.Predicate; +import com.google.common.base.Predicates; +import com.google.common.reflect.TypeToken; + public class Entitlements { private static final Logger log = LoggerFactory.getLogger(Entitlements.class); @@ -55,6 +56,31 @@ public class Entitlements { * secondary check required for any operation which could potentially grant root-level access */ public static EntitlementClass ROOT = new BasicEntitlementClassDefinition("root", Void.class); + public static enum EntitlementClassesEnum { + ENTITLEMENT_SEE_ENTITY(SEE_ENTITY), + ENTITLEMENT_SEE_SENSOR(SEE_SENSOR), + ENTITLEMENT_INVOKE_EFFECTOR(INVOKE_EFFECTOR), + ENTITLEMENT_DEPLOY_APPLICATION(DEPLOY_APPLICATION), + ENTITLEMENT_SEE_ALL_SERVER_INFO(SEE_ALL_SERVER_INFO), + ENTITLEMENT_ROOT(ROOT), + ; + + private EntitlementClass entitlementClass; + + private EntitlementClassesEnum(EntitlementClass specificClass) { + this.entitlementClass = specificClass; + } + public EntitlementClass getEntitlementClass() { + return entitlementClass; + } + + public static EntitlementClassesEnum of(EntitlementClass entitlementClass) { + for (EntitlementClassesEnum x: values()) { + if (entitlementClass.equals(x.getEntitlementClass())) return x; + } + return null; + } + } public static class EntityAndItem { final Entity entity; @@ -207,13 +233,14 @@ public static void requireEntitled(EntitlementManager checker, EntitlementCl // ----------------- initialization ---------------- public static ConfigKey GLOBAL_ENTITLEMENT_MANAGER = ConfigKeys.newStringConfigKey("brooklyn.entitlements.global", - "Class for entitlements in effect globally; many instances accept further per user entitlements; " - + "short names 'minimal', 'readonly', or 'root' are permitted here, with the default 'root' giving full access to all declared users", + "Class for entitlements in effect globally; " + + "short names 'minimal', 'readonly', or 'root' are permitted here, with the default 'root' giving full access to all declared users; " + + "or supply the name of an "+EntitlementManager.class+" class to instantiate, taking a 1-arg BrooklynProperties constructor or a 0-arg constructor", "root"); public static EntitlementManager newManager(ResourceUtils loader, BrooklynProperties brooklynProperties) { EntitlementManager result = newGlobalManager(loader, brooklynProperties); - // TODO per user settings + // TODO read per user settings from brooklyn.properties, if set there ? return result; } private static EntitlementManager newGlobalManager(ResourceUtils loader, BrooklynProperties brooklynProperties) { @@ -223,7 +250,12 @@ private static EntitlementManager newGlobalManager(ResourceUtils loader, Brookly if ("minimal".equalsIgnoreCase(type)) return new PerUserEntitlementManagerWithDefault(minimal()); if (Strings.isNonBlank(type)) { try { - return (EntitlementManager) loader.getLoader().loadClass(type).newInstance(); + Class clazz = loader.getLoader().loadClass(type); + if (clazz.getConstructor(BrooklynProperties.class)!=null) { + return (EntitlementManager) clazz.getConstructor(BrooklynProperties.class).newInstance(brooklynProperties); + } else { + return (EntitlementManager) clazz.newInstance(); + } } catch (Exception e) { throw Exceptions.propagate(e); } } throw new IllegalStateException("Invalid entitlement manager specified: '"+type+"'"); diff --git a/utils/common/src/main/java/brooklyn/util/guava/Maybe.java b/utils/common/src/main/java/brooklyn/util/guava/Maybe.java index dc64349815..85f72336d0 100644 --- a/utils/common/src/main/java/brooklyn/util/guava/Maybe.java +++ b/utils/common/src/main/java/brooklyn/util/guava/Maybe.java @@ -15,7 +15,7 @@ import com.google.common.collect.ImmutableSet; /** Like Guava Optional but permitting null and permitting errors to be thrown. */ -public abstract class Maybe implements Serializable { +public abstract class Maybe implements Serializable, Supplier { private static final long serialVersionUID = -6372099069863179019L; diff --git a/utils/common/src/main/java/brooklyn/util/time/Duration.java b/utils/common/src/main/java/brooklyn/util/time/Duration.java index 2b854fa842..1c01f824b5 100644 --- a/utils/common/src/main/java/brooklyn/util/time/Duration.java +++ b/utils/common/src/main/java/brooklyn/util/time/Duration.java @@ -117,7 +117,13 @@ public long nanos() { /** see {@link #of(Object)} and {@link Time#parseTimeString(String)} */ public static Duration parse(String textualDescription) { + if (textualDescription==null) return null; if ("null".equalsIgnoreCase(textualDescription)) return null; + + if ("forever".equalsIgnoreCase(textualDescription)) return Duration.PRACTICALLY_FOREVER; + if ("practicallyforever".equalsIgnoreCase(textualDescription)) return Duration.PRACTICALLY_FOREVER; + if ("practically_forever".equalsIgnoreCase(textualDescription)) return Duration.PRACTICALLY_FOREVER; + return new Duration(Time.parseTimeString(textualDescription), TimeUnit.MILLISECONDS); } From 82136c7a951617be81fc57263dbe1cd35945ec0e Mon Sep 17 00:00:00 2001 From: Andrea Turli Date: Mon, 30 Jun 2014 18:58:32 +0200 Subject: [PATCH 2/2] filter the applicationresource children according to the entitlements --- .../management/entitlement/Entitlements.java | 10 +++---- .../rest/resources/ApplicationResource.java | 26 ++++++++++++------- 2 files changed, 22 insertions(+), 14 deletions(-) diff --git a/core/src/main/java/brooklyn/management/entitlement/Entitlements.java b/core/src/main/java/brooklyn/management/entitlement/Entitlements.java index 6e3fe71e2b..667bb3b7f7 100644 --- a/core/src/main/java/brooklyn/management/entitlement/Entitlements.java +++ b/core/src/main/java/brooklyn/management/entitlement/Entitlements.java @@ -18,6 +18,11 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import com.google.common.base.Objects; +import com.google.common.base.Predicate; +import com.google.common.base.Predicates; +import com.google.common.reflect.TypeToken; + import brooklyn.config.BrooklynProperties; import brooklyn.config.ConfigKey; import brooklyn.entity.Entity; @@ -27,11 +32,6 @@ import brooklyn.util.exceptions.Exceptions; import brooklyn.util.text.Strings; -import com.google.common.base.Objects; -import com.google.common.base.Predicate; -import com.google.common.base.Predicates; -import com.google.common.reflect.TypeToken; - public class Entitlements { private static final Logger log = LoggerFactory.getLogger(Entitlements.class); diff --git a/usage/rest-server/src/main/java/brooklyn/rest/resources/ApplicationResource.java b/usage/rest-server/src/main/java/brooklyn/rest/resources/ApplicationResource.java index 95eefb82d3..68e8bcd907 100644 --- a/usage/rest-server/src/main/java/brooklyn/rest/resources/ApplicationResource.java +++ b/usage/rest-server/src/main/java/brooklyn/rest/resources/ApplicationResource.java @@ -140,26 +140,32 @@ private JsonNode fromEntity(Entity entity) { private ArrayNode childEntitiesRecursiveAsArray(Entity entity) { ArrayNode node = mapper().createArrayNode(); for (Entity e : entity.getChildren()) { - node.add(recursiveTreeFromEntity(e)); + if (Entitlements.isEntitled(mgmt().getEntitlementManager(), Entitlements.SEE_ENTITY, entity)) { + node.add(recursiveTreeFromEntity(e)); + } } return node; } private ArrayNode entitiesIdAndNameAsArray(Collection entities) { ArrayNode node = mapper().createArrayNode(); - for (Entity e : entities) { - ObjectNode holder = mapper().createObjectNode(); - holder.put("id", e.getId()); - holder.put("name", e.getDisplayName()); - node.add(holder); + for (Entity entity : entities) { + if (Entitlements.isEntitled(mgmt().getEntitlementManager(), Entitlements.SEE_ENTITY, entity)) { + ObjectNode holder = mapper().createObjectNode(); + holder.put("id", entity.getId()); + holder.put("name", entity.getDisplayName()); + node.add(holder); + } } return node; } private ArrayNode entitiesIdAsArray(Collection entities) { ArrayNode node = mapper().createArrayNode(); - for (Entity e : entities) { - node.add(e.getId()); + for (Entity entity : entities) { + if (Entitlements.isEntitled(mgmt().getEntitlementManager(), Entitlements.SEE_ENTITY, entity)) { + node.add(entity.getId()); + } } return node; } @@ -173,7 +179,9 @@ public JsonNode fetch(String entityIds) { for (String entityId: entityIds.split(",")) { Entity entity = mgmt().getEntityManager().getEntity(entityId.trim()); while (entity != null && entity.getParent() != null) { - jsonEntitiesById.put(entity.getId(), fromEntity(entity)); + if (Entitlements.isEntitled(mgmt().getEntitlementManager(), Entitlements.SEE_ENTITY, entity)) { + jsonEntitiesById.put(entity.getId(), fromEntity(entity)); + } entity = entity.getParent(); } }