This is an automated email from the ASF dual-hosted git repository.
eyang pushed a commit to branch trunk
in repository https://gitbox.apache.org/repos/asf/hadoop.git
The following commit(s) were added to refs/heads/trunk by this push:
new ea0b1d8 HADOOP-16287. Implement ProxyUserAuthenticationFilter for
web protocol impersonation. Contributed by Prabhu Joseph
ea0b1d8 is described below
commit ea0b1d8fba57f56e2a75e9a70d4768ba75952823
Author: Eric Yang <[email protected]>
AuthorDate: Thu May 23 11:36:32 2019 -0400
HADOOP-16287. Implement ProxyUserAuthenticationFilter for web protocol
impersonation.
Contributed by Prabhu Joseph
---
hadoop-common-project/hadoop-common/pom.xml | 10 ++
.../server/ProxyUserAuthenticationFilter.java | 115 +++++++++++++++++++
.../ProxyUserAuthenticationFilterInitializer.java | 60 ++++++++++
.../authentication/server/package-info.java | 22 ++++
.../src/site/markdown/HttpAuthentication.md | 8 ++
.../server/TestProxyUserAuthenticationFilter.java | 125 +++++++++++++++++++++
6 files changed, 340 insertions(+)
diff --git a/hadoop-common-project/hadoop-common/pom.xml
b/hadoop-common-project/hadoop-common/pom.xml
index 73b4c18..54efeeb 100644
--- a/hadoop-common-project/hadoop-common/pom.xml
+++ b/hadoop-common-project/hadoop-common/pom.xml
@@ -161,6 +161,16 @@
<scope>test</scope>
</dependency>
<dependency>
+ <groupId>org.assertj</groupId>
+ <artifactId>assertj-core</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.glassfish.grizzly</groupId>
+ <artifactId>grizzly-http-servlet</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
<groupId>commons-beanutils</groupId>
<artifactId>commons-beanutils</artifactId>
<scope>compile</scope>
diff --git
a/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/security/authentication/server/ProxyUserAuthenticationFilter.java
b/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/security/authentication/server/ProxyUserAuthenticationFilter.java
new file mode 100644
index 0000000..42902b3
--- /dev/null
+++
b/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/security/authentication/server/ProxyUserAuthenticationFilter.java
@@ -0,0 +1,115 @@
+/**
+ * Licensed 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. See accompanying LICENSE file.
+ */
+package org.apache.hadoop.security.authentication.server;
+
+import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.security.authorize.AuthorizationException;
+import org.apache.hadoop.security.authorize.ProxyUsers;
+import org.apache.hadoop.security.UserGroupInformation;
+import org.apache.hadoop.util.HttpExceptionUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.IOException;
+import java.security.Principal;
+import java.util.Enumeration;
+import javax.servlet.FilterChain;
+import javax.servlet.FilterConfig;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletRequestWrapper;
+import javax.servlet.http.HttpServletResponse;
+
+/**
+ * AuthenticationFilter which adds support to perform operations
+ * using end user instead of proxy user. Fetches the end user from
+ * doAs Query Parameter.
+ */
+public class ProxyUserAuthenticationFilter extends AuthenticationFilter {
+
+ private static final Logger LOG = LoggerFactory.getLogger(
+ ProxyUserAuthenticationFilter.class);
+
+ private static final String DO_AS = "doAs";
+ public static final String PROXYUSER_PREFIX = "proxyuser";
+
+ @Override
+ public void init(FilterConfig filterConfig) throws ServletException {
+ Configuration conf = getProxyuserConfiguration(filterConfig);
+ ProxyUsers.refreshSuperUserGroupsConfiguration(conf, PROXYUSER_PREFIX);
+ super.init(filterConfig);
+ }
+
+ @Override
+ protected void doFilter(FilterChain filterChain, HttpServletRequest request,
+ HttpServletResponse response) throws IOException, ServletException {
+
+ String doAsUser = request.getParameter(DO_AS);
+ if (doAsUser != null && !doAsUser.equals(request.getRemoteUser())) {
+ LOG.debug("doAsUser = {}, RemoteUser = {} , RemoteAddress = {} ",
+ doAsUser, request.getRemoteUser(), request.getRemoteAddr());
+ UserGroupInformation requestUgi = (request.getUserPrincipal() != null) ?
+ UserGroupInformation.createRemoteUser(request.getRemoteUser())
+ : null;
+ if (requestUgi != null) {
+ requestUgi = UserGroupInformation.createProxyUser(doAsUser,
+ requestUgi);
+ try {
+ ProxyUsers.authorize(requestUgi, request.getRemoteAddr());
+
+ final UserGroupInformation ugiF = requestUgi;
+ request = new HttpServletRequestWrapper(request) {
+ @Override
+ public String getRemoteUser() {
+ return ugiF.getShortUserName();
+ }
+
+ @Override
+ public Principal getUserPrincipal() {
+ return new Principal() {
+ @Override
+ public String getName() {
+ return ugiF.getUserName();
+ }
+ };
+ }
+ };
+ LOG.debug("Proxy user Authentication successful");
+ } catch (AuthorizationException ex) {
+ HttpExceptionUtils.createServletExceptionResponse(response,
+ HttpServletResponse.SC_FORBIDDEN, ex);
+ LOG.warn("Proxy user Authentication exception", ex);
+ return;
+ }
+ }
+ }
+ super.doFilter(filterChain, request, response);
+ }
+
+ protected Configuration getProxyuserConfiguration(FilterConfig filterConfig)
+ throws ServletException {
+ Configuration conf = new Configuration(false);
+ Enumeration<?> names = filterConfig.getInitParameterNames();
+ while (names.hasMoreElements()) {
+ String name = (String) names.nextElement();
+ if (name.startsWith(PROXYUSER_PREFIX + ".")) {
+ String value = filterConfig.getInitParameter(name);
+ conf.set(name, value);
+ }
+ }
+ return conf;
+ }
+
+}
+
diff --git
a/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/security/authentication/server/ProxyUserAuthenticationFilterInitializer.java
b/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/security/authentication/server/ProxyUserAuthenticationFilterInitializer.java
new file mode 100644
index 0000000..ad79742
--- /dev/null
+++
b/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/security/authentication/server/ProxyUserAuthenticationFilterInitializer.java
@@ -0,0 +1,60 @@
+/**
+ * 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.hadoop.security.authentication.server;
+
+import java.util.Map;
+import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.http.FilterContainer;
+import org.apache.hadoop.http.FilterInitializer;
+import org.apache.hadoop.security.AuthenticationFilterInitializer;
+import org.apache.hadoop.security.authorize.ProxyUsers;
+
+/**
+ * Filter initializer to initialize
+ * {@link ProxyUserAuthenticationFilter} which adds support
+ * to perform operations using end user instead of proxy user.
+ */
+public class ProxyUserAuthenticationFilterInitializer
+ extends FilterInitializer {
+
+ private String configPrefix;
+
+ public ProxyUserAuthenticationFilterInitializer() {
+ this.configPrefix = "hadoop.http.authentication.";
+ }
+
+ protected Map<String, String> createFilterConfig(Configuration conf) {
+ Map<String, String> filterConfig = AuthenticationFilterInitializer
+ .getFilterConfigMap(conf, configPrefix);
+ //Add proxy user configs
+ for (Map.Entry<String, String> entry : conf.getPropsWithPrefix(
+ ProxyUsers.CONF_HADOOP_PROXYUSER).entrySet()) {
+ filterConfig.put("proxyuser" + entry.getKey(), entry.getValue());
+ }
+ return filterConfig;
+ }
+
+ @Override
+ public void initFilter(FilterContainer container, Configuration conf) {
+ Map<String, String> filterConfig = createFilterConfig(conf);
+ container.addFilter("ProxyUserAuthenticationFilter",
+ ProxyUserAuthenticationFilter.class.getName(), filterConfig);
+ }
+
+}
\ No newline at end of file
diff --git
a/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/security/authentication/server/package-info.java
b/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/security/authentication/server/package-info.java
new file mode 100644
index 0000000..b0accf7
--- /dev/null
+++
b/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/security/authentication/server/package-info.java
@@ -0,0 +1,22 @@
+/*
+ * 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.
+ */
+
+/**
+ * Provides the server-side framework for authentication.
+ */
+package org.apache.hadoop.security.authentication.server;
diff --git
a/hadoop-common-project/hadoop-common/src/site/markdown/HttpAuthentication.md
b/hadoop-common-project/hadoop-common/src/site/markdown/HttpAuthentication.md
index 721abea..97d12fb 100644
---
a/hadoop-common-project/hadoop-common/src/site/markdown/HttpAuthentication.md
+++
b/hadoop-common-project/hadoop-common/src/site/markdown/HttpAuthentication.md
@@ -64,3 +64,11 @@ Add
org.apache.hadoop.security.HttpCrossOriginFilterInitializer to hadoop.http.f
| hadoop.http.cross-origin.allowed-methods | `GET,POST,HEAD`
| Comma separated list of methods that are allowed
|
| hadoop.http.cross-origin.allowed-headers |
`X-Requested-With,Content-Type,Accept,Origin` | Comma separated list of headers
that are allowed |
| hadoop.http.cross-origin.max-age | `1800`
| Number of seconds a pre-flighted request can be cached
|
+
+
+Trusted Proxy
+-------------
+Trusted Proxy adds support to perform operations using end user instead of
proxy user. It fetches the end user from
+doAs query parameter. To enable Trusted Proxy, please set the following
configuration parameter:
+
+Add
org.apache.hadoop.security.authentication.server.ProxyUserAuthenticationFilterInitializer
to hadoop.http.filter.initializers at the end in core-site.xml.
diff --git
a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/security/authentication/server/TestProxyUserAuthenticationFilter.java
b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/security/authentication/server/TestProxyUserAuthenticationFilter.java
new file mode 100644
index 0000000..019ab79
--- /dev/null
+++
b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/security/authentication/server/TestProxyUserAuthenticationFilter.java
@@ -0,0 +1,125 @@
+/**
+ * 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.hadoop.security.authentication.server;
+
+import java.security.Principal;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.servlet.FilterConfig;
+import javax.servlet.FilterChain;
+import javax.servlet.ServletContext;
+import javax.servlet.ServletResponse;
+import javax.servlet.ServletRequest;
+import javax.servlet.http.HttpServletRequest;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import org.glassfish.grizzly.servlet.HttpServletResponseImpl;
+import org.junit.Test;
+import org.mockito.Mockito;
+
+
+/**
+ * Test ProxyUserAuthenticationFilter with doAs Request Parameter.
+ */
+public class TestProxyUserAuthenticationFilter {
+
+ private String actualUser;
+
+ private static class DummyFilterConfig implements FilterConfig {
+ private final Map<String, String> map;
+
+ DummyFilterConfig(Map<String, String> map) {
+ this.map = map;
+ }
+
+ @Override
+ public String getFilterName() {
+ return "dummy";
+ }
+
+ @Override
+ public String getInitParameter(String param) {
+ return map.get(param);
+ }
+
+ @Override
+ public Enumeration<String> getInitParameterNames() {
+ return Collections.enumeration(map.keySet());
+ }
+
+ @Override
+ public ServletContext getServletContext() {
+ ServletContext context = Mockito.mock(ServletContext.class);
+ Mockito.when(context.getAttribute(
+ AuthenticationFilter.SIGNER_SECRET_PROVIDER_ATTRIBUTE))
+ .thenReturn(null);
+ return context;
+ }
+ }
+
+ private class HttpServletResponseForTest extends HttpServletResponseImpl {
+
+ }
+
+
+ @Test(timeout = 10000)
+ public void testFilter() throws Exception {
+ Map<String, String> params = new HashMap<String, String>();
+ params.put("proxyuser.knox.users", "testuser");
+ params.put("proxyuser.knox.hosts", "127.0.0.1");
+ params.put("type", "simple");
+
+ FilterConfig config = new DummyFilterConfig(params);
+
+ FilterChain chain = new FilterChain() {
+ @Override
+ public void doFilter(ServletRequest servletRequest,
+ ServletResponse servletResponse) {
+ HttpServletRequest request = (HttpServletRequest) servletRequest;
+ actualUser = request.getRemoteUser();
+ }
+ };
+
+ ProxyUserAuthenticationFilter testFilter =
+ new ProxyUserAuthenticationFilter();
+ testFilter.init(config);
+
+ HttpServletRequest request = Mockito.mock(HttpServletRequest.class);
+ Mockito.when(request.getRemoteUser()).thenReturn("knox");
+ Mockito.when(request.getParameter("doAs")).thenReturn("testuser");
+ Mockito.when(request.getRemoteAddr()).thenReturn("127.0.0.1");
+ Mockito.when(request.getUserPrincipal()).thenReturn(new Principal() {
+ @Override
+ public String getName() {
+ return "[email protected]";
+ }
+ });
+
+ HttpServletResponseForTest response = new HttpServletResponseForTest();
+
+ testFilter.doFilter(chain, request, response);
+
+ assertThat(actualUser).isEqualTo("testuser");
+ }
+
+
+}
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]