Skip to content

Commit 294695d

Browse files
committed
HADOOP-16314. Make sure all web end points are covered by the same authentication filter.
Contributed by Prabhu Joseph
1 parent 3b1c257 commit 294695d

File tree

18 files changed

+412
-54
lines changed

18 files changed

+412
-54
lines changed

hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/http/HttpServer2.java

Lines changed: 20 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
import java.net.MalformedURLException;
2828
import java.net.URI;
2929
import java.net.URL;
30+
import java.util.Arrays;
3031
import java.util.ArrayList;
3132
import java.util.Collections;
3233
import java.util.Enumeration;
@@ -66,6 +67,8 @@
6667
import org.apache.hadoop.security.SecurityUtil;
6768
import org.apache.hadoop.security.UserGroupInformation;
6869
import org.apache.hadoop.security.authentication.server.AuthenticationFilter;
70+
import org.apache.hadoop.security.authentication.server.ProxyUserAuthenticationFilterInitializer;
71+
import org.apache.hadoop.security.authentication.server.PseudoAuthenticationHandler;
6972
import org.apache.hadoop.security.authentication.util.SignerSecretProvider;
7073
import org.apache.hadoop.security.authorize.AccessControlList;
7174
import org.apache.hadoop.security.ssl.SSLFactory;
@@ -90,7 +93,6 @@
9093
import org.eclipse.jetty.server.handler.RequestLogHandler;
9194
import org.eclipse.jetty.server.session.AbstractSessionManager;
9295
import org.eclipse.jetty.server.session.SessionHandler;
93-
import org.eclipse.jetty.servlet.DefaultServlet;
9496
import org.eclipse.jetty.servlet.FilterHolder;
9597
import org.eclipse.jetty.servlet.FilterMapping;
9698
import org.eclipse.jetty.servlet.ServletContextHandler;
@@ -155,7 +157,7 @@ public final class HttpServer2 implements FilterContainer {
155157
// gets stored.
156158
public static final String CONF_CONTEXT_ATTRIBUTE = "hadoop.conf";
157159
public static final String ADMINS_ACL = "admins.acl";
158-
public static final String SPNEGO_FILTER = "SpnegoFilter";
160+
public static final String SPNEGO_FILTER = "authentication";
159161
public static final String NO_CACHE_FILTER = "NoCacheFilter";
160162

161163
public static final String BIND_ADDRESS = "bind.address";
@@ -433,7 +435,9 @@ public HttpServer2 build() throws IOException {
433435

434436
HttpServer2 server = new HttpServer2(this);
435437

436-
if (this.securityEnabled) {
438+
if (this.securityEnabled &&
439+
!this.conf.get(authFilterConfigurationPrefix + "type").
440+
equals(PseudoAuthenticationHandler.TYPE)) {
437441
server.initSpnego(conf, hostName, usernameConfKey, keytabConfKey);
438442
}
439443

@@ -608,13 +612,6 @@ private void initializeWebServer(String name, String hostName,
608612
}
609613

610614
addDefaultServlets();
611-
612-
if (pathSpecs != null) {
613-
for (String path : pathSpecs) {
614-
LOG.info("adding path spec: " + path);
615-
addFilterPathMapping(path, webAppContext);
616-
}
617-
}
618615
}
619616

620617
private void addListener(ServerConnector connector) {
@@ -625,7 +622,7 @@ private static WebAppContext createWebAppContext(Builder b,
625622
AccessControlList adminsAcl, final String appDir) {
626623
WebAppContext ctx = new WebAppContext();
627624
ctx.setDefaultsDescriptor(null);
628-
ServletHolder holder = new ServletHolder(new DefaultServlet());
625+
ServletHolder holder = new ServletHolder(new WebServlet());
629626
Map<String, String> params = ImmutableMap. <String, String> builder()
630627
.put("acceptRanges", "true")
631628
.put("dirAllowed", "false")
@@ -684,10 +681,16 @@ private static FilterInitializer[] getFilterInitializers(Configuration conf) {
684681
return null;
685682
}
686683

687-
FilterInitializer[] initializers = new FilterInitializer[classes.length];
688-
for(int i = 0; i < classes.length; i++) {
684+
List<Class<?>> classList = new ArrayList<>(Arrays.asList(classes));
685+
if (classList.contains(AuthenticationFilterInitializer.class) &&
686+
classList.contains(ProxyUserAuthenticationFilterInitializer.class)) {
687+
classList.remove(AuthenticationFilterInitializer.class);
688+
}
689+
690+
FilterInitializer[] initializers = new FilterInitializer[classList.size()];
691+
for(int i = 0; i < classList.size(); i++) {
689692
initializers[i] = (FilterInitializer)ReflectionUtils.newInstance(
690-
classes[i], conf);
693+
classList.get(i), conf);
691694
}
692695
return initializers;
693696
}
@@ -735,7 +738,7 @@ protected void addDefaultApps(ContextHandlerCollection parent,
735738
ServletContextHandler staticContext =
736739
new ServletContextHandler(parent, "/static");
737740
staticContext.setResourceBase(appDir + "/static");
738-
staticContext.addServlet(DefaultServlet.class, "/*");
741+
staticContext.addServlet(WebServlet.class, "/*");
739742
staticContext.setDisplayName("static");
740743
@SuppressWarnings("unchecked")
741744
Map<String, String> params = staticContext.getInitParams();
@@ -812,7 +815,6 @@ public void addJerseyResourcePackage(final String packageName,
812815
public void addServlet(String name, String pathSpec,
813816
Class<? extends HttpServlet> clazz) {
814817
addInternalServlet(name, pathSpec, clazz, false);
815-
addFilterPathMapping(pathSpec, webAppContext);
816818
}
817819

818820
/**
@@ -869,16 +871,6 @@ public void addInternalServlet(String name, String pathSpec,
869871
}
870872
}
871873
webAppContext.addServlet(holder, pathSpec);
872-
873-
if(requireAuth && UserGroupInformation.isSecurityEnabled()) {
874-
LOG.info("Adding Kerberos (SPNEGO) filter to " + name);
875-
ServletHandler handler = webAppContext.getServletHandler();
876-
FilterMapping fmap = new FilterMapping();
877-
fmap.setPathSpec(pathSpec);
878-
fmap.setFilterName(SPNEGO_FILTER);
879-
fmap.setDispatches(FilterMapping.ALL);
880-
handler.addFilterMapping(fmap);
881-
}
882874
}
883875

884876
/**
@@ -945,8 +937,8 @@ public void addFilter(String name, String classname,
945937
Map<String, String> parameters) {
946938

947939
FilterHolder filterHolder = getFilterHolder(name, classname, parameters);
948-
final String[] USER_FACING_URLS = { "*.html", "*.jsp" };
949-
FilterMapping fmap = getFilterMapping(name, USER_FACING_URLS);
940+
final String[] userFacingUrls = {"/", "/*" };
941+
FilterMapping fmap = getFilterMapping(name, userFacingUrls);
950942
defineFilter(webAppContext, filterHolder, fmap);
951943
LOG.info(
952944
"Added filter " + name + " (class=" + classname + ") to context "
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
/**
2+
* Licensed to the Apache Software Foundation (ASF) under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ASF licenses this file
6+
* to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing, software
13+
* distributed under the License is distributed on an "AS IS" BASIS,
14+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
* See the License for the specific language governing permissions and
16+
* limitations under the License.
17+
*/
18+
package org.apache.hadoop.http;
19+
20+
import java.io.IOException;
21+
22+
import javax.servlet.ServletException;
23+
import javax.servlet.http.HttpServletRequest;
24+
import javax.servlet.http.HttpServletResponse;
25+
import org.eclipse.jetty.servlet.DefaultServlet;
26+
import org.slf4j.Logger;
27+
import org.slf4j.LoggerFactory;
28+
29+
30+
/**
31+
* Hadoop DefaultServlet for serving static web content.
32+
*/
33+
public class WebServlet extends DefaultServlet {
34+
private static final long serialVersionUID = 3910031415927L;
35+
public static final Logger LOG = LoggerFactory.getLogger(WebServlet.class);
36+
37+
/**
38+
* Get method is modified to support impersonation and Kerberos
39+
* SPNEGO token by forcing client side redirect when accessing
40+
* "/" (root) of the web application context.
41+
*/
42+
@Override
43+
protected void doGet(HttpServletRequest request, HttpServletResponse response)
44+
throws ServletException, IOException {
45+
if (request.getRequestURI().equals("/")) {
46+
StringBuilder location = new StringBuilder();
47+
location.append("index.html");
48+
if (request.getQueryString()!=null) {
49+
// echo query string but prevent HTTP response splitting
50+
location.append("?");
51+
location.append(request.getQueryString()
52+
.replaceAll("\n", "").replaceAll("\r", ""));
53+
}
54+
response.sendRedirect(location.toString());
55+
} else {
56+
super.doGet(request, response);
57+
}
58+
}
59+
}

hadoop-common-project/hadoop-common/src/site/markdown/HttpAuthentication.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,4 +71,6 @@ Trusted Proxy
7171
Trusted Proxy adds support to perform operations using end user instead of proxy user. It fetches the end user from
7272
doAs query parameter. To enable Trusted Proxy, please set the following configuration parameter:
7373

74-
Add org.apache.hadoop.security.authentication.server.ProxyUserAuthenticationFilterInitializer to hadoop.http.filter.initializers at the end in core-site.xml.
74+
Add org.apache.hadoop.security.authentication.server.ProxyUserAuthenticationFilterInitializer to hadoop.http.filter.initializers in core-site.xml
75+
instead of org.apache.hadoop.security.AuthenticationFilterInitializer.
76+

hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/http/TestGlobalFilter.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,8 @@ public void testServletFilter() throws Exception {
142142
for(int i = 0; i < urls.length; i++) {
143143
assertTrue(RECORDS.remove(urls[i]));
144144
}
145-
assertTrue(RECORDS.isEmpty());
145+
assertTrue(RECORDS.size()==1);
146+
// Accesing "/" will redirect to /index.html
147+
assertTrue(RECORDS.contains("/index.html"));
146148
}
147149
}

0 commit comments

Comments
 (0)