You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ambari.apache.org by sw...@apache.org on 2014/09/27 02:28:37 UTC
[2/3] git commit: AMBARI-7530. Admin: /users and /groups resources
should only be accessible from AMBARI.ADMIN.
AMBARI-7530. Admin: /users and /groups resources should only be accessible from AMBARI.ADMIN.
Project: http://git-wip-us.apache.org/repos/asf/ambari/repo
Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/f92ad8f5
Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/f92ad8f5
Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/f92ad8f5
Branch: refs/heads/trunk
Commit: f92ad8f520b230feaf6c0bc7d8c7248448566e0b
Parents: 1ea0f47
Author: Siddharth Wagle <sw...@hortonworks.com>
Authored: Fri Sep 26 17:15:55 2014 -0700
Committer: Siddharth Wagle <sw...@hortonworks.com>
Committed: Fri Sep 26 17:15:55 2014 -0700
----------------------------------------------------------------------
.../server/orm/entities/ViewInstanceEntity.java | 34 +--
.../AmbariAuthorizationFilter.java | 81 +++++-
.../server/security/authorization/Users.java | 3 +-
.../orm/entities/ViewInstanceEntityTest.java | 19 +-
.../AmbariAuthorizationFilterTest.java | 266 ++++++++++++++++++-
.../security/authorization/TestUsers.java | 1 +
6 files changed, 335 insertions(+), 69 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/ambari/blob/f92ad8f5/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/ViewInstanceEntity.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/ViewInstanceEntity.java b/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/ViewInstanceEntity.java
index f84be60..8f8712c 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/ViewInstanceEntity.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/ViewInstanceEntity.java
@@ -23,9 +23,6 @@ import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
import javax.persistence.Basic;
import javax.persistence.CascadeType;
import javax.persistence.Column;
@@ -47,6 +44,7 @@ import javax.persistence.UniqueConstraint;
import org.apache.ambari.server.controller.spi.Resource;
import org.apache.ambari.server.security.SecurityHelper;
import org.apache.ambari.server.security.SecurityHelperImpl;
+import org.apache.ambari.server.security.authorization.AmbariAuthorizationFilter;
import org.apache.ambari.server.view.configuration.InstanceConfig;
import org.apache.ambari.view.ResourceProvider;
import org.apache.ambari.view.ViewDefinition;
@@ -70,15 +68,6 @@ import org.apache.ambari.view.ViewInstanceDefinition;
)
@Entity
public class ViewInstanceEntity implements ViewInstanceDefinition {
- /**
- * The prefix for every view instance context path.
- */
- public static final String VIEWS_CONTEXT_PATH_PREFIX = "/views/";
-
- /**
- * The pattern for matching view instance context path.
- */
- public static final String VIEWS_CONTEXT_PATH_PATTERN = "" + VIEWS_CONTEXT_PATH_PREFIX + "([^/]+)/([^/]+)/([^/]+)(.*)";
@Id
@Column(name = "view_instance_id", nullable = false)
@@ -680,26 +669,7 @@ public class ViewInstanceEntity implements ViewInstanceDefinition {
* @return the context path
*/
public static String getContextPath(String viewName, String version, String viewInstanceName) {
- return VIEWS_CONTEXT_PATH_PREFIX + viewName + "/" + version + "/" + viewInstanceName;
- }
-
- /**
- * Parses context path into view name, version and instance name
- *
- * @param contextPath the context path
- * @return null if context path doesn't match correct pattern
- */
- public static ViewInstanceVersionDTO parseContextPath(String contextPath) {
- final Pattern pattern = Pattern.compile(VIEWS_CONTEXT_PATH_PATTERN);
- Matcher matcher = pattern.matcher(contextPath);
- if (!matcher.matches()) {
- return null;
- } else {
- final String viewName = matcher.group(1);
- final String version = matcher.group(2);
- final String instanceName = matcher.group(3);
- return new ViewInstanceVersionDTO(viewName, version, instanceName);
- }
+ return AmbariAuthorizationFilter.VIEWS_CONTEXT_PATH_PREFIX + viewName + "/" + version + "/" + viewInstanceName;
}
/**
http://git-wip-us.apache.org/repos/asf/ambari/blob/f92ad8f5/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/AmbariAuthorizationFilter.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/AmbariAuthorizationFilter.java b/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/AmbariAuthorizationFilter.java
index 658fc80..f1c2a26 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/AmbariAuthorizationFilter.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/AmbariAuthorizationFilter.java
@@ -32,7 +32,6 @@ import javax.servlet.http.HttpServletResponse;
import org.apache.ambari.server.orm.entities.PermissionEntity;
import org.apache.ambari.server.orm.entities.PrivilegeEntity;
-import org.apache.ambari.server.orm.entities.ViewInstanceEntity;
import org.apache.ambari.server.orm.entities.ViewInstanceEntity.ViewInstanceVersionDTO;
import org.apache.ambari.server.security.authorization.internal.InternalAuthenticationToken;
import org.apache.ambari.server.view.ViewRegistry;
@@ -50,6 +49,19 @@ public class AmbariAuthorizationFilter implements Filter {
private static final Pattern STACK_ADVISOR_REGEX = Pattern.compile("/api/v[0-9]+/stacks/[^/]+/versions/[^/]+/validations.*");
+ public static final String API_VERSION_PREFIX = "/api/v[0-9]+";
+ public static final String VIEWS_CONTEXT_PATH_PREFIX = "/views/";
+
+ private static final String VIEWS_CONTEXT_PATH_PATTERN = VIEWS_CONTEXT_PATH_PREFIX + "([^/]+)/([^/]+)/([^/]+)(.*)";
+ private static final String VIEWS_CONTEXT_ALL_PATTERN = VIEWS_CONTEXT_PATH_PREFIX + ".*";
+ private static final String API_USERS_USERNAME_PATTERN = API_VERSION_PREFIX + "/users/([^/?]+)(.*)";
+ private static final String API_USERS_ALL_PATTERN = API_VERSION_PREFIX + "/users.*";
+ private static final String API_GROUPS_ALL_PATTERN = API_VERSION_PREFIX + "/groups.*";
+ private static final String API_CLUSTERS_ALL_PATTERN = API_VERSION_PREFIX + "/clusters.*";
+ private static final String API_VIEWS_ALL_PATTERN = API_VERSION_PREFIX + "/views.*";
+ private static final String API_PERSIST_ALL_PATTERN = API_VERSION_PREFIX + "/persist.*";
+ private static final String API_LDAP_SYNC_EVENTS_ALL_PATTERN = API_VERSION_PREFIX + "/ldap_sync_events.*";
+
/**
* The realm to use for the basic http auth
*/
@@ -92,8 +104,8 @@ public class AmbariAuthorizationFilter implements Filter {
break;
}
- if (requestURI.matches("/api/v[0-9]+/clusters.*")) {
// clusters require permission
+ if (requestURI.matches(API_CLUSTERS_ALL_PATTERN)) {
if (permissionId.equals(PermissionEntity.CLUSTER_READ_PERMISSION) ||
permissionId.equals(PermissionEntity.CLUSTER_OPERATE_PERMISSION)) {
authorized = true;
@@ -105,13 +117,13 @@ public class AmbariAuthorizationFilter implements Filter {
authorized = true;
break;
}
- } else if (requestURI.matches("/api/v[0-9]+/views.*")) {
+ } else if (requestURI.matches(API_VIEWS_ALL_PATTERN)) {
// views require permission
if (permissionId.equals(PermissionEntity.VIEW_USE_PERMISSION)) {
authorized = true;
break;
}
- } else if (requestURI.matches("/api/v[0-9]+/persist.*")) {
+ } else if (requestURI.matches(API_PERSIST_ALL_PATTERN)) {
if (permissionId.equals(PermissionEntity.CLUSTER_OPERATE_PERMISSION)) {
authorized = true;
break;
@@ -120,14 +132,26 @@ public class AmbariAuthorizationFilter implements Filter {
}
}
- if (!authorized && requestURI.matches(ViewInstanceEntity.VIEWS_CONTEXT_PATH_PATTERN)) {
- final ViewInstanceVersionDTO dto = ViewInstanceEntity.parseContextPath(requestURI);
- authorized = ViewRegistry.getInstance().checkPermission(dto.getViewName(), dto.getVersion(), dto.getInstanceName(), true);
+ if (!authorized && requestURI.matches(VIEWS_CONTEXT_PATH_PATTERN)) {
+ final ViewInstanceVersionDTO dto = parseViewInstanceInfo(requestURI);
+ authorized = getViewRegistry().checkPermission(dto.getViewName(), dto.getVersion(), dto.getInstanceName(), true);
}
- // allow GET for everything except views
+ // allow all types of requests for /users/{current_user}
+ if (!authorized && requestURI.matches(API_USERS_USERNAME_PATTERN)) {
+ final SecurityContext securityContext = getSecurityContext();
+ final String currentUserName = securityContext.getAuthentication().getName();
+ final String urlUserName = parseUserName(requestURI);
+ authorized = currentUserName.equalsIgnoreCase(urlUserName);
+ }
+
+ // allow GET for everything except /views, /api/v1/users, /api/v1/groups, /api/v1/ldap_sync_events
if (!authorized &&
- (!httpRequest.getMethod().equals("GET") || requestURI.matches("/views.*"))) {
+ (!httpRequest.getMethod().equals("GET")
+ || requestURI.matches(VIEWS_CONTEXT_ALL_PATTERN)
+ || requestURI.matches(API_USERS_ALL_PATTERN)
+ || requestURI.matches(API_GROUPS_ALL_PATTERN)
+ || requestURI.matches(API_LDAP_SYNC_EVENTS_ALL_PATTERN))) {
httpResponse.setHeader("WWW-Authenticate", "Basic realm=\"" + realm + "\"");
httpResponse.sendError(HttpServletResponse.SC_FORBIDDEN, "You do not have permissions to access this resource.");
@@ -166,7 +190,46 @@ public class AmbariAuthorizationFilter implements Filter {
return value == null || value.length() == 0 ? defaultValue : value;
}
+ /**
+ * Parses context path into view name, version and instance name
+ *
+ * @param contextPath the context path
+ * @return null if context path doesn't match correct pattern
+ */
+ static ViewInstanceVersionDTO parseViewInstanceInfo(String contextPath) {
+ final Pattern pattern = Pattern.compile(VIEWS_CONTEXT_PATH_PATTERN);
+ final Matcher matcher = pattern.matcher(contextPath);
+ if (!matcher.matches()) {
+ return null;
+ } else {
+ final String viewName = matcher.group(1);
+ final String version = matcher.group(2);
+ final String instanceName = matcher.group(3);
+ return new ViewInstanceVersionDTO(viewName, version, instanceName);
+ }
+ }
+
+ /**
+ * Parses url to get user name.
+ *
+ * @param url the url
+ * @return null if url doesn't match correct pattern
+ */
+ static String parseUserName(String url) {
+ final Pattern pattern = Pattern.compile(API_USERS_USERNAME_PATTERN);
+ final Matcher matcher = pattern.matcher(url);
+ if (!matcher.matches()) {
+ return null;
+ } else {
+ return matcher.group(1);
+ }
+ }
+
SecurityContext getSecurityContext() {
return SecurityContextHolder.getContext();
}
+
+ ViewRegistry getViewRegistry() {
+ return ViewRegistry.getInstance();
+ }
}
http://git-wip-us.apache.org/repos/asf/ambari/blob/f92ad8f5/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/Users.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/Users.java b/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/Users.java
index 26daa1b..1cd3fc8 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/Users.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/Users.java
@@ -24,7 +24,6 @@ import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
-
import javax.persistence.EntityManager;
import org.apache.ambari.server.AmbariException;
@@ -66,7 +65,7 @@ import com.google.inject.persist.Transactional;
@Singleton
public class Users {
- private final static Logger LOG = LoggerFactory.getLogger(Users.class);
+ private static final Logger LOG = LoggerFactory.getLogger(Users.class);
@Inject
Provider<EntityManager> entityManagerProvider;
http://git-wip-us.apache.org/repos/asf/ambari/blob/f92ad8f5/ambari-server/src/test/java/org/apache/ambari/server/orm/entities/ViewInstanceEntityTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/orm/entities/ViewInstanceEntityTest.java b/ambari-server/src/test/java/org/apache/ambari/server/orm/entities/ViewInstanceEntityTest.java
index c0545da..08aea6e 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/orm/entities/ViewInstanceEntityTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/orm/entities/ViewInstanceEntityTest.java
@@ -20,8 +20,8 @@ package org.apache.ambari.server.orm.entities;
import org.apache.ambari.server.configuration.Configuration;
import org.apache.ambari.server.controller.spi.Resource;
-import org.apache.ambari.server.orm.entities.ViewInstanceEntity.ViewInstanceVersionDTO;
import org.apache.ambari.server.security.SecurityHelper;
+import org.apache.ambari.server.security.authorization.AmbariAuthorizationFilter;
import org.apache.ambari.server.view.ViewRegistryTest;
import org.apache.ambari.server.view.configuration.InstanceConfig;
import org.apache.ambari.server.view.configuration.InstanceConfigTest;
@@ -295,26 +295,11 @@ public class ViewInstanceEntityTest {
public void testContextPath() throws Exception {
ViewInstanceEntity viewInstanceDefinition = getViewInstanceEntity();
- Assert.assertEquals(ViewInstanceEntity.VIEWS_CONTEXT_PATH_PREFIX + "MY_VIEW/1.0.0/INSTANCE1",
+ Assert.assertEquals(AmbariAuthorizationFilter.VIEWS_CONTEXT_PATH_PREFIX + "MY_VIEW/1.0.0/INSTANCE1",
viewInstanceDefinition.getContextPath());
}
@Test
- public void testParseContextPath() throws Exception {
- final String[] pathesToTest = {
- ViewInstanceEntity.VIEWS_CONTEXT_PATH_PREFIX + "MY_VIEW/1.0.0/INSTANCE1",
- ViewInstanceEntity.VIEWS_CONTEXT_PATH_PREFIX + "MY_VIEW/1.0.0/INSTANCE1/index.html",
- ViewInstanceEntity.VIEWS_CONTEXT_PATH_PREFIX + "MY_VIEW/1.0.0/INSTANCE1/api/test"
- };
- for (String contextPath: pathesToTest) {
- final ViewInstanceVersionDTO dto = ViewInstanceEntity.parseContextPath(contextPath);
- Assert.assertEquals("INSTANCE1", dto.getInstanceName());
- Assert.assertEquals("MY_VIEW", dto.getViewName());
- Assert.assertEquals("1.0.0", dto.getVersion());
- }
- }
-
- @Test
public void testInstanceData() throws Exception {
TestSecurityHelper securityHelper = new TestSecurityHelper("user1");
http://git-wip-us.apache.org/repos/asf/ambari/blob/f92ad8f5/ambari-server/src/test/java/org/apache/ambari/server/security/authorization/AmbariAuthorizationFilterTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/security/authorization/AmbariAuthorizationFilterTest.java b/ambari-server/src/test/java/org/apache/ambari/server/security/authorization/AmbariAuthorizationFilterTest.java
index a950eb6..116b6ec 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/security/authorization/AmbariAuthorizationFilterTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/security/authorization/AmbariAuthorizationFilterTest.java
@@ -18,23 +18,40 @@
package org.apache.ambari.server.security.authorization;
+import static org.easymock.EasyMock.createMockBuilder;
+import static org.easymock.EasyMock.createNiceMock;
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.replay;
+import static org.easymock.EasyMock.verify;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+
+import javax.servlet.FilterChain;
+import javax.servlet.FilterConfig;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import junit.framework.Assert;
+
import org.apache.ambari.server.orm.entities.PermissionEntity;
import org.apache.ambari.server.orm.entities.PrivilegeEntity;
+import org.apache.ambari.server.orm.entities.ViewInstanceEntity.ViewInstanceVersionDTO;
+import org.apache.ambari.server.view.ViewRegistry;
import org.easymock.EasyMock;
-import org.junit.BeforeClass;
+import org.easymock.IAnswer;
import org.junit.Test;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.context.SecurityContext;
-import javax.servlet.FilterChain;
-import javax.servlet.FilterConfig;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-import java.util.Collection;
-import java.util.Collections;
-
-import static org.easymock.EasyMock.*;
+import com.google.common.collect.HashBasedTable;
+import com.google.common.collect.Table;
+import com.google.common.collect.Table.Cell;
public class AmbariAuthorizationFilterTest {
@@ -121,4 +138,235 @@ public class AmbariAuthorizationFilterTest {
verify(request, response, chain, filter, securityContext, authentication, authority,
privilegeEntity, permission, filterConfig);
}
+
+ @Test
+ public void testDoFilter_adminAccess() throws Exception {
+ final Table<String, String, Boolean> urlTests = HashBasedTable.create();
+ urlTests.put("/api/v1/clusters/cluster", "GET", true);
+ urlTests.put("/api/v1/clusters/cluster", "POST", true);
+ urlTests.put("/api/v1/views", "GET", true);
+ urlTests.put("/api/v1/views", "POST", true);
+ urlTests.put("/api/v1/persist/SomeValue", "GET", true);
+ urlTests.put("/api/v1/persist/SomeValue", "POST", true);
+ urlTests.put("/views/AllowedView/SomeVersion/SomeInstance", "GET", true);
+ urlTests.put("/views/AllowedView/SomeVersion/SomeInstance", "POST", true);
+ urlTests.put("/views/DeniedView/AnotherVersion/AnotherInstance", "GET", true);
+ urlTests.put("/views/DeniedView/AnotherVersion/AnotherInstance", "POST", true);
+ urlTests.put("/api/v1/users/user1", "GET", true);
+ urlTests.put("/api/v1/users/user1", "POST", true);
+ urlTests.put("/api/v1/users/user2", "GET", true);
+ urlTests.put("/api/v1/users/user2", "POST", true);
+ urlTests.put("/api/v1/groups", "GET", true);
+ urlTests.put("/api/v1/ldap_sync_events", "GET", true);
+ urlTests.put("/any/other/URL", "GET", true);
+ urlTests.put("/any/other/URL", "POST", true);
+
+ performGeneralDoFilterTest("admin", new int[] {PermissionEntity.AMBARI_ADMIN_PERMISSION}, urlTests);
+ }
+
+ @Test
+ public void testDoFilter_clusterViewerAccess() throws Exception {
+ final Table<String, String, Boolean> urlTests = HashBasedTable.create();
+ urlTests.put("/api/v1/clusters/cluster", "GET", true);
+ urlTests.put("/api/v1/clusters/cluster", "POST", true);
+ urlTests.put("/api/v1/views", "GET", true);
+ urlTests.put("/api/v1/views", "POST", false);
+ urlTests.put("/api/v1/persist/SomeValue", "GET", true);
+ urlTests.put("/api/v1/persist/SomeValue", "POST", false);
+ urlTests.put("/views/AllowedView/SomeVersion/SomeInstance", "GET", false);
+ urlTests.put("/views/AllowedView/SomeVersion/SomeInstance", "POST", false);
+ urlTests.put("/views/DeniedView/AnotherVersion/AnotherInstance", "GET", false);
+ urlTests.put("/views/DeniedView/AnotherVersion/AnotherInstance", "POST", false);
+ urlTests.put("/api/v1/users/user1", "GET", true);
+ urlTests.put("/api/v1/users/user1", "POST", true);
+ urlTests.put("/api/v1/users/user2", "GET", false);
+ urlTests.put("/api/v1/users/user2", "POST", false);
+ urlTests.put("/api/v1/groups", "GET", false);
+ urlTests.put("/api/v1/ldap_sync_events", "GET", false);
+ urlTests.put("/any/other/URL", "GET", true);
+ urlTests.put("/any/other/URL", "POST", false);
+
+ performGeneralDoFilterTest("user1", new int[] {PermissionEntity.CLUSTER_READ_PERMISSION}, urlTests);
+ }
+
+ @Test
+ public void testDoFilter_clusterOperatorAccess() throws Exception {
+ final Table<String, String, Boolean> urlTests = HashBasedTable.create();
+ urlTests.put("/api/v1/clusters/cluster", "GET", true);
+ urlTests.put("/api/v1/clusters/cluster", "POST", true);
+ urlTests.put("/api/v1/views", "GET", true);
+ urlTests.put("/api/v1/views", "POST", false);
+ urlTests.put("/api/v1/persist/SomeValue", "GET", true);
+ urlTests.put("/api/v1/persist/SomeValue", "POST", true);
+ urlTests.put("/views/AllowedView/SomeVersion/SomeInstance", "GET", false);
+ urlTests.put("/views/AllowedView/SomeVersion/SomeInstance", "POST", false);
+ urlTests.put("/views/DeniedView/AnotherVersion/AnotherInstance", "GET", false);
+ urlTests.put("/views/DeniedView/AnotherVersion/AnotherInstance", "POST", false);
+ urlTests.put("/api/v1/users/user1", "GET", true);
+ urlTests.put("/api/v1/users/user1", "POST", true);
+ urlTests.put("/api/v1/users/user2", "GET", false);
+ urlTests.put("/api/v1/users/user2", "POST", false);
+ urlTests.put("/api/v1/groups", "GET", false);
+ urlTests.put("/api/v1/ldap_sync_events", "GET", false);
+ urlTests.put("/any/other/URL", "GET", true);
+ urlTests.put("/any/other/URL", "POST", false);
+
+ performGeneralDoFilterTest("user1", new int[] {PermissionEntity.CLUSTER_OPERATE_PERMISSION}, urlTests);
+ }
+
+ @Test
+ public void testDoFilter_viewUserAccess() throws Exception {
+ final Table<String, String, Boolean> urlTests = HashBasedTable.create();
+ urlTests.put("/api/v1/clusters/cluster", "GET", true);
+ urlTests.put("/api/v1/clusters/cluster", "POST", false);
+ urlTests.put("/api/v1/views", "GET", true);
+ urlTests.put("/api/v1/views", "POST", true);
+ urlTests.put("/api/v1/persist/SomeValue", "GET", true);
+ urlTests.put("/api/v1/persist/SomeValue", "POST", false);
+ urlTests.put("/views/AllowedView/SomeVersion/SomeInstance", "GET", true);
+ urlTests.put("/views/AllowedView/SomeVersion/SomeInstance", "POST", true);
+ urlTests.put("/views/DeniedView/AnotherVersion/AnotherInstance", "GET", false);
+ urlTests.put("/views/DeniedView/AnotherVersion/AnotherInstance", "POST", false);
+ urlTests.put("/api/v1/users/user1", "GET", true);
+ urlTests.put("/api/v1/users/user1", "POST", true);
+ urlTests.put("/api/v1/users/user2", "GET", false);
+ urlTests.put("/api/v1/users/user2", "POST", false);
+ urlTests.put("/api/v1/groups", "GET", false);
+ urlTests.put("/api/v1/ldap_sync_events", "GET", false);
+ urlTests.put("/any/other/URL", "GET", true);
+ urlTests.put("/any/other/URL", "POST", false);
+
+ performGeneralDoFilterTest("user1", new int[] {PermissionEntity.VIEW_USE_PERMISSION}, urlTests);
+ }
+
+ @Test
+ public void testDoFilter_userNoPermissionsAccess() throws Exception {
+ final Table<String, String, Boolean> urlTests = HashBasedTable.create();
+ urlTests.put("/api/v1/clusters/cluster", "GET", true);
+ urlTests.put("/api/v1/clusters/cluster", "POST", false);
+ urlTests.put("/api/v1/views", "GET", true);
+ urlTests.put("/api/v1/views", "POST", false);
+ urlTests.put("/api/v1/persist/SomeValue", "GET", true);
+ urlTests.put("/api/v1/persist/SomeValue", "POST", false);
+ urlTests.put("/views/AllowedView/SomeVersion/SomeInstance", "GET", false);
+ urlTests.put("/views/AllowedView/SomeVersion/SomeInstance", "POST", false);
+ urlTests.put("/views/DeniedView/AnotherVersion/AnotherInstance", "GET", false);
+ urlTests.put("/views/DeniedView/AnotherVersion/AnotherInstance", "POST", false);
+ urlTests.put("/api/v1/users/user1", "GET", false);
+ urlTests.put("/api/v1/users/user1", "POST", false);
+ urlTests.put("/api/v1/users/user2", "GET", true);
+ urlTests.put("/api/v1/users/user2", "POST", true);
+ urlTests.put("/any/other/URL", "GET", true);
+ urlTests.put("/any/other/URL", "POST", false);
+
+ performGeneralDoFilterTest("user2", new int[0], urlTests);
+ }
+
+ /**
+ * Creates mocks with given permissions and performs all given url tests.
+ *
+ * @param username user name
+ * @param permissionsGranted array of user permissions
+ * @param urlTests map of triples: url - http method - is allowed
+ * @throws Exception
+ */
+ private void performGeneralDoFilterTest(String username, final int[] permissionsGranted, Table<String, String, Boolean> urlTests) throws Exception {
+ final SecurityContext securityContext = createNiceMock(SecurityContext.class);
+ final Authentication authentication = createNiceMock(Authentication.class);
+ final FilterConfig filterConfig = createNiceMock(FilterConfig.class);
+ final AmbariAuthorizationFilter filter = createMockBuilder(AmbariAuthorizationFilter.class)
+ .addMockedMethod("getSecurityContext").addMockedMethod("getViewRegistry").withConstructor().createMock();
+ final List<AmbariGrantedAuthority> authorities = new ArrayList<AmbariGrantedAuthority>();
+ final ViewRegistry viewRegistry = createNiceMock(ViewRegistry.class);
+
+ for (int permissionGranted: permissionsGranted) {
+ final AmbariGrantedAuthority authority = createNiceMock(AmbariGrantedAuthority.class);
+ final PrivilegeEntity privilegeEntity = createNiceMock(PrivilegeEntity.class);
+ final PermissionEntity permission = createNiceMock(PermissionEntity.class);
+
+ expect(authority.getPrivilegeEntity()).andReturn(privilegeEntity).anyTimes();
+ expect(privilegeEntity.getPermission()).andReturn(permission).anyTimes();
+ expect(permission.getId()).andReturn(permissionGranted).anyTimes();
+
+ replay(authority, privilegeEntity, permission);
+ authorities.add(authority);
+ }
+
+ EasyMock.<Collection<? extends GrantedAuthority>>expect(authentication.getAuthorities()).andReturn(authorities).anyTimes();
+ expect(filterConfig.getInitParameter("realm")).andReturn("AuthFilter").anyTimes();
+ expect(authentication.isAuthenticated()).andReturn(true).anyTimes();
+ expect(authentication.getName()).andReturn(username).anyTimes();
+ expect(filter.getSecurityContext()).andReturn(securityContext).anyTimes();
+ expect(filter.getViewRegistry()).andReturn(viewRegistry).anyTimes();
+ expect(securityContext.getAuthentication()).andReturn(authentication).anyTimes();
+ expect(viewRegistry.checkPermission(EasyMock.eq("AllowedView"), EasyMock.<String>anyObject(), EasyMock.<String>anyObject(), EasyMock.anyBoolean())).andAnswer(new IAnswer<Boolean>() {
+ @Override
+ public Boolean answer() throws Throwable {
+ for (int permissionGranted: permissionsGranted) {
+ if (permissionGranted == PermissionEntity.VIEW_USE_PERMISSION) {
+ return true;
+ }
+ }
+ return false;
+ }
+ }).anyTimes();
+ expect(viewRegistry.checkPermission(EasyMock.eq("DeniedView"), EasyMock.<String>anyObject(), EasyMock.<String>anyObject(), EasyMock.anyBoolean())).andReturn(false).anyTimes();
+
+ replay(authentication, filterConfig, filter, securityContext, viewRegistry);
+
+ for (final Cell<String, String, Boolean> urlTest: urlTests.cellSet()) {
+ final FilterChain chain = EasyMock.createStrictMock(FilterChain.class);
+ final HttpServletRequest request = createNiceMock(HttpServletRequest.class);
+ final HttpServletResponse response = createNiceMock(HttpServletResponse.class);
+
+ expect(request.getRequestURI()).andReturn(urlTest.getRowKey()).anyTimes();
+ expect(request.getMethod()).andReturn(urlTest.getColumnKey()).anyTimes();
+ if (urlTest.getValue()) {
+ chain.doFilter(EasyMock.<ServletRequest>anyObject(), EasyMock.<ServletResponse>anyObject());
+ EasyMock.expectLastCall().once();
+ }
+
+ replay(request, response, chain);
+
+ try {
+ filter.doFilter(request, response, chain);
+ } catch (AssertionError error) {
+ throw new Exception("doFilter() should not be chained on " + urlTest.getColumnKey() + " " + urlTest.getRowKey(), error);
+ }
+
+ try {
+ verify(chain);
+ } catch (AssertionError error) {
+ throw new Exception("verify( failed on " + urlTest.getColumnKey() + " " + urlTest.getRowKey(), error);
+ }
+ }
+ }
+
+ @Test
+ public void testParseUserName() throws Exception {
+ final String[] pathesToTest = {
+ "/api/v1/users/user",
+ "/api/v1/users/user?fields=*",
+ "/api/v22/users/user?fields=*"
+ };
+ for (String contextPath: pathesToTest) {
+ final String username = AmbariAuthorizationFilter.parseUserName(contextPath);
+ Assert.assertEquals("user", username);
+ }
+ }
+
+ @Test
+ public void testParseViewContextPath() throws Exception {
+ final String[] pathesToTest = {
+ AmbariAuthorizationFilter.VIEWS_CONTEXT_PATH_PREFIX + "MY_VIEW/1.0.0/INSTANCE1",
+ AmbariAuthorizationFilter.VIEWS_CONTEXT_PATH_PREFIX + "MY_VIEW/1.0.0/INSTANCE1/index.html",
+ AmbariAuthorizationFilter.VIEWS_CONTEXT_PATH_PREFIX + "MY_VIEW/1.0.0/INSTANCE1/api/test"
+ };
+ for (String contextPath: pathesToTest) {
+ final ViewInstanceVersionDTO dto = AmbariAuthorizationFilter.parseViewInstanceInfo(contextPath);
+ Assert.assertEquals("INSTANCE1", dto.getInstanceName());
+ Assert.assertEquals("MY_VIEW", dto.getViewName());
+ Assert.assertEquals("1.0.0", dto.getVersion());
+ }
+ }
}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/ambari/blob/f92ad8f5/ambari-server/src/test/java/org/apache/ambari/server/security/authorization/TestUsers.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/security/authorization/TestUsers.java b/ambari-server/src/test/java/org/apache/ambari/server/security/authorization/TestUsers.java
index 5487db8..dbdb469 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/security/authorization/TestUsers.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/security/authorization/TestUsers.java
@@ -313,4 +313,5 @@ public class TestUsers {
userDAO.merge(ldapUser);
}
+
}