blob: 6b6640768c407bf744587024226301091b6afaba [file] [log] [blame]
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.falcon.security;
import org.apache.falcon.cluster.util.EntityBuilderTestUtil;
import org.apache.falcon.entity.store.ConfigurationStore;
import org.apache.falcon.entity.v0.EntityType;
import org.apache.falcon.entity.v0.cluster.Cluster;
import org.apache.falcon.util.FalconTestUtil;
import org.apache.falcon.util.StartupProperties;
import org.apache.hadoop.security.UserGroupInformation;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import org.testng.Assert;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.ws.rs.HttpMethod;
import java.io.IOException;
/**
* Test for FalconAuthorizationFilter using mock objects.
*/
public class FalconAuthorizationFilterTest {
public static final String CLUSTER_ENTITY_NAME = "primary-cluster";
public static final String PROCESS_ENTITY_NAME = "sample-process";
@Mock
private HttpServletRequest mockRequest;
@Mock
private HttpServletResponse mockResponse;
@Mock
private FilterChain mockChain;
@Mock
private FilterConfig mockConfig;
@Mock
private UserGroupInformation mockUgi;
private ConfigurationStore configStore;
private Cluster clusterEntity;
private org.apache.falcon.entity.v0.process.Process processEntity;
@BeforeClass
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
CurrentUser.authenticate(EntityBuilderTestUtil.USER);
Assert.assertEquals(CurrentUser.getUser(), EntityBuilderTestUtil.USER);
configStore = ConfigurationStore.get();
addClusterEntity();
addProcessEntity();
Assert.assertNotNull(processEntity);
}
@DataProvider(name = "resourceWithNoEntity")
private Object[][] createOptions() {
return new Object[][] {
{"/admin/version"},
{"/entities/list/feed"},
{"/entities/list/process"},
{"/entities/list/cluster"},
{"/metadata/lineage/vertices/all"},
{"/metadata/lineage/vertices/_1"},
{"/metadata/lineage/vertices/properties/_1"},
{"/metadata/discovery/process_entity/sample-process/relations"},
{"/metadata/discovery/process_entity/list?cluster=primary-cluster"},
};
}
@Test (dataProvider = "resourceWithNoEntity")
public void testDoFilter(String resource) throws Exception {
boolean[] enabledFlags = {false, true};
for (boolean enabled : enabledFlags) {
StartupProperties.get().setProperty(
"falcon.security.authorization.enabled", String.valueOf(enabled));
Filter filter = new FalconAuthorizationFilter();
synchronized (StartupProperties.get()) {
filter.init(mockConfig);
}
StringBuffer requestUrl = new StringBuffer("http://localhost" + resource);
Mockito.when(mockRequest.getRequestURL()).thenReturn(requestUrl);
Mockito.when(mockRequest.getRequestURI()).thenReturn("/api" + resource);
Mockito.when(mockRequest.getPathInfo()).thenReturn(resource);
try {
filter.doFilter(mockRequest, mockResponse, mockChain);
} finally {
filter.destroy();
}
}
}
@DataProvider(name = "invalidResource")
private Object[][] createBadOptions() {
return new Object[][] {
{"/admin1/version"},
{"/entities1/list/feed"},
{"/metadata1/lineage/vertices/all"},
{"/foo/bar"},
};
}
@Test (dataProvider = "invalidResource")
public void testDoFilterBadResource(String resource) throws Exception {
boolean[] enabledFlags = {false, true};
for (boolean enabled : enabledFlags) {
StartupProperties.get().setProperty(
"falcon.security.authorization.enabled", String.valueOf(enabled));
Filter filter = new FalconAuthorizationFilter();
synchronized (StartupProperties.get()) {
filter.init(mockConfig);
}
StringBuffer requestUrl = new StringBuffer("http://localhost" + resource);
Mockito.when(mockRequest.getRequestURL()).thenReturn(requestUrl);
Mockito.when(mockRequest.getRequestURI()).thenReturn("/api" + resource);
Mockito.when(mockRequest.getPathInfo()).thenReturn(resource);
Mockito.when(mockResponse.getOutputStream()).thenReturn(
new ServletOutputStream() {
@Override
public void write(int b) throws IOException {
System.out.print(b);
}
});
try {
filter.doFilter(mockRequest, mockResponse, mockChain);
// todo: verify the response error code to 400
} finally {
filter.destroy();
}
}
}
@DataProvider(name = "resourceWithEntity")
private Object[][] createOptionsForResourceWithEntity() {
return new Object[][] {
{"/entities/status/process/"},
{"/entities/suspend/process/"},
{"/instance/running/process/"},
};
}
@Test (dataProvider = "resourceWithEntity")
public void testDoFilterForEntity(String resource) throws Exception {
boolean[] enabledFlags = {false, true};
for (boolean enabled : enabledFlags) {
StartupProperties.get().setProperty(
"falcon.security.authorization.enabled", String.valueOf(enabled));
Filter filter = new FalconAuthorizationFilter();
synchronized (StartupProperties.get()) {
filter.init(mockConfig);
}
String uri = resource + processEntity.getName();
StringBuffer requestUrl = new StringBuffer("http://localhost" + uri);
Mockito.when(mockRequest.getRequestURL()).thenReturn(requestUrl);
Mockito.when(mockRequest.getRequestURI()).thenReturn("/api" + uri);
Mockito.when(mockRequest.getPathInfo()).thenReturn(uri);
try {
filter.doFilter(mockRequest, mockResponse, mockChain);
} finally {
filter.destroy();
}
}
}
@Test
public void testDoFilterForEntityWithInvalidEntity() throws Exception {
CurrentUser.authenticate(FalconTestUtil.TEST_USER_1);
StartupProperties.get().setProperty("falcon.security.authorization.enabled", "true");
Filter filter = new FalconAuthorizationFilter();
synchronized (StartupProperties.get()) {
filter.init(mockConfig);
}
String uri = "/entities/suspend/process/bad-entity";
StringBuffer requestUrl = new StringBuffer("http://localhost" + uri);
Mockito.when(mockRequest.getRequestURL()).thenReturn(requestUrl);
Mockito.when(mockRequest.getRequestURI()).thenReturn("/api" + uri);
Mockito.when(mockRequest.getPathInfo()).thenReturn(uri);
Mockito.when(mockRequest.getMethod()).thenReturn(HttpMethod.GET);
try {
filter.doFilter(mockRequest, mockResponse, mockChain);
// todo: verify the response error code to 403
} finally {
filter.destroy();
}
}
@Test
public void testDoFilterForDeleteEntityInvalidEntity() throws Exception {
CurrentUser.authenticate(FalconTestUtil.TEST_USER_1);
StartupProperties.get().setProperty("falcon.security.authorization.enabled", "true");
Filter filter = new FalconAuthorizationFilter();
synchronized (StartupProperties.get()) {
filter.init(mockConfig);
}
String uri = "/entities/suspend/process/bad-entity";
StringBuffer requestUrl = new StringBuffer("http://localhost" + uri);
Mockito.when(mockRequest.getRequestURL()).thenReturn(requestUrl);
Mockito.when(mockRequest.getRequestURI()).thenReturn("/api" + uri);
Mockito.when(mockRequest.getPathInfo()).thenReturn(uri);
Mockito.when(mockRequest.getMethod()).thenReturn(HttpMethod.DELETE);
try {
filter.doFilter(mockRequest, mockResponse, mockChain);
} finally {
filter.destroy();
}
}
public void addClusterEntity() throws Exception {
clusterEntity = EntityBuilderTestUtil.buildCluster(CLUSTER_ENTITY_NAME);
configStore.publish(EntityType.CLUSTER, clusterEntity);
}
public void addProcessEntity() throws Exception {
processEntity = EntityBuilderTestUtil.buildProcess(PROCESS_ENTITY_NAME,
clusterEntity, "classified-as=Critical");
EntityBuilderTestUtil.addProcessWorkflow(processEntity);
EntityBuilderTestUtil.addProcessACL(processEntity);
configStore.publish(EntityType.PROCESS, processEntity);
}
}