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
|
||||
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
|
||||
|
||||
HADOOP-7042. Updates to test-patch.sh to include failed test names and
|
||||
|
@ -45,7 +45,7 @@
|
||||
|
||||
<property>
|
||||
<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
|
||||
must extend org.apache.hadoop.http.FilterInitializer. The corresponding
|
||||
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