HADOOP-6832. Add an authentication plugin using a configurable static user
for the web UI. Contributed by Owen O'Malley and Todd Lipcon git-svn-id: https://svn.apache.org/repos/asf/hadoop/common/trunk@1125043 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
ef543e386d
commit
da15b2118c
@ -32,6 +32,9 @@ Trunk (unreleased changes)
|
|||||||
HADOOP-7214. Add Common functionality necessary to provide an equivalent
|
HADOOP-7214. Add Common functionality necessary to provide an equivalent
|
||||||
of /usr/bin/groups for Hadoop. (Aaron T. Myers via todd)
|
of /usr/bin/groups for Hadoop. (Aaron T. Myers via todd)
|
||||||
|
|
||||||
|
HADOOP-6832. Add an authentication plugin using a configurable static user
|
||||||
|
for the web UI. (Owen O'Malley and Todd Lipcon via cdouglas)
|
||||||
|
|
||||||
IMPROVEMENTS
|
IMPROVEMENTS
|
||||||
|
|
||||||
HADOOP-7042. Updates to test-patch.sh to include failed test names and
|
HADOOP-7042. Updates to test-patch.sh to include failed test names and
|
||||||
|
@ -45,7 +45,7 @@
|
|||||||
|
|
||||||
<property>
|
<property>
|
||||||
<name>hadoop.http.filter.initializers</name>
|
<name>hadoop.http.filter.initializers</name>
|
||||||
<value></value>
|
<value>org.apache.hadoop.http.lib.StaticUserWebFilter</value>
|
||||||
<description>A comma separated list of class names. Each class in the list
|
<description>A comma separated list of class names. Each class in the list
|
||||||
must extend org.apache.hadoop.http.FilterInitializer. The corresponding
|
must extend org.apache.hadoop.http.FilterInitializer. The corresponding
|
||||||
Filter will be initialized. Then, the Filter will be applied to all user
|
Filter will be initialized. Then, the Filter will be applied to all user
|
||||||
|
150
src/java/org/apache/hadoop/http/lib/StaticUserWebFilter.java
Normal file
150
src/java/org/apache/hadoop/http/lib/StaticUserWebFilter.java
Normal file
@ -0,0 +1,150 @@
|
|||||||
|
/**
|
||||||
|
* 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.http.lib;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.security.Principal;
|
||||||
|
import java.util.HashMap;
|
||||||
|
|
||||||
|
import javax.servlet.FilterChain;
|
||||||
|
import javax.servlet.FilterConfig;
|
||||||
|
import javax.servlet.ServletException;
|
||||||
|
import javax.servlet.ServletRequest;
|
||||||
|
import javax.servlet.ServletResponse;
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import javax.servlet.http.HttpServletRequestWrapper;
|
||||||
|
|
||||||
|
import org.apache.commons.logging.Log;
|
||||||
|
import org.apache.commons.logging.LogFactory;
|
||||||
|
import org.apache.hadoop.conf.Configuration;
|
||||||
|
import org.apache.hadoop.http.FilterContainer;
|
||||||
|
import org.apache.hadoop.http.FilterInitializer;
|
||||||
|
|
||||||
|
import javax.servlet.Filter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides a servlet filter that pretends to authenticate a fake user (Dr.Who)
|
||||||
|
* so that the web UI is usable for a secure cluster without authentication.
|
||||||
|
*/
|
||||||
|
public class StaticUserWebFilter extends FilterInitializer {
|
||||||
|
static final String DEPRECATED_UGI_KEY = "dfs.web.ugi";
|
||||||
|
|
||||||
|
static final String USERNAME_KEY = "hadoop.http.staticuser.user";
|
||||||
|
static final String USERNAME_DEFAULT = "dr.who";
|
||||||
|
|
||||||
|
private static final Log LOG = LogFactory.getLog(StaticUserWebFilter.class);
|
||||||
|
|
||||||
|
static class User implements Principal {
|
||||||
|
private final String name;
|
||||||
|
public User(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return name.hashCode();
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object other) {
|
||||||
|
if (other == this) {
|
||||||
|
return true;
|
||||||
|
} else if (other == null || other.getClass() != getClass()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return ((User) other).name.equals(name);
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class StaticUserFilter implements Filter {
|
||||||
|
private User user;
|
||||||
|
private String username;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void destroy() {
|
||||||
|
// NOTHING
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void doFilter(ServletRequest request, ServletResponse response,
|
||||||
|
FilterChain chain
|
||||||
|
) throws IOException, ServletException {
|
||||||
|
HttpServletRequest httpRequest = (HttpServletRequest) request;
|
||||||
|
// if the user is already authenticated, don't override it
|
||||||
|
if (httpRequest.getRemoteUser() != null) {
|
||||||
|
chain.doFilter(request, response);
|
||||||
|
} else {
|
||||||
|
HttpServletRequestWrapper wrapper =
|
||||||
|
new HttpServletRequestWrapper(httpRequest) {
|
||||||
|
@Override
|
||||||
|
public Principal getUserPrincipal() {
|
||||||
|
return user;
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public String getRemoteUser() {
|
||||||
|
return username;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
chain.doFilter(wrapper, response);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void init(FilterConfig conf) throws ServletException {
|
||||||
|
this.username = conf.getInitParameter(USERNAME_KEY);
|
||||||
|
this.user = new User(username);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void initFilter(FilterContainer container, Configuration conf) {
|
||||||
|
HashMap<String, String> options = new HashMap<String, String>();
|
||||||
|
|
||||||
|
String username = getUsernameFromConf(conf);
|
||||||
|
options.put(USERNAME_KEY, username);
|
||||||
|
|
||||||
|
container.addFilter("static_user_filter",
|
||||||
|
StaticUserFilter.class.getName(),
|
||||||
|
options);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve the static username from the configuration.
|
||||||
|
*/
|
||||||
|
static String getUsernameFromConf(Configuration conf) {
|
||||||
|
String oldStyleUgi = conf.get(DEPRECATED_UGI_KEY);
|
||||||
|
if (oldStyleUgi != null) {
|
||||||
|
// We can't use the normal configuration deprecation mechanism here
|
||||||
|
// since we need to split out the username from the configured UGI.
|
||||||
|
LOG.warn(DEPRECATED_UGI_KEY + " should not be used. Instead, use " +
|
||||||
|
USERNAME_KEY + ".");
|
||||||
|
String[] parts = oldStyleUgi.split(",");
|
||||||
|
return parts[0];
|
||||||
|
} else {
|
||||||
|
return conf.get(USERNAME_KEY, USERNAME_DEFAULT);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
30
src/java/org/apache/hadoop/http/lib/package.html
Normal file
30
src/java/org/apache/hadoop/http/lib/package.html
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
<html>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
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.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<body>
|
||||||
|
This package provides user-selectable (via configuration) classes that add
|
||||||
|
functionality to the web UI. They are configured as a list of classes in the
|
||||||
|
configuration parameter <b>hadoop.http.filter.initializers</b>.
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
<li> <b>StaticUserWebFilter</b> - An authorization plugin that makes all
|
||||||
|
users a static configured user.
|
||||||
|
</ul>
|
||||||
|
</body>
|
||||||
|
</html>
|
@ -0,0 +1,80 @@
|
|||||||
|
/**
|
||||||
|
* 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.http.lib;
|
||||||
|
|
||||||
|
import static org.junit.Assert.*;
|
||||||
|
import static org.mockito.Mockito.mock;
|
||||||
|
|
||||||
|
import javax.servlet.FilterChain;
|
||||||
|
import javax.servlet.FilterConfig;
|
||||||
|
import javax.servlet.ServletResponse;
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import javax.servlet.http.HttpServletRequestWrapper;
|
||||||
|
|
||||||
|
import org.apache.hadoop.conf.Configuration;
|
||||||
|
import org.apache.hadoop.http.lib.StaticUserWebFilter.StaticUserFilter;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.mockito.ArgumentCaptor;
|
||||||
|
import org.mockito.Mockito;
|
||||||
|
|
||||||
|
public class TestStaticUserWebFilter {
|
||||||
|
private FilterConfig mockConfig(String username) {
|
||||||
|
FilterConfig mock = Mockito.mock(FilterConfig.class);
|
||||||
|
Mockito.doReturn(username).when(mock).getInitParameter(
|
||||||
|
StaticUserWebFilter.USERNAME_KEY);
|
||||||
|
return mock;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testFilter() throws Exception {
|
||||||
|
FilterConfig config = mockConfig("myuser");
|
||||||
|
StaticUserFilter suf = new StaticUserFilter();
|
||||||
|
suf.init(config);
|
||||||
|
|
||||||
|
ArgumentCaptor<HttpServletRequestWrapper> wrapperArg =
|
||||||
|
ArgumentCaptor.forClass(HttpServletRequestWrapper.class);
|
||||||
|
|
||||||
|
FilterChain chain = mock(FilterChain.class);
|
||||||
|
|
||||||
|
suf.doFilter(mock(HttpServletRequest.class), mock(ServletResponse.class),
|
||||||
|
chain);
|
||||||
|
|
||||||
|
Mockito.verify(chain).doFilter(wrapperArg.capture(), Mockito.<ServletResponse>anyObject());
|
||||||
|
|
||||||
|
HttpServletRequestWrapper wrapper = wrapperArg.getValue();
|
||||||
|
assertEquals("myuser", wrapper.getUserPrincipal().getName());
|
||||||
|
assertEquals("myuser", wrapper.getRemoteUser());
|
||||||
|
|
||||||
|
suf.destroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testOldStyleConfiguration() {
|
||||||
|
Configuration conf = new Configuration();
|
||||||
|
conf.set("dfs.web.ugi", "joe,group1,group2");
|
||||||
|
assertEquals("joe", StaticUserWebFilter.getUsernameFromConf(conf));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testConfiguration() {
|
||||||
|
Configuration conf = new Configuration();
|
||||||
|
conf.set(StaticUserWebFilter.USERNAME_KEY, "joe");
|
||||||
|
assertEquals("joe", StaticUserWebFilter.getUsernameFromConf(conf));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user