You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@falcon.apache.org by so...@apache.org on 2015/09/15 03:46:38 UTC

[1/3] falcon git commit: FALCON-1027 Falcon proxy user support. Contributed by Sowmya Ramesh.

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",
-                "consumer=consumer@xyz.com, owner=producer@xyz.com", "", "name", "", 0, 2);
+                "consumer=consumer@xyz.com, owner=producer@xyz.com", "", "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",
-                "consumer=consumer@xyz.com, owner=producer@xyz.com", "", "name", "", 10, 2);
+                "consumer=consumer@xyz.com, owner=producer@xyz.com", "", "name", "", 10, 2, "");
         Assert.assertEquals(entityList.getElements().length, 0);
 
         entityList = this.getEntityList("pipelines", "", "", "process",
-                "owner=producer@xyz.com", "", "name", "", 1, 2);
+                "owner=producer@xyz.com", "", "name", "", 1, 2, "");
         Assert.assertEquals(entityList.getElements().length, 2);
 
         // Test negative value for numResults, should throw an exception.
         try {
             this.getEntityList("pipelines", "", "", "process",
-                    "consumer=consumer@xyz.com, owner=producer@xyz.com", "", "name", "", 10, -1);
+                    "consumer=consumer@xyz.com, owner=producer@xyz.com", "", "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",
-                    "consumer=consumer@xyz.com, owner=producer@xyz.com", "", "name", "invalid", 10, 2);
+                    "consumer=consumer@xyz.com, owner=producer@xyz.com", "", "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 #########


[2/3] falcon git commit: FALCON-1027 Falcon proxy user support. Contributed by Sowmya Ramesh.

Posted by so...@apache.org.
http://git-wip-us.apache.org/repos/asf/falcon/blob/d8fbec9f/common/src/test/java/org/apache/falcon/security/CurrentUserTest.java
----------------------------------------------------------------------
diff --git a/common/src/test/java/org/apache/falcon/security/CurrentUserTest.java b/common/src/test/java/org/apache/falcon/security/CurrentUserTest.java
index 5780c94..5cc6c70 100644
--- a/common/src/test/java/org/apache/falcon/security/CurrentUserTest.java
+++ b/common/src/test/java/org/apache/falcon/security/CurrentUserTest.java
@@ -19,16 +19,44 @@
 package org.apache.falcon.security;
 
 import org.apache.falcon.cluster.util.EntityBuilderTestUtil;
+import org.apache.falcon.service.GroupsService;
+import org.apache.falcon.service.ProxyUserService;
+import org.apache.falcon.service.Services;
+import org.apache.falcon.util.RuntimeProperties;
 import org.apache.falcon.util.FalconTestUtil;
 import org.apache.hadoop.security.UserGroupInformation;
 import org.testng.Assert;
+import org.testng.annotations.AfterClass;
 import org.testng.annotations.AfterMethod;
+import org.testng.annotations.BeforeClass;
 import org.testng.annotations.Test;
 
 /**
  * Test for current user's thread safety.
  */
 public class CurrentUserTest {
+    private ProxyUserService proxyUserService;
+    private GroupsService groupsService;
+
+    @BeforeClass
+    public void setUp() throws Exception {
+        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();
+    }
 
     @AfterMethod
     public void cleanUp() {
@@ -115,4 +143,35 @@ public class CurrentUserTest {
         Assert.assertEquals(CurrentUser.getAuthenticatedUser(), EntityBuilderTestUtil.USER);
         Assert.assertEquals(CurrentUser.getUser(), "proxy");
     }
+
+    @Test(expectedExceptions = IllegalStateException.class)
+    public void testProxyDoAsUserWithNoAuth() throws Exception {
+        CurrentUser.proxyDoAsUser("falcon", "localhost");
+    }
+
+    @Test
+    public void testProxyDoAsUser() throws Exception {
+        CurrentUser.authenticate("foo");
+
+        CurrentUser.proxyDoAsUser(EntityBuilderTestUtil.USER, "localhost");
+        UserGroupInformation proxyUgi = CurrentUser.getProxyUGI();
+        Assert.assertNotNull(proxyUgi);
+        Assert.assertEquals(proxyUgi.getUserName(), EntityBuilderTestUtil.USER);
+
+        Assert.assertEquals(CurrentUser.getAuthenticatedUser(), "foo");
+        Assert.assertEquals(CurrentUser.getUser(), EntityBuilderTestUtil.USER);
+    }
+
+    @Test
+    public void testProxyDoAsSameUser() throws Exception {
+        CurrentUser.authenticate("foo");
+
+        CurrentUser.proxyDoAsUser("foo", "localhost");
+        UserGroupInformation proxyUgi = CurrentUser.getProxyUGI();
+        Assert.assertNotNull(proxyUgi);
+        Assert.assertEquals(proxyUgi.getUserName(), "foo");
+
+        Assert.assertEquals(CurrentUser.getAuthenticatedUser(), "foo");
+        Assert.assertEquals(CurrentUser.getUser(), "foo");
+    }
 }

http://git-wip-us.apache.org/repos/asf/falcon/blob/d8fbec9f/common/src/test/java/org/apache/falcon/security/SecurityUtilTest.java
----------------------------------------------------------------------
diff --git a/common/src/test/java/org/apache/falcon/security/SecurityUtilTest.java b/common/src/test/java/org/apache/falcon/security/SecurityUtilTest.java
index e40308e..76d9f45 100644
--- a/common/src/test/java/org/apache/falcon/security/SecurityUtilTest.java
+++ b/common/src/test/java/org/apache/falcon/security/SecurityUtilTest.java
@@ -22,10 +22,16 @@ package org.apache.falcon.security;
 import org.apache.falcon.FalconException;
 import org.apache.falcon.entity.v0.process.ACL;
 import org.apache.falcon.entity.v0.process.Process;
+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.mockito.Mockito;
 import org.testng.Assert;
+import org.testng.annotations.AfterClass;
+import org.testng.annotations.BeforeClass;
 import org.testng.annotations.Test;
 
 import java.io.IOException;
@@ -35,6 +41,29 @@ import java.io.IOException;
  */
 public class SecurityUtilTest {
 
+    private ProxyUserService proxyUserService;
+    private GroupsService groupsService;
+
+    @BeforeClass
+    public void setUp() throws Exception {
+        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();
+    }
+
     @Test
     public void testDefaultGetAuthenticationType() throws Exception {
         Assert.assertEquals(SecurityUtil.getAuthenticationType(), "simple");
@@ -98,7 +127,7 @@ public class SecurityUtilTest {
 
         // When ACL not specified
         CurrentUser.authenticate(currentUser);
-        SecurityUtil.tryProxy(process);
+        SecurityUtil.tryProxy(process, "");
         Assert.assertEquals(CurrentUser.getUser(), currentUser);
 
         ACL acl = new ACL();
@@ -107,7 +136,27 @@ public class SecurityUtilTest {
         Mockito.when(process.getACL()).thenReturn(acl);
 
         // When ACL is specified
-        SecurityUtil.tryProxy(process);
+        SecurityUtil.tryProxy(process, "");
         Assert.assertEquals(CurrentUser.getUser(), FalconTestUtil.TEST_USER_2);
     }
+
+    @Test (expectedExceptions = FalconException.class,
+           expectedExceptionsMessageRegExp = "doAs user and ACL owner mismatch.*")
+    public void testTryProxyWithDoAsUser() throws IOException, FalconException {
+        Process process = Mockito.mock(Process.class);
+        StartupProperties.get().setProperty("falcon.security.authorization.enabled", "true");
+        final String currentUser = "foo";
+
+        ACL acl = new ACL();
+        acl.setOwner("testuser");
+        acl.setGroup("users");
+        Mockito.when(process.getACL()).thenReturn(acl);
+
+        CurrentUser.authenticate(currentUser);
+        CurrentUser.proxyDoAsUser("doAsUser", "localhost");
+
+        Assert.assertEquals(CurrentUser.getUser(), "doAsUser");
+        SecurityUtil.tryProxy(process, "doAsUser");
+    }
+
 }

http://git-wip-us.apache.org/repos/asf/falcon/blob/d8fbec9f/common/src/test/java/org/apache/falcon/service/GroupsServiceTest.java
----------------------------------------------------------------------
diff --git a/common/src/test/java/org/apache/falcon/service/GroupsServiceTest.java b/common/src/test/java/org/apache/falcon/service/GroupsServiceTest.java
new file mode 100644
index 0000000..be5cbe7
--- /dev/null
+++ b/common/src/test/java/org/apache/falcon/service/GroupsServiceTest.java
@@ -0,0 +1,56 @@
+/**
+ * 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.service;
+
+import org.testng.annotations.AfterClass;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+import org.testng.Assert;
+
+import java.util.List;
+
+/**
+ * Unit tests for GroupsService.
+ */
+public class GroupsServiceTest {
+
+    private GroupsService service;
+
+    @BeforeClass
+    public void setUp() throws Exception {
+        service = new GroupsService();
+        service.init();
+    }
+
+    @AfterClass
+    public void tearDown() throws Exception {
+        service.destroy();
+    }
+
+    @Test
+    public void testGetName() throws Exception {
+        Assert.assertEquals(service.getName(), GroupsService.SERVICE_NAME);
+    }
+
+    @Test
+    public void testGroupsService() throws Exception {
+        List<String> g = service.getGroups(System.getProperty("user.name"));
+        Assert.assertNotSame(g.size(), 0);
+    }
+}

http://git-wip-us.apache.org/repos/asf/falcon/blob/d8fbec9f/common/src/test/java/org/apache/falcon/service/ProxyUserServiceTest.java
----------------------------------------------------------------------
diff --git a/common/src/test/java/org/apache/falcon/service/ProxyUserServiceTest.java b/common/src/test/java/org/apache/falcon/service/ProxyUserServiceTest.java
new file mode 100644
index 0000000..83ec6c2
--- /dev/null
+++ b/common/src/test/java/org/apache/falcon/service/ProxyUserServiceTest.java
@@ -0,0 +1,167 @@
+/**
+ * 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.service;
+
+import org.apache.falcon.FalconException;
+import org.apache.falcon.util.RuntimeProperties;
+import org.testng.Assert;
+import org.testng.annotations.AfterClass;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+import java.security.AccessControlException;
+import java.util.List;
+
+/**
+ * Unit tests for ProxyUserService.
+ */
+public class ProxyUserServiceTest {
+
+    private ProxyUserService proxyUserService;
+    private GroupsService groupsService;
+
+    @BeforeClass
+    public void setUp() throws Exception {
+        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();
+    }
+
+    @AfterClass
+    public void tearDown() throws Exception {
+        proxyUserService.destroy();
+        groupsService.destroy();
+        Services.get().reset();
+    }
+
+    @Test
+    public void testGetName() throws Exception {
+        proxyUserService.init();
+        Assert.assertEquals(proxyUserService.getName(), ProxyUserService.SERVICE_NAME);
+    }
+
+    @Test (expectedExceptions = FalconException.class, expectedExceptionsMessageRegExp = ".*falcon.service"
+            + ".ProxyUserService.proxyuser.foo.groups property not set in runtime properties.*")
+    public void testWrongConfigGroups() throws Exception {
+        RuntimeProperties.get().setProperty("falcon.service.ProxyUserService.proxyuser.foo.hosts", "*");
+        RuntimeProperties.get().remove("falcon.service.ProxyUserService.proxyuser.foo.groups");
+        proxyUserService.init();
+    }
+
+    @Test (expectedExceptions = FalconException.class, expectedExceptionsMessageRegExp = ".*falcon.service"
+            + ".ProxyUserService.proxyuser.foo.hosts property not set in runtime properties.*")
+    public void testWrongConfigHosts() throws Exception {
+        RuntimeProperties.get().setProperty("falcon.service.ProxyUserService.proxyuser.foo.groups", "*");
+        RuntimeProperties.get().remove("falcon.service.ProxyUserService.proxyuser.foo.hosts");
+        proxyUserService.init();
+    }
+
+    @Test (expectedExceptions = FalconException.class,
+           expectedExceptionsMessageRegExp = "Exception normalizing host name.*")
+    public void testWrongHost() throws Exception {
+        RuntimeProperties.get().setProperty("falcon.service.ProxyUserService.proxyuser.foo.hosts", "otherhost");
+        RuntimeProperties.get().setProperty("falcon.service.ProxyUserService.proxyuser.foo.groups", "*");
+        proxyUserService.init();
+    }
+
+    @Test
+    public void testValidateAnyHostAnyUser() throws Exception {
+        RuntimeProperties.get().setProperty("falcon.service.ProxyUserService.proxyuser.foo.hosts", "*");
+        RuntimeProperties.get().setProperty("falcon.service.ProxyUserService.proxyuser.foo.groups", "*");
+        proxyUserService.init();
+        proxyUserService.validate("foo", "localhost", "bar");
+    }
+
+    @Test (expectedExceptions = AccessControlException.class,
+           expectedExceptionsMessageRegExp = "User .* not defined as proxyuser.*")
+    public void testInvalidProxyUser() throws Exception {
+        RuntimeProperties.get().setProperty("falcon.service.ProxyUserService.proxyuser.foo.hosts", "*");
+        RuntimeProperties.get().setProperty("falcon.service.ProxyUserService.proxyuser.foo.groups", "*");
+        proxyUserService.init();
+        proxyUserService.validate("bar", "localhost", "foo");
+    }
+
+    @Test
+    public void testValidateHost() throws Exception {
+        RuntimeProperties.get().setProperty("falcon.service.ProxyUserService.proxyuser.foo.hosts", "*");
+        RuntimeProperties.get().setProperty("falcon.service.ProxyUserService.proxyuser.foo.groups", "*");
+        proxyUserService.init();
+        proxyUserService.validate("foo", "localhost", "bar");
+    }
+
+    private String getGroup() throws Exception {
+        List<String> g = groupsService.getGroups(System.getProperty("user.name"));
+        return g.get(0);
+    }
+
+    @Test
+    public void testValidateGroup() throws Exception {
+        RuntimeProperties.get().setProperty("falcon.service.ProxyUserService.proxyuser.foo.hosts", "*");
+        RuntimeProperties.get().setProperty("falcon.service.ProxyUserService.proxyuser.foo.groups",
+                    getGroup());
+
+        proxyUserService.init();
+        proxyUserService.validate("foo", "localhost", System.getProperty("user.name"));
+    }
+
+    @Test (expectedExceptions = AccessControlException.class,
+        expectedExceptionsMessageRegExp = "Could not resolve host .*")
+    public void testUnknownHost() throws Exception {
+        RuntimeProperties.get().setProperty("falcon.service.ProxyUserService.proxyuser.foo.hosts", "localhost");
+        RuntimeProperties.get().setProperty("falcon.service.ProxyUserService.proxyuser.foo.groups", "*");
+        proxyUserService.init();
+        proxyUserService.validate("foo", "unknownhost.bar.foo", "bar");
+    }
+
+    @Test (expectedExceptions = AccessControlException.class,
+            expectedExceptionsMessageRegExp = "Unauthorized host .*")
+    public void testInvalidHost() throws Exception {
+        RuntimeProperties.get().setProperty("falcon.service.ProxyUserService.proxyuser.foo.hosts", "localhost");
+        RuntimeProperties.get().setProperty("falcon.service.ProxyUserService.proxyuser.foo.groups", "*");
+        proxyUserService.init();
+        proxyUserService.validate("foo", "www.example.com", "bar");
+    }
+
+    @Test (expectedExceptions = AccessControlException.class,
+           expectedExceptionsMessageRegExp = "Unauthorized proxyuser .*, not in proxyuser groups")
+    public void testInvalidGroup() throws Exception {
+        RuntimeProperties.get().setProperty("falcon.service.ProxyUserService.proxyuser.foo.hosts", "localhost");
+        RuntimeProperties.get().setProperty("falcon.service.ProxyUserService.proxyuser.foo.groups", "nobody");
+        proxyUserService.init();
+        proxyUserService.validate("foo", "localhost", System.getProperty("user.name"));
+    }
+
+    @Test (expectedExceptions = IllegalArgumentException.class,
+           expectedExceptionsMessageRegExp = "proxyUser cannot be null or empty, .*")
+    public void testNullProxyUser() throws Exception {
+        proxyUserService.init();
+        proxyUserService.validate(null, "localhost", "bar");
+    }
+
+    @Test (expectedExceptions = IllegalArgumentException.class,
+           expectedExceptionsMessageRegExp = "proxyHost cannot be null or empty, .*")
+    public void testNullHost() throws Exception {
+        proxyUserService.init();
+        proxyUserService.validate("foo", null, "bar");
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/falcon/blob/d8fbec9f/docs/src/site/twiki/FalconCLI.twiki
----------------------------------------------------------------------
diff --git a/docs/src/site/twiki/FalconCLI.twiki b/docs/src/site/twiki/FalconCLI.twiki
index 8bf3155..4f72bf8 100644
--- a/docs/src/site/twiki/FalconCLI.twiki
+++ b/docs/src/site/twiki/FalconCLI.twiki
@@ -2,6 +2,20 @@
 
 FalconCLI is a interface between user and Falcon. It is a command line utility provided by Falcon. FalconCLI supports Entity Management, Instance Management and Admin operations.There is a set of web services that are used by FalconCLI to interact with Falcon.
 
+---++Common CLI Options
+
+---+++Falcon URL
+
+Optional -url option indicating the URL of the Falcon system to run the command against can be provided.  If not mentioned it will be picked from the system environment variable FALCON_URL. If FALCON_URL is not set then it will be picked from client.properties file. If the option is not
+provided and also not set in client.properties, Falcon CLI will fail.
+
+---+++Proxy user support
+
+The -doAs option allows the current user to impersonate other users when interacting with the Falcon system. The current user must be configured as a proxyuser in the Falcon system. The proxyuser configuration may restrict from
+which hosts a user may impersonate users, as well as users of which groups can be impersonated.
+
+<a href="./FalconDocumentation.html#Proxyuser_support">Proxyuser support described here.</a>
+
 ---++Entity Management Operations
 
 ---+++Submit

http://git-wip-us.apache.org/repos/asf/falcon/blob/d8fbec9f/docs/src/site/twiki/FalconDocumentation.twiki
----------------------------------------------------------------------
diff --git a/docs/src/site/twiki/FalconDocumentation.twiki b/docs/src/site/twiki/FalconDocumentation.twiki
index 29d93f7..68ed2e2 100644
--- a/docs/src/site/twiki/FalconDocumentation.twiki
+++ b/docs/src/site/twiki/FalconDocumentation.twiki
@@ -16,6 +16,7 @@
    * <a href="#Recipes">Recipes</a>
    * <a href="#Monitoring">Monitoring</a>
    * <a href="#Backwards_Compatibility">Backwards Compatibility Instructions</a>
+   * <a href="#Proxyuser_support">Proxyuser support</a>
 
 ---++ Architecture
 
@@ -724,3 +725,28 @@ Monitoring and Operationalizing Falcon is detailed in [[Operability][Operability
 ---++ Backwards Compatibility
 
 Backwards compatibility instructions are [[Compatibility][detailed here.]]
+
+---++ Proxyuser support
+Falcon supports impersonation or proxyuser functionality (identical to Hadoop proxyuser capabilities and conceptually
+similar to Unix 'sudo').
+
+Proxyuser enables Falcon clients to submit entities on behalf of other users. Falcon will utilize Hadoop core's hadoop-auth
+module to implement this functionality.
+
+Because proxyuser is a powerful capability, Falcon provides the following restriction capabilities (similar to Hadoop):
+
+   * Proxyuser is an explicit configuration on per proxyuser user basis.
+   * A proxyuser user can be restricted to impersonate other users from a set of hosts.
+   * A proxyuser user can be restricted to impersonate users belonging to a set of groups.
+
+There are 2 configuration properties needed in runtime properties to set up a proxyuser:
+   * falcon.service.ProxyUserService.proxyuser.#USER#.hosts: hosts from where the user #USER# can impersonate other users.
+   * falcon.service.ProxyUserService.proxyuser.#USER#.groups: groups the users being impersonated by user #USER# must belong to.
+
+If these configurations are not present, impersonation will not be allowed and connection will fail. If more lax security is preferred,
+the wildcard value * may be used to allow impersonation from any host or of any user, although this is recommended only for testing/development.
+
+-doAs option via  CLI or doAs query parameter can be appended if using API to enable impersonation.
+
+
+

http://git-wip-us.apache.org/repos/asf/falcon/blob/d8fbec9f/docs/src/site/twiki/restapi/AdjacentVertices.twiki
----------------------------------------------------------------------
diff --git a/docs/src/site/twiki/restapi/AdjacentVertices.twiki b/docs/src/site/twiki/restapi/AdjacentVertices.twiki
index 44b4d70..1e60866 100644
--- a/docs/src/site/twiki/restapi/AdjacentVertices.twiki
+++ b/docs/src/site/twiki/restapi/AdjacentVertices.twiki
@@ -9,6 +9,7 @@ Get a list of adjacent vertices or edges with a direction.
 
 ---++ Parameters
    * :id is the id of the vertex.
+   * doAs <optional query param> allows the current user to impersonate the user passed in doAs when interacting with the Falcon system.
    * :direction is the direction associated with the edges.
 
    To get the adjacent out vertices of vertex pass direction as out, in to get adjacent in vertices
@@ -68,3 +69,23 @@ GET http://localhost:15000/api/metadata/lineage/vertices/4/bothE
     "totalSize":1
 }
 </verbatim>
+
+---+++ Rest Call
+<verbatim>
+GET http://localhost:15000/api/metadata/lineage/vertices/4/bothE?doAs=joe
+</verbatim>
+---+++ Result
+<verbatim>
+{
+    "results":[
+        {
+            "_id":"Q5V-4-5g",
+            "_type":"edge",
+            "_outV":4,
+            "_inV":8,
+            "_label":"output"
+        }
+    ],
+    "totalSize":1
+}
+</verbatim>

http://git-wip-us.apache.org/repos/asf/falcon/blob/d8fbec9f/docs/src/site/twiki/restapi/AdminStack.twiki
----------------------------------------------------------------------
diff --git a/docs/src/site/twiki/restapi/AdminStack.twiki b/docs/src/site/twiki/restapi/AdminStack.twiki
index 79dbd9b..08903a2 100644
--- a/docs/src/site/twiki/restapi/AdminStack.twiki
+++ b/docs/src/site/twiki/restapi/AdminStack.twiki
@@ -8,14 +8,15 @@
 Get stack trace of the falcon server.
 
 ---++ Parameters
-None.
+   * doAs <optional query param> allows the current user to impersonate the user passed in doAs when interacting with the Falcon system.
+
 ---++ Results
 Stack trace of the server.
 
 ---++ Examples
 ---+++ Rest Call
 <verbatim>
-GET http://localhost:15000/api/admin/stack
+GET http://localhost:15000/api/admin/stack?doAs=joe
 </verbatim>
 ---+++ Result
 <verbatim>

http://git-wip-us.apache.org/repos/asf/falcon/blob/d8fbec9f/docs/src/site/twiki/restapi/AdminVersion.twiki
----------------------------------------------------------------------
diff --git a/docs/src/site/twiki/restapi/AdminVersion.twiki b/docs/src/site/twiki/restapi/AdminVersion.twiki
index 00b0283..7db2d8f 100644
--- a/docs/src/site/twiki/restapi/AdminVersion.twiki
+++ b/docs/src/site/twiki/restapi/AdminVersion.twiki
@@ -8,14 +8,15 @@
 Get version of the falcon server.
 
 ---++ Parameters
-None.
+   * doAs <optional query param> allows the current user to impersonate the user passed in doAs when interacting with the Falcon system.
+
 ---++ Results
 Version of the server.
 
 ---++ Examples
 ---+++ Rest Call
 <verbatim>
-GET http://localhost:15000/api/admin/version
+GET http://localhost:15000/api/admin/version?doAs=joe
 </verbatim>
 ---+++ Result
 <verbatim>

http://git-wip-us.apache.org/repos/asf/falcon/blob/d8fbec9f/docs/src/site/twiki/restapi/AllEdges.twiki
----------------------------------------------------------------------
diff --git a/docs/src/site/twiki/restapi/AllEdges.twiki b/docs/src/site/twiki/restapi/AllEdges.twiki
index 2fb662e..303ac50 100644
--- a/docs/src/site/twiki/restapi/AllEdges.twiki
+++ b/docs/src/site/twiki/restapi/AllEdges.twiki
@@ -8,7 +8,7 @@
 Get all edges.
 
 ---++ Parameters
-None.
+   * doAs <optional query param> allows the current user to impersonate the user passed in doAs when interacting with the Falcon system.
 
 ---++ Results
 All edges in lineage graph.
@@ -16,7 +16,7 @@ All edges in lineage graph.
 ---++ Examples
 ---+++ Rest Call
 <verbatim>
-GET http://localhost:15000/api/metadata/lineage/edges/all
+GET http://localhost:15000/api/metadata/lineage/edges/all?doAs=joe
 </verbatim>
 ---+++ Result
 <verbatim>

http://git-wip-us.apache.org/repos/asf/falcon/blob/d8fbec9f/docs/src/site/twiki/restapi/AllVertices.twiki
----------------------------------------------------------------------
diff --git a/docs/src/site/twiki/restapi/AllVertices.twiki b/docs/src/site/twiki/restapi/AllVertices.twiki
index 4b29afe..d2beb48 100644
--- a/docs/src/site/twiki/restapi/AllVertices.twiki
+++ b/docs/src/site/twiki/restapi/AllVertices.twiki
@@ -8,7 +8,7 @@
 Get all vertices.
 
 ---++ Parameters
-None.
+   * doAs <optional query param> allows the current user to impersonate the user passed in doAs when interacting with the Falcon system.
 
 ---++ Results
 All vertices in lineage graph.
@@ -16,7 +16,7 @@ All vertices in lineage graph.
 ---++ Examples
 ---+++ Rest Call
 <verbatim>
-GET http://localhost:15000/api/metadata/lineage/vertices/all
+GET http://localhost:15000/api/metadata/lineage/vertices/all?doAs=joe
 </verbatim>
 ---+++ Result
 <verbatim>

http://git-wip-us.apache.org/repos/asf/falcon/blob/d8fbec9f/docs/src/site/twiki/restapi/Edge.twiki
----------------------------------------------------------------------
diff --git a/docs/src/site/twiki/restapi/Edge.twiki b/docs/src/site/twiki/restapi/Edge.twiki
index be4f20e..7c4dbe5 100644
--- a/docs/src/site/twiki/restapi/Edge.twiki
+++ b/docs/src/site/twiki/restapi/Edge.twiki
@@ -9,6 +9,7 @@ Gets the edge with specified id.
 
 ---++ Parameters
    * :id is the unique id of the edge.
+   * doAs <optional query param> allows the current user to impersonate the user passed in doAs when interacting with the Falcon system.
 
 ---++ Results
 Edge with the specified id.
@@ -16,7 +17,7 @@ Edge with the specified id.
 ---++ Examples
 ---+++ Rest Call
 <verbatim>
-GET http://localhost:15000/api/metadata/lineage/edges/Q6t-c-5g
+GET http://localhost:15000/api/metadata/lineage/edges/Q6t-c-5g?doAs=joe
 </verbatim>
 ---+++ Result
 <verbatim>

http://git-wip-us.apache.org/repos/asf/falcon/blob/d8fbec9f/docs/src/site/twiki/restapi/EntityDefinition.twiki
----------------------------------------------------------------------
diff --git a/docs/src/site/twiki/restapi/EntityDefinition.twiki b/docs/src/site/twiki/restapi/EntityDefinition.twiki
index 1f76a4f..5e1165b 100644
--- a/docs/src/site/twiki/restapi/EntityDefinition.twiki
+++ b/docs/src/site/twiki/restapi/EntityDefinition.twiki
@@ -10,6 +10,7 @@ Get definition of the entity.
 ---++ Parameters
    * :entity-type can be cluster, feed or process.
    * :entity-name is name of the entity.
+   * doAs <optional query param> allows the current user to impersonate the user passed in doAs when interacting with the Falcon system.
 
 ---++ Results
 Definition of the entity.
@@ -17,7 +18,7 @@ Definition of the entity.
 ---++ Examples
 ---+++ Rest Call
 <verbatim>
-GET http://localhost:15000/api/entities/definition/process/SampleProcess
+GET http://localhost:15000/api/entities/definition/process/SampleProcess?doAs=joe
 </verbatim>
 ---+++ Result
 <verbatim>

http://git-wip-us.apache.org/repos/asf/falcon/blob/d8fbec9f/docs/src/site/twiki/restapi/EntityDelete.twiki
----------------------------------------------------------------------
diff --git a/docs/src/site/twiki/restapi/EntityDelete.twiki b/docs/src/site/twiki/restapi/EntityDelete.twiki
index 850b451..a488943 100644
--- a/docs/src/site/twiki/restapi/EntityDelete.twiki
+++ b/docs/src/site/twiki/restapi/EntityDelete.twiki
@@ -10,6 +10,7 @@ Delete the specified entity.
 ---++ Parameters
    * :entity-type can be feed or process.
    * :entity-name is name of the feed or process.
+   * doAs <optional query param> allows the current user to impersonate the user passed in doAs when interacting with the Falcon system.
 
 ---++ Results
 Results of the delete operation.
@@ -17,7 +18,7 @@ Results of the delete operation.
 ---++ Examples
 ---+++ Rest Call
 <verbatim>
-DELETE http://localhost:15000/api/entities/delete/cluster/SampleProcess
+DELETE http://localhost:15000/api/entities/delete/cluster/SampleProcess?doAs=joe
 </verbatim>
 ---+++ Result
 <verbatim>

http://git-wip-us.apache.org/repos/asf/falcon/blob/d8fbec9f/docs/src/site/twiki/restapi/EntityDependencies.twiki
----------------------------------------------------------------------
diff --git a/docs/src/site/twiki/restapi/EntityDependencies.twiki b/docs/src/site/twiki/restapi/EntityDependencies.twiki
index 57fc256..864b084 100644
--- a/docs/src/site/twiki/restapi/EntityDependencies.twiki
+++ b/docs/src/site/twiki/restapi/EntityDependencies.twiki
@@ -10,6 +10,7 @@ Get dependencies of the entity.
 ---++ Parameters
    * :entity-type can be cluster, feed or process.
    * :entity-name is name of the entity.
+   * doAs <optional query param> allows the current user to impersonate the user passed in doAs when interacting with the Falcon system.
 
 ---++ Results
 Dependenciess of the entity.
@@ -17,7 +18,7 @@ Dependenciess of the entity.
 ---++ Examples
 ---+++ Rest Call
 <verbatim>
-GET http://localhost:15000/api/entities/dependencies/process/SampleProcess
+GET http://localhost:15000/api/entities/dependencies/process/SampleProcess?doAs=joe
 </verbatim>
 ---+++ Result
 <verbatim>

http://git-wip-us.apache.org/repos/asf/falcon/blob/d8fbec9f/docs/src/site/twiki/restapi/EntityLineage.twiki
----------------------------------------------------------------------
diff --git a/docs/src/site/twiki/restapi/EntityLineage.twiki b/docs/src/site/twiki/restapi/EntityLineage.twiki
index ea747b1..f2258f2 100644
--- a/docs/src/site/twiki/restapi/EntityLineage.twiki
+++ b/docs/src/site/twiki/restapi/EntityLineage.twiki
@@ -9,6 +9,7 @@ It returns the graph depicting the relationship between the various processes an
 
 ---++ Parameters
    * :pipeline is the name of the pipeline
+   * doAs <optional query param> allows the current user to impersonate the user passed in doAs when interacting with the Falcon system.
 
 ---++ Results
 It returns a json graph
@@ -16,7 +17,7 @@ It returns a json graph
 ---++ Examples
 ---+++ Rest Call
 <verbatim>
-GET http://localhost:15000/api/metadata/lineage/entities?pipeline=my-pipeline
+GET http://localhost:15000/api/metadata/lineage/entities?pipeline=my-pipeline&doAs=joe
 </verbatim>
 ---+++ Result
 <verbatim>

http://git-wip-us.apache.org/repos/asf/falcon/blob/d8fbec9f/docs/src/site/twiki/restapi/EntityList.twiki
----------------------------------------------------------------------
diff --git a/docs/src/site/twiki/restapi/EntityList.twiki b/docs/src/site/twiki/restapi/EntityList.twiki
index 00046e2..2c2a734 100644
--- a/docs/src/site/twiki/restapi/EntityList.twiki
+++ b/docs/src/site/twiki/restapi/EntityList.twiki
@@ -27,6 +27,7 @@ Get list of the entities.
    * sortOrder <optional param> Valid options are "asc" and "desc"
    * offset <optional param> Show results from the offset, used for pagination. Defaults to 0.
    * numResults <optional param> Number of results to show per request, used for pagination. Only integers > 0 are valid, Default is 10.
+   * doAs <optional query param> allows the current user to impersonate the user passed in doAs when interacting with the Falcon system.
    * Note:
       * We have two filtering parameters for entity tags: "tags" and "tagkeys". "tags" does the exact match in key=value fashion, while "tagkeys" finds all the entities with the given key as a substring in the tags. This "tagkeys" filter is introduced for the user who doesn't remember the exact tag but some keywords in the tag. It also helps users to save the time of typing long tags.
       * The returned entities will match all the filtering criteria.
@@ -137,7 +138,7 @@ GET http://localhost:15000/api/entities/list/process?filterBy=STATUS:RUNNING,PIP
 
 ---+++ Rest Call
 <verbatim>
-GET http://localhost:15000/api/entities/list/feed,process?nameseq=samplebill&tagkeys=billing,healthcare&numResults=2&offset=1&fields=status,clusters,tags
+GET http://localhost:15000/api/entities/list/feed,process?nameseq=samplebill&tagkeys=billing,healthcare&numResults=2&offset=1&fields=status,clusters,tags&doAs=joe
 </verbatim>
 ---+++ Result
 <verbatim>

http://git-wip-us.apache.org/repos/asf/falcon/blob/d8fbec9f/docs/src/site/twiki/restapi/EntityResume.twiki
----------------------------------------------------------------------
diff --git a/docs/src/site/twiki/restapi/EntityResume.twiki b/docs/src/site/twiki/restapi/EntityResume.twiki
index a2d5184..d0bbe41 100644
--- a/docs/src/site/twiki/restapi/EntityResume.twiki
+++ b/docs/src/site/twiki/restapi/EntityResume.twiki
@@ -10,6 +10,7 @@ Resume a supended entity.
 ---++ Parameters
    * :entity-type can either be a feed or a process.
    * :entity-name is name of the entity.
+   * doAs <optional query param> allows the current user to impersonate the user passed in doAs when interacting with the Falcon system.
 
 ---++ Results
 Result of the resume command.
@@ -17,7 +18,7 @@ Result of the resume command.
 ---++ Examples
 ---+++ Rest Call
 <verbatim>
-POST http://localhost:15000/api/entities/resume/process/SampleProcess
+POST http://localhost:15000/api/entities/resume/process/SampleProcess?doAs=joe
 </verbatim>
 ---+++ Result
 <verbatim>

http://git-wip-us.apache.org/repos/asf/falcon/blob/d8fbec9f/docs/src/site/twiki/restapi/EntitySchedule.twiki
----------------------------------------------------------------------
diff --git a/docs/src/site/twiki/restapi/EntitySchedule.twiki b/docs/src/site/twiki/restapi/EntitySchedule.twiki
index 1ebdf30..263d152 100644
--- a/docs/src/site/twiki/restapi/EntitySchedule.twiki
+++ b/docs/src/site/twiki/restapi/EntitySchedule.twiki
@@ -1,4 +1,4 @@
----++  POST /api/entities/schedule/:entity-type/:entity-name?skipDryRun=false
+---++  POST /api/entities/schedule/:entity-type/:entity-name
    * <a href="#Description">Description</a>
    * <a href="#Parameters">Parameters</a>
    * <a href="#Results">Results</a>
@@ -11,6 +11,7 @@ Schedule an entity.
    * :entity-type can either be a feed or a process.
    * :entity-name is name of the entity.
    * skipDryRun : Optional query param, Falcon skips oozie dryrun when value is set to true.
+   * doAs <optional query param> allows the current user to impersonate the user passed in doAs when interacting with the Falcon system.
 
 
 ---++ Results
@@ -19,7 +20,7 @@ Result of the schedule command.
 ---++ Examples
 ---+++ Rest Call
 <verbatim>
-POST http://localhost:15000/api/entities/schedule/process/SampleProcess
+POST http://localhost:15000/api/entities/schedule/process/SampleProcess?skipDryRun=false&doAs=joe
 </verbatim>
 ---+++ Result
 <verbatim>

http://git-wip-us.apache.org/repos/asf/falcon/blob/d8fbec9f/docs/src/site/twiki/restapi/EntityStatus.twiki
----------------------------------------------------------------------
diff --git a/docs/src/site/twiki/restapi/EntityStatus.twiki b/docs/src/site/twiki/restapi/EntityStatus.twiki
index 34d166d..188019d 100644
--- a/docs/src/site/twiki/restapi/EntityStatus.twiki
+++ b/docs/src/site/twiki/restapi/EntityStatus.twiki
@@ -10,6 +10,7 @@ Get status of the entity.
 ---++ Parameters
    * :entity-type can be cluster, feed or process.
    * :entity-name is name of the entity.
+   * doAs <optional query param> allows the current user to impersonate the user passed in doAs when interacting with the Falcon system.
 
 ---++ Results
 Status of the entity.
@@ -17,7 +18,7 @@ Status of the entity.
 ---++ Examples
 ---+++ Rest Call
 <verbatim>
-GET http://localhost:15000/api/entities/status/process/SampleProcess
+GET http://localhost:15000/api/entities/status/process/SampleProcess?doAs=joe
 </verbatim>
 ---+++ Result
 <verbatim>

http://git-wip-us.apache.org/repos/asf/falcon/blob/d8fbec9f/docs/src/site/twiki/restapi/EntitySubmit.twiki
----------------------------------------------------------------------
diff --git a/docs/src/site/twiki/restapi/EntitySubmit.twiki b/docs/src/site/twiki/restapi/EntitySubmit.twiki
index 925381c..a8dc9d7 100644
--- a/docs/src/site/twiki/restapi/EntitySubmit.twiki
+++ b/docs/src/site/twiki/restapi/EntitySubmit.twiki
@@ -8,7 +8,8 @@
 Submit the given entity.
 
 ---++ Parameters
-:entity-type can be cluster, feed or process.
+   * :entity-type can be cluster, feed or process.
+   * doAs <optional query param> allows the current user to impersonate the user passed in doAs when interacting with the Falcon system.
 
 ---++ Results
 Result of the submission.
@@ -57,7 +58,7 @@ POST http://localhost:15000/api/entities/submit/feed
 
 ---+++ Rest Call
 <verbatim>
-POST http://localhost:15000/api/entities/submit/process
+POST http://localhost:15000/api/entities/submit/process?doAs=joe
 <?xml version="1.0" encoding="UTF-8"?>
 <!-- Daily sample process. Runs at 6th hour every day. Input - last day's hourly data. Generates output for yesterday -->
 <process xmlns="uri:falcon:process:0.1" name="SampleProcess" >

http://git-wip-us.apache.org/repos/asf/falcon/blob/d8fbec9f/docs/src/site/twiki/restapi/EntitySubmitAndSchedule.twiki
----------------------------------------------------------------------
diff --git a/docs/src/site/twiki/restapi/EntitySubmitAndSchedule.twiki b/docs/src/site/twiki/restapi/EntitySubmitAndSchedule.twiki
index a6516bb..3cc23e9 100644
--- a/docs/src/site/twiki/restapi/EntitySubmitAndSchedule.twiki
+++ b/docs/src/site/twiki/restapi/EntitySubmitAndSchedule.twiki
@@ -1,4 +1,4 @@
----++  POST /api/entities/submitAndSchedule/:entity-type?skipDryRun=false
+---++  POST /api/entities/submitAndSchedule/:entity-type
    * <a href="#Description">Description</a>
    * <a href="#Parameters">Parameters</a>
    * <a href="#Results">Results</a>
@@ -10,6 +10,7 @@ Submits and schedules an entity.
 ---++ Parameters
    * :entity-type can either be a feed or a process.
    * skipDryRun : Optional query param, Falcon skips oozie dryrun when value is set to true.
+   * doAs <optional query param> allows the current user to impersonate the user passed in doAs when interacting with the Falcon system.
 
 ---++ Results
 Result of the submit and schedule command.
@@ -17,7 +18,7 @@ Result of the submit and schedule command.
 ---++ Examples
 ---+++ Rest Call
 <verbatim>
-POST http://localhost:15000/api/entities/submitAndSchedule/process
+POST http://localhost:15000/api/entities/submitAndSchedule/process?skipDryRun=false&doAs=joe
 <?xml version="1.0" encoding="UTF-8"?>
 <!-- Daily sample process. Runs at 6th hour every day. Input - last day's hourly data. Generates output for yesterday -->
 <process xmlns="uri:falcon:process:0.1" name="SampleProcess" >

http://git-wip-us.apache.org/repos/asf/falcon/blob/d8fbec9f/docs/src/site/twiki/restapi/EntitySummary.twiki
----------------------------------------------------------------------
diff --git a/docs/src/site/twiki/restapi/EntitySummary.twiki b/docs/src/site/twiki/restapi/EntitySummary.twiki
index 8e05a12..763c2a7 100644
--- a/docs/src/site/twiki/restapi/EntitySummary.twiki
+++ b/docs/src/site/twiki/restapi/EntitySummary.twiki
@@ -27,6 +27,7 @@ Given an EntityType and cluster, get list of entities along with summary of N re
    * offset <optional param> Show results from the offset, used for pagination. Defaults to 0.
    * numResults <optional param> Number of results to show per request, used for pagination. Only integers > 0 are valid, Default is 10.
    * numInstances <optional param> Number of recent instances to show per entity. Only integers > 0 are valid, Default is 7.
+   * doAs <optional query param> allows the current user to impersonate the user passed in doAs when interacting with the Falcon system.
 
 ---++ Results
 Show entities along with summary of N instances for each entity.
@@ -34,7 +35,7 @@ Show entities along with summary of N instances for each entity.
 ---++ Examples
 ---+++ Rest Call
 <verbatim>
-GET http://localhost:15000/api/entities/summary/feed?cluster=primary-cluster&filterBy=STATUS:RUNNING&fields=status&tags=consumer=consumer@xyz.com&orderBy=name&offset=0&numResults=1&numInstances=2
+GET http://localhost:15000/api/entities/summary/feed?cluster=primary-cluster&filterBy=STATUS:RUNNING&fields=status&tags=consumer=consumer@xyz.com&orderBy=name&offset=0&numResults=1&numInstances=2&doAs=joe
 </verbatim>
 ---+++ Result
 <verbatim>

http://git-wip-us.apache.org/repos/asf/falcon/blob/d8fbec9f/docs/src/site/twiki/restapi/EntitySuspend.twiki
----------------------------------------------------------------------
diff --git a/docs/src/site/twiki/restapi/EntitySuspend.twiki b/docs/src/site/twiki/restapi/EntitySuspend.twiki
index 9e5efca..b322b27 100644
--- a/docs/src/site/twiki/restapi/EntitySuspend.twiki
+++ b/docs/src/site/twiki/restapi/EntitySuspend.twiki
@@ -10,6 +10,7 @@ Suspend an entity.
 ---++ Parameters
    * :entity-type can either be a feed or a process.
    * :entity-name is name of the entity.
+   * doAs <optional query param> allows the current user to impersonate the user passed in doAs when interacting with the Falcon system.
 
 ---++ Results
 Status of the entity.
@@ -17,7 +18,7 @@ Status of the entity.
 ---++ Examples
 ---+++ Rest Call
 <verbatim>
-POST http://localhost:15000/api/entities/suspend/process/SampleProcess
+POST http://localhost:15000/api/entities/suspend/process/SampleProcess?doAs=joe
 </verbatim>
 ---+++ Result
 <verbatim>

http://git-wip-us.apache.org/repos/asf/falcon/blob/d8fbec9f/docs/src/site/twiki/restapi/EntityTouch.twiki
----------------------------------------------------------------------
diff --git a/docs/src/site/twiki/restapi/EntityTouch.twiki b/docs/src/site/twiki/restapi/EntityTouch.twiki
index 69e6d1b..5b58ce2 100644
--- a/docs/src/site/twiki/restapi/EntityTouch.twiki
+++ b/docs/src/site/twiki/restapi/EntityTouch.twiki
@@ -1,4 +1,4 @@
----++ POST  api/entities/touch/:entity-type/:entity-name?skipDryRun=true
+---++ POST  api/entities/touch/:entity-type/:entity-name
    * <a href="#Description">Description</a>
    * <a href="#Parameters">Parameters</a>
    * <a href="#Results">Results</a>
@@ -11,6 +11,7 @@ Force updates the entity.
    * :entity-type can be feed or process.
    * :entity-name is name of the feed or process.
    * skipDryRun : Optional query param, Falcon skips oozie dryrun when value is set to true.
+   * doAs <optional query param> allows the current user to impersonate the user passed in doAs when interacting with the Falcon system.
 
 ---++ Results
 Result of the validation.
@@ -18,7 +19,7 @@ Result of the validation.
 ---++ Examples
 ---+++ Rest Call
 <verbatim>
-POST http://localhost:15000/api/entities/touch/process/SampleProcess
+POST http://localhost:15000/api/entities/touch/process/SampleProcess?skipDryRun=true&doAs=joe
 </verbatim>
 ---+++ Result
 <verbatim>
@@ -27,4 +28,4 @@ POST http://localhost:15000/api/entities/touch/process/SampleProcess
     "message": "touch\/default\/SampleProcess updated successfully\n\n",
     "status": "SUCCEEDED"
 }
-</verbatim>
\ No newline at end of file
+</verbatim>

http://git-wip-us.apache.org/repos/asf/falcon/blob/d8fbec9f/docs/src/site/twiki/restapi/EntityUpdate.twiki
----------------------------------------------------------------------
diff --git a/docs/src/site/twiki/restapi/EntityUpdate.twiki b/docs/src/site/twiki/restapi/EntityUpdate.twiki
index ba618df..46b01fc 100644
--- a/docs/src/site/twiki/restapi/EntityUpdate.twiki
+++ b/docs/src/site/twiki/restapi/EntityUpdate.twiki
@@ -1,4 +1,4 @@
----++ POST  api/entities/update/:entity-type/:entity-name?skipDryRun=false
+---++ POST  api/entities/update/:entity-type/:entity-name
    * <a href="#Description">Description</a>
    * <a href="#Parameters">Parameters</a>
    * <a href="#Results">Results</a>
@@ -11,6 +11,7 @@ Updates the submitted entity.
    * :entity-type can be feed or process.
    * :entity-name is name of the feed or process.
    * skipDryRun : Optional query param, Falcon skips oozie dryrun when value is set to true.
+   * doAs <optional query param> allows the current user to impersonate the user passed in doAs when interacting with the Falcon system.
 
 ---++ Results
 Result of the validation.
@@ -18,7 +19,7 @@ Result of the validation.
 ---++ Examples
 ---+++ Rest Call
 <verbatim>
-POST http://localhost:15000/api/entities/update/process/SampleProcess
+POST http://localhost:15000/api/entities/update/process/SampleProcess?skipDryRun=false&doAs=joe
 <?xml version="1.0" encoding="UTF-8"?>
 <!-- Daily sample process. Runs at 6th hour every day. Input - last day's hourly data. Generates output for yesterday -->
 <process xmlns="uri:falcon:process:0.1" name="SampleProcess" >

http://git-wip-us.apache.org/repos/asf/falcon/blob/d8fbec9f/docs/src/site/twiki/restapi/EntityValidate.twiki
----------------------------------------------------------------------
diff --git a/docs/src/site/twiki/restapi/EntityValidate.twiki b/docs/src/site/twiki/restapi/EntityValidate.twiki
index 86de630..054b083 100644
--- a/docs/src/site/twiki/restapi/EntityValidate.twiki
+++ b/docs/src/site/twiki/restapi/EntityValidate.twiki
@@ -1,4 +1,4 @@
----++ POST  api/entities/validate/entity-type?skipDryRun=false
+---++ POST  api/entities/validate/entity-type
    * <a href="#Description">Description</a>
    * <a href="#Parameters">Parameters</a>
    * <a href="#Results">Results</a>
@@ -10,6 +10,7 @@ Validates the submitted entity.
 ---++ Parameters
    * :entity-type can be cluster, feed or process.
    * skipDryRun : Optional query param, Falcon skips oozie dryrun when value is set to true.
+   * doAs <optional query param> allows the current user to impersonate the user passed in doAs when interacting with the Falcon system.
 
 ---++ Results
 Result of the validation.
@@ -122,7 +123,7 @@ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
 
 ---+++ Rest Call
 <verbatim>
-POST http://localhost:15000/api/entities/validate/process
+POST http://localhost:15000/api/entities/validate/process?skipDryRun=false&doAs=joe
 <?xml version="1.0" encoding="UTF-8"?>
 <!-- Daily sample process. Runs at 6th hour every day. Input - last day's hourly data. Generates output for yesterday -->
 <process xmlns="uri:falcon:process:0.1" name="SampleProcess" >

http://git-wip-us.apache.org/repos/asf/falcon/blob/d8fbec9f/docs/src/site/twiki/restapi/FeedInstanceListing.twiki
----------------------------------------------------------------------
diff --git a/docs/src/site/twiki/restapi/FeedInstanceListing.twiki b/docs/src/site/twiki/restapi/FeedInstanceListing.twiki
index a3e306d..03f3c57 100644
--- a/docs/src/site/twiki/restapi/FeedInstanceListing.twiki
+++ b/docs/src/site/twiki/restapi/FeedInstanceListing.twiki
@@ -14,6 +14,7 @@ Get falcon feed instance availability.
    * end <optional param> Show instances up to this date. Date format is yyyy-MM-dd'T'HH:mm'Z'.
       * Default is set to now.
    * colo <optional param> Colo on which the query should be run.
+   * doAs <optional query param> allows the current user to impersonate the user passed in doAs when interacting with the Falcon system.
 
 ---++ Results
 Feed instance availability status
@@ -21,7 +22,7 @@ Feed instance availability status
 ---++ Examples
 ---+++ Rest Call
 <verbatim>
-GET http://localhost:15000/api/instance/listing/feed/SampleFeed?colo=*&start=2012-04-03T07:00Z
+GET http://localhost:15000/api/instance/listing/feed/SampleFeed?colo=*&start=2012-04-03T07:00Z&doAs=joe
 </verbatim>
 ---+++ Result
 <verbatim>

http://git-wip-us.apache.org/repos/asf/falcon/blob/d8fbec9f/docs/src/site/twiki/restapi/FeedLookup.twiki
----------------------------------------------------------------------
diff --git a/docs/src/site/twiki/restapi/FeedLookup.twiki b/docs/src/site/twiki/restapi/FeedLookup.twiki
index 1ad91d8..053182b 100644
--- a/docs/src/site/twiki/restapi/FeedLookup.twiki
+++ b/docs/src/site/twiki/restapi/FeedLookup.twiki
@@ -9,6 +9,7 @@
 ---++ Parameters
     * path path of the instance for which you want to determine the feed. e.g. /data/project1/2014/10/10/23/
     Path has to be the complete path and can't be a part of it.
+    * doAs <optional query param> allows the current user to impersonate the user passed in doAs when interacting with the Falcon system.
 
 ---++ Results
 Returns the name of the feed along with the location type(meta/data/stats) and cluster on which the given path belongs to this feed.
@@ -16,7 +17,7 @@ Returns the name of the feed along with the location type(meta/data/stats) and c
 ---++ Examples
 ---+++ Rest Call
 <verbatim>
-GET http://localhost:15000/api/entities/lookup/feed?path=/data/project1/2014/10/10/23
+GET http://localhost:15000/api/entities/lookup/feed?path=/data/project1/2014/10/10/23&doAs=joe
 </verbatim>
 ---+++ Result
 {
@@ -33,4 +34,4 @@ GET http://localhost:15000/api/entities/lookup/feed?path=/data/project1/2014/10/
            "clusterName": "My-cluster2"
         }
     ]
-}
\ No newline at end of file
+}

http://git-wip-us.apache.org/repos/asf/falcon/blob/d8fbec9f/docs/src/site/twiki/restapi/Graph.twiki
----------------------------------------------------------------------
diff --git a/docs/src/site/twiki/restapi/Graph.twiki b/docs/src/site/twiki/restapi/Graph.twiki
index 6cf6faa..db58d2e 100644
--- a/docs/src/site/twiki/restapi/Graph.twiki
+++ b/docs/src/site/twiki/restapi/Graph.twiki
@@ -8,7 +8,7 @@
 Dump the graph.
 
 ---++ Parameters
-None.
+   * doAs <optional query param> allows the current user to impersonate the user passed in doAs when interacting with the Falcon system.
 
 ---++ Results
 Serialize graph to a file configured using *.falcon.graph.serialize.path in Custom startup.properties.
@@ -16,7 +16,7 @@ Serialize graph to a file configured using *.falcon.graph.serialize.path in Cust
 ---++ Examples
 ---+++ Rest Call
 <verbatim>
-GET http://localhost:15000/api/metadata/lineage/serialize
+GET http://localhost:15000/api/metadata/lineage/serialize?doAs=joe
 </verbatim>
 ---+++ Result
 None.

http://git-wip-us.apache.org/repos/asf/falcon/blob/d8fbec9f/docs/src/site/twiki/restapi/InstanceKill.twiki
----------------------------------------------------------------------
diff --git a/docs/src/site/twiki/restapi/InstanceKill.twiki b/docs/src/site/twiki/restapi/InstanceKill.twiki
index 4cdd4ac..eb22945 100644
--- a/docs/src/site/twiki/restapi/InstanceKill.twiki
+++ b/docs/src/site/twiki/restapi/InstanceKill.twiki
@@ -13,6 +13,7 @@ Kill currently running instance(s) of an entity.
    * start is the start time of the instance(s) that you want to refer to
    * end is the end time of the instance(s) that you want to refer to
    * lifecycle <optional param> can be Eviction/Replication(default) for feed and Execution(default) for process.
+   * doAs <optional query param> allows the current user to impersonate the user passed in doAs when interacting with the Falcon system.
 
 ---++ Results
 Result of the kill operation.
@@ -20,7 +21,7 @@ Result of the kill operation.
 ---++ Examples
 ---+++ Rest Call
 <verbatim>
-POST http://localhost:15000/api/instance/kill/process/SampleProcess?colo=*&start=2012-04-03T07:00Z&end=2014-04-03T07:00Z
+POST http://localhost:15000/api/instance/kill/process/SampleProcess?colo=*&start=2012-04-03T07:00Z&end=2014-04-03T07:00Z&doAs=joe
 </verbatim>
 ---+++ Result
 <verbatim>

http://git-wip-us.apache.org/repos/asf/falcon/blob/d8fbec9f/docs/src/site/twiki/restapi/InstanceList.twiki
----------------------------------------------------------------------
diff --git a/docs/src/site/twiki/restapi/InstanceList.twiki b/docs/src/site/twiki/restapi/InstanceList.twiki
index 2cd9b1c..229d6f9 100644
--- a/docs/src/site/twiki/restapi/InstanceList.twiki
+++ b/docs/src/site/twiki/restapi/InstanceList.twiki
@@ -24,6 +24,7 @@ Get list of all instances of a given entity.
    * sortOrder <optional param> Valid options are "asc" and "desc"
    * offset <optional param> Show results from the offset, used for pagination. Defaults to 0.
    * numResults <optional param> Number of results to show per request, used for pagination. Only integers > 0 are valid, Default is 10.
+   * doAs <optional query param> allows the current user to impersonate the user passed in doAs when interacting with the Falcon system.
    
 ---++ Results
 List of instances of given entity.
@@ -56,7 +57,7 @@ GET http://localhost:15000/api/instance/list/process/SampleProcess?colo=*&start=
 
 ---+++ Rest Call
 <verbatim>
-GET http://localhost:15000/api/instance/list/process/SampleProcess?colo=*&start=2012-04-03T07:00Z&filterBy=STATUS:SUCCEEDED,CLUSTER:primary-cluster&orderBy=startTime&offset=2&numResults=2
+GET http://localhost:15000/api/instance/list/process/SampleProcess?colo=*&start=2012-04-03T07:00Z&filterBy=STATUS:SUCCEEDED,CLUSTER:primary-cluster&orderBy=startTime&offset=2&numResults=2&doAs=joe
 </verbatim>
 ---+++ Result
 <verbatim>

http://git-wip-us.apache.org/repos/asf/falcon/blob/d8fbec9f/docs/src/site/twiki/restapi/InstanceLogs.twiki
----------------------------------------------------------------------
diff --git a/docs/src/site/twiki/restapi/InstanceLogs.twiki b/docs/src/site/twiki/restapi/InstanceLogs.twiki
index c1103b7..1e1c98d 100644
--- a/docs/src/site/twiki/restapi/InstanceLogs.twiki
+++ b/docs/src/site/twiki/restapi/InstanceLogs.twiki
@@ -25,6 +25,7 @@ Get log of a specific instance of an entity.
    * sortOrder <optional param> Valid options are "asc" and "desc"
    * offset <optional param> Show results from the offset, used for pagination. Defaults to 0.
    * numResults <optional param> Number of results to show per request, used for pagination. Only integers > 0 are valid, Default is 10.
+   * doAs <optional query param> allows the current user to impersonate the user passed in doAs when interacting with the Falcon system.
 
 ---++ Results
 Log of specified instance.
@@ -63,7 +64,7 @@ GET http://localhost:15000/api/instance/logs/process/SampleProcess?colo=*&start=
 
 ---+++ Rest Call
 <verbatim>
-GET http://localhost:15000/api/instance/logs/process/SampleProcess?colo=*&start=2012-04-03T07:00Z&filterBy=STATUS:SUCCEEDED,CLUSTER:primary-cluster&orderBy=startTime&offset=2&numResults=2
+GET http://localhost:15000/api/instance/logs/process/SampleProcess?colo=*&start=2012-04-03T07:00Z&filterBy=STATUS:SUCCEEDED,CLUSTER:primary-cluster&orderBy=startTime&offset=2&numResults=2&doAs=joe
 </verbatim>
 ---+++ Result
 <verbatim>

http://git-wip-us.apache.org/repos/asf/falcon/blob/d8fbec9f/docs/src/site/twiki/restapi/InstanceParams.twiki
----------------------------------------------------------------------
diff --git a/docs/src/site/twiki/restapi/InstanceParams.twiki b/docs/src/site/twiki/restapi/InstanceParams.twiki
index 2c69152..7a340a5 100644
--- a/docs/src/site/twiki/restapi/InstanceParams.twiki
+++ b/docs/src/site/twiki/restapi/InstanceParams.twiki
@@ -13,6 +13,7 @@ Get the params passed to the workflow for an instance of feed/process.
    * start should be the nominal time of the instance for which you want the params to be returned
    * colo <optional param> Colo on which the query should be run.
    * lifecycle <optional param> Valid lifecycles for feed are Eviction/Replication(default) and for process is Execution(default).
+   * doAs <optional query param> allows the current user to impersonate the user passed in doAs when interacting with the Falcon system.
 
 
 ---++ Results
@@ -21,7 +22,7 @@ List of instances currently running.
 ---++ Examples
 ---+++ Rest Call
 <verbatim>
-http://userqa.user.com:16000/api/instance/params/process/Sample-Process?start=2014-10-01T11:00Z&colo=*
+http://userqa.user.com:16000/api/instance/params/process/Sample-Process?start=2014-10-01T11:00Z&colo=*&doAs=joe
 </verbatim>
 ---+++ Result
 {
@@ -79,4 +80,4 @@ http://userqa.user.com:16000/api/instance/params/process/Sample-Process?start=20
             }
         }
     ]
-}
\ No newline at end of file
+}

http://git-wip-us.apache.org/repos/asf/falcon/blob/d8fbec9f/docs/src/site/twiki/restapi/InstanceRerun.twiki
----------------------------------------------------------------------
diff --git a/docs/src/site/twiki/restapi/InstanceRerun.twiki b/docs/src/site/twiki/restapi/InstanceRerun.twiki
index ec30a1e..eef0e1a 100644
--- a/docs/src/site/twiki/restapi/InstanceRerun.twiki
+++ b/docs/src/site/twiki/restapi/InstanceRerun.twiki
@@ -14,6 +14,7 @@ Rerun instances of an entity. On issuing a rerun, by default the execution resum
    * end is the end time of the instance that you want to refer to
    * lifecycle <optional param> can be Eviction/Replication(default) for feed and Execution(default) for process.
    * force <optional param> can be used to forcefully rerun the entire instance.
+   * doAs <optional query param> allows the current user to impersonate the user passed in doAs when interacting with the Falcon system.
 
 ---++ Results
 Results of the rerun command.
@@ -43,7 +44,7 @@ POST http://localhost:15000/api/instance/rerun/process/SampleProcess?colo=*&star
 </verbatim>
 
 <verbatim>
-POST http://localhost:15000/api/instance/rerun/process/SampleProcess?colo=*&start=2013-04-03T07:00Z&end=2014-04-03T07:00Z&force=true
+POST http://localhost:15000/api/instance/rerun/process/SampleProcess?colo=*&start=2013-04-03T07:00Z&end=2014-04-03T07:00Z&force=true&doAs=joe
 </verbatim>
 ---+++ Result
 <verbatim>

http://git-wip-us.apache.org/repos/asf/falcon/blob/d8fbec9f/docs/src/site/twiki/restapi/InstanceResume.twiki
----------------------------------------------------------------------
diff --git a/docs/src/site/twiki/restapi/InstanceResume.twiki b/docs/src/site/twiki/restapi/InstanceResume.twiki
index ab1d06b..1254785 100644
--- a/docs/src/site/twiki/restapi/InstanceResume.twiki
+++ b/docs/src/site/twiki/restapi/InstanceResume.twiki
@@ -13,29 +13,31 @@ Resume suspended instances of an entity.
    * start is the start time of the instance(s) that you want to refer to
    * end is the end time of the instance(s) that you want to refer to
    * lifecycle <optional param> can be Eviction/Replication(default) for feed and Execution(default) for process.
+   * doAs <optional query param> allows the current user to impersonate the user passed in doAs when interacting with the Falcon system.
+
 ---++ Results
 Results of the resume command.
 
 ---++ Examples
 ---+++ Rest Call
-<verbatim>
-POST http://localhost:15000/api/instance/resume/process/SampleProcess?colo=*&start=2012-04-03T07:00Z&end=2014-04-03T07:00Z
-</verbatim>
----+++ Result
-<verbatim>
-{
-    "instances": [
-        {
-            "details": "",
-            "startTime": "2013-10-21T15:19:57-07:00",
-            "cluster": "primary-cluster",
-            "logFile": "http:\/\/localhost:11000\/oozie?job=0000070-131021115933395-oozie-rgau-W",
-            "status": "RUNNING",
-            "instance": "2012-04-03T07:00Z"
-        }
-    ],
-    "requestId": "default\/e88ff2e0-2af7-4829-a360-f92e95be2981\n",
-    "message": "default\/RESUME\n",
-    "status": "SUCCEEDED"
-}
-</verbatim>
+           <verbatim>
+           POST http://localhost:15000/api/instance/resume/process/SampleProcess?colo=*&start=2012-04-03T07:00Z&end=2014-04-03T07:00Z&doAs=joe
+           </verbatim>
+           ---+++ Result
+           <verbatim>
+           {
+               "instances": [
+                   {
+                       "details": "",
+                       "startTime": "2013-10-21T15:19:57-07:00",
+                       "cluster": "primary-cluster",
+                       "logFile": "http:\/\/localhost:11000\/oozie?job=0000070-131021115933395-oozie-rgau-W",
+                       "status": "RUNNING",
+                       "instance": "2012-04-03T07:00Z"
+                   }
+               ],
+               "requestId": "default\/e88ff2e0-2af7-4829-a360-f92e95be2981\n",
+               "message": "default\/RESUME\n",
+               "status": "SUCCEEDED"
+           }
+           </verbatim>

http://git-wip-us.apache.org/repos/asf/falcon/blob/d8fbec9f/docs/src/site/twiki/restapi/InstanceRunning.twiki
----------------------------------------------------------------------
diff --git a/docs/src/site/twiki/restapi/InstanceRunning.twiki b/docs/src/site/twiki/restapi/InstanceRunning.twiki
index dcd2230..3d1cabc 100644
--- a/docs/src/site/twiki/restapi/InstanceRunning.twiki
+++ b/docs/src/site/twiki/restapi/InstanceRunning.twiki
@@ -20,7 +20,7 @@ Get a list of instances currently running for a given entity.
    * sortOrder <optional param> Valid options are "asc" and "desc"
    * offset <optional param> Show results from the offset, used for pagination. Defaults to 0.
    * numResults <optional param> Number of results to show per request, used for pagination. Only integers > 0 are valid, Default is 10.
-
+   * doAs <optional query param> allows the current user to impersonate the user passed in doAs when interacting with the Falcon system.
 
 ---++ Results
 List of instances currently running.
@@ -50,7 +50,7 @@ GET http://localhost:15000/api/instance/running/process/SampleProcess?colo=*
 
 ---+++ Rest Call
 <verbatim>
-GET http://localhost:15000/api/instance/running/process/SampleProcess?colo=*&start=2012-04-03T07:00Z&filterBy=CLUSTER:primary-cluster&orderBy=startTime&offset=2&numResults=2
+GET http://localhost:15000/api/instance/running/process/SampleProcess?colo=*&start=2012-04-03T07:00Z&filterBy=CLUSTER:primary-cluster&orderBy=startTime&offset=2&numResults=2&doAs=joe
 </verbatim>
 ---+++ Result
 <verbatim>
@@ -82,4 +82,3 @@ GET http://localhost:15000/api/instance/running/process/SampleProcess?colo=*&sta
 }
 </verbatim>
 
-

http://git-wip-us.apache.org/repos/asf/falcon/blob/d8fbec9f/docs/src/site/twiki/restapi/InstanceStatus.twiki
----------------------------------------------------------------------
diff --git a/docs/src/site/twiki/restapi/InstanceStatus.twiki b/docs/src/site/twiki/restapi/InstanceStatus.twiki
index cebc9c8..53f512f 100644
--- a/docs/src/site/twiki/restapi/InstanceStatus.twiki
+++ b/docs/src/site/twiki/restapi/InstanceStatus.twiki
@@ -24,7 +24,7 @@ Get status of a specific instance of an entity.
    * sortOrder <optional param> Valid options are "asc" and "desc"
    * offset <optional param> Show results from the offset, used for pagination. Defaults to 0.
    * numResults <optional param> Number of results to show per request, used for pagination. Only integers > 0 are valid, Default is 10.
-
+   * doAs <optional query param> allows the current user to impersonate the user passed in doAs when interacting with the Falcon system.
    
 ---++ Results
 Status of the specified instance along with job urls for all actions of user workflow and non-succeeded actions of the main-workflow.
@@ -64,7 +64,7 @@ GET https://localhost:15443/api/instance/status/process/WordCount?start=2014-11-
 
 ---+++ Rest Call
 <verbatim>
-GET http://localhost:15000/api/instance/status/process/SampleProcess?colo=*&start=2012-04-03T07:00Z&filterBy=STATUS:SUCCEEDED,CLUSTER:primary-cluster&orderBy=startTime&offset=2&numResults=2
+GET http://localhost:15000/api/instance/status/process/SampleProcess?colo=*&start=2012-04-03T07:00Z&filterBy=STATUS:SUCCEEDED,CLUSTER:primary-cluster&orderBy=startTime&offset=2&numResults=2&doAs=joe
 </verbatim>
 ---+++ Result
 <verbatim>

http://git-wip-us.apache.org/repos/asf/falcon/blob/d8fbec9f/docs/src/site/twiki/restapi/InstanceSummary.twiki
----------------------------------------------------------------------
diff --git a/docs/src/site/twiki/restapi/InstanceSummary.twiki b/docs/src/site/twiki/restapi/InstanceSummary.twiki
index 2e44598..0e1ffee 100644
--- a/docs/src/site/twiki/restapi/InstanceSummary.twiki
+++ b/docs/src/site/twiki/restapi/InstanceSummary.twiki
@@ -25,6 +25,7 @@ Get summary of instance/instances of an entity.
        * Supports ordering by "cluster".
    * sortOrder <optional param> Valid options are "asc" and "desc"
    Example: orderBy=cluster sortOrder=asc
+   * doAs <optional query param> allows the current user to impersonate the user passed in doAs when interacting with the Falcon system.
 
 ---++ Results
 Summary of the instances over the specified time range
@@ -86,7 +87,7 @@ GET https://localhost:16443/api/instance/summary/process/WordCount?filterBy=Stat
 
 ---+++ Rest Call
 <verbatim>
-GET https://localhost:16443/api/instance/summary/process/WordCount?orderBy=cluster&sortOrder=asc&start=2015-06-24T16:00Z&end=2015-06-24T23:00Z&colo=*
+GET https://localhost:16443/api/instance/summary/process/WordCount?orderBy=cluster&sortOrder=asc&start=2015-06-24T16:00Z&end=2015-06-24T23:00Z&colo=*&doAs=joe
 </verbatim>
 ---+++ Result
 <verbatim>

http://git-wip-us.apache.org/repos/asf/falcon/blob/d8fbec9f/docs/src/site/twiki/restapi/InstanceSuspend.twiki
----------------------------------------------------------------------
diff --git a/docs/src/site/twiki/restapi/InstanceSuspend.twiki b/docs/src/site/twiki/restapi/InstanceSuspend.twiki
index c4404b5..2ba8663 100644
--- a/docs/src/site/twiki/restapi/InstanceSuspend.twiki
+++ b/docs/src/site/twiki/restapi/InstanceSuspend.twiki
@@ -13,6 +13,7 @@ Suspend instances of an entity.
    * start is the start time of the instance(s) that you want to refer to
    * end is the end time of the instance(s) that you want to refer to
    * lifecycle <optional param> can be Eviction/Replication(default) for feed and Execution(default) for process.
+   * doAs <optional query param> allows the current user to impersonate the user passed in doAs when interacting with the Falcon system.
 
 ---++ Results
 Results of the suspend command.
@@ -20,7 +21,7 @@ Results of the suspend command.
 ---++ Examples
 ---+++ Rest Call
 <verbatim>
-POST http://localhost:15000/api/instance/suspend/process/SampleProcess?colo=*&start=2012-04-03T07:00Z&end=2014-04-03T07:00Z
+POST http://localhost:15000/api/instance/suspend/process/SampleProcess?colo=*&start=2012-04-03T07:00Z&end=2014-04-03T07:00Z&doAs=joe
 </verbatim>
 ---+++ Result
 <verbatim>
@@ -40,4 +41,4 @@ POST http://localhost:15000/api/instance/suspend/process/SampleProcess?colo=*&st
     "message": "default\/SUSPEND\n",
     "status": "SUCCEEDED"
 }
-</verbatim>
+</verbatim>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/falcon/blob/d8fbec9f/docs/src/site/twiki/restapi/MetadataList.twiki
----------------------------------------------------------------------
diff --git a/docs/src/site/twiki/restapi/MetadataList.twiki b/docs/src/site/twiki/restapi/MetadataList.twiki
index baf7d45..98abf46 100644
--- a/docs/src/site/twiki/restapi/MetadataList.twiki
+++ b/docs/src/site/twiki/restapi/MetadataList.twiki
@@ -10,6 +10,7 @@ Get all dimensions of specified type.
 ---++ Parameters
    * :type Valid dimension types are cluster_entity,feed_entity, process_entity, user, colo, tags, groups, pipelines
    * cluster <optional query param> Show dimensions related to this cluster.
+   * doAs <optional query param> allows the current user to impersonate the user passed in doAs when interacting with the Falcon system.
 
 
 ---++ Results
@@ -18,7 +19,7 @@ List of dimensions that match requested type [and cluster].
 ---++ Examples
 ---+++ Rest Call
 <verbatim>
-GET http://localhost:15000/api/metadata/discovery/process_entity/list?cluster=primary-cluster
+GET http://localhost:15000/api/metadata/discovery/process_entity/list?cluster=primary-cluster&doAs=joe
 </verbatim>
 ---+++ Result
 <verbatim>

http://git-wip-us.apache.org/repos/asf/falcon/blob/d8fbec9f/docs/src/site/twiki/restapi/MetadataRelations.twiki
----------------------------------------------------------------------
diff --git a/docs/src/site/twiki/restapi/MetadataRelations.twiki b/docs/src/site/twiki/restapi/MetadataRelations.twiki
index 11eb4e0..b29fd2a 100644
--- a/docs/src/site/twiki/restapi/MetadataRelations.twiki
+++ b/docs/src/site/twiki/restapi/MetadataRelations.twiki
@@ -10,6 +10,7 @@ Get all relations of a specific dimension.
 ---++ Parameters
    * :type Valid dimension types are cluster_entity,feed_entity, process_entity, user, colo, tags, groups, pipelines
    * :name Name of the dimension.
+   * doAs <optional query param> allows the current user to impersonate the user passed in doAs when interacting with the Falcon system.
 
 ---++ Results
 Get all relations of a specific dimension.
@@ -17,7 +18,7 @@ Get all relations of a specific dimension.
 ---++ Examples
 ---+++ Rest Call
 <verbatim>
-GET http://localhost:15000/api/metadata/discovery/process_entity/sample-process/relations
+GET http://localhost:15000/api/metadata/discovery/process_entity/sample-process/relations?doAs=joe
 </verbatim>
 ---+++ Result
 <verbatim>

http://git-wip-us.apache.org/repos/asf/falcon/blob/d8fbec9f/docs/src/site/twiki/restapi/Triage.twiki
----------------------------------------------------------------------
diff --git a/docs/src/site/twiki/restapi/Triage.twiki b/docs/src/site/twiki/restapi/Triage.twiki
index 30a04b4..9ff95c8 100644
--- a/docs/src/site/twiki/restapi/Triage.twiki
+++ b/docs/src/site/twiki/restapi/Triage.twiki
@@ -14,6 +14,7 @@ lot of instances are failing in a pipeline as it then finds out the root cause o
    * :entity-name name of the feed/process.
    * :start instance time of the entity instance.
    * :colo <optional param> name of the colo on which you want to triage
+   * doAs <optional query param> allows the current user to impersonate the user passed in doAs when interacting with the Falcon system.
 
 ---++ Results
 It returns a json graph
@@ -21,7 +22,7 @@ It returns a json graph
 ---++ Examples
 ---+++ Rest Call
 <verbatim>
-GET http://localhost:15000/api/instance/triage/feed/my-feed?start=2015-03-02T00:00Z&colo=local
+GET http://localhost:15000/api/instance/triage/feed/my-feed?start=2015-03-02T00:00Z&colo=local&doAs=joe
 </verbatim>
 ---+++ Result
 <verbatim>

http://git-wip-us.apache.org/repos/asf/falcon/blob/d8fbec9f/docs/src/site/twiki/restapi/Vertex.twiki
----------------------------------------------------------------------
diff --git a/docs/src/site/twiki/restapi/Vertex.twiki b/docs/src/site/twiki/restapi/Vertex.twiki
index ac2cebf..82f5bfb 100644
--- a/docs/src/site/twiki/restapi/Vertex.twiki
+++ b/docs/src/site/twiki/restapi/Vertex.twiki
@@ -9,6 +9,7 @@ Gets the vertex with specified id.
 
 ---++ Parameters
    * :id is the unique id of the vertex.
+   * doAs <optional query param> allows the current user to impersonate the user passed in doAs when interacting with the Falcon system.
 
 ---++ Results
 Vertex with the specified id.
@@ -16,7 +17,7 @@ Vertex with the specified id.
 ---++ Examples
 ---+++ Rest Call
 <verbatim>
-GET http://localhost:15000/api/metadata/lineage/vertices/4
+GET http://localhost:15000/api/metadata/lineage/vertices/4?doAs=joe
 </verbatim>
 ---+++ Result
 <verbatim>

http://git-wip-us.apache.org/repos/asf/falcon/blob/d8fbec9f/docs/src/site/twiki/restapi/VertexProperties.twiki
----------------------------------------------------------------------
diff --git a/docs/src/site/twiki/restapi/VertexProperties.twiki b/docs/src/site/twiki/restapi/VertexProperties.twiki
index 1d146cc..11c64b5 100644
--- a/docs/src/site/twiki/restapi/VertexProperties.twiki
+++ b/docs/src/site/twiki/restapi/VertexProperties.twiki
@@ -10,6 +10,7 @@ Gets the properties of the vertex with specified id.
 ---++ Parameters
    * :id is the unique id of the vertex.
    * :relationships has default value of false. Pass true if relationships should be fetched.
+   * doAs <optional query param> allows the current user to impersonate the user passed in doAs when interacting with the Falcon system.
 
 ---++ Results
  Properties associated with the specified vertex.
@@ -17,7 +18,7 @@ Gets the properties of the vertex with specified id.
 ---++ Examples
 ---+++ Rest Call
 <verbatim>
-GET http://localhost:15000/api/metadata/lineage/vertices/properties/40004?relationships=true
+GET http://localhost:15000/api/metadata/lineage/vertices/properties/40004?relationships=true&doAs=joe
 </verbatim>
 ---+++ Result
 <verbatim>

http://git-wip-us.apache.org/repos/asf/falcon/blob/d8fbec9f/docs/src/site/twiki/restapi/Vertices.twiki
----------------------------------------------------------------------
diff --git a/docs/src/site/twiki/restapi/Vertices.twiki b/docs/src/site/twiki/restapi/Vertices.twiki
index 3ece037..643e6e9 100644
--- a/docs/src/site/twiki/restapi/Vertices.twiki
+++ b/docs/src/site/twiki/restapi/Vertices.twiki
@@ -10,6 +10,7 @@ Get all vertices for a key index given the specified value.
 ---++ Parameters
    * :key is the key to be matched.
    * :value is the associated value of the key.
+   * doAs <optional query param> allows the current user to impersonate the user passed in doAs when interacting with the Falcon system.
 
 ---++ Results
 All vertices matching given property key and a value.
@@ -17,7 +18,7 @@ All vertices matching given property key and a value.
 ---++ Examples
 ---+++ Rest Call
 <verbatim>
-GET http://localhost:15000/api/metadata/lineage/vertices?key=name&value=sampleIngestProcess
+GET http://localhost:15000/api/metadata/lineage/vertices?key=name&value=sampleIngestProcess&doAs=joe
 </verbatim>
 ---+++ Result
 <verbatim>
@@ -34,4 +35,4 @@ GET http://localhost:15000/api/metadata/lineage/vertices?key=name&value=sampleIn
     ],
     "totalSize": 1
 }
-</verbatim>
+</verbatim>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/falcon/blob/d8fbec9f/prism/src/main/java/org/apache/falcon/resource/AbstractEntityManager.java
----------------------------------------------------------------------
diff --git a/prism/src/main/java/org/apache/falcon/resource/AbstractEntityManager.java b/prism/src/main/java/org/apache/falcon/resource/AbstractEntityManager.java
index 63c5d39..b867055 100644
--- a/prism/src/main/java/org/apache/falcon/resource/AbstractEntityManager.java
+++ b/prism/src/main/java/org/apache/falcon/resource/AbstractEntityManager.java
@@ -76,6 +76,7 @@ import java.util.Set;
 public abstract class AbstractEntityManager {
     private static final Logger LOG = LoggerFactory.getLogger(AbstractEntityManager.class);
     private static MemoryLocks memoryLocks = MemoryLocks.getInstance();
+    private static final String DO_AS_PARAM = "doAs";
 
     protected static final int XML_DEBUG_LEN = 10 * 1024;
     private AbstractWorkflowEngine workflowEngine;
@@ -425,7 +426,8 @@ public abstract class AbstractEntityManager {
                             + "Can't be submitted again. Try removing before submitting.");
         }
 
-        SecurityUtil.tryProxy(entity); // proxy before validating since FS/Oozie needs to be proxied
+        String doAsUser = request.getParameter(DO_AS_PARAM);
+        SecurityUtil.tryProxy(entity, doAsUser); // proxy before validating since FS/Oozie needs to be proxied
         validate(entity);
         configStore.publish(entityType, entity);
         LOG.info("Submit successful: ({}): {}", type, entity.getName());
@@ -599,7 +601,8 @@ public abstract class AbstractEntityManager {
      */
     public EntityList getEntityList(String fieldStr, String nameSubsequence, String tagKeywords,
                                     String filterType, String filterTags, String filterBy,
-                                    String orderBy, String sortOrder, Integer offset, Integer resultsPerPage) {
+                                    String orderBy, String sortOrder, Integer offset,
+                                    Integer resultsPerPage, final String doAsUser) {
 
         HashSet<String> fields = new HashSet<String>(Arrays.asList(fieldStr.toUpperCase().split(",")));
         Map<String, List<String>> filterByFieldsValues = getFilterByFieldsValues(filterBy);
@@ -620,14 +623,14 @@ public abstract class AbstractEntityManager {
                 // return entities of all types if no entity type specified
                 for (EntityType entityType : EntityType.values()) {
                     entities.addAll(getFilteredEntities(
-                            entityType, nameSubsequence, tagKeywords, filterByFieldsValues, "", "", ""));
+                            entityType, nameSubsequence, tagKeywords, filterByFieldsValues, "", "", "", doAsUser));
                 }
             } else {
                 String[] types = filterType.split(",");
                 for (String type : types) {
                     EntityType entityType = EntityType.getEnum(type);
                     entities.addAll(getFilteredEntities(
-                            entityType, nameSubsequence, tagKeywords, filterByFieldsValues, "", "", ""));
+                            entityType, nameSubsequence, tagKeywords, filterByFieldsValues, "", "", "", doAsUser));
                 }
             }
         } catch (Exception e) {
@@ -679,7 +682,8 @@ public abstract class AbstractEntityManager {
 
     protected List<Entity> getFilteredEntities(
             EntityType entityType, String nameSubsequence, String tagKeywords,
-            Map<String, List<String>> filterByFieldsValues, String startDate, String endDate, String cluster)
+            Map<String, List<String>> filterByFieldsValues,
+            String startDate, String endDate, String cluster, final String doAsUser)
         throws FalconException, IOException {
         Collection<String> entityNames = configStore.getEntities(entityType);
         if (entityNames.isEmpty()) {
@@ -714,7 +718,7 @@ public abstract class AbstractEntityManager {
                 // this is for entity summary
                 continue;
             }
-            SecurityUtil.tryProxy(entity);
+            SecurityUtil.tryProxy(entity, doAsUser);
 
             // filter by fields
             if (isFilteredByFields(entity, filterByFieldsValues)) {

http://git-wip-us.apache.org/repos/asf/falcon/blob/d8fbec9f/prism/src/main/java/org/apache/falcon/resource/AbstractSchedulableEntityManager.java
----------------------------------------------------------------------
diff --git a/prism/src/main/java/org/apache/falcon/resource/AbstractSchedulableEntityManager.java b/prism/src/main/java/org/apache/falcon/resource/AbstractSchedulableEntityManager.java
index f9405dc..61638f3 100644
--- a/prism/src/main/java/org/apache/falcon/resource/AbstractSchedulableEntityManager.java
+++ b/prism/src/main/java/org/apache/falcon/resource/AbstractSchedulableEntityManager.java
@@ -201,7 +201,7 @@ public abstract class AbstractSchedulableEntityManager extends AbstractInstanceM
     public EntitySummaryResult getEntitySummary(String type, String cluster, String startDate, String endDate,
                                                 String fields, String filterBy, String filterTags,
                                                 String orderBy, String sortOrder, Integer offset,
-                                                Integer resultsPerPage, Integer numInstances) {
+                                                Integer resultsPerPage, Integer numInstances, final String doAsUser) {
         HashSet<String> fieldSet = new HashSet<String>(Arrays.asList(fields.toLowerCase().split(",")));
         Pair<Date, Date> startAndEndDates = getStartEndDatesForSummary(startDate, endDate);
         validateTypeForEntitySummary(type);
@@ -218,7 +218,7 @@ public abstract class AbstractSchedulableEntityManager extends AbstractInstanceM
                     getFilteredEntities(EntityType.valueOf(type.toUpperCase()), "", "", filterByFieldsValues,
                             SchemaHelper.getDateFormat().format(startAndEndDates.first),
                             SchemaHelper.getDateFormat().format(startAndEndDates.second),
-                            cluster),
+                            cluster, doAsUser),
                     orderBy, sortOrder, offset, resultsPerPage);
             colo = ((Cluster) configStore.get(EntityType.CLUSTER, cluster)).getColo();
         } catch (Exception e) {

http://git-wip-us.apache.org/repos/asf/falcon/blob/d8fbec9f/prism/src/main/java/org/apache/falcon/resource/channel/HTTPChannel.java
----------------------------------------------------------------------
diff --git a/prism/src/main/java/org/apache/falcon/resource/channel/HTTPChannel.java b/prism/src/main/java/org/apache/falcon/resource/channel/HTTPChannel.java
index 78f68ba..5bf084b 100644
--- a/prism/src/main/java/org/apache/falcon/resource/channel/HTTPChannel.java
+++ b/prism/src/main/java/org/apache/falcon/resource/channel/HTTPChannel.java
@@ -56,6 +56,8 @@ public class HTTPChannel extends AbstractChannel {
 
     private static final Properties DEPLOYMENT_PROPERTIES = DeploymentProperties.get();
 
+    private static final String DO_AS_PARAM = "doAs";
+
     private String colo;
     private String serviceName;
     private Class service;
@@ -95,9 +97,12 @@ public class HTTPChannel extends AbstractChannel {
             String accept = MediaType.WILDCARD;
             String user = CurrentUser.getUser();
 
+            String doAsUser = incomingRequest.getParameter(DO_AS_PARAM);
+
             ClientResponse response = getClient()
                     .resource(UriBuilder.fromUri(url).build().normalize())
                     .queryParam("user.name", user)
+                    .queryParam("doAs", doAsUser)
                     .accept(accept).type(mimeType)
                     .method(httpMethod, ClientResponse.class,
                             (isPost(httpMethod) ? incomingRequest.getInputStream() : null));

http://git-wip-us.apache.org/repos/asf/falcon/blob/d8fbec9f/prism/src/main/java/org/apache/falcon/resource/proxy/SchedulableEntityManagerProxy.java
----------------------------------------------------------------------
diff --git a/prism/src/main/java/org/apache/falcon/resource/proxy/SchedulableEntityManagerProxy.java b/prism/src/main/java/org/apache/falcon/resource/proxy/SchedulableEntityManagerProxy.java
index ceabb06..23f1605 100644
--- a/prism/src/main/java/org/apache/falcon/resource/proxy/SchedulableEntityManagerProxy.java
+++ b/prism/src/main/java/org/apache/falcon/resource/proxy/SchedulableEntityManagerProxy.java
@@ -486,13 +486,14 @@ public class SchedulableEntityManagerProxy extends AbstractSchedulableEntityMana
                                     @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,
+                                    @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
@@ -512,9 +513,10 @@ public class SchedulableEntityManagerProxy extends AbstractSchedulableEntityMana
             @DefaultValue("asc") @QueryParam("sortOrder") String entitySortOrder,
             @DefaultValue("0") @QueryParam("offset") final Integer entityOffset,
             @DefaultValue("10") @QueryParam("numResults") final Integer numEntities,
-            @DefaultValue("7") @QueryParam("numInstances") final Integer numInstanceResults) {
+            @DefaultValue("7") @QueryParam("numInstances") final Integer numInstanceResults,
+            @DefaultValue("") @QueryParam("doAs") final String doAsUser) {
         return super.getEntitySummary(type, cluster, startStr, endStr, entityFields, entityFilter,
-                entityTags, entityOrderBy, entitySortOrder, entityOffset, numEntities, numInstanceResults);
+                entityTags, entityOrderBy, entitySortOrder, entityOffset, numEntities, numInstanceResults, doAsUser);
     }
 
     @GET

http://git-wip-us.apache.org/repos/asf/falcon/blob/d8fbec9f/prism/src/main/java/org/apache/falcon/security/FalconAuthenticationFilter.java
----------------------------------------------------------------------
diff --git a/prism/src/main/java/org/apache/falcon/security/FalconAuthenticationFilter.java b/prism/src/main/java/org/apache/falcon/security/FalconAuthenticationFilter.java
index df64b44..1cb5205 100644
--- a/prism/src/main/java/org/apache/falcon/security/FalconAuthenticationFilter.java
+++ b/prism/src/main/java/org/apache/falcon/security/FalconAuthenticationFilter.java
@@ -52,6 +52,8 @@ public class FalconAuthenticationFilter
 
     private static final Logger LOG = LoggerFactory.getLogger(FalconAuthenticationFilter.class);
 
+    protected static final String DO_AS_PARAM = "doAs";
+
     /**
      * Constant for the configuration property that indicates the prefix.
      */
@@ -177,9 +179,11 @@ public class FalconAuthenticationFilter
                     } else {
                         try {
                             NDC.push(user + ":" + httpRequest.getMethod() + "/" + httpRequest.getPathInfo());
+                            String doAsUser = httpRequest.getParameter(DO_AS_PARAM);
                             CurrentUser.authenticate(user);
-                            LOG.info("Request from authenticated user: {}, URL={}", user,
-                                    Servlets.getRequestURI(httpRequest));
+                            CurrentUser.proxyDoAsUser(doAsUser, HostnameFilter.get());
+                            LOG.info("Request from authenticated user: {}, URL={}, doAs user: {}", user,
+                                    Servlets.getRequestURI(httpRequest), doAsUser);
 
                             filterChain.doFilter(servletRequest, servletResponse);
                         } finally {


[3/3] falcon git commit: FALCON-1027 Falcon proxy user support. Contributed by Sowmya Ramesh.

Posted by so...@apache.org.
FALCON-1027 Falcon proxy user support. Contributed by Sowmya Ramesh.


Project: http://git-wip-us.apache.org/repos/asf/falcon/repo
Commit: http://git-wip-us.apache.org/repos/asf/falcon/commit/d8fbec9f
Tree: http://git-wip-us.apache.org/repos/asf/falcon/tree/d8fbec9f
Diff: http://git-wip-us.apache.org/repos/asf/falcon/diff/d8fbec9f

Branch: refs/heads/master
Commit: d8fbec9f97ba2bd2207827c7b83a8b861c25f9f0
Parents: cbd7c80
Author: Sowmya Ramesh <sr...@hortonworks.com>
Authored: Mon Sep 14 18:46:21 2015 -0700
Committer: Sowmya Ramesh <sr...@hortonworks.com>
Committed: Mon Sep 14 18:46:21 2015 -0700

----------------------------------------------------------------------
 CHANGES.txt                                     |   1 +
 .../java/org/apache/falcon/cli/FalconCLI.java   |  83 ++++--
 .../apache/falcon/cli/FalconMetadataCLI.java    |  18 +-
 .../falcon/client/AbstractFalconClient.java     |   4 +-
 .../org/apache/falcon/client/FalconClient.java  | 298 ++++++++++++-------
 .../org/apache/falcon/security/CurrentUser.java |  40 ++-
 .../apache/falcon/security/SecurityUtil.java    |  14 +-
 .../apache/falcon/service/GroupsService.java    |  67 +++++
 .../apache/falcon/service/ProxyUserService.java | 203 +++++++++++++
 common/src/main/resources/runtime.properties    |  18 +-
 common/src/main/resources/startup.properties    |   4 +-
 .../apache/falcon/security/CurrentUserTest.java |  59 ++++
 .../falcon/security/SecurityUtilTest.java       |  53 +++-
 .../falcon/service/GroupsServiceTest.java       |  56 ++++
 .../falcon/service/ProxyUserServiceTest.java    | 167 +++++++++++
 docs/src/site/twiki/FalconCLI.twiki             |  14 +
 docs/src/site/twiki/FalconDocumentation.twiki   |  26 ++
 .../site/twiki/restapi/AdjacentVertices.twiki   |  21 ++
 docs/src/site/twiki/restapi/AdminStack.twiki    |   5 +-
 docs/src/site/twiki/restapi/AdminVersion.twiki  |   5 +-
 docs/src/site/twiki/restapi/AllEdges.twiki      |   4 +-
 docs/src/site/twiki/restapi/AllVertices.twiki   |   4 +-
 docs/src/site/twiki/restapi/Edge.twiki          |   3 +-
 .../site/twiki/restapi/EntityDefinition.twiki   |   3 +-
 docs/src/site/twiki/restapi/EntityDelete.twiki  |   3 +-
 .../site/twiki/restapi/EntityDependencies.twiki |   3 +-
 docs/src/site/twiki/restapi/EntityLineage.twiki |   3 +-
 docs/src/site/twiki/restapi/EntityList.twiki    |   3 +-
 docs/src/site/twiki/restapi/EntityResume.twiki  |   3 +-
 .../src/site/twiki/restapi/EntitySchedule.twiki |   5 +-
 docs/src/site/twiki/restapi/EntityStatus.twiki  |   3 +-
 docs/src/site/twiki/restapi/EntitySubmit.twiki  |   5 +-
 .../twiki/restapi/EntitySubmitAndSchedule.twiki |   5 +-
 docs/src/site/twiki/restapi/EntitySummary.twiki |   3 +-
 docs/src/site/twiki/restapi/EntitySuspend.twiki |   3 +-
 docs/src/site/twiki/restapi/EntityTouch.twiki   |   7 +-
 docs/src/site/twiki/restapi/EntityUpdate.twiki  |   5 +-
 .../src/site/twiki/restapi/EntityValidate.twiki |   5 +-
 .../twiki/restapi/FeedInstanceListing.twiki     |   3 +-
 docs/src/site/twiki/restapi/FeedLookup.twiki    |   5 +-
 docs/src/site/twiki/restapi/Graph.twiki         |   4 +-
 docs/src/site/twiki/restapi/InstanceKill.twiki  |   3 +-
 docs/src/site/twiki/restapi/InstanceList.twiki  |   3 +-
 docs/src/site/twiki/restapi/InstanceLogs.twiki  |   3 +-
 .../src/site/twiki/restapi/InstanceParams.twiki |   5 +-
 docs/src/site/twiki/restapi/InstanceRerun.twiki |   3 +-
 .../src/site/twiki/restapi/InstanceResume.twiki |  44 +--
 .../site/twiki/restapi/InstanceRunning.twiki    |   5 +-
 .../src/site/twiki/restapi/InstanceStatus.twiki |   4 +-
 .../site/twiki/restapi/InstanceSummary.twiki    |   3 +-
 .../site/twiki/restapi/InstanceSuspend.twiki    |   5 +-
 docs/src/site/twiki/restapi/MetadataList.twiki  |   3 +-
 .../site/twiki/restapi/MetadataRelations.twiki  |   3 +-
 docs/src/site/twiki/restapi/Triage.twiki        |   3 +-
 docs/src/site/twiki/restapi/Vertex.twiki        |   3 +-
 .../site/twiki/restapi/VertexProperties.twiki   |   3 +-
 docs/src/site/twiki/restapi/Vertices.twiki      |   5 +-
 .../falcon/resource/AbstractEntityManager.java  |  16 +-
 .../AbstractSchedulableEntityManager.java       |   4 +-
 .../falcon/resource/channel/HTTPChannel.java    |   5 +
 .../proxy/SchedulableEntityManagerProxy.java    |  10 +-
 .../security/FalconAuthenticationFilter.java    |   8 +-
 .../security/FalconAuthorizationFilter.java     |   9 +-
 .../apache/falcon/security/HostnameFilter.java  | 105 +++++++
 prism/src/main/webapp/WEB-INF/web.xml           |  10 +
 .../falcon/resource/EntityManagerTest.java      |  29 +-
 .../FalconAuthenticationFilterTest.java         |  83 +++++-
 .../falcon/security/HostnameFilterTest.java     |  93 ++++++
 src/conf/runtime.properties                     |  16 +
 src/conf/startup.properties                     |   4 +-
 .../apache/falcon/unit/FalconUnitClient.java    |   6 +-
 .../apache/falcon/unit/FalconUnitTestBase.java  |   4 +-
 webapp/pom.xml                                  |  22 ++
 webapp/src/conf/oozie/conf/oozie-site.xml       |   4 +-
 .../resource/SchedulableEntityManager.java      |  10 +-
 .../src/main/webapp/WEB-INF/distributed/web.xml |  10 +
 webapp/src/main/webapp/WEB-INF/embedded/web.xml |  10 +
 webapp/src/main/webapp/WEB-INF/web.xml          |  10 +
 .../java/org/apache/falcon/cli/FalconCLIIT.java | 162 ++++++++--
 .../falcon/resource/EntityManagerJerseyIT.java  |  26 +-
 .../resource/MetadataResourceJerseyIT.java      |   1 +
 .../org/apache/falcon/resource/TestContext.java |  54 +++-
 webapp/src/test/resources/runtime.properties    |  50 ++++
 83 files changed, 1772 insertions(+), 325 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/falcon/blob/d8fbec9f/CHANGES.txt
----------------------------------------------------------------------
diff --git a/CHANGES.txt b/CHANGES.txt
index 688c3c4..be4324c 100755
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -5,6 +5,7 @@ Trunk (Unreleased)
   INCOMPATIBLE CHANGES
 
   NEW FEATURES
+    FALCON-1027 Falcon proxy user support(Sowmya Ramesh)
 
   IMPROVEMENTS
     FALCON-1357 Update CHANGES.txt to change 0.7 branch to release.(Ajay Yadava)

http://git-wip-us.apache.org/repos/asf/falcon/blob/d8fbec9f/client/src/main/java/org/apache/falcon/cli/FalconCLI.java
----------------------------------------------------------------------
diff --git a/client/src/main/java/org/apache/falcon/cli/FalconCLI.java b/client/src/main/java/org/apache/falcon/cli/FalconCLI.java
index d4da302..e684678 100644
--- a/client/src/main/java/org/apache/falcon/cli/FalconCLI.java
+++ b/client/src/main/java/org/apache/falcon/cli/FalconCLI.java
@@ -142,6 +142,9 @@ public class FalconCLI {
         clientProperties = getClientProperties();
     }
 
+    // doAs option
+    public static final String DO_AS_OPT = "doAs";
+
     /**
      * Entry point for the Falcon CLI when invoked from the command line. Upon
      * completion this method exits the JVM with '0' (success) or '-1'
@@ -255,6 +258,7 @@ public class FalconCLI {
         String filterBy = commandLine.getOptionValue(FILTER_BY_OPT);
         String orderBy = commandLine.getOptionValue(ORDER_BY_OPT);
         String sortOrder = commandLine.getOptionValue(SORT_ORDER_OPT);
+        String doAsUser = commandLine.getOptionValue(DO_AS_OPT);
         Integer offset = parseIntegerInput(commandLine.getOptionValue(OFFSET_OPT), 0, "offset");
         Integer numResults = parseIntegerInput(commandLine.getOptionValue(NUM_RESULTS_OPT), null, "numResults");
 
@@ -281,7 +285,7 @@ public class FalconCLI {
             result =
                 ResponseHelper.getString(client.getRunningInstances(type,
                         entity, colo, lifeCycles, filterBy, orderBy, sortOrder,
-                        offset, numResults));
+                        offset, numResults, doAsUser));
         } else if (optionsList.contains(STATUS_OPT) || optionsList.contains(LIST_OPT)) {
             validateOrderBy(orderBy, instanceAction);
             validateFilterBy(filterBy, instanceAction);
@@ -289,35 +293,35 @@ public class FalconCLI {
                 ResponseHelper.getString(client
                         .getStatusOfInstances(type, entity, start, end, colo,
                                 lifeCycles,
-                                filterBy, orderBy, sortOrder, offset, numResults));
+                                filterBy, orderBy, sortOrder, offset, numResults, doAsUser));
         } else if (optionsList.contains(SUMMARY_OPT)) {
             validateOrderBy(orderBy, "summary");
             validateFilterBy(filterBy, "summary");
             result =
-                ResponseHelper.getString(client
-                        .getSummaryOfInstances(type, entity, start, end, colo,
-                                lifeCycles, filterBy, orderBy, sortOrder));
+                    ResponseHelper.getString(client
+                            .getSummaryOfInstances(type, entity, start, end, colo,
+                                    lifeCycles, filterBy, orderBy, sortOrder, doAsUser));
         } else if (optionsList.contains(KILL_OPT)) {
             validateNotEmpty(start, START_OPT);
             validateNotEmpty(end, END_OPT);
             result =
                 ResponseHelper.getString(client
                         .killInstances(type, entity, start, end, colo, clusters,
-                                sourceClusters, lifeCycles));
+                                sourceClusters, lifeCycles, doAsUser));
         } else if (optionsList.contains(SUSPEND_OPT)) {
             validateNotEmpty(start, START_OPT);
             validateNotEmpty(end, END_OPT);
             result =
                 ResponseHelper.getString(client
                         .suspendInstances(type, entity, start, end, colo, clusters,
-                                sourceClusters, lifeCycles));
+                                sourceClusters, lifeCycles, doAsUser));
         } else if (optionsList.contains(RESUME_OPT)) {
             validateNotEmpty(start, START_OPT);
             validateNotEmpty(end, END_OPT);
             result =
                 ResponseHelper.getString(client
                         .resumeInstances(type, entity, start, end, colo, clusters,
-                                sourceClusters, lifeCycles));
+                                sourceClusters, lifeCycles, doAsUser));
         } else if (optionsList.contains(RERUN_OPT)) {
             validateNotEmpty(start, START_OPT);
             validateNotEmpty(end, END_OPT);
@@ -329,7 +333,7 @@ public class FalconCLI {
                 ResponseHelper.getString(client
                         .rerunInstances(type, entity, start, end, filePath, colo,
                                 clusters, sourceClusters,
-                                lifeCycles, isForced));
+                                lifeCycles, isForced, doAsUser));
         } else if (optionsList.contains(LOG_OPT)) {
             validateOrderBy(orderBy, instanceAction);
             validateFilterBy(filterBy, instanceAction);
@@ -337,18 +341,18 @@ public class FalconCLI {
                 ResponseHelper.getString(client
                                 .getLogsOfInstances(type, entity, start, end, colo, runId,
                                         lifeCycles,
-                                        filterBy, orderBy, sortOrder, offset, numResults),
+                                        filterBy, orderBy, sortOrder, offset, numResults, doAsUser),
                         runId);
         } else if (optionsList.contains(PARARMS_OPT)) {
             // start time is the nominal time of instance
             result =
                 ResponseHelper
                     .getString(client.getParamsOfInstance(
-                            type, entity, start, colo, lifeCycles));
+                            type, entity, start, colo, lifeCycles, doAsUser));
         } else if (optionsList.contains(LISTING_OPT)) {
             result =
                 ResponseHelper.getString(client
-                        .getFeedListing(type, entity, start, end, colo));
+                        .getFeedListing(type, entity, start, end, colo, doAsUser));
         } else {
             throw new FalconCLIException("Invalid command");
         }
@@ -429,6 +433,8 @@ public class FalconCLI {
         Integer offset = parseIntegerInput(commandLine.getOptionValue(OFFSET_OPT), 0, "offset");
         Integer numResults = parseIntegerInput(commandLine.getOptionValue(NUM_RESULTS_OPT),
                 null, "numResults");
+        String doAsUser = commandLine.getOptionValue(DO_AS_OPT);
+
         Integer numInstances = parseIntegerInput(commandLine.getOptionValue(NUM_INSTANCES_OPT), 7, "numInstances");
         Boolean skipDryRun = null;
         if (optionsList.contains(SKIPDRYRUN_OPT)) {
@@ -456,61 +462,61 @@ public class FalconCLI {
         if (optionsList.contains(SUBMIT_OPT)) {
             validateNotEmpty(filePath, "file");
             validateColo(optionsList);
-            result = client.submit(entityType, filePath).getMessage();
+            result = client.submit(entityType, filePath, doAsUser).getMessage();
         } else if (optionsList.contains(LOOKUP_OPT)) {
             validateNotEmpty(feedInstancePath, PATH_OPT);
-            FeedLookupResult resp = client.reverseLookUp(entityType, feedInstancePath);
+            FeedLookupResult resp = client.reverseLookUp(entityType, feedInstancePath, doAsUser);
             result = ResponseHelper.getString(resp);
 
         } else if (optionsList.contains(UPDATE_OPT)) {
             validateNotEmpty(filePath, "file");
             validateColo(optionsList);
             validateNotEmpty(entityName, ENTITY_NAME_OPT);
-            result = client.update(entityType, entityName, filePath, skipDryRun).getMessage();
+            result = client.update(entityType, entityName, filePath, skipDryRun, doAsUser).getMessage();
         } else if (optionsList.contains(SUBMIT_AND_SCHEDULE_OPT)) {
             validateNotEmpty(filePath, "file");
             validateColo(optionsList);
-            result = client.submitAndSchedule(entityType, filePath, skipDryRun).getMessage();
+            result = client.submitAndSchedule(entityType, filePath, skipDryRun, doAsUser).getMessage();
         } else if (optionsList.contains(VALIDATE_OPT)) {
             validateNotEmpty(filePath, "file");
             validateColo(optionsList);
-            result = client.validate(entityType, filePath, skipDryRun).getMessage();
+            result = client.validate(entityType, filePath, skipDryRun, doAsUser).getMessage();
         } else if (optionsList.contains(SCHEDULE_OPT)) {
             validateNotEmpty(entityName, ENTITY_NAME_OPT);
             colo = getColo(colo);
-            result = client.schedule(entityTypeEnum, entityName, colo, skipDryRun).getMessage();
+            result = client.schedule(entityTypeEnum, entityName, colo, skipDryRun, doAsUser).getMessage();
         } else if (optionsList.contains(SUSPEND_OPT)) {
             validateNotEmpty(entityName, ENTITY_NAME_OPT);
             colo = getColo(colo);
-            result = client.suspend(entityTypeEnum, entityName, colo).getMessage();
+            result = client.suspend(entityTypeEnum, entityName, colo, doAsUser).getMessage();
         } else if (optionsList.contains(RESUME_OPT)) {
             validateNotEmpty(entityName, ENTITY_NAME_OPT);
             colo = getColo(colo);
-            result = client.resume(entityTypeEnum, entityName, colo).getMessage();
+            result = client.resume(entityTypeEnum, entityName, colo, doAsUser).getMessage();
         } else if (optionsList.contains(DELETE_OPT)) {
             validateColo(optionsList);
             validateNotEmpty(entityName, ENTITY_NAME_OPT);
-            result = client.delete(entityTypeEnum, entityName).getMessage();
+            result = client.delete(entityTypeEnum, entityName, doAsUser).getMessage();
         } else if (optionsList.contains(STATUS_OPT)) {
             validateNotEmpty(entityName, ENTITY_NAME_OPT);
             colo = getColo(colo);
             result =
-                    client.getStatus(entityTypeEnum, entityName, colo).getMessage();
+                    client.getStatus(entityTypeEnum, entityName, colo, doAsUser).getMessage();
         } else if (optionsList.contains(DEFINITION_OPT)) {
             validateColo(optionsList);
             validateNotEmpty(entityName, ENTITY_NAME_OPT);
-            result = client.getDefinition(entityType, entityName).toString();
+            result = client.getDefinition(entityType, entityName, doAsUser).toString();
         } else if (optionsList.contains(DEPENDENCY_OPT)) {
             validateColo(optionsList);
             validateNotEmpty(entityName, ENTITY_NAME_OPT);
-            result = client.getDependency(entityType, entityName).toString();
+            result = client.getDependency(entityType, entityName, doAsUser).toString();
         } else if (optionsList.contains(LIST_OPT)) {
             validateColo(optionsList);
             validateEntityFields(fields);
             validateOrderBy(orderBy, entityAction);
             validateFilterBy(filterBy, entityAction);
             EntityList entityList = client.getEntityList(entityType, fields, nameSubsequence, tagKeywords,
-                    filterBy, filterTags, orderBy, sortOrder, offset, numResults);
+                    filterBy, filterTags, orderBy, sortOrder, offset, numResults, doAsUser);
             result = entityList != null ? entityList.toString() : "No entity of type (" + entityType + ") found.";
         }  else if (optionsList.contains(SUMMARY_OPT)) {
             validateEntityTypeForSummary(entityType);
@@ -523,11 +529,12 @@ public class FalconCLI {
                             .getEntitySummary(
                                     entityType, cluster, start, end, fields, filterBy,
                                     filterTags,
-                                    orderBy, sortOrder, offset, numResults, numInstances));
+                                    orderBy, sortOrder, offset, numResults,
+                                    numInstances, doAsUser));
         } else if (optionsList.contains(TOUCH_OPT)) {
             validateNotEmpty(entityName, ENTITY_NAME_OPT);
             colo = getColo(colo);
-            result = client.touch(entityType, entityName, colo, skipDryRun).getMessage();
+            result = client.touch(entityType, entityName, colo, skipDryRun, doAsUser).getMessage();
         } else if (optionsList.contains(HELP_CMD)) {
             OUT.get().println("Falcon Help");
         } else {
@@ -658,6 +665,8 @@ public class FalconCLI {
                 "show Falcon server build version");
         Option stack = new Option(STACK_OPTION, false,
                 "show the thread stack dump");
+        Option doAs = new Option(DO_AS_OPT, true,
+                "doAs user");
         Option help = new Option("help", false, "show Falcon help");
         group.addOption(status);
         group.addOption(version);
@@ -665,6 +674,7 @@ public class FalconCLI {
         group.addOption(help);
 
         adminOptions.addOptionGroup(group);
+        adminOptions.addOption(doAs);
         return adminOptions;
     }
 
@@ -748,6 +758,7 @@ public class FalconCLI {
                 "Number of instances to return per entity summary request");
         Option path = new Option(PATH_OPT, true, "Path for a feed's instance");
         Option skipDryRun = new Option(SKIPDRYRUN_OPT, false, "skip dry run in workflow engine");
+        Option doAs = new Option(DO_AS_OPT, true, "doAs user");
 
         entityOptions.addOption(url);
         entityOptions.addOption(path);
@@ -770,6 +781,7 @@ public class FalconCLI {
         entityOptions.addOption(numResults);
         entityOptions.addOption(numInstances);
         entityOptions.addOption(skipDryRun);
+        entityOptions.addOption(doAs);
 
         return entityOptions;
     }
@@ -893,6 +905,7 @@ public class FalconCLI {
                 "Number of results to return per request");
         Option forceRerun = new Option(FORCE_RERUN_FLAG, false,
                 "Flag to forcefully rerun entire workflow of an instance");
+        Option doAs = new Option(DO_AS_OPT, true, "doAs user");
 
         Option instanceTime = new Option(INSTANCE_TIME_OPT, true, "Time for an instance");
 
@@ -914,6 +927,7 @@ public class FalconCLI {
         instanceOptions.addOption(sortOrder);
         instanceOptions.addOption(numResults);
         instanceOptions.addOption(forceRerun);
+        instanceOptions.addOption(doAs);
         instanceOptions.addOption(instanceTime);
 
         return instanceOptions;
@@ -936,6 +950,9 @@ public class FalconCLI {
         Option skipDryRunOperation = new Option(SKIPDRYRUN_OPT, false, "skip dryrun operation");
         recipeOptions.addOption(skipDryRunOperation);
 
+        Option doAs = new Option(DO_AS_OPT, true, "doAs user");
+        recipeOptions.addOption(doAs);
+
         return recipeOptions;
     }
 
@@ -964,14 +981,16 @@ public class FalconCLI {
             optionsList.add(option.getOpt());
         }
 
+        String doAsUser = commandLine.getOptionValue(DO_AS_OPT);
+
         if (optionsList.contains(STACK_OPTION)) {
-            result = client.getThreadDump();
+            result = client.getThreadDump(doAsUser);
             OUT.get().println(result);
         }
         int exitValue = 0;
         if (optionsList.contains(STATUS_OPTION)) {
             try {
-                int status = client.getStatus();
+                int status = client.getStatus(doAsUser);
                 if (status != 200) {
                     ERR.get().println("Falcon server is not fully operational (on " + falconUrl + "). "
                             + "Please check log files.");
@@ -984,7 +1003,7 @@ public class FalconCLI {
                 exitValue = -1;
             }
         } else if (optionsList.contains(VERSION_OPTION)) {
-            result = client.getVersion();
+            result = client.getVersion(doAsUser);
             OUT.get().println("Falcon server build version: " + result);
         } else if (optionsList.contains(HELP_CMD)) {
             OUT.get().println("Falcon Help");
@@ -1033,6 +1052,7 @@ public class FalconCLI {
         String recipeName = commandLine.getOptionValue(RECIPE_NAME);
         String recipeToolClass = commandLine.getOptionValue(RECIPE_TOOL_CLASS_NAME);
         String recipeOperation = commandLine.getOptionValue(RECIPE_OPERATION);
+        String doAsUser = commandLine.getOptionValue(DO_AS_OPT);
 
         validateNotEmpty(recipeName, RECIPE_NAME);
         validateNotEmpty(recipeOperation, RECIPE_OPERATION);
@@ -1042,7 +1062,8 @@ public class FalconCLI {
             skipDryRun = true;
         }
 
-        String result = client.submitRecipe(recipeName, recipeToolClass, recipeOperation, skipDryRun).toString();
+        String result = client.submitRecipe(recipeName, recipeToolClass,
+                recipeOperation, skipDryRun, doAsUser).toString();
         OUT.get().println(result);
     }
 

http://git-wip-us.apache.org/repos/asf/falcon/blob/d8fbec9f/client/src/main/java/org/apache/falcon/cli/FalconMetadataCLI.java
----------------------------------------------------------------------
diff --git a/client/src/main/java/org/apache/falcon/cli/FalconMetadataCLI.java b/client/src/main/java/org/apache/falcon/cli/FalconMetadataCLI.java
index 2f57c7d..dbc553c 100644
--- a/client/src/main/java/org/apache/falcon/cli/FalconMetadataCLI.java
+++ b/client/src/main/java/org/apache/falcon/cli/FalconMetadataCLI.java
@@ -81,29 +81,30 @@ public class FalconMetadataCLI {
         String value = commandLine.getOptionValue(VALUE_OPT);
         String direction = commandLine.getOptionValue(DIRECTION_OPT);
         String pipeline = commandLine.getOptionValue(PIPELINE_OPT);
+        String doAsUser = commandLine.getOptionValue(FalconCLI.DO_AS_OPT);
 
         if (optionsList.contains(LINEAGE_OPT)) {
             validatePipelineName(pipeline);
-            result = client.getEntityLineageGraph(pipeline).getDotNotation();
+            result = client.getEntityLineageGraph(pipeline, doAsUser).getDotNotation();
         } else if (optionsList.contains(LIST_OPT)) {
             validateDimensionType(dimensionType.toUpperCase());
-            result = client.getDimensionList(dimensionType, cluster);
+            result = client.getDimensionList(dimensionType, cluster, doAsUser);
         } else if (optionsList.contains(RELATIONS_OPT)) {
             validateDimensionType(dimensionType.toUpperCase());
             validateDimensionName(dimensionName, RELATIONS_OPT);
-            result = client.getDimensionRelations(dimensionType, dimensionName);
+            result = client.getDimensionRelations(dimensionType, dimensionName, doAsUser);
         } else if (optionsList.contains(VERTEX_CMD)) {
             validateId(id);
-            result = client.getVertex(id);
+            result = client.getVertex(id, doAsUser);
         } else if (optionsList.contains(VERTICES_CMD)) {
             validateVerticesCommand(key, value);
-            result = client.getVertices(key, value);
+            result = client.getVertices(key, value, doAsUser);
         } else if (optionsList.contains(VERTEX_EDGES_CMD)) {
             validateVertexEdgesCommand(id, direction);
-            result = client.getVertexEdges(id, direction);
+            result = client.getVertexEdges(id, direction, doAsUser);
         } else if (optionsList.contains(EDGE_CMD)) {
             validateId(id);
-            result = client.getEdge(id);
+            result = client.getEdge(id, doAsUser);
         } else {
             throw new FalconCLIException("Invalid metadata command");
         }
@@ -211,6 +212,9 @@ public class FalconMetadataCLI {
         metadataOptions.addOption(value);
         metadataOptions.addOption(direction);
 
+        Option doAs = new Option(FalconCLI.DO_AS_OPT, true, "doAs user");
+        metadataOptions.addOption(doAs);
+
         return metadataOptions;
     }
 }

http://git-wip-us.apache.org/repos/asf/falcon/blob/d8fbec9f/client/src/main/java/org/apache/falcon/client/AbstractFalconClient.java
----------------------------------------------------------------------
diff --git a/client/src/main/java/org/apache/falcon/client/AbstractFalconClient.java b/client/src/main/java/org/apache/falcon/client/AbstractFalconClient.java
index 282b41b..1146011 100644
--- a/client/src/main/java/org/apache/falcon/client/AbstractFalconClient.java
+++ b/client/src/main/java/org/apache/falcon/client/AbstractFalconClient.java
@@ -37,7 +37,7 @@ public abstract class AbstractFalconClient {
      * @return
      * @throws FalconCLIException
      */
-    public abstract APIResult submit(String entityType, String filePath) throws FalconCLIException,
+    public abstract APIResult submit(String entityType, String filePath, String doAsUser) throws FalconCLIException,
             IOException;
 
     /**
@@ -49,6 +49,6 @@ public abstract class AbstractFalconClient {
      * @throws FalconCLIException
      */
     public abstract APIResult schedule(EntityType entityType, String entityName,
-                                       String colo, Boolean skipDryRun) throws FalconCLIException;
+                                       String colo, Boolean skipDryRun, String doAsuser) throws FalconCLIException;
 
 }

http://git-wip-us.apache.org/repos/asf/falcon/blob/d8fbec9f/client/src/main/java/org/apache/falcon/client/FalconClient.java
----------------------------------------------------------------------
diff --git a/client/src/main/java/org/apache/falcon/client/FalconClient.java b/client/src/main/java/org/apache/falcon/client/FalconClient.java
index 44436d2..6075f5c 100644
--- a/client/src/main/java/org/apache/falcon/client/FalconClient.java
+++ b/client/src/main/java/org/apache/falcon/client/FalconClient.java
@@ -27,6 +27,7 @@ import org.apache.commons.io.IOUtils;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.commons.net.util.TrustManagerUtils;
 import org.apache.falcon.LifeCycle;
+import org.apache.falcon.cli.FalconCLI;
 import org.apache.falcon.cli.FalconMetadataCLI;
 import org.apache.falcon.entity.v0.Entity;
 import org.apache.falcon.entity.v0.EntityType;
@@ -285,52 +286,54 @@ public class FalconClient extends AbstractFalconClient {
         return str;
     }
 
-    public APIResult schedule(EntityType entityType, String entityName, String colo, Boolean skipDryRun)
+    public APIResult schedule(EntityType entityType, String entityName, String colo,
+                              Boolean skipDryRun, String doAsUser)
         throws FalconCLIException {
 
         return sendEntityRequest(Entities.SCHEDULE, entityType, entityName,
-                colo, skipDryRun);
+                colo, skipDryRun, doAsUser);
 
     }
 
-    public APIResult suspend(EntityType entityType, String entityName, String colo)
+    public APIResult suspend(EntityType entityType, String entityName, String colo, String doAsUser)
         throws FalconCLIException {
 
-        return sendEntityRequest(Entities.SUSPEND, entityType, entityName, colo, null);
+        return sendEntityRequest(Entities.SUSPEND, entityType, entityName, colo, null, doAsUser);
 
     }
 
-    public APIResult resume(EntityType entityType, String entityName, String colo)
+    public APIResult resume(EntityType entityType, String entityName, String colo, String doAsUser)
         throws FalconCLIException {
 
-        return sendEntityRequest(Entities.RESUME, entityType, entityName, colo, null);
+        return sendEntityRequest(Entities.RESUME, entityType, entityName, colo, null, doAsUser);
 
     }
 
-    public APIResult delete(EntityType entityType, String entityName)
+    public APIResult delete(EntityType entityType, String entityName, String doAsUser)
         throws FalconCLIException {
 
-        return sendEntityRequest(Entities.DELETE, entityType, entityName, null, null);
+        return sendEntityRequest(Entities.DELETE, entityType, entityName, null, null, doAsUser);
 
     }
 
-    public APIResult validate(String entityType, String filePath, Boolean skipDryRun)
+    public APIResult validate(String entityType, String filePath, Boolean skipDryRun, String doAsUser)
         throws FalconCLIException {
 
         InputStream entityStream = getServletInputStream(filePath);
         return sendEntityRequestWithObject(Entities.VALIDATE, entityType,
-                entityStream, null, skipDryRun);
+                entityStream, null, skipDryRun, doAsUser);
     }
 
-    public APIResult submit(String entityType, String filePath)
+    public APIResult submit(String entityType, String filePath, String doAsUser)
         throws FalconCLIException {
 
         InputStream entityStream = getServletInputStream(filePath);
         return sendEntityRequestWithObject(Entities.SUBMIT, entityType,
-                entityStream, null, null);
+                entityStream, null, null, doAsUser);
     }
 
-    public APIResult update(String entityType, String entityName, String filePath, Boolean skipDryRun)
+    public APIResult update(String entityType, String entityName, String filePath,
+                            Boolean skipDryRun, String doAsUser)
         throws FalconCLIException {
         InputStream entityStream = getServletInputStream(filePath);
         Entities operation = Entities.UPDATE;
@@ -338,6 +341,9 @@ public class FalconClient extends AbstractFalconClient {
         if (null != skipDryRun) {
             resource = resource.queryParam("skipDryRun", String.valueOf(skipDryRun));
         }
+        if (StringUtils.isNotEmpty(doAsUser)) {
+            resource = resource.queryParam(FalconCLI.DO_AS_OPT, doAsUser);
+        }
         ClientResponse clientResponse = resource
                 .header("Cookie", AUTH_COOKIE_EQ + authenticationToken)
                 .accept(operation.mimeType).type(MediaType.TEXT_XML)
@@ -346,30 +352,31 @@ public class FalconClient extends AbstractFalconClient {
         return parseAPIResult(clientResponse);
     }
 
-    public APIResult submitAndSchedule(String entityType, String filePath, Boolean skipDryRun)
+    public APIResult submitAndSchedule(String entityType, String filePath,
+                                       Boolean skipDryRun, String doAsUser)
         throws FalconCLIException {
 
         InputStream entityStream = getServletInputStream(filePath);
         return sendEntityRequestWithObject(Entities.SUBMITandSCHEDULE,
-                entityType, entityStream, null, skipDryRun);
+                entityType, entityStream, null, skipDryRun, doAsUser);
     }
 
-    public APIResult getStatus(EntityType entityType, String entityName, String colo)
+    public APIResult getStatus(EntityType entityType, String entityName, String colo, String doAsUser)
         throws FalconCLIException {
 
-        return sendEntityRequest(Entities.STATUS, entityType, entityName, colo, null);
+        return sendEntityRequest(Entities.STATUS, entityType, entityName, colo, null, doAsUser);
     }
 
-    public Entity getDefinition(String entityType, String entityName)
+    public Entity getDefinition(String entityType, String entityName, String doAsUser)
         throws FalconCLIException {
 
         return sendDefinitionRequest(Entities.DEFINITION, entityType,
-                entityName);
+                entityName, doAsUser);
     }
 
-    public EntityList getDependency(String entityType, String entityName)
+    public EntityList getDependency(String entityType, String entityName, String doAsUser)
         throws FalconCLIException {
-        return sendDependencyRequest(Entities.DEPENDENCY, entityType, entityName);
+        return sendDependencyRequest(Entities.DEPENDENCY, entityType, entityName, doAsUser);
     }
 
     //SUSPEND CHECKSTYLE CHECK ParameterNumberCheck
@@ -389,22 +396,22 @@ public class FalconClient extends AbstractFalconClient {
 
     public EntityList getEntityList(String entityType, String fields, String nameSubsequence, String tagKeywords,
                                     String filterBy, String filterTags, String orderBy, String sortOrder,
-                                    Integer offset, Integer numResults) throws FalconCLIException {
+                                    Integer offset, Integer numResults, String doAsUser) throws FalconCLIException {
         return sendListRequest(Entities.LIST, entityType, fields, nameSubsequence, tagKeywords, filterBy,
-                filterTags, orderBy, sortOrder, offset, numResults);
+                filterTags, orderBy, sortOrder, offset, numResults, doAsUser);
     }
 
     public EntitySummaryResult getEntitySummary(String entityType, String cluster, String start, String end,
                                    String fields, String filterBy, String filterTags,
                                    String orderBy, String sortOrder,
-                                   Integer offset, Integer numResults, Integer numInstances)
+                                   Integer offset, Integer numResults, Integer numInstances, String doAsUser)
         throws FalconCLIException {
         return sendEntitySummaryRequest(Entities.SUMMARY, entityType, cluster, start, end, fields, filterBy, filterTags,
-                orderBy, sortOrder, offset, numResults, numInstances);
+                orderBy, sortOrder, offset, numResults, numInstances, doAsUser);
     }
 
-    public APIResult touch(String entityType, String entityName,
-                           String colo, Boolean skipDryRun) throws FalconCLIException {
+    public APIResult touch(String entityType, String entityName, String colo,
+                           Boolean skipDryRun, String doAsUser) throws FalconCLIException {
         Entities operation = Entities.TOUCH;
         WebResource resource = service.path(operation.path).path(entityType).path(entityName);
         if (colo != null) {
@@ -413,6 +420,9 @@ public class FalconClient extends AbstractFalconClient {
         if (null != skipDryRun) {
             resource = resource.queryParam("skipDryRun", String.valueOf(skipDryRun));
         }
+        if (StringUtils.isNotEmpty(doAsUser)) {
+            resource = resource.queryParam(FalconCLI.DO_AS_OPT, doAsUser);
+        }
         ClientResponse clientResponse = resource
                 .header("Cookie", AUTH_COOKIE_EQ + authenticationToken)
                 .accept(operation.mimeType).type(MediaType.TEXT_XML)
@@ -423,10 +433,10 @@ public class FalconClient extends AbstractFalconClient {
 
     public InstancesResult getRunningInstances(String type, String entity, String colo, List<LifeCycle> lifeCycles,
                                       String filterBy, String orderBy, String sortOrder,
-                                      Integer offset, Integer numResults) throws FalconCLIException {
+                                      Integer offset, Integer numResults, String doAsUser) throws FalconCLIException {
 
         return sendInstanceRequest(Instances.RUNNING, type, entity, null, null,
-                null, null, colo, lifeCycles, filterBy, orderBy, sortOrder, offset, numResults)
+                null, null, colo, lifeCycles, filterBy, orderBy, sortOrder, offset, numResults, doAsUser)
                 .getEntity(InstancesResult.class);
     }
 
@@ -434,62 +444,66 @@ public class FalconClient extends AbstractFalconClient {
                                        String start, String end,
                                        String colo, List<LifeCycle> lifeCycles, String filterBy,
                                        String orderBy, String sortOrder,
-                                       Integer offset, Integer numResults) throws FalconCLIException {
+                                       Integer offset, Integer numResults, String doAsUser) throws FalconCLIException {
 
         return sendInstanceRequest(Instances.STATUS, type, entity, start, end,
-                null, null, colo, lifeCycles, filterBy, orderBy, sortOrder, offset, numResults)
+                null, null, colo, lifeCycles, filterBy, orderBy, sortOrder, offset, numResults, doAsUser)
                 .getEntity(InstancesResult.class);
     }
 
     public InstancesSummaryResult getSummaryOfInstances(String type, String entity,
                                         String start, String end,
                                         String colo, List<LifeCycle> lifeCycles,
-                                        String filterBy, String orderBy, String sortOrder) throws FalconCLIException {
+                                        String filterBy, String orderBy, String sortOrder,
+                                        String doAsUser) throws FalconCLIException {
 
         return sendInstanceRequest(Instances.SUMMARY, type, entity, start, end, null,
-            null, colo, lifeCycles, filterBy, orderBy, sortOrder, 0, null)
+                null, colo, lifeCycles, filterBy, orderBy, sortOrder, 0, null, doAsUser)
                 .getEntity(InstancesSummaryResult.class);
     }
 
     public FeedInstanceResult getFeedListing(String type, String entity, String start,
-                                     String end, String colo)
+                                     String end, String colo, String doAsUser)
         throws FalconCLIException {
 
         return sendInstanceRequest(Instances.LISTING, type, entity, start, end, null,
-            null, colo, null, "", "", "", 0, null).getEntity(FeedInstanceResult.class);
+                null, colo, null, "", "", "", 0, null, doAsUser).getEntity(FeedInstanceResult.class);
     }
 
     public InstancesResult killInstances(String type, String entity, String start,
                                 String end, String colo, String clusters,
-                                String sourceClusters, List<LifeCycle> lifeCycles)
+                                String sourceClusters, List<LifeCycle> lifeCycles,
+                                String doAsUser)
         throws FalconCLIException, UnsupportedEncodingException {
 
         return sendInstanceRequest(Instances.KILL, type, entity, start, end,
-                getServletInputStream(clusters, sourceClusters, null), null, colo, lifeCycles);
+                getServletInputStream(clusters, sourceClusters, null), null, colo, lifeCycles, doAsUser);
     }
 
     public InstancesResult suspendInstances(String type, String entity, String start,
                                    String end, String colo, String clusters,
-                                   String sourceClusters, List<LifeCycle> lifeCycles)
+                                   String sourceClusters, List<LifeCycle> lifeCycles,
+                                   String doAsUser)
         throws FalconCLIException, UnsupportedEncodingException {
 
         return sendInstanceRequest(Instances.SUSPEND, type, entity, start, end,
-                getServletInputStream(clusters, sourceClusters, null), null, colo, lifeCycles);
+                getServletInputStream(clusters, sourceClusters, null), null, colo, lifeCycles, doAsUser);
     }
 
     public InstancesResult resumeInstances(String type, String entity, String start,
                                   String end, String colo, String clusters,
-                                  String sourceClusters, List<LifeCycle> lifeCycles)
+                                  String sourceClusters, List<LifeCycle> lifeCycles,
+                                  String doAsUser)
         throws FalconCLIException, UnsupportedEncodingException {
 
         return sendInstanceRequest(Instances.RESUME, type, entity, start, end,
-                getServletInputStream(clusters, sourceClusters, null), null, colo, lifeCycles);
+                getServletInputStream(clusters, sourceClusters, null), null, colo, lifeCycles, doAsUser);
     }
 
     public InstancesResult rerunInstances(String type, String entity, String start,
                                  String end, String filePath, String colo,
                                  String clusters, String sourceClusters, List<LifeCycle> lifeCycles,
-                                 Boolean isForced)
+                                 Boolean isForced, String doAsUser)
         throws FalconCLIException, IOException {
 
         StringBuilder buffer = new StringBuilder();
@@ -508,55 +522,69 @@ public class FalconClient extends AbstractFalconClient {
         }
         String temp = (buffer.length() == 0) ? null : buffer.toString();
         return sendInstanceRequest(Instances.RERUN, type, entity, start, end,
-                getServletInputStream(clusters, sourceClusters, temp), null, colo, lifeCycles, isForced);
+                getServletInputStream(clusters, sourceClusters, temp), null, colo, lifeCycles, isForced, doAsUser);
     }
 
     public InstancesResult getLogsOfInstances(String type, String entity, String start,
                                      String end, String colo, String runId,
                                      List<LifeCycle> lifeCycles, String filterBy,
-                                     String orderBy, String sortOrder, Integer offset, Integer numResults)
+                                     String orderBy, String sortOrder, Integer offset,
+                                     Integer numResults, String doAsUser)
         throws FalconCLIException {
 
         return sendInstanceRequest(Instances.LOG, type, entity, start, end,
-                null, runId, colo, lifeCycles, filterBy, orderBy, sortOrder, offset, numResults)
+                null, runId, colo, lifeCycles, filterBy, orderBy, sortOrder, offset, numResults, doAsUser)
                 .getEntity(InstancesResult.class);
     }
 
     public InstancesResult getParamsOfInstance(String type, String entity,
                                       String start, String colo,
-                                      List<LifeCycle> lifeCycles)
+                                      List<LifeCycle> lifeCycles,
+                                      String doAsUser)
         throws FalconCLIException, UnsupportedEncodingException {
 
         return sendInstanceRequest(Instances.PARAMS, type, entity,
-                start, null, null, null, colo, lifeCycles);
+                start, null, null, null, colo, lifeCycles, doAsUser);
     }
 
-    public String getThreadDump() throws FalconCLIException {
-        return sendAdminRequest(AdminOperations.STACK);
+    public String getThreadDump(String doAsUser) throws FalconCLIException {
+        return sendAdminRequest(AdminOperations.STACK, doAsUser);
     }
 
-    public String getVersion() throws FalconCLIException {
-        return sendAdminRequest(AdminOperations.VERSION);
+    public String getVersion(String doAsUser) throws FalconCLIException {
+        return sendAdminRequest(AdminOperations.VERSION, doAsUser);
     }
 
-    public int getStatus() throws FalconCLIException {
+    public int getStatus(String doAsUser) throws FalconCLIException {
         AdminOperations job =  AdminOperations.VERSION;
-        ClientResponse clientResponse = service.path(job.path)
+
+        WebResource resource = service.path(job.path);
+
+        if (StringUtils.isNotEmpty(doAsUser)) {
+            resource = resource.queryParam(FalconCLI.DO_AS_OPT, doAsUser);
+        }
+
+        ClientResponse clientResponse = resource
                 .header("Cookie", AUTH_COOKIE_EQ + authenticationToken)
                 .accept(job.mimeType).type(MediaType.TEXT_PLAIN)
                 .method(job.method, ClientResponse.class);
         return clientResponse.getStatus();
     }
 
-    public String getDimensionList(String dimensionType, String cluster) throws FalconCLIException {
-        return sendMetadataDiscoveryRequest(MetadataOperations.LIST, dimensionType, null, cluster);
+    public String getDimensionList(String dimensionType, String cluster, String doAsUser) throws FalconCLIException {
+        return sendMetadataDiscoveryRequest(MetadataOperations.LIST, dimensionType, null, cluster, doAsUser);
     }
 
-    public LineageGraphResult getEntityLineageGraph(String pipelineName) throws FalconCLIException {
+    public LineageGraphResult getEntityLineageGraph(String pipelineName, String doAsUser) throws FalconCLIException {
         MetadataOperations operation = MetadataOperations.LINEAGE;
+
         WebResource resource = service.path(operation.path)
                 .queryParam(FalconMetadataCLI.PIPELINE_OPT, pipelineName);
 
+        if (StringUtils.isNotEmpty(doAsUser)) {
+            resource = resource.queryParam(FalconCLI.DO_AS_OPT, doAsUser);
+        }
+
         ClientResponse clientResponse = resource
             .header("Cookie", AUTH_COOKIE_EQ + authenticationToken)
             .accept(operation.mimeType).type(operation.mimeType)
@@ -565,8 +593,9 @@ public class FalconClient extends AbstractFalconClient {
         return clientResponse.getEntity(LineageGraphResult.class);
     }
 
-    public String getDimensionRelations(String dimensionType, String dimensionName) throws FalconCLIException {
-        return sendMetadataDiscoveryRequest(MetadataOperations.RELATIONS, dimensionType, dimensionName, null);
+    public String getDimensionRelations(String dimensionType, String dimensionName,
+                                        String doAsUser) throws FalconCLIException {
+        return sendMetadataDiscoveryRequest(MetadataOperations.RELATIONS, dimensionType, dimensionName, null, doAsUser);
     }
 
     /**
@@ -611,7 +640,8 @@ public class FalconClient extends AbstractFalconClient {
     }
 
     private APIResult sendEntityRequest(Entities entities, EntityType entityType,
-                                     String entityName, String colo, Boolean skipDryRun) throws FalconCLIException {
+                                     String entityName, String colo, Boolean skipDryRun,
+                                     String doAsUser) throws FalconCLIException {
 
         WebResource resource = service.path(entities.path)
                 .path(entityType.toString().toLowerCase()).path(entityName);
@@ -621,6 +651,9 @@ public class FalconClient extends AbstractFalconClient {
         if (null != skipDryRun) {
             resource = resource.queryParam("skipDryRun", String.valueOf(skipDryRun));
         }
+        if (StringUtils.isNotEmpty(doAsUser)) {
+            resource = resource.queryParam(FalconCLI.DO_AS_OPT, doAsUser);
+        }
 
         ClientResponse clientResponse = resource
                 .header("Cookie", AUTH_COOKIE_EQ + authenticationToken)
@@ -637,7 +670,8 @@ public class FalconClient extends AbstractFalconClient {
                                             String start, String end, String runId, String colo,
                                             String fields, String nameSubsequence, String tagKeywords, String filterBy,
                                             String tags, String orderBy, String sortOrder, Integer offset,
-                                            Integer numResults, Integer numInstances, Boolean isForced) {
+                                            Integer numResults, Integer numInstances, Boolean isForced,
+                                            String doAsUser) {
         if (StringUtils.isNotEmpty(fields)) {
             resource = resource.queryParam("fields", fields);
         }
@@ -683,6 +717,10 @@ public class FalconClient extends AbstractFalconClient {
         if (isForced != null) {
             resource = resource.queryParam("force", String.valueOf(isForced));
         }
+
+        if (StringUtils.isNotEmpty(doAsUser)) {
+            resource = resource.queryParam(FalconCLI.DO_AS_OPT, doAsUser);
+        }
         return resource;
 
     }
@@ -691,7 +729,7 @@ public class FalconClient extends AbstractFalconClient {
                                             String start, String end,
                                             String fields, String filterBy, String filterTags,
                                             String orderBy, String sortOrder, Integer offset, Integer numResults,
-                                            Integer numInstances) throws FalconCLIException {
+                                            Integer numInstances, String doAsUser) throws FalconCLIException {
         WebResource resource = service.path(entities.path).path(entityType);
         if (StringUtils.isNotEmpty(cluster)) {
             resource = resource.queryParam("cluster", cluster);
@@ -700,7 +738,7 @@ public class FalconClient extends AbstractFalconClient {
         resource = addParamsToResource(resource, start, end, null, null,
                 fields, null, null, filterBy, filterTags,
                 orderBy, sortOrder,
-                offset, numResults, numInstances, null);
+                offset, numResults, numInstances, null, doAsUser);
 
         ClientResponse clientResponse = resource
                 .header("Cookie", AUTH_COOKIE_EQ + authenticationToken)
@@ -713,10 +751,14 @@ public class FalconClient extends AbstractFalconClient {
     //RESUME CHECKSTYLE CHECK ParameterNumberCheck
 
     private Entity sendDefinitionRequest(Entities entities, String entityType,
-                                         String entityName) throws FalconCLIException {
+                                         String entityName, String doAsUser) throws FalconCLIException {
 
-        ClientResponse clientResponse = service
-                .path(entities.path).path(entityType).path(entityName)
+        WebResource resource = service.path(entities.path).path(entityType).path(entityName);
+        if (StringUtils.isNotEmpty(doAsUser)) {
+            resource = resource.queryParam(FalconCLI.DO_AS_OPT, doAsUser);
+        }
+
+        ClientResponse clientResponse = resource
                 .header("Cookie", AUTH_COOKIE_EQ + authenticationToken)
                 .accept(entities.mimeType).type(MediaType.TEXT_XML)
                 .method(entities.method, ClientResponse.class);
@@ -729,10 +771,13 @@ public class FalconClient extends AbstractFalconClient {
     }
 
     private EntityList sendDependencyRequest(Entities entities, String entityType,
-                                         String entityName) throws FalconCLIException {
+                                         String entityName, String doAsUser) throws FalconCLIException {
 
-        ClientResponse clientResponse = service
-                .path(entities.path).path(entityType).path(entityName)
+        WebResource resource = service.path(entities.path).path(entityType).path(entityName);
+        if (StringUtils.isNotEmpty(doAsUser)) {
+            resource = resource.queryParam(FalconCLI.DO_AS_OPT, doAsUser);
+        }
+        ClientResponse clientResponse = resource
                 .header("Cookie", AUTH_COOKIE_EQ + authenticationToken)
                 .accept(entities.mimeType).type(MediaType.TEXT_XML)
                 .method(entities.method, ClientResponse.class);
@@ -742,16 +787,22 @@ public class FalconClient extends AbstractFalconClient {
         return parseEntityList(clientResponse);
     }
 
-    private APIResult sendEntityRequestWithObject(Entities entities, String entityType, Object requestObject,
-                                                  String colo, Boolean skipDryRun) throws FalconCLIException {
+    private APIResult sendEntityRequestWithObject(Entities entities, String entityType,
+                                               Object requestObject, String colo,
+                                               Boolean skipDryRun, String doAsUser) throws FalconCLIException {
         WebResource resource = service.path(entities.path)
                 .path(entityType);
         if (colo != null) {
             resource = resource.queryParam("colo", colo);
         }
+
         if (null != skipDryRun) {
             resource = resource.queryParam("skipDryRun", String.valueOf(skipDryRun));
         }
+
+        if (StringUtils.isNotEmpty(doAsUser)) {
+            resource = resource.queryParam(FalconCLI.DO_AS_OPT, doAsUser);
+        }
         ClientResponse clientResponse = resource
                 .header("Cookie", AUTH_COOKIE_EQ + authenticationToken)
                 .accept(entities.mimeType).type(MediaType.TEXT_XML)
@@ -763,10 +814,13 @@ public class FalconClient extends AbstractFalconClient {
         return clientResponse.getEntity(APIResult.class);
     }
 
-    public FeedLookupResult reverseLookUp(String type, String path) throws FalconCLIException {
+    public FeedLookupResult reverseLookUp(String type, String path, String doAsUser) throws FalconCLIException {
         Entities api = Entities.LOOKUP;
         WebResource resource = service.path(api.path).path(type);
         resource = resource.queryParam("path", path);
+        if (StringUtils.isNotEmpty(doAsUser)) {
+            resource = resource.queryParam(FalconCLI.DO_AS_OPT, doAsUser);
+        }
         ClientResponse response = resource.header("Cookie", AUTH_COOKIE_EQ + authenticationToken)
                 .accept(api.mimeType)
                 .method(api.method, ClientResponse.class);
@@ -778,18 +832,18 @@ public class FalconClient extends AbstractFalconClient {
     private InstancesResult sendInstanceRequest(Instances instances, String type,
                                        String entity, String start, String end, InputStream props,
                                        String runid, String colo,
-                                       List<LifeCycle> lifeCycles) throws FalconCLIException {
+                                       List<LifeCycle> lifeCycles, String doAsUser) throws FalconCLIException {
         return sendInstanceRequest(instances, type, entity, start, end, props,
-                runid, colo, lifeCycles, "", "", "", 0, null)
+                runid, colo, lifeCycles, "", "", "", 0, null, doAsUser)
                 .getEntity(InstancesResult.class);
     }
 
     private InstancesResult sendInstanceRequest(Instances instances, String type,
                                                 String entity, String start, String end, InputStream props,
                                                 String runid, String colo, List<LifeCycle> lifeCycles,
-                                                Boolean isForced) throws FalconCLIException {
+                                                Boolean isForced, String doAsUser) throws FalconCLIException {
         return sendInstanceRequest(instances, type, entity, start, end, props,
-                runid, colo, lifeCycles, "", "", "", 0, null, isForced).getEntity(InstancesResult.class);
+                runid, colo, lifeCycles, "", "", "", 0, null, isForced, doAsUser).getEntity(InstancesResult.class);
     }
 
 
@@ -797,22 +851,23 @@ public class FalconClient extends AbstractFalconClient {
     private ClientResponse sendInstanceRequest(Instances instances, String type, String entity,
                                        String start, String end, InputStream props, String runid, String colo,
                                        List<LifeCycle> lifeCycles, String filterBy, String orderBy, String sortOrder,
-                                       Integer offset, Integer numResults) throws FalconCLIException {
+                                       Integer offset, Integer numResults, String doAsUser) throws FalconCLIException {
 
         return sendInstanceRequest(instances, type, entity, start, end, props,
-                runid, colo, lifeCycles, filterBy, orderBy, sortOrder, offset, numResults, null);
+                runid, colo, lifeCycles, filterBy, orderBy, sortOrder, offset, numResults, null, doAsUser);
     }
 
     private ClientResponse sendInstanceRequest(Instances instances, String type, String entity,
                                        String start, String end, InputStream props, String runid, String colo,
-                                       List<LifeCycle> lifeCycles, String filterBy, String orderBy, String sortOrder,
-                                       Integer offset, Integer numResults, Boolean isForced) throws FalconCLIException {
+                                       List<LifeCycle> lifeCycles, String filterBy, String orderBy,
+                                       String sortOrder, Integer offset, Integer numResults, Boolean isForced,
+                                       String doAsUser) throws FalconCLIException {
         checkType(type);
         WebResource resource = service.path(instances.path).path(type)
                 .path(entity);
 
         resource = addParamsToResource(resource, start, end, runid, colo,
-                null, null, null, filterBy, null, orderBy, sortOrder, offset, numResults, null, isForced);
+                null, null, null, filterBy, null, orderBy, sortOrder, offset, numResults, null, isForced, doAsUser);
 
         if (lifeCycles != null) {
             checkLifeCycleOption(lifeCycles, type);
@@ -881,11 +936,12 @@ public class FalconClient extends AbstractFalconClient {
     //SUSPEND CHECKSTYLE CHECK ParameterNumberCheck
     private EntityList sendListRequest(Entities entities, String entityType, String fields, String nameSubsequence,
                                        String tagKeywords, String filterBy, String filterTags, String orderBy,
-                                       String sortOrder, Integer offset, Integer numResults) throws FalconCLIException {
+                                       String sortOrder, Integer offset, Integer numResults, String doAsUser
+                                       ) throws FalconCLIException {
         WebResource resource = service.path(entities.path)
                 .path(entityType);
         resource = addParamsToResource(resource, null, null, null, null, fields, nameSubsequence, tagKeywords,
-                filterBy, filterTags, orderBy, sortOrder, offset, numResults, null, null);
+                filterBy, filterTags, orderBy, sortOrder, offset, numResults, null, null, doAsUser);
 
         ClientResponse clientResponse = resource
                 .header("Cookie", AUTH_COOKIE_EQ + authenticationToken)
@@ -898,8 +954,14 @@ public class FalconClient extends AbstractFalconClient {
     }
     // RESUME CHECKSTYLE CHECK ParameterNumberCheck
 
-    private String sendAdminRequest(AdminOperations job) throws FalconCLIException {
-        ClientResponse clientResponse = service.path(job.path)
+    private String sendAdminRequest(AdminOperations job, String doAsUser) throws FalconCLIException {
+        WebResource resource = service.path(job.path);
+
+        if (StringUtils.isNotEmpty(doAsUser)) {
+            resource = resource.queryParam(FalconCLI.DO_AS_OPT, doAsUser);
+        }
+
+        ClientResponse clientResponse = resource
                 .header("Cookie", AUTH_COOKIE_EQ + authenticationToken)
                 .accept(job.mimeType)
                 .type(job.mimeType)
@@ -910,7 +972,8 @@ public class FalconClient extends AbstractFalconClient {
     private String sendMetadataDiscoveryRequest(final MetadataOperations operation,
                                                 final String dimensionType,
                                                 final String dimensionName,
-                                                final String cluster) throws FalconCLIException {
+                                                final String cluster,
+                                                final String doAsUser) throws FalconCLIException {
         WebResource resource;
         switch (operation) {
         case LIST:
@@ -934,6 +997,10 @@ public class FalconClient extends AbstractFalconClient {
             resource = resource.queryParam(FalconMetadataCLI.CLUSTER_OPT, cluster);
         }
 
+        if (StringUtils.isNotEmpty(doAsUser)) {
+            resource = resource.queryParam(FalconCLI.DO_AS_OPT, doAsUser);
+        }
+
         ClientResponse clientResponse = resource
                 .header("Cookie", AUTH_COOKIE_EQ + authenticationToken)
                 .accept(operation.mimeType).type(operation.mimeType)
@@ -960,24 +1027,27 @@ public class FalconClient extends AbstractFalconClient {
 
     }
 
-    public String getVertex(String id) throws FalconCLIException {
-        return sendMetadataLineageRequest(MetadataOperations.VERTICES, id);
+    public String getVertex(String id, String doAsUser) throws FalconCLIException {
+        return sendMetadataLineageRequest(MetadataOperations.VERTICES, id, doAsUser);
     }
 
-    public String getVertices(String key, String value) throws FalconCLIException {
-        return sendMetadataLineageRequest(MetadataOperations.VERTICES, key, value);
+    public String getVertices(String key, String value, String doAsUser) throws FalconCLIException {
+        return sendMetadataLineageRequest(MetadataOperations.VERTICES, key, value, doAsUser);
     }
 
-    public String getVertexEdges(String id, String direction) throws FalconCLIException {
-        return sendMetadataLineageRequestForEdges(MetadataOperations.VERTICES, id, direction);
+    public String getVertexEdges(String id, String direction, String doAsUser) throws FalconCLIException {
+        return sendMetadataLineageRequestForEdges(MetadataOperations.VERTICES, id, direction, doAsUser);
     }
 
-    public String getEdge(String id) throws FalconCLIException {
-        return sendMetadataLineageRequest(MetadataOperations.EDGES, id);
+    public String getEdge(String id, String doAsUser) throws FalconCLIException {
+        return sendMetadataLineageRequest(MetadataOperations.EDGES, id, doAsUser);
     }
 
-    public APIResult submitRecipe(String recipeName, String recipeToolClassName,
-                                  final String recipeOperation, Boolean skipDryRun) throws FalconCLIException {
+    public APIResult submitRecipe(String recipeName,
+                                  String recipeToolClassName,
+                                  final String recipeOperation,
+                                  Boolean skipDryRun,
+                                  final String doAsUser) throws FalconCLIException {
         String recipePath = clientProperties.getProperty("falcon.recipe.path");
 
         if (StringUtils.isEmpty(recipePath)) {
@@ -1023,16 +1093,21 @@ public class FalconClient extends AbstractFalconClient {
             } else {
                 RecipeTool.main(args);
             }
-            validate(EntityType.PROCESS.toString(), processFile, skipDryRun);
-            return submitAndSchedule(EntityType.PROCESS.toString(), processFile, skipDryRun);
+            validate(EntityType.PROCESS.toString(), processFile, skipDryRun, doAsUser);
+            return submitAndSchedule(EntityType.PROCESS.toString(), processFile, skipDryRun, doAsUser);
         } catch (Exception e) {
             throw new FalconCLIException(e.getMessage(), e);
         }
     }
 
-    private String sendMetadataLineageRequest(MetadataOperations job, String id) throws FalconCLIException {
-        ClientResponse clientResponse = service.path(job.path)
-                .path(id)
+    private String sendMetadataLineageRequest(MetadataOperations job, String id,
+                                              String doAsUser) throws FalconCLIException {
+        WebResource resource = service.path(job.path).path(id);
+        if (StringUtils.isNotEmpty(doAsUser)) {
+            resource = resource.queryParam(FalconCLI.DO_AS_OPT, doAsUser);
+        }
+
+        ClientResponse clientResponse = resource
                 .header("Cookie", AUTH_COOKIE_EQ + authenticationToken)
                 .accept(job.mimeType)
                 .type(job.mimeType)
@@ -1041,9 +1116,13 @@ public class FalconClient extends AbstractFalconClient {
     }
 
     private String sendMetadataLineageRequest(MetadataOperations job, String key,
-                                              String value) throws FalconCLIException {
-        ClientResponse clientResponse = service.path(job.path)
-                .queryParam("key", key)
+                                              String value, String doAsUser) throws FalconCLIException {
+        WebResource resource = service.path(job.path);
+
+        if (StringUtils.isNotEmpty(doAsUser)) {
+            resource = resource.queryParam(FalconCLI.DO_AS_OPT, doAsUser);
+        }
+        ClientResponse clientResponse = resource.queryParam("key", key)
                 .queryParam("value", value)
                 .header("Cookie", AUTH_COOKIE_EQ + authenticationToken)
                 .accept(job.mimeType)
@@ -1053,10 +1132,15 @@ public class FalconClient extends AbstractFalconClient {
     }
 
     private String sendMetadataLineageRequestForEdges(MetadataOperations job, String id,
-                                                      String direction) throws FalconCLIException {
-        ClientResponse clientResponse = service.path(job.path)
-                .path(id)
-                .path(direction)
+                                                      String direction, String doAsUser) throws FalconCLIException {
+        WebResource resource = service.path(job.path)
+                .path(id).path(direction);
+
+        if (StringUtils.isNotEmpty(doAsUser)) {
+            resource = resource.queryParam(FalconCLI.DO_AS_OPT, doAsUser);
+        }
+
+        ClientResponse clientResponse = resource
                 .header("Cookie", AUTH_COOKIE_EQ + authenticationToken)
                 .accept(job.mimeType)
                 .type(job.mimeType)

http://git-wip-us.apache.org/repos/asf/falcon/blob/d8fbec9f/common/src/main/java/org/apache/falcon/security/CurrentUser.java
----------------------------------------------------------------------
diff --git a/common/src/main/java/org/apache/falcon/security/CurrentUser.java b/common/src/main/java/org/apache/falcon/security/CurrentUser.java
index 4aed5d7..e7c1594 100644
--- a/common/src/main/java/org/apache/falcon/security/CurrentUser.java
+++ b/common/src/main/java/org/apache/falcon/security/CurrentUser.java
@@ -19,6 +19,8 @@
 package org.apache.falcon.security;
 
 import org.apache.commons.lang3.StringUtils;
+import org.apache.falcon.service.ProxyUserService;
+import org.apache.falcon.service.Services;
 import org.apache.hadoop.security.UserGroupInformation;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -66,6 +68,40 @@ public final class CurrentUser {
     }
 
     /**
+     * Proxies doAs user.
+     *
+     * @param doAsUser doAs user
+     * @param proxyHost proxy host
+     * @throws IOException
+     */
+    public static void proxyDoAsUser(final String doAsUser,
+                                     final String proxyHost) throws IOException {
+        if (!isAuthenticated()) {
+            throw new IllegalStateException("Authentication not done");
+        }
+
+        String currentUser = CURRENT_USER.get().authenticatedUser;
+        if (StringUtils.isNotEmpty(doAsUser) && !doAsUser.equalsIgnoreCase(currentUser)) {
+            if (StringUtils.isEmpty(proxyHost)) {
+                throw new IllegalArgumentException("proxy host cannot be null or empty");
+            }
+            ProxyUserService proxyUserService = Services.get().getService(ProxyUserService.SERVICE_NAME);
+            try {
+                proxyUserService.validate(currentUser, proxyHost, doAsUser);
+            } catch (IOException ex) {
+                throw new RuntimeException(ex);
+            }
+
+            CurrentUser user = CURRENT_USER.get();
+            LOG.info("Authenticated user {} is proxying doAs user {} from host {}",
+                    user.authenticatedUser, doAsUser, proxyHost);
+            AUDIT.info("Authenticated user {} is proxying doAs user {} from host {}",
+                    user.authenticatedUser, doAsUser, proxyHost);
+            user.proxyUser = doAsUser;
+        }
+    }
+
+    /**
      * Captures the entity owner if authenticated user is a super user.
      *
      * @param aclOwner entity acl owner
@@ -80,9 +116,9 @@ public final class CurrentUser {
 
         CurrentUser user = CURRENT_USER.get();
         LOG.info("Authenticated user {} is proxying entity owner {}/{}",
-            user.authenticatedUser, aclOwner, aclGroup);
+                user.authenticatedUser, aclOwner, aclGroup);
         AUDIT.info("Authenticated user {} is proxying entity owner {}/{}",
-            user.authenticatedUser, aclOwner, aclGroup);
+                user.authenticatedUser, aclOwner, aclGroup);
         user.proxyUser = aclOwner;
     }
 

http://git-wip-us.apache.org/repos/asf/falcon/blob/d8fbec9f/common/src/main/java/org/apache/falcon/security/SecurityUtil.java
----------------------------------------------------------------------
diff --git a/common/src/main/java/org/apache/falcon/security/SecurityUtil.java b/common/src/main/java/org/apache/falcon/security/SecurityUtil.java
index 861f80f..123a1a2 100644
--- a/common/src/main/java/org/apache/falcon/security/SecurityUtil.java
+++ b/common/src/main/java/org/apache/falcon/security/SecurityUtil.java
@@ -18,12 +18,15 @@
 
 package org.apache.falcon.security;
 
+import org.apache.commons.lang3.StringUtils;
 import org.apache.falcon.FalconException;
 import org.apache.falcon.entity.v0.Entity;
 import org.apache.falcon.util.ReflectionUtils;
 import org.apache.falcon.util.StartupProperties;
 import org.apache.hadoop.security.authentication.server.KerberosAuthenticationHandler;
 import org.apache.hadoop.security.authentication.server.PseudoAuthenticationHandler;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 import java.io.IOException;
 import java.net.InetAddress;
@@ -55,6 +58,7 @@ public final class SecurityUtil {
      */
     public static final String HIVE_METASTORE_PRINCIPAL = "hive.metastore.kerberos.principal";
 
+    private static final Logger LOG = LoggerFactory.getLogger(SecurityUtil.class);
 
     private SecurityUtil() {
     }
@@ -107,11 +111,19 @@ public final class SecurityUtil {
         return ReflectionUtils.getInstanceByClassName(providerClassName);
     }
 
-    public static void tryProxy(Entity entity) throws IOException, FalconException {
+    public static void tryProxy(Entity entity, final String doAsUser) throws IOException, FalconException {
         if (entity != null && entity.getACL() != null && SecurityUtil.isAuthorizationEnabled()) {
             final String aclOwner = entity.getACL().getOwner();
             final String aclGroup = entity.getACL().getGroup();
 
+            if (StringUtils.isNotEmpty(doAsUser)) {
+                if (!doAsUser.equalsIgnoreCase(aclOwner)) {
+                    LOG.warn("doAs user {} not same as acl owner {}. Ignoring acl owner.", doAsUser, aclOwner);
+                    throw new FalconException("doAs user and ACL owner mismatch. doAs user " + doAsUser
+                            +  " should be same as ACL owner " + aclOwner);
+                }
+                return;
+            }
             if (SecurityUtil.getAuthorizationProvider().shouldProxy(
                     CurrentUser.getAuthenticatedUGI(), aclOwner, aclGroup)) {
                 CurrentUser.proxy(aclOwner, aclGroup);

http://git-wip-us.apache.org/repos/asf/falcon/blob/d8fbec9f/common/src/main/java/org/apache/falcon/service/GroupsService.java
----------------------------------------------------------------------
diff --git a/common/src/main/java/org/apache/falcon/service/GroupsService.java b/common/src/main/java/org/apache/falcon/service/GroupsService.java
new file mode 100644
index 0000000..dd4d946
--- /dev/null
+++ b/common/src/main/java/org/apache/falcon/service/GroupsService.java
@@ -0,0 +1,67 @@
+/**
+ * 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.service;
+
+import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.security.Groups;
+
+import java.io.IOException;
+import java.util.List;
+
+/**
+ * The GroupsService class delegates to the Hadoop's <code>org.apache.hadoop.security.Groups</code>
+ * to retrieve the groups a user belongs to.
+ */
+public class GroupsService implements FalconService {
+    private org.apache.hadoop.security.Groups hGroups;
+
+    public static final String SERVICE_NAME = GroupsService.class.getSimpleName();
+
+    /**
+     * Initializes the service.
+     */
+    @Override
+    public void init() {
+        hGroups = new Groups(new Configuration(true));
+    }
+
+    /**
+     * Destroys the service.
+     */
+    @Override
+    public void destroy() {
+    }
+
+    @Override
+    public String getName() {
+        return SERVICE_NAME;
+    }
+
+    /**
+     * Returns the list of groups a user belongs to.
+     *
+     * @param user user name.
+     * @return the groups the given user belongs to.
+     * @throws java.io.IOException thrown if there was an error retrieving the groups of the user.
+     */
+    public List<String> getGroups(String user) throws IOException {
+        return hGroups.getGroups(user);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/falcon/blob/d8fbec9f/common/src/main/java/org/apache/falcon/service/ProxyUserService.java
----------------------------------------------------------------------
diff --git a/common/src/main/java/org/apache/falcon/service/ProxyUserService.java b/common/src/main/java/org/apache/falcon/service/ProxyUserService.java
new file mode 100644
index 0000000..0ad6663
--- /dev/null
+++ b/common/src/main/java/org/apache/falcon/service/ProxyUserService.java
@@ -0,0 +1,203 @@
+/**
+ * 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.service;
+
+import org.apache.commons.lang3.StringUtils;
+import org.apache.falcon.FalconException;
+import org.apache.falcon.util.RuntimeProperties;
+
+import java.io.IOException;
+import java.net.InetAddress;
+import java.security.AccessControlException;
+import java.text.MessageFormat;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * The ProxyUserService checks if a user of a request has proxyuser privileges.
+ * <p>
+ * This check is based on the following criteria:
+ * <p>
+ * <ul>
+ *     <li>The user of the request must be configured as proxy user in Falcon runtime properties.</li>
+ *     <li>The user of the request must be making the request from a whitelisted host.</li>
+ *     <li>The user of the request must be making the request on behalf of a user of a whitelisted group.</li>
+ * </ul>
+ * <p>
+ */
+public class ProxyUserService implements FalconService {
+    private static final Logger LOG = LoggerFactory.getLogger(ProxyUserService.class);
+
+
+    private Map<String, Set<String>> proxyUserHosts = new HashMap<>();
+    private Map<String, Set<String>> proxyUserGroups = new HashMap<>();
+
+    private static final String CONF_PREFIX = "falcon.service.ProxyUserService.proxyuser.";
+    private static final String GROUPS = ".groups";
+    private static final String HOSTS = ".hosts";
+    public static final String SERVICE_NAME = ProxyUserService.class.getSimpleName();
+
+    @Override
+    public String getName() {
+        return SERVICE_NAME;
+    }
+
+    /**
+     * Initializes the service.
+     * @throws FalconException thrown if the service could not be configured correctly.
+     */
+    @Override
+    public void init() throws FalconException {
+        Set<Map.Entry<Object, Object>> entrySet = RuntimeProperties.get().entrySet();
+
+        for (Map.Entry<Object, Object> entry : entrySet) {
+            String key = (String) entry.getKey();
+
+            if (key.startsWith(CONF_PREFIX) && key.endsWith(GROUPS)) {
+                String proxyUser = key.substring(0, key.lastIndexOf(GROUPS));
+                if (RuntimeProperties.get().getProperty(proxyUser + HOSTS) == null) {
+                    throw new FalconException(CONF_PREFIX + proxyUser + HOSTS + " property not set in runtime "
+                            + "properties. Please add it.");
+                }
+                proxyUser = proxyUser.substring(CONF_PREFIX.length());
+                String value = ((String) entry.getValue()).trim();
+                LOG.info("Loading proxyuser settings [{}]=[{}]", key, value);
+                Set<String> values = null;
+                if (!value.equals("*")) {
+                    values = new HashSet<>(Arrays.asList(value.split(",")));
+                }
+                proxyUserGroups.put(proxyUser, values);
+            }
+            if (key.startsWith(CONF_PREFIX) && key.endsWith(HOSTS)) {
+                String proxyUser = key.substring(0, key.lastIndexOf(HOSTS));
+                if (RuntimeProperties.get().getProperty(proxyUser + GROUPS) == null) {
+                    throw new FalconException(CONF_PREFIX + proxyUser + GROUPS + " property not set in runtime "
+                            + "properties. Please add it.");
+                }
+                proxyUser = proxyUser.substring(CONF_PREFIX.length());
+                String value = ((String) entry.getValue()).trim();
+                LOG.info("Loading proxyuser settings [{}]=[{}]", key, value);
+                Set<String> values = null;
+                if (!value.equals("*")) {
+                    String[] hosts = value.split(",");
+                    for (int i = 0; i < hosts.length; i++) {
+                        String hostName = hosts[i];
+                        try {
+                            hosts[i] = normalizeHostname(hostName);
+                        } catch (Exception ex) {
+                            throw new FalconException("Exception normalizing host name: " + hostName + "."
+                                    + ex.getMessage(), ex);
+                        }
+                        LOG.info("Hostname, original [{}], normalized [{}]", hostName, hosts[i]);
+                    }
+                    values = new HashSet<>(Arrays.asList(hosts));
+                }
+                proxyUserHosts.put(proxyUser, values);
+            }
+        }
+    }
+
+    /**
+     * Verifies a proxyuser.
+     *
+     * @param proxyUser user name of the proxy user.
+     * @param proxyHost host the proxy user is making the request from.
+     * @param doAsUser user the proxy user is impersonating.
+     * @throws java.io.IOException thrown if an error during the validation has occurred.
+     * @throws java.security.AccessControlException thrown if the user is not allowed to perform the proxyuser request.
+     */
+    public void validate(String proxyUser, String proxyHost, String doAsUser) throws IOException {
+        validateNotEmpty(proxyUser, "proxyUser",
+                "If you're attempting to use user-impersonation via a proxy user, please make sure that "
+                        + "falcon.service.ProxyUserService.proxyuser.#USER#.hosts and "
+                        + "falcon.service.ProxyUserService.proxyuser.#USER#.groups are configured correctly"
+        );
+        validateNotEmpty(proxyHost, "proxyHost",
+                "If you're attempting to use user-impersonation via a proxy user, please make sure that "
+                        + "falcon.service.ProxyUserService.proxyuser." + proxyUser + ".hosts and "
+                        + "falcon.service.ProxyUserService.proxyuser." + proxyUser + ".groups are configured correctly"
+        );
+        validateNotEmpty(doAsUser, "doAsUser", null);
+        LOG.debug("Authorization check proxyuser [{}] host [{}] doAs [{}]",
+                proxyUser, proxyHost, doAsUser);
+        if (proxyUserHosts.containsKey(proxyUser)) {
+            validateRequestorHost(proxyUser, proxyHost, proxyUserHosts.get(proxyUser));
+            validateGroup(proxyUser, doAsUser, proxyUserGroups.get(proxyUser));
+        } else {
+            throw new AccessControlException(MessageFormat.format("User [{0}] not defined as proxyuser. Please add it"
+                            + " to runtime properties.", proxyUser));
+        }
+    }
+
+    private void validateRequestorHost(String proxyUser, String hostname, Set<String> validHosts)
+        throws IOException {
+        if (validHosts != null) {
+            if (!validHosts.contains(hostname) && !validHosts.contains(normalizeHostname(hostname))) {
+                throw new AccessControlException(MessageFormat.format("Unauthorized host [{0}] for proxyuser [{1}]",
+                        hostname, proxyUser));
+            }
+        }
+    }
+
+    private void validateGroup(String proxyUser, String user, Set<String> validGroups) throws IOException {
+        if (validGroups != null) {
+            List<String> userGroups =  Services.get().<GroupsService>getService(GroupsService.SERVICE_NAME)
+            .getGroups(user);
+            for (String g : validGroups) {
+                if (userGroups.contains(g)) {
+                    return;
+                }
+            }
+            throw new AccessControlException(
+                    MessageFormat.format("Unauthorized proxyuser [{0}] for user [{1}], not in proxyuser groups",
+                            proxyUser, user));
+        }
+    }
+
+    private String normalizeHostname(String name) {
+        try {
+            InetAddress address = InetAddress.getByName(name);
+            return address.getCanonicalHostName();
+        }  catch (IOException ex) {
+            throw new AccessControlException(MessageFormat.format("Could not resolve host [{0}], [{1}]", name,
+                    ex.getMessage()));
+        }
+    }
+
+    private static void validateNotEmpty(String str, String name, String info) {
+        if (StringUtils.isBlank(str)) {
+            throw new IllegalArgumentException(name + " cannot be null or empty" + (info == null ? "" : ", " + info));
+        }
+    }
+
+    /**
+     * Destroys the service.
+     */
+    @Override
+    public void destroy() {
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/falcon/blob/d8fbec9f/common/src/main/resources/runtime.properties
----------------------------------------------------------------------
diff --git a/common/src/main/resources/runtime.properties b/common/src/main/resources/runtime.properties
index 23ecc16..f499dd9 100644
--- a/common/src/main/resources/runtime.properties
+++ b/common/src/main/resources/runtime.properties
@@ -31,4 +31,20 @@
 *.feed.late.policy=exp-backoff
 
 # If true, Falcon skips oozie dryrun while scheduling entities.
-*.falcon.skip.dryrun=false
\ No newline at end of file
+*.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 #########
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/falcon/blob/d8fbec9f/common/src/main/resources/startup.properties
----------------------------------------------------------------------
diff --git a/common/src/main/resources/startup.properties b/common/src/main/resources/startup.properties
index c48188c..0593b96 100644
--- a/common/src/main/resources/startup.properties
+++ b/common/src/main/resources/startup.properties
@@ -37,7 +37,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
 
 ##### Falcon Configuration Store Change listeners #####
 *.configstore.listeners=org.apache.falcon.entity.v0.EntityGraph,\