You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@brooklyn.apache.org by sj...@apache.org on 2016/04/11 19:31:13 UTC

[2/4] brooklyn-server git commit: Adds a new entitlement group for regular access

Adds a new entitlement group for regular access

It is intended to disallow access to destructive server methods, thus
forbids ROOT and SEE_ALL_SERVER_INFO classes.


Project: http://git-wip-us.apache.org/repos/asf/brooklyn-server/repo
Commit: http://git-wip-us.apache.org/repos/asf/brooklyn-server/commit/27dacc3e
Tree: http://git-wip-us.apache.org/repos/asf/brooklyn-server/tree/27dacc3e
Diff: http://git-wip-us.apache.org/repos/asf/brooklyn-server/diff/27dacc3e

Branch: refs/heads/master
Commit: 27dacc3e49abdd6b924a497901fe85ddd6a303fd
Parents: 235e0c3
Author: Sam Corbett <sa...@cloudsoftcorp.com>
Authored: Thu Apr 7 15:53:54 2016 +0100
Committer: Sam Corbett <sa...@cloudsoftcorp.com>
Committed: Mon Apr 11 15:47:00 2016 +0100

----------------------------------------------------------------------
 .../entitlement/EntitlementManagerAdapter.java  |   4 +
 .../core/mgmt/entitlement/Entitlements.java     | 116 ++++++++++++-------
 .../entitlement/PerUserEntitlementManager.java  |   6 +-
 .../org/apache/brooklyn/rest/api/ScriptApi.java |   8 +-
 .../AbstractRestApiEntitlementsTest.java        |  35 +++++-
 .../ActivityApiEntitlementsTest.java            |   2 +
 .../EntityConfigApiEntitlementsTest.java        |   2 +
 .../entitlement/SensorApiEntitlementsTest.java  |   2 +
 8 files changed, 123 insertions(+), 52 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/27dacc3e/core/src/main/java/org/apache/brooklyn/core/mgmt/entitlement/EntitlementManagerAdapter.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/mgmt/entitlement/EntitlementManagerAdapter.java b/core/src/main/java/org/apache/brooklyn/core/mgmt/entitlement/EntitlementManagerAdapter.java
index b722a00..57c6d3b 100644
--- a/core/src/main/java/org/apache/brooklyn/core/mgmt/entitlement/EntitlementManagerAdapter.java
+++ b/core/src/main/java/org/apache/brooklyn/core/mgmt/entitlement/EntitlementManagerAdapter.java
@@ -53,10 +53,12 @@ public abstract class EntitlementManagerAdapter implements EntitlementManager {
         public Boolean handleSeeCatalogItem(String catalogItemId) {
             return isEntitledToSeeCatalogItem(context, catalogItemId);
         }
+
         @Override
         public Boolean handleAddCatalogItem(Object catalogItemBeingAdded) {
             return isEntitledToAddCatalogItem(context, catalogItemBeingAdded);
         }
+
         @Override
         public Boolean handleModifyCatalogItem(StringAndArgument catalogItemIdAndModification) {
             return isEntitledToModifyCatalogItem(context, catalogItemIdAndModification==null ? null : catalogItemIdAndModification.getString(),
@@ -67,6 +69,7 @@ public abstract class EntitlementManagerAdapter implements EntitlementManager {
         public Boolean handleSeeEntity(Entity entity) {
             return isEntitledToSeeEntity(context, entity);
         }
+
         @Override
         public Boolean handleSeeSensor(EntityAndItem<String> sensorInfo) {
             return isEntitledToSeeSensor(context, sensorInfo.getEntity(), sensorInfo.getItem());
@@ -76,6 +79,7 @@ public abstract class EntitlementManagerAdapter implements EntitlementManager {
             StringAndArgument item = effectorInfo.getItem();
             return isEntitledToInvokeEffector(context, effectorInfo.getEntity(), item==null ? null : item.getString(), item==null ? null : item.getArgument());
         }
+
         @Override
         public Boolean handleModifyEntity(Entity entity) {
             return isEntitledToModifyEntity(context, entity);

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/27dacc3e/core/src/main/java/org/apache/brooklyn/core/mgmt/entitlement/Entitlements.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/mgmt/entitlement/Entitlements.java b/core/src/main/java/org/apache/brooklyn/core/mgmt/entitlement/Entitlements.java
index 6d2c85c..7199267 100644
--- a/core/src/main/java/org/apache/brooklyn/core/mgmt/entitlement/Entitlements.java
+++ b/core/src/main/java/org/apache/brooklyn/core/mgmt/entitlement/Entitlements.java
@@ -21,6 +21,7 @@ package org.apache.brooklyn.core.mgmt.entitlement;
 import java.util.Arrays;
 import java.util.List;
 
+import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
 
 import org.apache.brooklyn.api.entity.Entity;
@@ -72,23 +73,32 @@ public class Entitlements {
     public static EntitlementClass<EntityAndItem<StringAndArgument>> INVOKE_EFFECTOR = new BasicEntitlementClassDefinition<EntityAndItem<StringAndArgument>>("effector.invoke", EntityAndItem.typeToken(StringAndArgument.class));
     public static EntitlementClass<Entity> MODIFY_ENTITY = new BasicEntitlementClassDefinition<Entity>("entity.modify", Entity.class);
     
-    /** the permission to deploy an application, where parameter is some representation of the app to be deployed (spec instance or yaml plan) */
+    /**
+     * Permission to deploy an application, where parameter is some representation
+     * of the app to be deployed (spec instance or yaml plan)
+     */
     public static EntitlementClass<Object> DEPLOY_APPLICATION = new BasicEntitlementClassDefinition<Object>("app.deploy", Object.class);
 
-    /** catch-all for catalog, locations, scripting, usage, etc - exporting persistence, shutting down, etc;
+    /**
+     * Catch-all for catalog, locations, scripting, usage, etc - exporting persistence, shutting down, etc;
      * this is significantly more powerful than {@link #SERVER_STATUS}.
-     * NB: this may be refactored and deprecated in future */
+     * NB: this may be refactored and deprecated in future
+     */
     public static EntitlementClass<Void> SEE_ALL_SERVER_INFO = new BasicEntitlementClassDefinition<Void>("server.info.all.see", Void.class);
 
-    /** permission to see general server status info: basically HA status; not nearly as much as {@link #SEE_ALL_SERVER_INFO} */
+    /**
+     * Permission to see general server status info: basically HA status; not nearly as much as {@link #SEE_ALL_SERVER_INFO}
+     */
     public static EntitlementClass<Void> SERVER_STATUS = new BasicEntitlementClassDefinition<Void>("server.status", Void.class);
     
-    /** permission to run untrusted code or embedded scripts at the server; 
-     * secondary check required for any operation which could potentially grant root-level access */ 
+    /**
+     * Permission to run untrusted code or embedded scripts at the server.
+     * A secondary check is required for any operation which could potentially grant root-level access.
+     */
     public static EntitlementClass<Void> ROOT = new BasicEntitlementClassDefinition<Void>("root", Void.class);
 
     @SuppressWarnings("unchecked")
-    public static enum EntitlementClassesEnum {
+    public enum EntitlementClassesEnum {
         ENTITLEMENT_SEE_CATALOG_ITEM(SEE_CATALOG_ITEM) { public <T> T handle(EntitlementClassesHandler<T> handler, Object argument) { return handler.handleSeeCatalogItem((String)argument); } },
         ENTITLEMENT_ADD_CATALOG_ITEM(ADD_CATALOG_ITEM) { public <T> T handle(EntitlementClassesHandler<T> handler, Object argument) { return handler.handleAddCatalogItem(argument); } },
         ENTITLEMENT_MODIFY_CATALOG_ITEM(MODIFY_CATALOG_ITEM) { public <T> T handle(EntitlementClassesHandler<T> handler, Object argument) { return handler.handleModifyCatalogItem((StringAndArgument)argument); } },
@@ -107,7 +117,7 @@ public class Entitlements {
         
         private EntitlementClass<?> entitlementClass;
 
-        private EntitlementClassesEnum(EntitlementClass<?> specificClass) {
+        EntitlementClassesEnum(EntitlementClass<?> specificClass) {
             this.entitlementClass = specificClass;
         }
         public EntitlementClass<?> getEntitlementClass() {
@@ -194,7 +204,9 @@ public class Entitlements {
     
     // ------------- permission sets -------------
     
-    /** always ALLOW access to everything */
+    /**
+     * @return An entitlement manager allowing access to everything.
+     */
     public static EntitlementManager root() {
         return new EntitlementManager() {
             @Override
@@ -208,7 +220,25 @@ public class Entitlements {
         };
     }
 
-    /** always DENY access to anything which requires entitlements */
+    /**
+     * @return An entitlement manager allowing everything but {@link #ROOT} and {@link #SEE_ALL_SERVER_INFO}.
+     */
+    public static EntitlementManager user() {
+        return new EntitlementManager() {
+            @Override
+            public <T> boolean isEntitled(EntitlementContext context, EntitlementClass<T> permission, T entitlementClassArgument) {
+                return !SEE_ALL_SERVER_INFO.equals(permission) && !ROOT.equals(permission);
+            }
+            @Override
+            public String toString() {
+                return "Entitlements.user";
+            }
+        };
+    }
+
+    /**
+     * @return An entitlement manager denying access to anything that requires entitlements.
+     */
     public static EntitlementManager minimal() {
         return new EntitlementManager() {
             @Override
@@ -286,41 +316,32 @@ public class Entitlements {
             @SuppressWarnings("unchecked")
             @Override
             public <T> boolean isEntitled(EntitlementContext context, EntitlementClass<T> permission, T typeArgument) {
-                if (!Objects.equal(this.permission, permission)) return false;
-                return test.apply((U)typeArgument);
+                return Objects.equal(this.permission, permission) && test.apply((U) typeArgument);
             }
             @Override
             public String toString() {
                 return "Entitlements.allowing(" + permission + " -> " + test + ")";
             }
         }
-        
+
+        private static class NonSecretPredicate implements Predicate<EntityAndItem<String>> {
+            @Override
+            public boolean apply(EntityAndItem<String> input) {
+                return input != null && !Sanitizer.IS_SECRET_PREDICATE.apply(input.getItem());
+            }
+
+            @Override
+            public String toString() {
+                return "Predicates.nonSecret";
+            }
+        }
+
         public static EntitlementManager seeNonSecretSensors() {
-            return allowing(SEE_SENSOR, new Predicate<EntityAndItem<String>>() {
-                @Override
-                public boolean apply(EntityAndItem<String> input) {
-                    if (input == null) return false;
-                    return !Sanitizer.IS_SECRET_PREDICATE.apply(input.getItem());
-                }
-                @Override
-                public String toString() {
-                    return "Predicates.nonSecret";
-                }
-            });
+            return allowing(SEE_SENSOR, new NonSecretPredicate());
         }
         
         public static EntitlementManager seeNonSecretConfig() {
-            return allowing(SEE_CONFIG, new Predicate<EntityAndItem<String>>() {
-                @Override
-                public boolean apply(EntityAndItem<String> input) {
-                    if (input == null) return false;
-                    return !Sanitizer.IS_SECRET_PREDICATE.apply(input.getItem());
-                }
-                @Override
-                public String toString() {
-                    return "Predicates.nonSecret";
-                }
-            });
+            return allowing(SEE_CONFIG, new NonSecretPredicate());
         }
     }
     
@@ -399,6 +420,8 @@ public class Entitlements {
      * @since 0.7.0
      * @deprecated since 0.7.0, use {@link #checkEntitled(EntitlementManager, EntitlementClass, Object)};
      * kept briefly because there is some downstream usage*/
+    // Note: @Deprecated annotation only added from v0.10.0.
+    @Deprecated
     public static <T> void requireEntitled(EntitlementManager checker, EntitlementClass<T> permission, T typeArgument) {
         checkEntitled(checker, permission, typeArgument);
     }
@@ -406,10 +429,10 @@ public class Entitlements {
     // ----------------- initialization ----------------
 
     public final static String ENTITLEMENTS_CONFIG_PREFIX = "brooklyn.entitlements";
-    
-    public static ConfigKey<String> GLOBAL_ENTITLEMENT_MANAGER = ConfigKeys.newStringConfigKey(ENTITLEMENTS_CONFIG_PREFIX+".global", 
+
+    public static final ConfigKey<String> GLOBAL_ENTITLEMENT_MANAGER = ConfigKeys.newStringConfigKey(ENTITLEMENTS_CONFIG_PREFIX + ".global",
         "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; "
+        + "short names 'minimal', 'readonly', 'user' 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");
     
@@ -421,13 +444,20 @@ public class Entitlements {
     }
     
     public static EntitlementManager load(@Nullable ManagementContext mgmt, BrooklynProperties brooklynProperties, String type) {
-        if ("root".equalsIgnoreCase(type)) return root();
-        if ("readonly".equalsIgnoreCase(type) || "read_only".equalsIgnoreCase(type)) return readOnly();
-        if ("minimal".equalsIgnoreCase(type)) return minimal();
+        if ("root".equalsIgnoreCase(type)) {
+            return root();
+        } else if ("readonly".equalsIgnoreCase(type) || "read_only".equalsIgnoreCase(type)) {
+            return readOnly();
+        } else if ("minimal".equalsIgnoreCase(type)) {
+            return minimal();
+        } else if ("user".equalsIgnoreCase(type)) {
+            return user();
+        }
         if (Strings.isNonBlank(type)) {
             try {
-                ClassLoader cl = mgmt==null ? null : ((ManagementContextInternal)mgmt).getCatalogClassLoader();
-                if (cl==null) cl = Entitlements.class.getClassLoader();
+                ClassLoader cl = mgmt != null
+                        ? mgmt.getCatalogClassLoader()
+                        : Entitlements.class.getClassLoader();
                 Class<?> clazz = cl.loadClass(DeserializingClassRenamesProvider.findMappedName(type));
                 return (EntitlementManager) instantiate(clazz, ImmutableList.of(
                         new Object[] {mgmt, brooklynProperties},

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/27dacc3e/core/src/main/java/org/apache/brooklyn/core/mgmt/entitlement/PerUserEntitlementManager.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/mgmt/entitlement/PerUserEntitlementManager.java b/core/src/main/java/org/apache/brooklyn/core/mgmt/entitlement/PerUserEntitlementManager.java
index dd0b1ba..5452060 100644
--- a/core/src/main/java/org/apache/brooklyn/core/mgmt/entitlement/PerUserEntitlementManager.java
+++ b/core/src/main/java/org/apache/brooklyn/core/mgmt/entitlement/PerUserEntitlementManager.java
@@ -64,7 +64,7 @@ public class PerUserEntitlementManager implements EntitlementManager {
     public PerUserEntitlementManager(BrooklynProperties properties) {
         this(load(properties, properties.getConfig(DEFAULT_MANAGER)));
         
-        BrooklynProperties users = properties.submap(ConfigPredicates.startingWith(PER_USER_ENTITLEMENTS_CONFIG_PREFIX+"."));
+        BrooklynProperties users = properties.submap(ConfigPredicates.nameStartsWith(PER_USER_ENTITLEMENTS_CONFIG_PREFIX+"."));
         for (Map.Entry<ConfigKey<?>,?> key: users.getAllConfig().entrySet()) {
             if (key.getKey().getName().equals(DEFAULT_MANAGER.getName())) continue;
             String user = Strings.removeFromStart(key.getKey().getName(), PER_USER_ENTITLEMENTS_CONFIG_PREFIX+".");
@@ -85,12 +85,12 @@ public class PerUserEntitlementManager implements EntitlementManager {
 
     @Override
     public <T> boolean isEntitled(EntitlementContext context, EntitlementClass<T> entitlementClass, T entitlementClassArgument) {
-        EntitlementManager entitlementInEffect = null;
+        EntitlementManager entitlementInEffect;
         if (context==null || context.user()==null) {
             // no user means it is running as an internal process, always has root
             entitlementInEffect = Entitlements.root(); 
         } else {
-            if (context!=null) entitlementInEffect = perUserManagers.get(context.user());
+            entitlementInEffect = perUserManagers.get(context.user());
             if (entitlementInEffect==null) entitlementInEffect = defaultManager;
         }
         return entitlementInEffect.isEntitled(context, entitlementClass, entitlementClassArgument);

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/27dacc3e/rest/rest-api/src/main/java/org/apache/brooklyn/rest/api/ScriptApi.java
----------------------------------------------------------------------
diff --git a/rest/rest-api/src/main/java/org/apache/brooklyn/rest/api/ScriptApi.java b/rest/rest-api/src/main/java/org/apache/brooklyn/rest/api/ScriptApi.java
index 72af2c3..a50bf96 100644
--- a/rest/rest-api/src/main/java/org/apache/brooklyn/rest/api/ScriptApi.java
+++ b/rest/rest-api/src/main/java/org/apache/brooklyn/rest/api/ScriptApi.java
@@ -36,10 +36,14 @@ import javax.ws.rs.core.MediaType;
 @Produces(MediaType.APPLICATION_JSON)
 @Consumes(MediaType.APPLICATION_JSON)
 public interface ScriptApi {
-    
+
+    /** @deprecated since 0.10.0. Use constant in ScriptResource instead. */
+    @Deprecated
     public static final String USER_DATA_MAP_SESSION_ATTRIBUTE = "brooklyn.script.groovy.user.data";
+    /** @deprecated since 0.10.0. Use constant in ScriptResource instead. */
+    @Deprecated
     public static final String USER_LAST_VALUE_SESSION_ATTRIBUTE = "brooklyn.script.groovy.user.last";
-    
+
     @POST
     @Path("/groovy")
     @Consumes("application/text")

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/27dacc3e/rest/rest-server/src/test/java/org/apache/brooklyn/rest/entitlement/AbstractRestApiEntitlementsTest.java
----------------------------------------------------------------------
diff --git a/rest/rest-server/src/test/java/org/apache/brooklyn/rest/entitlement/AbstractRestApiEntitlementsTest.java b/rest/rest-server/src/test/java/org/apache/brooklyn/rest/entitlement/AbstractRestApiEntitlementsTest.java
index 7331b39..4a0d568 100644
--- a/rest/rest-server/src/test/java/org/apache/brooklyn/rest/entitlement/AbstractRestApiEntitlementsTest.java
+++ b/rest/rest-server/src/test/java/org/apache/brooklyn/rest/entitlement/AbstractRestApiEntitlementsTest.java
@@ -62,6 +62,7 @@ public abstract class AbstractRestApiEntitlementsTest extends BrooklynRestApiLau
         props.put(PerUserEntitlementManager.PER_USER_ENTITLEMENTS_CONFIG_PREFIX+".myRoot", "root");
         props.put(PerUserEntitlementManager.PER_USER_ENTITLEMENTS_CONFIG_PREFIX+".myReadonly", "readonly");
         props.put(PerUserEntitlementManager.PER_USER_ENTITLEMENTS_CONFIG_PREFIX+".myMinimal", "minimal");
+        props.put(PerUserEntitlementManager.PER_USER_ENTITLEMENTS_CONFIG_PREFIX+".myUser", "user");
         props.put(PerUserEntitlementManager.PER_USER_ENTITLEMENTS_CONFIG_PREFIX+".myCustom", StaticDelegatingEntitlementManager.class.getName());
         
         mgmt = LocalManagementContextForTests.builder(true).useProperties(props).build();
@@ -91,21 +92,47 @@ public abstract class AbstractRestApiEntitlementsTest extends BrooklynRestApiLau
 
     protected String httpGet(String user, String path) throws Exception {
         HttpToolResponse response = HttpTool.httpGet(newClient(user), URI.create(getBaseUriRest()).resolve(path), ImmutableMap.<String, String>of());
-        assertTrue(HttpAsserts.isHealthyStatusCode(response.getResponseCode()), "code="+response.getResponseCode()+"; reason="+response.getReasonPhrase());
+        assertHealthyStatusCode(response);
         return response.getContentAsString();
     }
-    
+
+    protected HttpToolResponse httpPost(String user, String path, byte[] body) throws Exception {
+        final ImmutableMap<String, String> headers = ImmutableMap.of();
+        final URI uri = URI.create(getBaseUriRest()).resolve(path);
+        return HttpTool.httpPost(newClient(user), uri, headers, body);
+    }
+
     protected String assertPermitted(String user, String path) throws Exception {
         return httpGet(user, path);
     }
 
+    public void assertPermittedPost(String user, String path, byte[] body) throws Exception {
+        HttpToolResponse response = httpPost(user, path, body);
+        assertHealthyStatusCode(response);
+    }
+
+    protected void assertHealthyStatusCode(HttpToolResponse response) {
+        assertTrue(HttpAsserts.isHealthyStatusCode(response.getResponseCode()), "code="+response.getResponseCode()+"; reason="+response.getReasonPhrase());
+    }
+
     protected void assertForbidden(String user, String path) throws Exception {
         HttpToolResponse response = HttpTool.httpGet(newClient(user), URI.create(getBaseUriRest()).resolve(path), ImmutableMap.<String, String>of());
-        assertEquals(response.getResponseCode(), 403, "code="+response.getResponseCode()+"; reason="+response.getReasonPhrase()+"; content="+response.getContentAsString());
+        assertStatusCodeEquals(response, 403);
+    }
+
+    public void assertForbiddenPost(String user, String path, byte[] body) throws Exception {
+        HttpToolResponse response = httpPost(user, path, body);
+        assertEquals(response.getResponseCode(), 403, "code=" + response.getResponseCode() + "; reason=" + response.getReasonPhrase());
     }
 
     protected void assert404(String user, String path) throws Exception {
         HttpToolResponse response = HttpTool.httpGet(newClient(user), URI.create(getBaseUriRest()).resolve(path), ImmutableMap.<String, String>of());
-        assertEquals(response.getResponseCode(), 404, "code="+response.getResponseCode()+"; reason="+response.getReasonPhrase()+"; content="+response.getContentAsString());
+        assertStatusCodeEquals(response, 404);
     }
+
+    protected void assertStatusCodeEquals(HttpToolResponse response, int expected) {
+        assertEquals(response.getResponseCode(), expected,
+                "code="+response.getResponseCode()+"; reason="+response.getReasonPhrase()+"; content="+response.getContentAsString());
+    }
+
 }

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/27dacc3e/rest/rest-server/src/test/java/org/apache/brooklyn/rest/entitlement/ActivityApiEntitlementsTest.java
----------------------------------------------------------------------
diff --git a/rest/rest-server/src/test/java/org/apache/brooklyn/rest/entitlement/ActivityApiEntitlementsTest.java b/rest/rest-server/src/test/java/org/apache/brooklyn/rest/entitlement/ActivityApiEntitlementsTest.java
index 2f1cc7b..4a7a0b3 100644
--- a/rest/rest-server/src/test/java/org/apache/brooklyn/rest/entitlement/ActivityApiEntitlementsTest.java
+++ b/rest/rest-server/src/test/java/org/apache/brooklyn/rest/entitlement/ActivityApiEntitlementsTest.java
@@ -76,6 +76,7 @@ public class ActivityApiEntitlementsTest extends AbstractRestApiEntitlementsTest
     public void testGetTask() throws Exception {
         String path = "/v1/activities/"+subTask.getId();
         assertPermitted("myRoot", path);
+        assertPermitted("myUser", path);
         assertPermitted("myReadonly", path);
         assertForbidden("myMinimal", path);
         assertForbidden("unrecognisedUser", path);
@@ -89,6 +90,7 @@ public class ActivityApiEntitlementsTest extends AbstractRestApiEntitlementsTest
             String expectedStream = entry.getValue();
 
             assertEquals(httpGet("myRoot", pathPrefix+streamId), expectedStream);
+            assertEquals(httpGet("myUser", pathPrefix+streamId), expectedStream);
             assertEquals(httpGet("myReadonly", pathPrefix+streamId), expectedStream);
             assertForbidden("myMinimal", pathPrefix+streamId);
             assertForbidden("unrecognisedUser", pathPrefix+streamId);

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/27dacc3e/rest/rest-server/src/test/java/org/apache/brooklyn/rest/entitlement/EntityConfigApiEntitlementsTest.java
----------------------------------------------------------------------
diff --git a/rest/rest-server/src/test/java/org/apache/brooklyn/rest/entitlement/EntityConfigApiEntitlementsTest.java b/rest/rest-server/src/test/java/org/apache/brooklyn/rest/entitlement/EntityConfigApiEntitlementsTest.java
index cbda515..b95392b 100644
--- a/rest/rest-server/src/test/java/org/apache/brooklyn/rest/entitlement/EntityConfigApiEntitlementsTest.java
+++ b/rest/rest-server/src/test/java/org/apache/brooklyn/rest/entitlement/EntityConfigApiEntitlementsTest.java
@@ -50,6 +50,7 @@ public class EntityConfigApiEntitlementsTest extends AbstractRestApiEntitlements
         String val = "\"myname\"";
         
         assertEquals(httpGet("myRoot", path), val);
+        assertEquals(httpGet("myUser", path), val);
         assertEquals(httpGet("myReadonly", path), val);
         assert404("myMinimal", path); // can't see app, to retrieve entity
         assert404("unrecognisedUser", path);
@@ -68,6 +69,7 @@ public class EntityConfigApiEntitlementsTest extends AbstractRestApiEntitlements
         String regex = ".*"+confName+".*myname.*";
         
         Asserts.assertStringMatchesRegex(httpGet("myRoot", path), regex);
+        Asserts.assertStringMatchesRegex(httpGet("myUser", path), regex);
         Asserts.assertStringMatchesRegex(httpGet("myReadonly", path), regex);
         assert404("myMinimal", path); // can't see app, to retrieve entity
         assert404("unrecognisedUser", path);

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/27dacc3e/rest/rest-server/src/test/java/org/apache/brooklyn/rest/entitlement/SensorApiEntitlementsTest.java
----------------------------------------------------------------------
diff --git a/rest/rest-server/src/test/java/org/apache/brooklyn/rest/entitlement/SensorApiEntitlementsTest.java b/rest/rest-server/src/test/java/org/apache/brooklyn/rest/entitlement/SensorApiEntitlementsTest.java
index dab72ec..931b7ae 100644
--- a/rest/rest-server/src/test/java/org/apache/brooklyn/rest/entitlement/SensorApiEntitlementsTest.java
+++ b/rest/rest-server/src/test/java/org/apache/brooklyn/rest/entitlement/SensorApiEntitlementsTest.java
@@ -53,6 +53,7 @@ public class SensorApiEntitlementsTest extends AbstractRestApiEntitlementsTest {
         String val = "\"myval\"";
         
         assertEquals(httpGet("myRoot", path), val);
+        assertEquals(httpGet("myUser", path), val);
         assertEquals(httpGet("myReadonly", path), val);
         assert404("myMinimal", path); // can't see app, to retrieve entity
         assert404("unrecognisedUser", path);
@@ -73,6 +74,7 @@ public class SensorApiEntitlementsTest extends AbstractRestApiEntitlementsTest {
         String regex = ".*"+sensorName+".*myval.*";
         
         Asserts.assertStringMatchesRegex(httpGet("myRoot", path), regex);
+        Asserts.assertStringMatchesRegex(httpGet("myUser", path), regex);
         Asserts.assertStringMatchesRegex(httpGet("myReadonly", path), regex);
         assert404("myMinimal", path); // can't see app, to retrieve entity
         assert404("unrecognisedUser", path);