Repository: ambari Updated Branches: refs/heads/branch-2.1 2acaf832d -> 5cbfb2a63
AMBARI-12476. Widget response differs when using ambarisessionid and basic auth. Project: http://git-wip-us.apache.org/repos/asf/ambari/repo Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/5cbfb2a6 Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/5cbfb2a6 Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/5cbfb2a6 Branch: refs/heads/branch-2.1 Commit: 5cbfb2a6318d96dd1facb4ec081c9a35134a260e Parents: 2acaf83 Author: Siddharth Wagle <swa...@hortonworks.com> Authored: Tue Sep 1 17:03:44 2015 -0700 Committer: Siddharth Wagle <swa...@hortonworks.com> Committed: Tue Sep 1 17:04:19 2015 -0700 ---------------------------------------------------------------------- .../api/services/WidgetLayoutService.java | 31 +++-------- .../server/api/services/WidgetService.java | 30 ++++------- .../internal/WidgetResourceProvider.java | 10 +++- .../apache/ambari/server/orm/dao/WidgetDAO.java | 10 ++++ .../server/orm/entities/WidgetEntity.java | 4 ++ .../internal/WidgetResourceProviderTest.java | 57 +++++++++++++++++--- 6 files changed, 90 insertions(+), 52 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/ambari/blob/5cbfb2a6/ambari-server/src/main/java/org/apache/ambari/server/api/services/WidgetLayoutService.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/WidgetLayoutService.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/WidgetLayoutService.java index fad83cb..7571396 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/api/services/WidgetLayoutService.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/api/services/WidgetLayoutService.java @@ -49,7 +49,7 @@ public class WidgetLayoutService extends BaseService { @PathParam("widgetLayoutId") String widgetLayoutId) { return handleRequest(headers, body, ui, Request.Type.GET, - createResource(getUserName(headers), widgetLayoutId)); + createResource(widgetLayoutId)); } /** @@ -64,9 +64,8 @@ public class WidgetLayoutService extends BaseService { @GET @Produces("text/plain") public Response getServices(String body, @Context HttpHeaders headers, @Context UriInfo ui) { - return handleRequest(headers, body, ui, Request.Type.GET, - createResource(getUserName(headers), null)); + createResource(null)); } @POST @@ -75,7 +74,7 @@ public class WidgetLayoutService extends BaseService { public Response createService(String body, @Context HttpHeaders headers, @Context UriInfo ui, @PathParam("widgetLayoutId") String widgetLayoutId) { return handleRequest(headers, body, ui, Request.Type.POST, - createResource(getUserName(headers), widgetLayoutId)); + createResource(widgetLayoutId)); } @POST @@ -83,7 +82,7 @@ public class WidgetLayoutService extends BaseService { public Response createServices(String body, @Context HttpHeaders headers, @Context UriInfo ui) { return handleRequest(headers, body, ui, Request.Type.POST, - createResource(getUserName(headers), null)); + createResource(null)); } @PUT @@ -92,14 +91,14 @@ public class WidgetLayoutService extends BaseService { public Response updateService(String body, @Context HttpHeaders headers, @Context UriInfo ui, @PathParam("widgetLayoutId") String widgetLayoutId) { - return handleRequest(headers, body, ui, Request.Type.PUT, createResource(getUserName(headers), widgetLayoutId)); + return handleRequest(headers, body, ui, Request.Type.PUT, createResource(widgetLayoutId)); } @PUT @Produces("text/plain") public Response updateServices(String body, @Context HttpHeaders headers, @Context UriInfo ui) { - return handleRequest(headers, body, ui, Request.Type.PUT, createResource(getUserName(headers), null)); + return handleRequest(headers, body, ui, Request.Type.PUT, createResource(null)); } @DELETE @@ -108,27 +107,13 @@ public class WidgetLayoutService extends BaseService { public Response deleteService(@Context HttpHeaders headers, @Context UriInfo ui, @PathParam("widgetLayoutId") String widgetLayoutId) { - return handleRequest(headers, null, ui, Request.Type.DELETE, createResource(getUserName(headers), widgetLayoutId)); + return handleRequest(headers, null, ui, Request.Type.DELETE, createResource(widgetLayoutId)); } - private ResourceInstance createResource(String userName, String widgetLayoutId) { + private ResourceInstance createResource(String widgetLayoutId) { Map<Resource.Type,String> mapIds = new HashMap<Resource.Type, String>(); - mapIds.put(Resource.Type.User, userName); mapIds.put(Resource.Type.WidgetLayout, widgetLayoutId); mapIds.put(Resource.Type.Cluster, clusterName); return createResource(Resource.Type.WidgetLayout, mapIds); } - - private String getUserName(HttpHeaders headers) { - List<String> authorizationHeaders = headers.getRequestHeaders().get("Authorization"); - if (authorizationHeaders != null && !authorizationHeaders.isEmpty()){ - String authorizationString = authorizationHeaders.get(0); - if (authorizationString != null && authorizationString.startsWith("Basic")) { - String base64Credentials = authorizationString.substring("Basic".length()).trim(); - String clearCredentials = new String(Base64.decode(base64Credentials),Charset.forName("UTF-8")); - return clearCredentials.split(":", 2)[0]; - } - } - return null; - } } http://git-wip-us.apache.org/repos/asf/ambari/blob/5cbfb2a6/ambari-server/src/main/java/org/apache/ambari/server/api/services/WidgetService.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/WidgetService.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/WidgetService.java index 07dae40..e6907db 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/api/services/WidgetService.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/api/services/WidgetService.java @@ -20,6 +20,7 @@ package org.apache.ambari.server.api.services; import com.sun.jersey.core.util.Base64; import org.apache.ambari.server.api.resources.ResourceInstance; import org.apache.ambari.server.controller.spi.Resource; +import org.apache.ambari.server.security.authorization.AuthorizationHelper; import javax.ws.rs.*; import javax.ws.rs.core.Context; @@ -49,7 +50,7 @@ public class WidgetService extends BaseService { @PathParam("widgetId") String widgetId) { return handleRequest(headers, body, ui, Request.Type.GET, - createResource(getUserName(headers), widgetId)); + createResource(widgetId)); } /** @@ -66,7 +67,7 @@ public class WidgetService extends BaseService { public Response getServices(String body, @Context HttpHeaders headers, @Context UriInfo ui) { return handleRequest(headers, body, ui, Request.Type.GET, - createResource(getUserName(headers), null)); + createResource(null)); } @POST @@ -75,7 +76,7 @@ public class WidgetService extends BaseService { public Response createService(String body, @Context HttpHeaders headers, @Context UriInfo ui, @PathParam("widgetId") String widgetId) { return handleRequest(headers, body, ui, Request.Type.POST, - createResource(getUserName(headers), widgetId)); + createResource(widgetId)); } @POST @@ -83,7 +84,7 @@ public class WidgetService extends BaseService { public Response createServices(String body, @Context HttpHeaders headers, @Context UriInfo ui) { return handleRequest(headers, body, ui, Request.Type.POST, - createResource(getUserName(headers), null)); + createResource(null)); } @PUT @@ -92,14 +93,14 @@ public class WidgetService extends BaseService { public Response updateService(String body, @Context HttpHeaders headers, @Context UriInfo ui, @PathParam("widgetId") String widgetId) { - return handleRequest(headers, body, ui, Request.Type.PUT, createResource(getUserName(headers), widgetId)); + return handleRequest(headers, body, ui, Request.Type.PUT, createResource(widgetId)); } @PUT @Produces("text/plain") public Response updateServices(String body, @Context HttpHeaders headers, @Context UriInfo ui) { - return handleRequest(headers, body, ui, Request.Type.PUT, createResource(getUserName(headers), null)); + return handleRequest(headers, body, ui, Request.Type.PUT, createResource(null)); } @DELETE @@ -108,27 +109,14 @@ public class WidgetService extends BaseService { public Response deleteService(@Context HttpHeaders headers, @Context UriInfo ui, @PathParam("widgetId") String widgetId) { - return handleRequest(headers, null, ui, Request.Type.DELETE, createResource(getUserName(headers), widgetId)); + return handleRequest(headers, null, ui, Request.Type.DELETE, createResource(widgetId)); } - private ResourceInstance createResource(String userName, String widgetId) { + private ResourceInstance createResource(String widgetId) { Map<Resource.Type,String> mapIds = new HashMap<Resource.Type, String>(); mapIds.put(Resource.Type.Cluster, clusterName); mapIds.put(Resource.Type.Widget, widgetId); - mapIds.put(Resource.Type.User, userName); return createResource(Resource.Type.Widget, mapIds); } - private String getUserName(HttpHeaders headers) { - List<String> authorizationHeaders = headers.getRequestHeaders().get("Authorization"); - if (authorizationHeaders != null && !authorizationHeaders.isEmpty()) { - String authorizationString = authorizationHeaders.get(0); - if (authorizationString != null && authorizationString.startsWith("Basic")) { - String base64Credentials = authorizationString.substring("Basic".length()).trim(); - String clearCredentials = new String(Base64.decode(base64Credentials), Charset.forName("UTF-8")); - return clearCredentials.split(":", 2)[0]; - } - } - return null; - } } http://git-wip-us.apache.org/repos/asf/ambari/blob/5cbfb2a6/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/WidgetResourceProvider.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/WidgetResourceProvider.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/WidgetResourceProvider.java index 897d7e8..5fc20fb 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/WidgetResourceProvider.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/WidgetResourceProvider.java @@ -39,8 +39,10 @@ import org.apache.ambari.server.orm.entities.PermissionEntity; import org.apache.ambari.server.orm.entities.WidgetEntity; import org.apache.ambari.server.orm.entities.WidgetLayoutUserWidgetEntity; import org.apache.ambari.server.security.authorization.AmbariGrantedAuthority; +import org.apache.ambari.server.security.authorization.AuthorizationHelper; import org.apache.commons.lang.ObjectUtils; import org.apache.commons.lang.StringUtils; +import org.springframework.security.access.AccessDeniedException; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.context.SecurityContext; import org.springframework.security.core.context.SecurityContextHolder; @@ -153,7 +155,7 @@ public class WidgetResourceProvider extends AbstractControllerResourceProvider { String scope = properties.get(WIDGET_SCOPE_PROPERTY_ID).toString(); if (!isScopeAllowedForUser(scope)) { - throw new AmbariException("Only cluster operator can create widgets with cluster scope"); + throw new AccessDeniedException("Only cluster operator can create widgets with cluster scope"); } entity.setWidgetName(properties.get(WIDGET_WIDGET_NAME_PROPERTY_ID).toString()); @@ -206,6 +208,7 @@ public class WidgetResourceProvider extends AbstractControllerResourceProvider { final Set<Resource> resources = new HashSet<Resource>(); final Set<String> requestedIds = getRequestPropertyIds(request, predicate); final Set<Map<String, Object>> propertyMaps = getPropertyMaps(predicate); + String author = AuthorizationHelper.getAuthenticatedName(); List<WidgetEntity> requestedEntities = new ArrayList<WidgetEntity>(); @@ -221,9 +224,12 @@ public class WidgetResourceProvider extends AbstractControllerResourceProvider { if (entity == null) { throw new NoSuchResourceException("WidgetLayout with id " + id + " does not exists"); } + if (!(entity.getAuthor().equals(author) || entity.getScope().equals(SCOPE.CLUSTER.name()))) { + throw new AccessDeniedException("User must be author of the widget or widget must have cluster scope"); + } requestedEntities.add(entity); } else { - requestedEntities.addAll(widgetDAO.findAll()); + requestedEntities.addAll(widgetDAO.findByScopeOrAuthor(author, SCOPE.CLUSTER.name())); } } http://git-wip-us.apache.org/repos/asf/ambari/blob/5cbfb2a6/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/WidgetDAO.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/WidgetDAO.java b/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/WidgetDAO.java index 93fd7c2..7c38316 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/WidgetDAO.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/WidgetDAO.java @@ -75,6 +75,16 @@ public class WidgetDAO { } @RequiresSession + public List<WidgetEntity> findByScopeOrAuthor(String author, String scope) { + TypedQuery<WidgetEntity> query = entityManagerProvider.get() + .createNamedQuery("WidgetEntity.findByScopeOrAuthor", WidgetEntity.class); + query.setParameter("author", author); + query.setParameter("scope", scope); + + return daoUtils.selectList(query); + } + + @RequiresSession public List<WidgetEntity> findAll() { TypedQuery<WidgetEntity> query = entityManagerProvider.get() .createNamedQuery("WidgetEntity.findAll", WidgetEntity.class); http://git-wip-us.apache.org/repos/asf/ambari/blob/5cbfb2a6/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/WidgetEntity.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/WidgetEntity.java b/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/WidgetEntity.java index 8710e5d..40eb7e1 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/WidgetEntity.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/WidgetEntity.java @@ -46,6 +46,10 @@ import java.util.List; ) @NamedQueries({ @NamedQuery(name = "WidgetEntity.findAll", query = "SELECT widget FROM WidgetEntity widget"), + @NamedQuery(name = "WidgetEntity.findByScopeOrAuthor", query = + "SELECT widget FROM WidgetEntity widget " + + "WHERE widget.author = :author " + + "OR widget.scope = :scope"), @NamedQuery(name = "WidgetEntity.findByCluster", query = "SELECT widget FROM WidgetEntity widget WHERE widget.clusterId = :clusterId"), @NamedQuery(name = "WidgetEntity.findByName", query = "SELECT widget FROM WidgetEntity widget " + http://git-wip-us.apache.org/repos/asf/ambari/blob/5cbfb2a6/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/WidgetResourceProviderTest.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/WidgetResourceProviderTest.java b/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/WidgetResourceProviderTest.java index 244049c..dff0a62 100644 --- a/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/WidgetResourceProviderTest.java +++ b/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/WidgetResourceProviderTest.java @@ -27,7 +27,6 @@ import org.apache.ambari.server.controller.AmbariManagementController; import org.apache.ambari.server.controller.spi.Predicate; import org.apache.ambari.server.controller.spi.Request; import org.apache.ambari.server.controller.spi.Resource; -import org.apache.ambari.server.controller.spi.SystemException; import org.apache.ambari.server.controller.utilities.PredicateBuilder; import org.apache.ambari.server.controller.utilities.PropertyHelper; import org.apache.ambari.server.orm.InMemoryDefaultTestModule; @@ -45,6 +44,7 @@ import org.powermock.api.easymock.PowerMock; import org.powermock.core.classloader.annotations.PowerMockIgnore; import org.powermock.core.classloader.annotations.PrepareForTest; import org.powermock.modules.junit4.PowerMockRunner; +import org.springframework.security.access.AccessDeniedException; import org.springframework.security.core.context.SecurityContextHolder; import java.util.Arrays; @@ -129,7 +129,7 @@ public class WidgetResourceProviderTest { .and().property(WidgetResourceProvider.WIDGET_ID_PROPERTY_ID).equals("1") .and().property(WidgetResourceProvider.WIDGET_AUTHOR_PROPERTY_ID).equals("username").toPredicate(); - expect(dao.findById(1L)).andReturn(getMockEntities().get(0)); + expect(dao.findById(1L)).andReturn(getMockEntities("CLUSTER").get(0)); replay(amc, clusters, cluster, dao); @@ -140,7 +140,7 @@ public class WidgetResourceProviderTest { Resource r = results.iterator().next(); Assert.assertEquals("GAUGE", r.getPropertyValue(WidgetResourceProvider.WIDGET_WIDGET_TYPE_PROPERTY_ID)); - Assert.assertEquals("USER", r.getPropertyValue(WidgetResourceProvider.WIDGET_SCOPE_PROPERTY_ID)); + Assert.assertEquals("CLUSTER", r.getPropertyValue(WidgetResourceProvider.WIDGET_SCOPE_PROPERTY_ID)); Assert.assertEquals("username", r.getPropertyValue(WidgetResourceProvider.WIDGET_AUTHOR_PROPERTY_ID)); Assert.assertEquals("widget name", r.getPropertyValue(WidgetResourceProvider.WIDGET_WIDGET_NAME_PROPERTY_ID)); Object metrics = r.getPropertyValue(WidgetResourceProvider.WIDGET_METRICS_PROPERTY_ID); @@ -160,6 +160,51 @@ public class WidgetResourceProviderTest { Assert.assertEquals("{\"name\":\"value\"}", r.getPropertyValue(WidgetResourceProvider.WIDGET_PROPERTIES_PROPERTY_ID)); } + /** + * @throws Exception + */ + @Test + public void testGetResourceOfOtherUser() throws Exception { + Request request = PropertyHelper.getReadRequest( + WidgetResourceProvider.WIDGET_ID_PROPERTY_ID, + WidgetResourceProvider.WIDGET_WIDGET_NAME_PROPERTY_ID, + WidgetResourceProvider.WIDGET_WIDGET_TYPE_PROPERTY_ID, + WidgetResourceProvider.WIDGET_TIME_CREATED_PROPERTY_ID, + WidgetResourceProvider.WIDGET_CLUSTER_NAME_PROPERTY_ID, + WidgetResourceProvider.WIDGET_AUTHOR_PROPERTY_ID, + WidgetResourceProvider.WIDGET_DESCRIPTION_PROPERTY_ID, + WidgetResourceProvider.WIDGET_SCOPE_PROPERTY_ID, + WidgetResourceProvider.WIDGET_METRICS_PROPERTY_ID, + WidgetResourceProvider.WIDGET_VALUES_PROPERTY_ID, + WidgetResourceProvider.WIDGET_PROPERTIES_PROPERTY_ID); + + AmbariManagementController amc = createMock(AmbariManagementController.class); + Clusters clusters = createMock(Clusters.class); + Cluster cluster = createMock(Cluster.class); + expect(amc.getClusters()).andReturn(clusters).atLeastOnce(); + expect(clusters.getClusterById(1L)).andReturn(cluster).atLeastOnce(); + expect(cluster.getClusterName()).andReturn("c1").anyTimes(); + + Predicate predicate = new PredicateBuilder().property( + WidgetResourceProvider.WIDGET_CLUSTER_NAME_PROPERTY_ID).equals("c1") + .and().property(WidgetResourceProvider.WIDGET_ID_PROPERTY_ID).equals("1") + .and().property(WidgetResourceProvider.WIDGET_AUTHOR_PROPERTY_ID).equals("username").toPredicate(); + + expect(dao.findById(1L)).andReturn(getMockEntities("USER").get(0)); + + replay(amc, clusters, cluster, dao); + + WidgetResourceProvider provider = createProvider(amc); + + try { + Set<Resource> results = provider.getResources(request, predicate); + } catch (AccessDeniedException ex) { + //Expected exception + Assert.assertEquals("User must be author of the widget or widget must have cluster scope", ex.getMessage()); + } + + } + /** * @throws Exception @@ -408,7 +453,7 @@ public class WidgetResourceProviderTest { try { widgetResourceProvider.createResources(request); - } catch (SystemException ex) { + } catch (AccessDeniedException ex) { //Expected exception } @@ -425,14 +470,14 @@ public class WidgetResourceProviderTest { /** * @return */ - private List<WidgetEntity> getMockEntities() throws Exception { + private List<WidgetEntity> getMockEntities(String scope) throws Exception { WidgetEntity widgetEntity = new WidgetEntity(); widgetEntity.setClusterId(Long.valueOf(1L)); widgetEntity.setWidgetName("widget name"); widgetEntity.setWidgetType("GAUGE"); widgetEntity.setAuthor("username"); - widgetEntity.setScope("USER"); + widgetEntity.setScope(scope); widgetEntity.setDefaultSectionName("default_section_name"); widgetEntity.setDescription("Description"); widgetEntity.setMetrics("[{\"widget_id\":\"metrics/jvm/HeapMemoryUsed\"," +