Repository: falcon Updated Branches: refs/heads/master cbd7c807e -> d8fbec9f9
http://git-wip-us.apache.org/repos/asf/falcon/blob/d8fbec9f/prism/src/main/java/org/apache/falcon/security/FalconAuthorizationFilter.java ---------------------------------------------------------------------- diff --git a/prism/src/main/java/org/apache/falcon/security/FalconAuthorizationFilter.java b/prism/src/main/java/org/apache/falcon/security/FalconAuthorizationFilter.java index 15e94cd..542e956 100644 --- a/prism/src/main/java/org/apache/falcon/security/FalconAuthorizationFilter.java +++ b/prism/src/main/java/org/apache/falcon/security/FalconAuthorizationFilter.java @@ -49,6 +49,7 @@ import java.io.IOException; public class FalconAuthorizationFilter implements Filter { private static final Logger LOG = LoggerFactory.getLogger(FalconAuthorizationFilter.class); + private static final String DO_AS_PARAM = "doAs"; private boolean isAuthorizationEnabled; private AuthorizationProvider authorizationProvider; @@ -81,8 +82,9 @@ public class FalconAuthorizationFilter implements Filter { authorizationProvider.authorizeResource(requestParts.getResource(), requestParts.getAction(), requestParts.getEntityType(), requestParts.getEntityName(), authenticatedUGI); + String doAsUser = request.getParameter(DO_AS_PARAM); tryProxy(authenticatedUGI, - requestParts.getEntityType(), requestParts.getEntityName()); + requestParts.getEntityType(), requestParts.getEntityName(), doAsUser); LOG.info("Authorization succeeded for user={}, proxy={}", authenticatedUGI.getShortUserName(), CurrentUser.getUser()); } catch (AuthorizationException e) { @@ -133,7 +135,8 @@ public class FalconAuthorizationFilter implements Filter { } private void tryProxy(UserGroupInformation authenticatedUGI, - String entityType, String entityName) throws IOException { + String entityType, String entityName, + final String doAsUser) throws IOException { if (entityType == null || entityName == null) { return; } @@ -141,7 +144,7 @@ public class FalconAuthorizationFilter implements Filter { try { EntityType type = EntityType.getEnum(entityType); Entity entity = EntityUtil.getEntity(type, entityName); - SecurityUtil.tryProxy(entity); + SecurityUtil.tryProxy(entity, doAsUser); } catch (FalconException ignore) { // do nothing } http://git-wip-us.apache.org/repos/asf/falcon/blob/d8fbec9f/prism/src/main/java/org/apache/falcon/security/HostnameFilter.java ---------------------------------------------------------------------- diff --git a/prism/src/main/java/org/apache/falcon/security/HostnameFilter.java b/prism/src/main/java/org/apache/falcon/security/HostnameFilter.java new file mode 100644 index 0000000..19e7bf4 --- /dev/null +++ b/prism/src/main/java/org/apache/falcon/security/HostnameFilter.java @@ -0,0 +1,105 @@ +/** + * 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 javax.servlet.Filter; +import javax.servlet.FilterChain; +import javax.servlet.FilterConfig; +import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import java.io.IOException; +import java.net.InetAddress; +import java.net.UnknownHostException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Filter that resolves the requester hostname. + */ +public class HostnameFilter implements Filter { + private static final Logger LOG = LoggerFactory.getLogger(HostnameFilter.class); + + static final ThreadLocal<String> HOSTNAME_TL = new ThreadLocal<>(); + + /** + * Initializes the filter. + * + * @param config filter configuration. + * + * @throws javax.servlet.ServletException thrown if the filter could not be initialized. + */ + @Override + public void init(FilterConfig config) throws ServletException { + } + + /** + * Resolves the requester hostname and delegates the request to the chain. + * <p> + * The requester hostname is available via the {@link #get} method. + * + * @param request servlet request. + * @param response servlet response. + * @param chain filter chain. + * + * @throws java.io.IOException thrown if an IO error occurs. + * @throws ServletException thrown if a servlet error occurs. + */ + @Override + public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) + throws IOException, ServletException { + try { + String hostname; + try { + String address = request.getRemoteAddr(); + if (address != null) { + hostname = InetAddress.getByName(address).getCanonicalHostName(); + } else { + LOG.warn("Request remote address is NULL"); + hostname = "???"; + } + } catch (UnknownHostException ex) { + LOG.warn("Request remote address could not be resolved, {}", ex.toString(), ex); + hostname = "???"; + } + HOSTNAME_TL.set(hostname); + chain.doFilter(request, response); + } finally { + HOSTNAME_TL.remove(); + } + } + + /** + * Returns the requester hostname. + * + * @return the requester hostname. + */ + public static String get() { + return HOSTNAME_TL.get(); + } + + /** + * Destroys the filter. + * <p> + * This implementation is a NOP. + */ + @Override + public void destroy() { + } +} http://git-wip-us.apache.org/repos/asf/falcon/blob/d8fbec9f/prism/src/main/webapp/WEB-INF/web.xml ---------------------------------------------------------------------- diff --git a/prism/src/main/webapp/WEB-INF/web.xml b/prism/src/main/webapp/WEB-INF/web.xml index 551bf56..7c1a7ad 100644 --- a/prism/src/main/webapp/WEB-INF/web.xml +++ b/prism/src/main/webapp/WEB-INF/web.xml @@ -31,6 +31,11 @@ </filter> <filter> + <filter-name>hostnameFilter</filter-name> + <filter-class>org.apache.falcon.security.HostnameFilter</filter-class> + </filter> + + <filter> <filter-name>authentication</filter-name> <filter-class>org.apache.falcon.security.FalconAuthenticationFilter</filter-class> </filter> @@ -46,6 +51,11 @@ </filter-mapping> <filter-mapping> + <filter-name>hostnameFilter</filter-name> + <url-pattern>/*</url-pattern> + </filter-mapping> + + <filter-mapping> <filter-name>authentication</filter-name> <servlet-name>FalconProxyAPI</servlet-name> </filter-mapping> http://git-wip-us.apache.org/repos/asf/falcon/blob/d8fbec9f/prism/src/test/java/org/apache/falcon/resource/EntityManagerTest.java ---------------------------------------------------------------------- diff --git a/prism/src/test/java/org/apache/falcon/resource/EntityManagerTest.java b/prism/src/test/java/org/apache/falcon/resource/EntityManagerTest.java index ea2c40f..5fabcf3 100644 --- a/prism/src/test/java/org/apache/falcon/resource/EntityManagerTest.java +++ b/prism/src/test/java/org/apache/falcon/resource/EntityManagerTest.java @@ -131,7 +131,7 @@ public class EntityManagerTest extends AbstractEntityManager { * Only one entity should be returned when the auth is enabled. */ try { - getEntityList("", "", "", "process", "", "", "", "", 0, 10); + getEntityList("", "", "", "process", "", "", "", "", 0, 10, ""); Assert.fail(); } catch (Throwable ignore) { // do nothing @@ -148,7 +148,7 @@ public class EntityManagerTest extends AbstractEntityManager { Entity process2 = buildProcess("processAuthUser", System.getProperty("user.name"), "", ""); configStore.publish(EntityType.PROCESS, process2); - EntityList entityList = this.getEntityList("", "", "", "process", "", "", "", "asc", 0, 10); + EntityList entityList = this.getEntityList("", "", "", "process", "", "", "", "asc", 0, 10, ""); Assert.assertNotNull(entityList.getElements()); Assert.assertEquals(entityList.getElements().length, 1); @@ -157,7 +157,7 @@ public class EntityManagerTest extends AbstractEntityManager { */ StartupProperties.get().setProperty("falcon.security.authorization.enabled", "true"); CurrentUser.authenticate(System.getProperty("user.name")); - entityList = this.getEntityList("", "", "", "process", "", "", "", "desc", 0, 10); + entityList = this.getEntityList("", "", "", "process", "", "", "", "desc", 0, 10, ""); Assert.assertNotNull(entityList.getElements()); Assert.assertEquals(entityList.getElements().length, 1); @@ -172,7 +172,8 @@ public class EntityManagerTest extends AbstractEntityManager { Entity process2 = buildProcess("processAuthUserFilterBy", System.getProperty("user.name"), "", "USER-DATA"); configStore.publish(EntityType.PROCESS, process2); - EntityList entityList = this.getEntityList("", "", "", "process", "", "PIPELINES:USER-DATA", "", "asc", 0, 10); + EntityList entityList = this.getEntityList("", "", "", "process", "", + "PIPELINES:USER-DATA", "", "asc", 0, 10, ""); Assert.assertNotNull(entityList.getElements()); Assert.assertEquals(entityList.getElements().length, 1); Assert.assertNotNull(entityList.getElements()[0].pipeline); @@ -183,7 +184,7 @@ public class EntityManagerTest extends AbstractEntityManager { */ StartupProperties.get().setProperty("falcon.security.authorization.enabled", "true"); CurrentUser.authenticate(System.getProperty("user.name")); - entityList = this.getEntityList("", "", "", "process", "", "PIPELINES:USER-DATA", "", "desc", 0, 10); + entityList = this.getEntityList("", "", "", "process", "", "PIPELINES:USER-DATA", "", "desc", 0, 10, ""); Assert.assertNotNull(entityList.getElements()); Assert.assertEquals(entityList.getElements().length, 1); Assert.assertNotNull(entityList.getElements()[0].pipeline); @@ -222,7 +223,7 @@ public class EntityManagerTest extends AbstractEntityManager { configStore.publish(EntityType.PROCESS, process4); EntityList entityList = this.getEntityList("tags", "", "", "process", "", "PIPELINES:dataReplicationPipeline", - "name", "desc", 1, 1); + "name", "desc", 1, 1, ""); Assert.assertNotNull(entityList.getElements()); Assert.assertEquals(entityList.getElements().length, 1); Assert.assertEquals(entityList.getElements()[0].name, "process1"); @@ -232,7 +233,7 @@ public class EntityManagerTest extends AbstractEntityManager { entityList = this.getEntityList("pipelines", "", "", "process", - "[email protected], [email protected]", "", "name", "", 0, 2); + "[email protected], [email protected]", "", "name", "", 0, 2, ""); Assert.assertNotNull(entityList.getElements()); Assert.assertEquals(entityList.getElements().length, 2); Assert.assertEquals(entityList.getElements()[1].name, "process2"); @@ -241,17 +242,17 @@ public class EntityManagerTest extends AbstractEntityManager { Assert.assertEquals(entityList.getElements()[0].tag, null); entityList = this.getEntityList("pipelines", "", "", "process", - "[email protected], [email protected]", "", "name", "", 10, 2); + "[email protected], [email protected]", "", "name", "", 10, 2, ""); Assert.assertEquals(entityList.getElements().length, 0); entityList = this.getEntityList("pipelines", "", "", "process", - "[email protected]", "", "name", "", 1, 2); + "[email protected]", "", "name", "", 1, 2, ""); Assert.assertEquals(entityList.getElements().length, 2); // Test negative value for numResults, should throw an exception. try { this.getEntityList("pipelines", "", "", "process", - "[email protected], [email protected]", "", "name", "", 10, -1); + "[email protected], [email protected]", "", "name", "", 10, -1, ""); Assert.assertTrue(false); } catch (Throwable e) { Assert.assertTrue(true); @@ -260,7 +261,7 @@ public class EntityManagerTest extends AbstractEntityManager { // Test invalid entry for sortOrder try { this.getEntityList("pipelines", "", "", "process", - "[email protected], [email protected]", "", "name", "invalid", 10, 2); + "[email protected], [email protected]", "", "name", "invalid", 10, 2, ""); Assert.assertTrue(false); } catch (Throwable e) { Assert.assertTrue(true); @@ -287,18 +288,18 @@ public class EntityManagerTest extends AbstractEntityManager { Entity process5 = buildProcess("Process5", user, "category=usHealthcarePlans,department=billingDepartment", ""); configStore.publish(EntityType.PROCESS, process5); - EntityList entityList = this.getEntityList("", "sample", "health,billing", "", "", "", "name", "", 0, 10); + EntityList entityList = this.getEntityList("", "sample", "health,billing", "", "", "", "name", "", 0, 10, ""); Assert.assertNotNull(entityList.getElements()); Assert.assertEquals(entityList.getElements().length, 2); Assert.assertEquals(entityList.getElements()[0].name, "SampleProcess1"); Assert.assertEquals(entityList.getElements()[1].name, "SampleProcess2"); - entityList = this.getEntityList("", "sample4", "", "", "", "", "", "", 0, 10); + entityList = this.getEntityList("", "sample4", "", "", "", "", "", "", 0, 10, ""); Assert.assertNotNull(entityList.getElements()); Assert.assertEquals(entityList.getElements().length, 1); Assert.assertEquals(entityList.getElements()[0].name, "SampleProcess4"); - entityList = this.getEntityList("", "", "health,us", "", "", "", "name", "", 0, 10); + entityList = this.getEntityList("", "", "health,us", "", "", "", "name", "", 0, 10, ""); Assert.assertNotNull(entityList.getElements()); Assert.assertEquals(entityList.getElements().length, 2); Assert.assertEquals(entityList.getElements()[0].name, "Process5"); http://git-wip-us.apache.org/repos/asf/falcon/blob/d8fbec9f/prism/src/test/java/org/apache/falcon/security/FalconAuthenticationFilterTest.java ---------------------------------------------------------------------- diff --git a/prism/src/test/java/org/apache/falcon/security/FalconAuthenticationFilterTest.java b/prism/src/test/java/org/apache/falcon/security/FalconAuthenticationFilterTest.java index df85529..5627e68 100644 --- a/prism/src/test/java/org/apache/falcon/security/FalconAuthenticationFilterTest.java +++ b/prism/src/test/java/org/apache/falcon/security/FalconAuthenticationFilterTest.java @@ -18,8 +18,12 @@ package org.apache.falcon.security; +import org.apache.falcon.service.GroupsService; +import org.apache.falcon.service.ProxyUserService; +import org.apache.falcon.service.Services; import org.apache.falcon.util.FalconTestUtil; import org.apache.falcon.util.StartupProperties; +import org.apache.falcon.util.RuntimeProperties; import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.security.UserGroupInformation; import org.apache.hadoop.security.authentication.server.KerberosAuthenticationHandler; @@ -27,6 +31,7 @@ import org.mockito.Mock; import org.mockito.Mockito; import org.mockito.MockitoAnnotations; import org.testng.Assert; +import org.testng.annotations.AfterClass; import org.testng.annotations.BeforeClass; import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; @@ -37,6 +42,7 @@ import javax.servlet.FilterConfig; import javax.servlet.ServletContext; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; +import java.security.AccessControlException; import java.util.Map; import java.util.Properties; import java.util.concurrent.ConcurrentHashMap; @@ -46,6 +52,9 @@ import java.util.concurrent.ConcurrentHashMap; * Test for FalconAuthenticationFilter using mock objects. */ public class FalconAuthenticationFilterTest { + private ProxyUserService proxyUserService; + + private GroupsService groupsService; @Mock private HttpServletRequest mockRequest; @@ -62,9 +71,28 @@ public class FalconAuthenticationFilterTest { @Mock private UserGroupInformation mockUgi; + @Mock + private HostnameFilter mockHostnameFilter; + @BeforeClass - public void init() { + public void setUp() throws Exception { MockitoAnnotations.initMocks(this); + Services.get().register(new ProxyUserService()); + Services.get().register(new GroupsService()); + groupsService = Services.get().getService(GroupsService.SERVICE_NAME); + proxyUserService = Services.get().getService(ProxyUserService.SERVICE_NAME); + groupsService.init(); + + RuntimeProperties.get().setProperty("falcon.service.ProxyUserService.proxyuser.foo.hosts", "*"); + RuntimeProperties.get().setProperty("falcon.service.ProxyUserService.proxyuser.foo.groups", "*"); + proxyUserService.init(); + } + + @AfterClass + public void tearDown() throws Exception { + proxyUserService.destroy(); + groupsService.destroy(); + Services.get().reset(); } @BeforeMethod @@ -215,4 +243,57 @@ public class FalconAuthenticationFilterTest { Properties properties = filter.getConfiguration(FalconAuthenticationFilter.FALCON_PREFIX, null); Assert.assertEquals(properties.get(KerberosAuthenticationHandler.PRINCIPAL), principal); } + + @Test + public void testDoFilterWithEmptyDoAsUser() throws Exception { + Filter filter = new FalconAuthenticationFilter(); + synchronized (StartupProperties.get()) { + filter.init(mockConfig); + } + + CurrentUser.authenticate("testuser"); + Mockito.when(mockRequest.getMethod()).thenReturn("POST"); + Mockito.when(mockRequest.getQueryString()).thenReturn("user.name=testuser"); + Mockito.when(mockRequest.getRemoteUser()).thenReturn("testuser"); + Mockito.when(mockRequest.getParameter(FalconAuthenticationFilter.DO_AS_PARAM)).thenReturn(""); + filter.doFilter(mockRequest, mockResponse, mockChain); + Assert.assertEquals(CurrentUser.getUser(), "testuser"); + } + + @Test + public void testDoFilterWithDoAsUser() throws Exception { + Filter filter = new FalconAuthenticationFilter(); + HostnameFilter.HOSTNAME_TL.set("localhost"); + synchronized (StartupProperties.get()) { + filter.init(mockConfig); + } + + CurrentUser.authenticate("foo"); + Mockito.when(mockRequest.getMethod()).thenReturn("POST"); + Mockito.when(mockRequest.getQueryString()).thenReturn("user.name=foo"); + Mockito.when(mockRequest.getRemoteUser()).thenReturn("foo"); + Mockito.when(mockRequest.getParameter(FalconAuthenticationFilter.DO_AS_PARAM)).thenReturn("doAsProxyUser"); + Mockito.when(mockRequest.getMethod()).thenReturn("POST"); + filter.doFilter(mockRequest, mockResponse, mockChain); + Assert.assertEquals(CurrentUser.getUser(), "doAsProxyUser"); + } + + @Test (expectedExceptions = AccessControlException.class, + expectedExceptionsMessageRegExp = "User .* not defined as proxyuser.*") + public void testDoFilterWithInvalidProxyUser() throws Exception { + Filter filter = new FalconAuthenticationFilter(); + HostnameFilter.HOSTNAME_TL.set("localhost"); + synchronized (StartupProperties.get()) { + filter.init(mockConfig); + } + + CurrentUser.authenticate("testuser"); + Mockito.when(mockRequest.getMethod()).thenReturn("POST"); + Mockito.when(mockRequest.getQueryString()).thenReturn("user.name=testuser"); + Mockito.when(mockRequest.getRemoteUser()).thenReturn("testuser"); + Mockito.when(mockRequest.getParameter(FalconAuthenticationFilter.DO_AS_PARAM)).thenReturn("doAsProxyUser"); + Mockito.when(mockRequest.getMethod()).thenReturn("POST"); + filter.doFilter(mockRequest, mockResponse, mockChain); + Assert.assertEquals(CurrentUser.getUser(), "doAsProxyUser"); + } } http://git-wip-us.apache.org/repos/asf/falcon/blob/d8fbec9f/prism/src/test/java/org/apache/falcon/security/HostnameFilterTest.java ---------------------------------------------------------------------- diff --git a/prism/src/test/java/org/apache/falcon/security/HostnameFilterTest.java b/prism/src/test/java/org/apache/falcon/security/HostnameFilterTest.java new file mode 100644 index 0000000..2606ece --- /dev/null +++ b/prism/src/test/java/org/apache/falcon/security/HostnameFilterTest.java @@ -0,0 +1,93 @@ +/** + * 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.hadoop.util.Shell; +import org.mockito.Mockito; + +import javax.servlet.Filter; +import javax.servlet.FilterChain; +import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import java.io.IOException; +import java.util.concurrent.atomic.AtomicBoolean; +import org.testng.Assert; +import org.testng.annotations.Test; + +/** + * Unit tests for HostnameFilter. + */ +public class HostnameFilterTest { + + @Test + public void testHostname() throws Exception { + ServletRequest request = Mockito.mock(ServletRequest.class); + Mockito.when(request.getRemoteAddr()).thenReturn("localhost"); + + ServletResponse response = Mockito.mock(ServletResponse.class); + + final AtomicBoolean invoked = new AtomicBoolean(); + + FilterChain chain = new FilterChain() { + @Override + public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse) + throws IOException, ServletException { + Assert.assertTrue(HostnameFilter.get(). + contains(Shell.WINDOWS ? "127.0.0.1" : "localhost")); + invoked.set(true); + } + }; + + Filter filter = new HostnameFilter(); + filter.init(null); + Assert.assertNull(HostnameFilter.get()); + filter.doFilter(request, response, chain); + Assert.assertTrue(invoked.get()); + Assert.assertNull(HostnameFilter.get()); + filter.destroy(); + } + + @Test + public void testMissingHostname() throws Exception { + ServletRequest request = Mockito.mock(ServletRequest.class); + Mockito.when(request.getRemoteAddr()).thenReturn(null); + + ServletResponse response = Mockito.mock(ServletResponse.class); + + final AtomicBoolean invoked = new AtomicBoolean(); + + FilterChain chain = new FilterChain() { + @Override + public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse) + throws IOException, ServletException { + Assert.assertTrue(HostnameFilter.get().contains("???")); + invoked.set(true); + } + }; + + Filter filter = new HostnameFilter(); + filter.init(null); + Assert.assertNull(HostnameFilter.get()); + filter.doFilter(request, response, chain); + Assert.assertTrue(invoked.get()); + Assert.assertNull(HostnameFilter.get()); + filter.destroy(); + } +} http://git-wip-us.apache.org/repos/asf/falcon/blob/d8fbec9f/src/conf/runtime.properties ---------------------------------------------------------------------- diff --git a/src/conf/runtime.properties b/src/conf/runtime.properties index b31e6a3..1260f55 100644 --- a/src/conf/runtime.properties +++ b/src/conf/runtime.properties @@ -43,3 +43,19 @@ falcon.current.colo=local # If true, Falcon skips oozie dryrun while scheduling entities. *.falcon.skip.dryrun=false + +######### Proxyuser Configuration Start ######### + +#List of hosts the '#USER#' user is allowed to perform 'doAs 'operations from. The '#USER#' must be replaced with the +#username of the user who is allowed to perform 'doAs' operations. The value can be the '*' wildcard or a list of +#comma separated hostnames + +*.falcon.service.ProxyUserService.proxyuser.#USER#.hosts=* + +#List of groups the '#USER#' user is allowed to 'doAs 'operations. The '#USER#' must be replaced with the +#username of the user who is allowed to perform 'doAs' operations. The value can be the '*' wildcard or a list of +#comma separated groups + +*.falcon.service.ProxyUserService.proxyuser.#USER#.groups=* + +######### Proxyuser Configuration End ######### http://git-wip-us.apache.org/repos/asf/falcon/blob/d8fbec9f/src/conf/startup.properties ---------------------------------------------------------------------- diff --git a/src/conf/startup.properties b/src/conf/startup.properties index 9925373..ca55689 100644 --- a/src/conf/startup.properties +++ b/src/conf/startup.properties @@ -41,7 +41,9 @@ org.apache.falcon.rerun.service.RetryService,\ org.apache.falcon.rerun.service.LateRunService,\ org.apache.falcon.metadata.MetadataMappingService,\ - org.apache.falcon.service.LogCleanupService + org.apache.falcon.service.LogCleanupService,\ + org.apache.falcon.service.GroupsService,\ + org.apache.falcon.service.ProxyUserService ##### Prism Services ##### prism.application.services=org.apache.falcon.entity.store.ConfigurationStore http://git-wip-us.apache.org/repos/asf/falcon/blob/d8fbec9f/unit/src/main/java/org/apache/falcon/unit/FalconUnitClient.java ---------------------------------------------------------------------- diff --git a/unit/src/main/java/org/apache/falcon/unit/FalconUnitClient.java b/unit/src/main/java/org/apache/falcon/unit/FalconUnitClient.java index eb65cb3..d907683 100644 --- a/unit/src/main/java/org/apache/falcon/unit/FalconUnitClient.java +++ b/unit/src/main/java/org/apache/falcon/unit/FalconUnitClient.java @@ -78,7 +78,7 @@ public class FalconUnitClient extends AbstractFalconClient { * @return boolean */ @Override - public APIResult submit(String type, String filePath) throws IOException, FalconCLIException { + public APIResult submit(String type, String filePath, String doAsUser) throws IOException, FalconCLIException { try { EntityType entityType = EntityType.getEnum(type); InputStream entityStream = FalconUnitHelper.getFileInputStream(filePath); @@ -118,8 +118,8 @@ public class FalconUnitClient extends AbstractFalconClient { * @throws FalconException */ @Override - public APIResult schedule(EntityType entityType, String entityName, - String cluster, Boolean skipDryRun) throws FalconCLIException { + public APIResult schedule(EntityType entityType, String entityName, String cluster, + Boolean skipDryRun, String doAsUser) throws FalconCLIException { return schedule(entityType, entityName, null, 0, cluster, skipDryRun); } http://git-wip-us.apache.org/repos/asf/falcon/blob/d8fbec9f/unit/src/test/java/org/apache/falcon/unit/FalconUnitTestBase.java ---------------------------------------------------------------------- diff --git a/unit/src/test/java/org/apache/falcon/unit/FalconUnitTestBase.java b/unit/src/test/java/org/apache/falcon/unit/FalconUnitTestBase.java index 997b301..df73628 100644 --- a/unit/src/test/java/org/apache/falcon/unit/FalconUnitTestBase.java +++ b/unit/src/test/java/org/apache/falcon/unit/FalconUnitTestBase.java @@ -125,7 +125,7 @@ public class FalconUnitTestBase { fs.mkdirs(new Path(STAGING_PATH), HadoopClientFactory.ALL_PERMISSION); fs.mkdirs(new Path(WORKING_PATH), HadoopClientFactory.READ_EXECUTE_PERMISSION); String clusterXmlPath = overlayParametersOverTemplate(CLUSTER_TEMPLATE, props); - APIResult result = falconUnitClient.submit(CLUSTER, clusterXmlPath); + APIResult result = falconUnitClient.submit(CLUSTER, clusterXmlPath, ""); return true ? APIResult.Status.SUCCEEDED.equals(result.getStatus()) : false; } @@ -138,7 +138,7 @@ public class FalconUnitTestBase { } public APIResult submit(String entityType, String filePath) throws FalconCLIException, IOException { - return falconUnitClient.submit(entityType, filePath); + return falconUnitClient.submit(entityType, filePath, ""); } public APIResult submitProcess(String filePath, String appDirectory) throws IOException, FalconCLIException { http://git-wip-us.apache.org/repos/asf/falcon/blob/d8fbec9f/webapp/pom.xml ---------------------------------------------------------------------- diff --git a/webapp/pom.xml b/webapp/pom.xml index ce37634..828f7f5 100644 --- a/webapp/pom.xml +++ b/webapp/pom.xml @@ -401,6 +401,28 @@ </plugin> <plugin> + <groupId>com.google.code.maven-replacer-plugin</groupId> + <artifactId>replacer</artifactId> + <version>1.5.3</version> + <executions> + <execution> + <phase>generate-test-resources</phase> + <goals> + <goal>replace</goal> + </goals> + </execution> + </executions> + <configuration> + <includes> + <include>${project.build.directory}/test-classes/runtime.properties</include> + <include>${project.build.directory}/webapps/oozie/conf/oozie-site.xml</include> + </includes> + <token>#USER#</token> + <value>${user.name}</value> + </configuration> + </plugin> + + <plugin> <groupId>org.mortbay.jetty</groupId> <artifactId>maven-jetty-plugin</artifactId> <version>${jetty.version}</version> http://git-wip-us.apache.org/repos/asf/falcon/blob/d8fbec9f/webapp/src/conf/oozie/conf/oozie-site.xml ---------------------------------------------------------------------- diff --git a/webapp/src/conf/oozie/conf/oozie-site.xml b/webapp/src/conf/oozie/conf/oozie-site.xml index ded4873..8545ef9 100644 --- a/webapp/src/conf/oozie/conf/oozie-site.xml +++ b/webapp/src/conf/oozie/conf/oozie-site.xml @@ -338,8 +338,6 @@ <!-- Proxyuser Configuration --> - <!-- - <property> <name>oozie.service.ProxyUserService.proxyuser.#USER#.hosts</name> <value>*</value> @@ -374,7 +372,7 @@ </description> </property> - --> + <property> <name>oozie.base.url</name> http://git-wip-us.apache.org/repos/asf/falcon/blob/d8fbec9f/webapp/src/main/java/org/apache/falcon/resource/SchedulableEntityManager.java ---------------------------------------------------------------------- diff --git a/webapp/src/main/java/org/apache/falcon/resource/SchedulableEntityManager.java b/webapp/src/main/java/org/apache/falcon/resource/SchedulableEntityManager.java index 1f8cc1b..3bafb25 100644 --- a/webapp/src/main/java/org/apache/falcon/resource/SchedulableEntityManager.java +++ b/webapp/src/main/java/org/apache/falcon/resource/SchedulableEntityManager.java @@ -76,13 +76,14 @@ public class SchedulableEntityManager extends AbstractSchedulableEntityManager { @DefaultValue("") @QueryParam("orderBy") String orderBy, @DefaultValue("asc") @QueryParam("sortOrder") String sortOrder, @DefaultValue("0") @QueryParam("offset") Integer offset, - @QueryParam("numResults") Integer resultsPerPage) { + @QueryParam("numResults") Integer resultsPerPage, + @DefaultValue("") @QueryParam("doAs") String doAsUser) { if (StringUtils.isNotEmpty(type)) { type = type.substring(1); } resultsPerPage = resultsPerPage == null ? getDefaultResultsPerPage() : resultsPerPage; return super.getEntityList(fields, nameSubsequence, tagKeywords, type, tags, filterBy, - orderBy, sortOrder, offset, resultsPerPage); + orderBy, sortOrder, offset, resultsPerPage, doAsUser); } @GET @@ -102,9 +103,10 @@ public class SchedulableEntityManager extends AbstractSchedulableEntityManager { @DefaultValue("asc") @QueryParam("sortOrder") String entitySortOrder, @DefaultValue("0") @QueryParam("offset") Integer entityOffset, @DefaultValue("10") @QueryParam("numResults") Integer numEntities, - @DefaultValue("7") @QueryParam("numInstances") Integer numInstanceResults) { + @DefaultValue("7") @QueryParam("numInstances") Integer numInstanceResults, + @DefaultValue("") @QueryParam("doAs") final String doAsUser) { return super.getEntitySummary(type, cluster, startStr, endStr, fields, entityFilter, entityTags, - entityOrderBy, entitySortOrder, entityOffset, numEntities, numInstanceResults); + entityOrderBy, entitySortOrder, entityOffset, numEntities, numInstanceResults, doAsUser); } //RESUME CHECKSTYLE CHECK ParameterNumberCheck http://git-wip-us.apache.org/repos/asf/falcon/blob/d8fbec9f/webapp/src/main/webapp/WEB-INF/distributed/web.xml ---------------------------------------------------------------------- diff --git a/webapp/src/main/webapp/WEB-INF/distributed/web.xml b/webapp/src/main/webapp/WEB-INF/distributed/web.xml index 31d78a2..4741897 100644 --- a/webapp/src/main/webapp/WEB-INF/distributed/web.xml +++ b/webapp/src/main/webapp/WEB-INF/distributed/web.xml @@ -31,6 +31,11 @@ </filter> <filter> + <filter-name>hostnameFilter</filter-name> + <filter-class>org.apache.falcon.security.HostnameFilter</filter-class> + </filter> + + <filter> <filter-name>authentication</filter-name> <filter-class>org.apache.falcon.security.FalconAuthenticationFilter</filter-class> </filter> @@ -51,6 +56,11 @@ </filter-mapping> <filter-mapping> + <filter-name>hostnameFilter</filter-name> + <url-pattern>/*</url-pattern> + </filter-mapping> + + <filter-mapping> <filter-name>authentication</filter-name> <servlet-name>FalconRESTApi</servlet-name> </filter-mapping> http://git-wip-us.apache.org/repos/asf/falcon/blob/d8fbec9f/webapp/src/main/webapp/WEB-INF/embedded/web.xml ---------------------------------------------------------------------- diff --git a/webapp/src/main/webapp/WEB-INF/embedded/web.xml b/webapp/src/main/webapp/WEB-INF/embedded/web.xml index fa2db39..5ecfe77 100644 --- a/webapp/src/main/webapp/WEB-INF/embedded/web.xml +++ b/webapp/src/main/webapp/WEB-INF/embedded/web.xml @@ -31,6 +31,11 @@ </filter> <filter> + <filter-name>hostnameFilter</filter-name> + <filter-class>org.apache.falcon.security.HostnameFilter</filter-class> + </filter> + + <filter> <filter-name>authentication</filter-name> <filter-class>org.apache.falcon.security.FalconAuthenticationFilter</filter-class> </filter> @@ -46,6 +51,11 @@ </filter-mapping> <filter-mapping> + <filter-name>hostnameFilter</filter-name> + <url-pattern>/*</url-pattern> + </filter-mapping> + + <filter-mapping> <filter-name>authentication</filter-name> <servlet-name>FalconRESTApi</servlet-name> </filter-mapping> http://git-wip-us.apache.org/repos/asf/falcon/blob/d8fbec9f/webapp/src/main/webapp/WEB-INF/web.xml ---------------------------------------------------------------------- diff --git a/webapp/src/main/webapp/WEB-INF/web.xml b/webapp/src/main/webapp/WEB-INF/web.xml index 2cfd7de..acfa938 100644 --- a/webapp/src/main/webapp/WEB-INF/web.xml +++ b/webapp/src/main/webapp/WEB-INF/web.xml @@ -31,6 +31,11 @@ </filter> <filter> + <filter-name>hostnameFilter</filter-name> + <filter-class>org.apache.falcon.security.HostnameFilter</filter-class> + </filter> + + <filter> <filter-name>authentication</filter-name> <filter-class>org.apache.falcon.security.FalconAuthenticationFilter</filter-class> </filter> @@ -46,6 +51,11 @@ </filter-mapping> <filter-mapping> + <filter-name>hostnameFilter</filter-name> + <url-pattern>/*</url-pattern> + </filter-mapping> + + <filter-mapping> <filter-name>authentication</filter-name> <servlet-name>FalconRESTApi</servlet-name> </filter-mapping> http://git-wip-us.apache.org/repos/asf/falcon/blob/d8fbec9f/webapp/src/test/java/org/apache/falcon/cli/FalconCLIIT.java ---------------------------------------------------------------------- diff --git a/webapp/src/test/java/org/apache/falcon/cli/FalconCLIIT.java b/webapp/src/test/java/org/apache/falcon/cli/FalconCLIIT.java index 0062070..b859256 100644 --- a/webapp/src/test/java/org/apache/falcon/cli/FalconCLIIT.java +++ b/webapp/src/test/java/org/apache/falcon/cli/FalconCLIIT.java @@ -80,14 +80,14 @@ public class FalconCLIIT { + "/falcon/test/input/2014/11/23/23"), 0); filePath = TestContext.overlayParametersOverTemplate(TestContext.FEED_TEMPLATE2, overlay); - Assert.assertEquals(executeWithURL("entity -submit -type feed -file " + filePath), 0); + Assert.assertEquals(executeWithURL("entity -submit -type feed -doAs testUser -file " + filePath), 0); Assert.assertEquals( stream.buffer.toString().trim(), "falcon/default/Submit successful (feed) " + overlay.get("outputFeedName")); filePath = TestContext.overlayParametersOverTemplate(TestContext.PROCESS_TEMPLATE, overlay); - Assert.assertEquals(executeWithURL("entity -submit -type process -file " + filePath), 0); + Assert.assertEquals(executeWithURL("entity -submit -type process -doAs testUser -file " + filePath), 0); Assert.assertEquals( stream.buffer.toString().trim(), "falcon/default/Submit successful (process) " @@ -109,14 +109,14 @@ public class FalconCLIIT { context.setCluster(overlay.get("cluster")); filePath = TestContext.overlayParametersOverTemplate(TestContext.FEED_TEMPLATE1, overlay); - Assert.assertEquals(executeWithURL("entity -submitAndSchedule -type feed -file " + filePath), 0); + Assert.assertEquals(executeWithURL("entity -submitAndSchedule -type feed -doAs testUser -file " + filePath), 0); filePath = TestContext.overlayParametersOverTemplate(TestContext.FEED_TEMPLATE2, overlay); Assert.assertEquals(executeWithURL("entity -submitAndSchedule -type feed -file " + filePath), 0); filePath = TestContext.overlayParametersOverTemplate(TestContext.FEED_TEMPLATE1, overlay); Assert.assertEquals(executeWithURL("entity -submit -type feed -file " + filePath), 0); filePath = TestContext.overlayParametersOverTemplate(TestContext.FEED_TEMPLATE2, overlay); - Assert.assertEquals(executeWithURL("entity -submit -type feed -file " + filePath), 0); + Assert.assertEquals(executeWithURL("entity -submit -type feed -doAs testUser -file " + filePath), 0); filePath = TestContext.overlayParametersOverTemplate(TestContext.PROCESS_TEMPLATE, overlay); Assert.assertEquals(executeWithURL("entity -submitAndSchedule -type process -file " + filePath), 0); @@ -147,7 +147,7 @@ public class FalconCLIIT { filePath = TestContext.overlayParametersOverTemplate(TestContext.FEED_TEMPLATE2, overlay); Assert.assertEquals(executeWithURL("entity -validate -type feed -file " + filePath), 0); - Assert.assertEquals(executeWithURL("entity -submit -type feed -file " + filePath), 0); + Assert.assertEquals(executeWithURL("entity -submit -type feed -doAs testUser -file " + filePath), 0); filePath = TestContext.overlayParametersOverTemplate(TestContext.PROCESS_TEMPLATE, overlay); Assert.assertEquals(executeWithURL("entity -validate -type process -file " + filePath), 0); @@ -164,7 +164,8 @@ public class FalconCLIIT { Assert.assertEquals(executeWithURL("entity -definition -type feed -name " + overlay.get("inputFeedName")), 0); - Assert.assertEquals(executeWithURL("entity -definition -type feed -name " + overlay.get("outputFeedName")), 0); + Assert.assertEquals(executeWithURL("entity -definition -type feed -doAs testUser -name " + overlay.get( + "outputFeedName")), 0); Assert.assertEquals(executeWithURL("entity -definition -type process -name " + overlay.get("processName")), 0); @@ -178,6 +179,9 @@ public class FalconCLIIT { Assert.assertEquals(executeWithURL("entity -schedule -type cluster -name " + overlay.get("cluster")), -1); + Assert.assertEquals(executeWithURL("entity -schedule -type feed -doAs testUser -name " + overlay.get( + "inputFeedName")), 0); + Assert.assertEquals(executeWithURL("entity -schedule -type feed -name " + overlay.get("outputFeedName")), 0); Assert.assertEquals(executeWithURL("entity -schedule -type process -name " + overlay.get("processName")), 0); @@ -217,28 +221,46 @@ public class FalconCLIIT { Map<String, String> overlay = context.getUniqueOverlay(); submitTestFiles(context, overlay); + Assert.assertEquals(executeWithURL("entity -status -type feed -doAs testUser -name " + + overlay.get("inputFeedName")), 0); + Assert.assertEquals(executeWithURL("entity -status -type feed -name " + overlay.get("outputFeedName")), 0); Assert.assertEquals(executeWithURL("entity -status -type process -name " + overlay.get("processName")), 0); + Assert.assertEquals(executeWithURL("entity -schedule -type feed -doAs testUser -name " + + overlay.get("inputFeedName")), 0); + Assert.assertEquals(executeWithURL("entity -schedule -type feed -name " + overlay.get("outputFeedName")), 0); Assert.assertEquals(executeWithURL("entity -schedule -type process -name " + overlay.get("processName")), 0); OozieTestUtils.waitForProcessWFtoStart(context); + Assert.assertEquals(executeWithURL("entity -suspend -type feed -doAs testUser -name " + + overlay.get("inputFeedName")), 0); + Assert.assertEquals(executeWithURL("entity -suspend -type feed -name " + overlay.get("outputFeedName")), 0); Assert.assertEquals(executeWithURL("entity -suspend -type process -name " + overlay.get("processName")), 0); + Assert.assertEquals(executeWithURL("entity -status -type feed -doAs testUser -name " + + overlay.get("inputFeedName")), 0); + Assert.assertEquals(executeWithURL("entity -status -type feed -name " + overlay.get("outputFeedName")), 0); Assert.assertEquals(executeWithURL("entity -status -type process -name " + overlay.get("processName")), 0); + Assert.assertEquals(executeWithURL("entity -resume -type feed -doAs testUse -name " + + overlay.get("inputFeedName")), 0); + Assert.assertEquals(executeWithURL("entity -resume -type feed -name " + overlay.get("outputFeedName")), 0); Assert.assertEquals(executeWithURL("entity -resume -type process -name " + overlay.get("processName")), 0); + Assert.assertEquals(executeWithURL("entity -status -type feed -doAs testUse -name " + + overlay.get("inputFeedName")), 0); + Assert.assertEquals(executeWithURL("entity -status -type feed -name " + overlay.get("outputFeedName")), 0); Assert.assertEquals(executeWithURL("entity -status -type process -name " + overlay.get("processName")), 0); @@ -262,8 +284,8 @@ public class FalconCLIIT { + " -filterBy TYPE:PROCESS -orderBy name -sortOrder invalid " + " -offset 0 -numResults 1 -numInstances 7"), -1); - // No start or end date - Assert.assertEquals(executeWithURL("entity -summary -type process -fields status,pipelines" + // No start or end date and with doAs option + Assert.assertEquals(executeWithURL("entity -summary -type process -doAs testUser -fields status,pipelines" + " -cluster " + overlay.get("cluster") + " -filterBy TYPE:PROCESS -orderBy name " + " -offset 0 -numResults 1 -numInstances 7"), 0); @@ -284,14 +306,15 @@ public class FalconCLIIT { Assert.assertEquals(executeWithURL("entity -delete -type feed -name " + overlay.get("inputFeedName")), -1); - Assert.assertEquals(executeWithURL("entity -delete -type feed -name " + overlay.get("outputFeedName")), -1); + Assert.assertEquals(executeWithURL("entity -delete -type feed -doAs testUser -name " + + overlay.get("outputFeedName")), -1); - Assert.assertEquals(executeWithURL("entity -delete -type process -name " + overlay.get("processName")), 0); + Assert.assertEquals(executeWithURL("entity -delete -type process -doAs testUser -name " + + overlay.get("processName")), 0); Assert.assertEquals(executeWithURL("entity -delete -type feed -name " + overlay.get("inputFeedName")), 0); Assert.assertEquals(executeWithURL("entity -delete -type feed -name " + overlay.get("outputFeedName")), 0); - } public void testInvalidCLIEntitycommands() throws Exception { @@ -318,41 +341,51 @@ public class FalconCLIIT { Assert.assertEquals(executeWithURL("instance -dependency -type feed -name " + overlay.get("inputFeedName") + " -instanceTime 2010-01-01T00:00Z"), 0); + //Test the dependency command with doAs + Assert.assertEquals(executeWithURL("instance -dependency -type feed -doAs testUser -name " + + overlay.get("inputFeedName") + " -instanceTime 2010-01-01T00:00Z"), 0); + Assert.assertEquals(executeWithURL("instance -status -type feed -name " + overlay.get("outputFeedName") + " -start " + START_INSTANCE), 0); Assert.assertEquals(executeWithURL("instance -running -type process -name " + overlay.get("processName")), 0); + // with doAs + Assert.assertEquals(executeWithURL("instance -running -type process -doAs testUser -name " + + overlay.get("processName")), 0); Assert.assertEquals(executeWithURL("instance -running -type feed -lifecycle eviction -name " - + overlay.get("outputFeedName") - + " -start " + SchemaHelper.getDateFormat().format(new Date())), 0); + + overlay.get("outputFeedName") + " -start " + SchemaHelper.getDateFormat().format(new Date())), 0); Assert.assertEquals(executeWithURL("instance -listing -type feed -name " - + overlay.get("outputFeedName") - + " -start " + SchemaHelper.getDateFormat().format(new Date())), 0); + + overlay.get("outputFeedName") + " -start " + SchemaHelper.getDateFormat().format(new Date())), 0); Assert.assertEquals(executeWithURL("instance -status -type process -name " - + overlay.get("processName") - + " -start " + START_INSTANCE), 0); + + overlay.get("processName") + " -start " + START_INSTANCE), 0); + + //TEst instance status with doAs + Assert.assertEquals(executeWithURL("instance -status -type process -doAs testUser -name " + + overlay.get("processName") + " -start " + START_INSTANCE), 0); + Assert.assertEquals(executeWithURL("instance -status -type feed -lifecycle eviction,replication -name " + overlay.get("outputFeedName") + " -start " + SchemaHelper.getDateFormat().format(new Date())), 0); Assert.assertEquals(executeWithURL("instance -status -type feed -lifecycle eviction -name " - + overlay.get("outputFeedName") - + " -start " + SchemaHelper.getDateFormat().format(new Date())), 0); + + overlay.get("outputFeedName") + " -start " + SchemaHelper.getDateFormat().format(new Date())), 0); Assert.assertEquals(executeWithURL("instance -params -type process -name " - + overlay.get("processName") - + " -start " + START_INSTANCE), 0); + + overlay.get("processName") + " -start " + START_INSTANCE), 0); + + // doAs option + Assert.assertEquals(executeWithURL("instance -params -type process -doAs testUser -name " + + overlay.get("processName") + " -start " + START_INSTANCE), 0); // test filterBy, orderBy, offset, numResults String startTimeString = SchemaHelper.getDateFormat().format(new Date()); Assert.assertEquals(executeWithURL("instance -running -type feed -lifecycle eviction -name " - + overlay.get("outputFeedName") - + " -start " + startTimeString + + overlay.get("outputFeedName") + " -start " + startTimeString + " -orderBy startTime -sortOrder asc -offset 0 -numResults 1"), 0); Assert.assertEquals(executeWithURL("instance -running -type feed -lifecycle eviction -name " @@ -361,18 +394,15 @@ public class FalconCLIIT { + " -orderBy INVALID -offset 0 -numResults 1"), -1); Assert.assertEquals(executeWithURL("instance -running -type feed -lifecycle eviction -name " - + overlay.get("outputFeedName") - + " -start " + startTimeString + + overlay.get("outputFeedName") + " -start " + startTimeString + " -orderBy startTime -sortOrder desc -offset 0 -numResults 1"), 0); Assert.assertEquals(executeWithURL("instance -running -type feed -lifecycle eviction -name " - + overlay.get("outputFeedName") - + " -start " + startTimeString + + overlay.get("outputFeedName") + " -start " + startTimeString + " -orderBy startTime -sortOrder invalid -offset 0 -numResults 1"), -1); Assert.assertEquals(executeWithURL("instance -running -type feed -lifecycle eviction -name " - + overlay.get("outputFeedName") - + " -start " + SchemaHelper.getDateFormat().format(new Date()) + + overlay.get("outputFeedName") + " -start " + SchemaHelper.getDateFormat().format(new Date()) + " -filterBy INVALID:FILTER -offset 0 -numResults 1"), -1); // testcase : start str is older than entity schedule time. @@ -404,6 +434,10 @@ public class FalconCLIIT { + " -filterBy SOURCECLUSTER:" + overlay.get("cluster") + " -orderBy startTime -sortOrder desc -offset 0 -numResults 1"), 0); + //Test list with doAs + Assert.assertEquals(executeWithURL("instance -list -type feed -doAs testUser -name " + + overlay.get("outputFeedName") + " -start " + SchemaHelper.getDateFormat().format(new Date())), 0); + Assert.assertEquals(executeWithURL("instance -list -type feed -lifecycle eviction -name " + overlay.get("outputFeedName") + " -start " + SchemaHelper.getDateFormat().format(new Date()) @@ -453,9 +487,17 @@ public class FalconCLIIT { Assert.assertEquals(executeWithURL("instance -running -type process -name " + overlay.get("processName")), 0); + //with doAs + Assert.assertEquals(executeWithURL("instance -running -type process -doAs testUser -name " + + overlay.get("processName")), 0); + Assert.assertEquals(executeWithURL("instance -summary -type process -name " + overlay.get("processName") + " -start " + START_INSTANCE), 0); + //with doAs + Assert.assertEquals(executeWithURL("instance -summary -type process -doAs testUser -name " + + overlay.get("processName") + " -start " + START_INSTANCE), 0); + Assert.assertEquals(executeWithURL("instance -summary -type feed -lifecycle eviction -name " + overlay.get("outputFeedName") + " -start " + SchemaHelper.getDateFormat().format(new Date())), 0); @@ -463,6 +505,10 @@ public class FalconCLIIT { Assert.assertEquals(executeWithURL("instance -params -type process -name " + overlay.get("processName") + " -start " + START_INSTANCE), 0); + + //with doAs + Assert.assertEquals(executeWithURL("instance -params -type process -doAs testUser -name " + + overlay.get("processName") + " -start " + START_INSTANCE), 0); } public void testInstanceSuspendAndResume() throws Exception { @@ -472,9 +518,15 @@ public class FalconCLIIT { Assert.assertEquals(executeWithURL("entity -schedule -type process -name " + overlay.get("processName")), 0); + Assert.assertEquals(executeWithURL("entity -schedule -type feed -name " + overlay.get("inputFeedName")), 0); + Assert.assertEquals(executeWithURL("entity -schedule -type feed -name " + overlay.get("outputFeedName")), 0); - Assert.assertEquals(executeWithURL("instance -suspend -type process -name " + Assert.assertEquals(executeWithURL("instance -suspend -type feed -name " + + overlay.get("inputFeedName") + + " -start " + START_INSTANCE + " -end " + START_INSTANCE), 0); + + Assert.assertEquals(executeWithURL("instance -suspend -type process -doAs testUser -name " + overlay.get("processName") + " -start " + START_INSTANCE + " -end " + START_INSTANCE), 0); @@ -487,6 +539,10 @@ public class FalconCLIIT { + overlay.get("processName") + " -start " + START_INSTANCE + " -end " + START_INSTANCE), 0); + Assert.assertEquals(executeWithURL("instance -resume -type feed -doAs testUser -name " + + overlay.get("inputFeedName") + + " -start " + START_INSTANCE + " -end " + START_INSTANCE), 0); + Assert.assertEquals(executeWithURL("instance -resume -type feed -lifecycle eviction -name " + overlay.get("outputFeedName") + " -start " + SchemaHelper.getDateFormat().format(new Date()) @@ -502,6 +558,9 @@ public class FalconCLIIT { Assert.assertEquals(executeWithURL("entity -schedule -type process -name " + overlay.get("processName")), 0); + Assert.assertEquals(executeWithURL("entity -schedule -type feed -doAs testUser -name " + + overlay.get("inputFeedName")), 0); + Assert.assertEquals(executeWithURL("entity -schedule -type feed -name " + overlay.get("outputFeedName")), 0); OozieTestUtils.waitForProcessWFtoStart(context); @@ -509,6 +568,10 @@ public class FalconCLIIT { + overlay.get("processName") + " -start " + START_INSTANCE + " -end " + START_INSTANCE), 0); + Assert.assertEquals(executeWithURL("instance -kill -type feed -doAs testUser -name " + + overlay.get("inputFeedName") + + " -start " + START_INSTANCE + " -end " + START_INSTANCE), 0); + // Fail due to no end date Assert.assertEquals(executeWithURL("instance -kill -type feed -lifecycle eviction -name " + overlay.get("outputFeedName") @@ -519,6 +582,11 @@ public class FalconCLIIT { + " -start " + START_INSTANCE + " -end " + START_INSTANCE + " -file " + createTempJobPropertiesFile()), 0); + Assert.assertEquals(executeWithURL("instance -rerun -type feed -doAs testUser -name " + + overlay.get("inputFeedName") + + " -start " + START_INSTANCE + " -end " + START_INSTANCE + + " -file " + createTempJobPropertiesFile()), 0); + Assert.assertEquals(executeWithURL("instance -rerun -type feed -lifecycle eviction -name " + overlay.get("outputFeedName") + " -start " + SchemaHelper.getDateFormat().format(new Date()) @@ -547,7 +615,7 @@ public class FalconCLIIT { Assert.assertEquals(executeWithURL("entity -submit -type process -file " + filePath), 0); Assert.assertEquals(executeWithURL("metadata -lineage -pipeline testPipeline"), 0); - + Assert.assertEquals(executeWithURL("metadata -lineage -doAs testUser -pipeline testPipeline"), 0); } @Test @@ -619,6 +687,11 @@ public class FalconCLIIT { Assert.assertEquals(executeWithURL("instance -status -type feed -name " + overlay.get("outputFeedName") + " -start " + START_INSTANCE), 0); Assert.assertEquals(executeWithURL("instance -running -type process -name " + overlay.get("processName")), 0); + + // with doAs + Assert.assertEquals(executeWithURL("entity -list -type process -doAs testUser -fields status " + + " -filterBy STATUS:SUBMITTED,TYPE:process -orderBy name " + + " -sortOrder asc -offset 1 -numResults 1"), 0); } @Test @@ -642,6 +715,10 @@ public class FalconCLIIT { String metadataListCommand = FalconCLI.METADATA_CMD + " -" + FalconMetadataCLI.LIST_OPT + " -" + FalconMetadataCLI.TYPE_OPT + " "; + String metadataListCommandWithDoAs = FalconCLI.METADATA_CMD + " -doAs testUser" + " -" + + FalconMetadataCLI.LIST_OPT + " -" + + FalconMetadataCLI.TYPE_OPT + " "; + String clusterString = " -" + FalconMetadataCLI.CLUSTER_OPT + " " + clusterName; Assert.assertEquals(executeWithURL(metadataListCommand + RelationshipType.CLUSTER_ENTITY.name()), 0); @@ -654,6 +731,9 @@ public class FalconCLIIT { Assert.assertEquals(executeWithURL(metadataListCommand + RelationshipType.CLUSTER_ENTITY.name() + clusterString), 0); + //with doAs + Assert.assertEquals(executeWithURL(metadataListCommandWithDoAs + RelationshipType.FEED_ENTITY.name()), 0); + Assert.assertEquals(executeWithURL(metadataListCommand + "feed"), -1); Assert.assertEquals(executeWithURL(metadataListCommand + "invalid"), -1); } @@ -680,11 +760,19 @@ public class FalconCLIIT { String metadataRelationsCommand = FalconCLI.METADATA_CMD + " -" + FalconMetadataCLI.RELATIONS_OPT + " -" + FalconMetadataCLI.TYPE_OPT + " "; + String metadataRelationsCommandWithDoAs = FalconCLI.METADATA_CMD + " -doAs testUser" + + " -" + FalconMetadataCLI.RELATIONS_OPT + " -" + + FalconMetadataCLI.TYPE_OPT + " "; + Assert.assertEquals(executeWithURL(metadataRelationsCommand + RelationshipType.CLUSTER_ENTITY.name() + " -" + FalconMetadataCLI.NAME_OPT + " " + clusterName), 0); Assert.assertEquals(executeWithURL(metadataRelationsCommand + RelationshipType.PROCESS_ENTITY.name() + " -" + FalconMetadataCLI.NAME_OPT + " " + processName), 0); + // with doAs + Assert.assertEquals(executeWithURL(metadataRelationsCommandWithDoAs + RelationshipType.PROCESS_ENTITY.name() + + " -" + FalconMetadataCLI.NAME_OPT + " " + processName), 0); + Assert.assertEquals(executeWithURL(metadataRelationsCommand + "feed -" + FalconMetadataCLI.NAME_OPT + " " + clusterName), -1); @@ -765,20 +853,26 @@ public class FalconCLIIT { + TestContext.BASE_URL).split("\\s+")), 0); Assert.assertEquals(new FalconCLI().run(("entity -schedule -type process -name " - + overlay.get("processName")+ " -url " + + overlay.get("processName") + " -url " + TestContext.BASE_URL).split("\\s+")), 0); } public void testGetVersion() throws Exception { Assert.assertEquals(new FalconCLI().run(("admin -version -url " + TestContext.BASE_URL).split("\\s")), 0); + Assert.assertEquals(new FalconCLI().run(("admin -doAs testUser -version -url " + + TestContext.BASE_URL).split("\\s")), 0); } public void testGetStatus() throws Exception { Assert.assertEquals(new FalconCLI().run(("admin -status -url " + TestContext.BASE_URL).split("\\s")), 0); + Assert.assertEquals(new FalconCLI().run(("admin -doAs testUser -status -url " + + TestContext.BASE_URL).split("\\s")), 0); } public void testGetThreadStackDump() throws Exception { Assert.assertEquals(new FalconCLI().run(("admin -stack -url " + TestContext.BASE_URL).split("\\s")), 0); + Assert.assertEquals(new FalconCLI().run(("admin -doAs testUser -stack -url " + + TestContext.BASE_URL).split("\\s")), 0); } public void testInstanceGetLogs() throws Exception { @@ -800,6 +894,10 @@ public class FalconCLIIT { + overlay.get("outputFeedName") + " -start "+ SchemaHelper.getDateFormat().format(new Date())), 0); + // with doAs + Assert.assertEquals(executeWithURL("instance -logs -doAs testUser -type feed -lifecycle eviction -name " + + overlay.get("outputFeedName") + " -start "+ SchemaHelper.getDateFormat().format(new Date())), 0); + // test filterBy, orderBy, offset, numResults Assert.assertEquals(executeWithURL("instance -logs -type process -name " + overlay.get("processName") http://git-wip-us.apache.org/repos/asf/falcon/blob/d8fbec9f/webapp/src/test/java/org/apache/falcon/resource/EntityManagerJerseyIT.java ---------------------------------------------------------------------- diff --git a/webapp/src/test/java/org/apache/falcon/resource/EntityManagerJerseyIT.java b/webapp/src/test/java/org/apache/falcon/resource/EntityManagerJerseyIT.java index bcd3bd5..220e5a7 100644 --- a/webapp/src/test/java/org/apache/falcon/resource/EntityManagerJerseyIT.java +++ b/webapp/src/test/java/org/apache/falcon/resource/EntityManagerJerseyIT.java @@ -19,6 +19,7 @@ package org.apache.falcon.resource; import com.sun.jersey.api.client.ClientResponse; import com.sun.jersey.api.client.WebResource; +import org.apache.falcon.cli.FalconCLI; import org.apache.falcon.entity.v0.Entity; import org.apache.falcon.entity.v0.EntityType; import org.apache.falcon.entity.v0.SchemaHelper; @@ -243,7 +244,7 @@ public class EntityManagerJerseyIT { ClientResponse response = context.validate(tmpFile.getAbsolutePath(), overlay, EntityType.PROCESS); context.assertFailure(response); - context.scheduleProcess(tmpFile.getAbsolutePath(), overlay, false, null); + context.scheduleProcess(tmpFile.getAbsolutePath(), overlay, false); //Fix the process and then submitAndSchedule should succeed Iterator<Property> itr = process.getProperties().getProperties().iterator(); @@ -624,6 +625,14 @@ public class EntityManagerJerseyIT { } public void testProcesssScheduleAndDelete() throws Exception { + scheduleAndDeleteProcess(false); + } + + public void testProcesssScheduleAndDeleteWithDoAs() throws Exception { + scheduleAndDeleteProcess(true); + } + + private void scheduleAndDeleteProcess(boolean withDoAs) throws Exception { TestContext context = newContext(); ClientResponse clientResponse; Map<String, String> overlay = context.getUniqueOverlay(); @@ -632,12 +641,21 @@ public class EntityManagerJerseyIT { updateEndtime(process); File tmpFile = TestContext.getTempFile(); EntityType.PROCESS.getMarshaller().marshal(process, tmpFile); - context.scheduleProcess(tmpFile.getAbsolutePath(), overlay); + if (withDoAs) { + context.scheduleProcess(tmpFile.getAbsolutePath(), overlay, null, "testUser"); + } else { + context.scheduleProcess(tmpFile.getAbsolutePath(), overlay); + } OozieTestUtils.waitForBundleStart(context, Status.RUNNING); + WebResource resource = context.service.path("api/entities/delete/process/" + context.processName); + + if (withDoAs) { + resource = resource.queryParam(FalconCLI.DO_AS_OPT, "testUser"); + } + //Delete a scheduled process - clientResponse = context.service - .path("api/entities/delete/process/" + context.processName) + clientResponse = resource .header("Cookie", context.getAuthenticationToken()) .accept(MediaType.TEXT_XML) .delete(ClientResponse.class); http://git-wip-us.apache.org/repos/asf/falcon/blob/d8fbec9f/webapp/src/test/java/org/apache/falcon/resource/MetadataResourceJerseyIT.java ---------------------------------------------------------------------- diff --git a/webapp/src/test/java/org/apache/falcon/resource/MetadataResourceJerseyIT.java b/webapp/src/test/java/org/apache/falcon/resource/MetadataResourceJerseyIT.java index eb1dda8..8594603 100644 --- a/webapp/src/test/java/org/apache/falcon/resource/MetadataResourceJerseyIT.java +++ b/webapp/src/test/java/org/apache/falcon/resource/MetadataResourceJerseyIT.java @@ -87,6 +87,7 @@ public class MetadataResourceJerseyIT { response = context.service .path("api/metadata/discovery/process_entity/list") .queryParam("cluster", "random") + .queryParam("doAs", "testUser") .header("Cookie", context.getAuthenticationToken()) .accept(MediaType.APPLICATION_JSON) .get(ClientResponse.class); http://git-wip-us.apache.org/repos/asf/falcon/blob/d8fbec9f/webapp/src/test/java/org/apache/falcon/resource/TestContext.java ---------------------------------------------------------------------- diff --git a/webapp/src/test/java/org/apache/falcon/resource/TestContext.java b/webapp/src/test/java/org/apache/falcon/resource/TestContext.java index 54671fb..f031137 100644 --- a/webapp/src/test/java/org/apache/falcon/resource/TestContext.java +++ b/webapp/src/test/java/org/apache/falcon/resource/TestContext.java @@ -25,6 +25,7 @@ import com.sun.jersey.api.client.config.ClientConfig; import com.sun.jersey.api.client.config.DefaultClientConfig; import com.sun.jersey.client.urlconnection.HTTPSProperties; import org.apache.commons.lang.RandomStringUtils; +import org.apache.commons.lang3.StringUtils; import org.apache.commons.net.util.TrustManagerUtils; import org.apache.falcon.FalconException; import org.apache.falcon.FalconRuntimException; @@ -230,11 +231,20 @@ public class TestContext { } public void scheduleProcess(String processTemplate, Map<String, String> overlay) throws Exception { - scheduleProcess(processTemplate, overlay, true, null); + scheduleProcess(processTemplate, overlay, true, null, ""); } public void scheduleProcess(String processTemplate, Map<String, String> overlay, - boolean succeed, Boolean skipDryRun) throws Exception { + Boolean skipDryRun, final String doAsUSer) throws Exception { + scheduleProcess(processTemplate, overlay, true, skipDryRun, doAsUSer); + } + + public void scheduleProcess(String processTemplate, Map<String, String> overlay, boolean succeed) throws Exception{ + scheduleProcess(processTemplate, overlay, succeed, null, ""); + } + + public void scheduleProcess(String processTemplate, Map<String, String> overlay, boolean succeed, + Boolean skipDryRun, final String doAsUser) throws Exception { ClientResponse response = submitToFalcon(CLUSTER_TEMPLATE, overlay, EntityType.CLUSTER); assertSuccessful(response); @@ -244,7 +254,7 @@ public class TestContext { response = submitToFalcon(FEED_TEMPLATE2, overlay, EntityType.FEED); assertSuccessful(response); - response = submitAndSchedule(processTemplate, overlay, EntityType.PROCESS, skipDryRun); + response = submitAndSchedule(processTemplate, overlay, EntityType.PROCESS, skipDryRun, doAsUser); if (succeed) { assertSuccessful(response); } else { @@ -279,21 +289,26 @@ public class TestContext { public ClientResponse submitAndSchedule(String template, Map<String, String> overlay, EntityType entityType) throws Exception { - return submitAndSchedule(template, overlay, entityType, null); + return submitAndSchedule(template, overlay, entityType, null, ""); } public ClientResponse submitAndSchedule(String template, Map<String, String> overlay, - EntityType entityType, Boolean skipDryRun) - throws Exception { + EntityType entityType, Boolean skipDryRun, + final String doAsUser) throws Exception { String tmpFile = overlayParametersOverTemplate(template, overlay); ServletInputStream rawlogStream = getServletInputStream(tmpFile); - WebResource resource = service.path("api/entities/submitAndSchedule/" + entityType.name().toLowerCase()); + WebResource resource = this.service.path("api/entities/submitAndSchedule/" + entityType.name().toLowerCase()); + if (null != skipDryRun) { resource = resource.queryParam("skipDryRun", String.valueOf(skipDryRun)); } - return resource - .header("Cookie", getAuthenticationToken()) + + if (StringUtils.isNotEmpty(doAsUser)) { + resource = resource.queryParam(FalconCLI.DO_AS_OPT, doAsUser); + } + + return resource.header("Cookie", getAuthenticationToken()) .accept(MediaType.TEXT_XML) .type(MediaType.TEXT_XML) .post(ClientResponse.class, rawlogStream); @@ -323,6 +338,11 @@ public class TestContext { public ClientResponse submitToFalcon(String template, Map<String, String> overlay, EntityType entityType) throws IOException { + return submitToFalcon(template, overlay, entityType, ""); + } + + public ClientResponse submitToFalcon(String template, Map<String, String> overlay, EntityType entityType, + final String doAsUser) throws IOException { String tmpFile = overlayParametersOverTemplate(template, overlay); if (entityType == EntityType.CLUSTER) { try { @@ -334,7 +354,7 @@ public class TestContext { throw new IOException("Unable to setup cluster info", e); } } - return submitFileToFalcon(entityType, tmpFile); + return submitFileToFalcon(entityType, tmpFile, doAsUser); } public static void deleteClusterLocations(Cluster clusterEntity, FileSystem fs) throws IOException { @@ -374,11 +394,21 @@ public class TestContext { } public ClientResponse submitFileToFalcon(EntityType entityType, String tmpFile) throws IOException { + return submitFileToFalcon(entityType, tmpFile, ""); + } + + public ClientResponse submitFileToFalcon(EntityType entityType, String tmpFile, + final String doAsUser) throws IOException { ServletInputStream rawlogStream = getServletInputStream(tmpFile); - return this.service.path("api/entities/submit/" + entityType.name().toLowerCase()) - .header("Cookie", getAuthenticationToken()) + WebResource resource = this.service.path("api/entities/submit/" + entityType.name().toLowerCase()); + + if (StringUtils.isNotEmpty(doAsUser)) { + resource = resource.queryParam(FalconCLI.DO_AS_OPT, doAsUser); + } + + return resource.header("Cookie", getAuthenticationToken()) .accept(MediaType.TEXT_XML) .type(MediaType.TEXT_XML) .post(ClientResponse.class, rawlogStream); http://git-wip-us.apache.org/repos/asf/falcon/blob/d8fbec9f/webapp/src/test/resources/runtime.properties ---------------------------------------------------------------------- diff --git a/webapp/src/test/resources/runtime.properties b/webapp/src/test/resources/runtime.properties new file mode 100644 index 0000000..1da0ca7 --- /dev/null +++ b/webapp/src/test/resources/runtime.properties @@ -0,0 +1,50 @@ +# +# 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. +# + +*.domain=debug + +*.falcon.parentworkflow.retry.max=3 +*.falcon.parentworkflow.retry.interval.secs=1 + +*.falcon.replication.workflow.maxmaps=5 +*.falcon.replication.workflow.mapbandwidth=100 +*.webservices.default.results.per.page=10 + +# Default configs to handle replication for late arriving feeds. +*.feed.late.allowed=true +*.feed.late.frequency=hours(3) +*.feed.late.policy=exp-backoff + +# If true, Falcon skips oozie dryrun while scheduling entities. +*.falcon.skip.dryrun=false + +######### Proxyuser Configuration Start ######### + +#List of hosts the '#USER#' user is allowed to perform 'doAs 'operations from. The '#USER#' must be replaced with the +#username of the user who is allowed to perform 'doAs' operations. The value can be the '*' wildcard or a list of +#comma separated hostnames + +*.falcon.service.ProxyUserService.proxyuser.#USER#.hosts=* + +#List of groups the '#USER#' user is allowed to 'doAs 'operations. The '#USER#' must be replaced with the +#username of the user who is allowed to perform 'doAs' operations. The value can be the '*' wildcard or a list of +#comma separated groups + +*.falcon.service.ProxyUserService.proxyuser.#USER#.groups=* + +######### Proxyuser Configuration End #########
