Author: tucu
Date: Fri Dec 7 18:46:41 2012
New Revision: 1418429
URL: http://svn.apache.org/viewvc?rev=1418429&view=rev
Log:
HADOOP-9054. Add AuthenticationHandler that uses Kerberos but allows for an alternate form
of authentication for browsers. (rkanter via tucu)
Added:
hadoop/common/trunk/hadoop-common-project/hadoop-auth/src/main/java/org/apache/hadoop/security/authentication/server/AltKerberosAuthenticationHandler.java
hadoop/common/trunk/hadoop-common-project/hadoop-auth/src/test/java/org/apache/hadoop/security/authentication/server/TestAltKerberosAuthenticationHandler.java
Modified:
hadoop/common/trunk/hadoop-common-project/hadoop-auth/pom.xml
hadoop/common/trunk/hadoop-common-project/hadoop-auth/src/site/apt/Configuration.apt.vm
hadoop/common/trunk/hadoop-common-project/hadoop-auth/src/site/apt/index.apt.vm
hadoop/common/trunk/hadoop-common-project/hadoop-auth/src/test/java/org/apache/hadoop/security/authentication/server/TestKerberosAuthenticationHandler.java
hadoop/common/trunk/hadoop-common-project/hadoop-common/CHANGES.txt
Modified: hadoop/common/trunk/hadoop-common-project/hadoop-auth/pom.xml
URL: http://svn.apache.org/viewvc/hadoop/common/trunk/hadoop-common-project/hadoop-auth/pom.xml?rev=1418429&r1=1418428&r2=1418429&view=diff
==============================================================================
--- hadoop/common/trunk/hadoop-common-project/hadoop-auth/pom.xml (original)
+++ hadoop/common/trunk/hadoop-common-project/hadoop-auth/pom.xml Fri Dec 7 18:46:41 2012
@@ -110,6 +110,7 @@
<exclude>**/${test.exclude}.java</exclude>
<exclude>${test.exclude.pattern}</exclude>
<exclude>**/TestKerberosAuth*.java</exclude>
+ <exclude>**/TestAltKerberosAuth*.java</exclude>
<exclude>**/Test*$*.java</exclude>
</excludes>
</configuration>
Added: hadoop/common/trunk/hadoop-common-project/hadoop-auth/src/main/java/org/apache/hadoop/security/authentication/server/AltKerberosAuthenticationHandler.java
URL: http://svn.apache.org/viewvc/hadoop/common/trunk/hadoop-common-project/hadoop-auth/src/main/java/org/apache/hadoop/security/authentication/server/AltKerberosAuthenticationHandler.java?rev=1418429&view=auto
==============================================================================
--- hadoop/common/trunk/hadoop-common-project/hadoop-auth/src/main/java/org/apache/hadoop/security/authentication/server/AltKerberosAuthenticationHandler.java
(added)
+++ hadoop/common/trunk/hadoop-common-project/hadoop-auth/src/main/java/org/apache/hadoop/security/authentication/server/AltKerberosAuthenticationHandler.java
Fri Dec 7 18:46:41 2012
@@ -0,0 +1,150 @@
+/**
+ * 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 java.io.IOException;
+import java.util.Properties;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import org.apache.hadoop.security.authentication.client.AuthenticationException;
+
+ /**
+ * The {@link AltKerberosAuthenticationHandler} behaves exactly the same way as
+ * the {@link KerberosAuthenticationHandler}, except that it allows for an
+ * alternative form of authentication for browsers while still using Kerberos
+ * for Java access. This is an abstract class that should be subclassed
+ * to allow a developer to implement their own custom authentication for browser
+ * access. The alternateAuthenticate method will be called whenever a request
+ * comes from a browser.
+ * <p/>
+ */
+public abstract class AltKerberosAuthenticationHandler
+ extends KerberosAuthenticationHandler {
+
+ /**
+ * Constant that identifies the authentication mechanism.
+ */
+ public static final String TYPE = "alt-kerberos";
+
+ /**
+ * Constant for the configuration property that indicates which user agents
+ * are not considered browsers (comma separated)
+ */
+ public static final String NON_BROWSER_USER_AGENTS =
+ TYPE + ".non-browser.user-agents";
+ private static final String NON_BROWSER_USER_AGENTS_DEFAULT =
+ "java,curl,wget,perl";
+
+ private String[] nonBrowserUserAgents;
+
+ /**
+ * Returns the authentication type of the authentication handler,
+ * 'alt-kerberos'.
+ * <p/>
+ *
+ * @return the authentication type of the authentication handler,
+ * 'alt-kerberos'.
+ */
+ @Override
+ public String getType() {
+ return TYPE;
+ }
+
+ @Override
+ public void init(Properties config) throws ServletException {
+ super.init(config);
+
+ nonBrowserUserAgents = config.getProperty(
+ NON_BROWSER_USER_AGENTS, NON_BROWSER_USER_AGENTS_DEFAULT)
+ .split("\\W*,\\W*");
+ for (int i = 0; i < nonBrowserUserAgents.length; i++) {
+ nonBrowserUserAgents[i] = nonBrowserUserAgents[i].toLowerCase();
+ }
+ }
+
+ /**
+ * It enforces the the Kerberos SPNEGO authentication sequence returning an
+ * {@link AuthenticationToken} only after the Kerberos SPNEGO sequence has
+ * completed successfully (in the case of Java access) and only after the
+ * custom authentication implemented by the subclass in alternateAuthenticate
+ * has completed successfully (in the case of browser access).
+ * <p/>
+ *
+ * @param request the HTTP client request.
+ * @param response the HTTP client response.
+ *
+ * @return an authentication token if the request is authorized or null
+ *
+ * @throws IOException thrown if an IO error occurred
+ * @throws AuthenticationException thrown if an authentication error occurred
+ */
+ @Override
+ public AuthenticationToken authenticate(HttpServletRequest request,
+ HttpServletResponse response)
+ throws IOException, AuthenticationException {
+ AuthenticationToken token;
+ if (isBrowser(request.getHeader("User-Agent"))) {
+ token = alternateAuthenticate(request, response);
+ }
+ else {
+ token = super.authenticate(request, response);
+ }
+ return token;
+ }
+
+ /**
+ * This method parses the User-Agent String and returns whether or not it
+ * refers to a browser. If its not a browser, then Kerberos authentication
+ * will be used; if it is a browser, alternateAuthenticate from the subclass
+ * will be used.
+ * <p/>
+ * A User-Agent String is considered to be a browser if it does not contain
+ * any of the values from alt-kerberos.non-browser.user-agents; the default
+ * behavior is to consider everything a browser unless it contains one of:
+ * "java", "curl", "wget", or "perl". Subclasses can optionally override
+ * this method to use different behavior.
+ *
+ * @param userAgent The User-Agent String, or null if there isn't one
+ * @return true if the User-Agent String refers to a browser, false if not
+ */
+ protected boolean isBrowser(String userAgent) {
+ if (userAgent == null) {
+ return false;
+ }
+ userAgent = userAgent.toLowerCase();
+ boolean isBrowser = true;
+ for (String nonBrowserUserAgent : nonBrowserUserAgents) {
+ if (userAgent.contains(nonBrowserUserAgent)) {
+ isBrowser = false;
+ break;
+ }
+ }
+ return isBrowser;
+ }
+
+ /**
+ * Subclasses should implement this method to provide the custom
+ * authentication to be used for browsers.
+ *
+ * @param request the HTTP client request.
+ * @param response the HTTP client response.
+ * @return an authentication token if the request is authorized, or null
+ * @throws IOException thrown if an IO error occurs
+ * @throws AuthenticationException thrown if an authentication error occurs
+ */
+ public abstract AuthenticationToken alternateAuthenticate(
+ HttpServletRequest request, HttpServletResponse response)
+ throws IOException, AuthenticationException;
+}
Modified: hadoop/common/trunk/hadoop-common-project/hadoop-auth/src/site/apt/Configuration.apt.vm
URL: http://svn.apache.org/viewvc/hadoop/common/trunk/hadoop-common-project/hadoop-auth/src/site/apt/Configuration.apt.vm?rev=1418429&r1=1418428&r2=1418429&view=diff
==============================================================================
--- hadoop/common/trunk/hadoop-common-project/hadoop-auth/src/site/apt/Configuration.apt.vm
(original)
+++ hadoop/common/trunk/hadoop-common-project/hadoop-auth/src/site/apt/Configuration.apt.vm
Fri Dec 7 18:46:41 2012
@@ -178,4 +178,71 @@ Configuration
</web-app>
+---+
+** AltKerberos Configuration
+
+ <<IMPORTANT>>: A KDC must be configured and running.
+
+ The AltKerberos authentication mechanism is a partially implemented derivative
+ of the Kerberos SPNEGO authentication mechanism which allows a "mixed" form of
+ authentication where Kerberos SPNEGO is used by non-browsers while an
+ alternate form of authentication (to be implemented by the user) is used for
+ browsers. To use AltKerberos as the authentication mechanism (besides
+ providing an implementation), the authentication filter must be configured
+ with the following init parameters, in addition to the previously mentioned
+ Kerberos SPNEGO ones:
+
+ * <<<[PREFIX.]type>>>: the full class name of the implementation of
+ AltKerberosAuthenticationHandler to use.
+
+ * <<<[PREFIX.]alt-kerberos.non-browser.user-agents>>>: a comma-separated
+ list of which user-agents should be considered non-browsers.
+
+ <<Example>>:
+
++---+
+<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee">
+ ...
+
+ <filter>
+ <filter-name>kerberosFilter</filter-name>
+ <filter-class>org.apache.hadoop.security.auth.server.AuthenticationFilter</filter-class>
+ <init-param>
+ <param-name>type</param-name>
+ <param-value>org.my.subclass.of.AltKerberosAuthenticationHandler</param-value>
+ </init-param>
+ <init-param>
+ <param-name>alt-kerberos.non-browser.user-agents</param-name>
+ <param-value>java,curl,wget,perl</param-value>
+ </init-param>
+ <init-param>
+ <param-name>token.validity</param-name>
+ <param-value>30</param-value>
+ </init-param>
+ <init-param>
+ <param-name>cookie.domain</param-name>
+ <param-value>.foo.com</param-value>
+ </init-param>
+ <init-param>
+ <param-name>cookie.path</param-name>
+ <param-value>/</param-value>
+ </init-param>
+ <init-param>
+ <param-name>kerberos.principal</param-name>
+ <param-value>HTTP/localhost@LOCALHOST</param-value>
+ </init-param>
+ <init-param>
+ <param-name>kerberos.keytab</param-name>
+ <param-value>/tmp/auth.keytab</param-value>
+ </init-param>
+ </filter>
+
+ <filter-mapping>
+ <filter-name>kerberosFilter</filter-name>
+ <url-pattern>/kerberos/*</url-pattern>
+ </filter-mapping>
+
+ ...
+</web-app>
++---+
+
\[ {{{./index.html}Go Back}} \]
Modified: hadoop/common/trunk/hadoop-common-project/hadoop-auth/src/site/apt/index.apt.vm
URL: http://svn.apache.org/viewvc/hadoop/common/trunk/hadoop-common-project/hadoop-auth/src/site/apt/index.apt.vm?rev=1418429&r1=1418428&r2=1418429&view=diff
==============================================================================
--- hadoop/common/trunk/hadoop-common-project/hadoop-auth/src/site/apt/index.apt.vm (original)
+++ hadoop/common/trunk/hadoop-common-project/hadoop-auth/src/site/apt/index.apt.vm Fri Dec
7 18:46:41 2012
@@ -24,6 +24,11 @@ Hadoop Auth, Java HTTP SPNEGO ${project.
Hadoop Auth also supports additional authentication mechanisms on the client
and the server side via 2 simple interfaces.
+ Additionally, it provides a partially implemented derivative of the Kerberos
+ SPNEGO authentication to allow a "mixed" form of authentication where Kerberos
+ SPNEGO is used by non-browsers while an alternate form of authentication
+ (to be implemented by the user) is used for browsers.
+
* License
Hadoop Auth is distributed under {{{http://www.apache.org/licenses/}Apache
Added: hadoop/common/trunk/hadoop-common-project/hadoop-auth/src/test/java/org/apache/hadoop/security/authentication/server/TestAltKerberosAuthenticationHandler.java
URL: http://svn.apache.org/viewvc/hadoop/common/trunk/hadoop-common-project/hadoop-auth/src/test/java/org/apache/hadoop/security/authentication/server/TestAltKerberosAuthenticationHandler.java?rev=1418429&view=auto
==============================================================================
--- hadoop/common/trunk/hadoop-common-project/hadoop-auth/src/test/java/org/apache/hadoop/security/authentication/server/TestAltKerberosAuthenticationHandler.java
(added)
+++ hadoop/common/trunk/hadoop-common-project/hadoop-auth/src/test/java/org/apache/hadoop/security/authentication/server/TestAltKerberosAuthenticationHandler.java
Fri Dec 7 18:46:41 2012
@@ -0,0 +1,110 @@
+/**
+ * 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 java.io.IOException;
+import java.util.Properties;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import org.apache.hadoop.security.authentication.client.AuthenticationException;
+import org.mockito.Mockito;
+
+public class TestAltKerberosAuthenticationHandler
+ extends TestKerberosAuthenticationHandler {
+
+ @Override
+ protected KerberosAuthenticationHandler getNewAuthenticationHandler() {
+ // AltKerberosAuthenticationHandler is abstract; a subclass would normally
+ // perform some other authentication when alternateAuthenticate() is called.
+ // For the test, we'll just return an AuthenticationToken as the other
+ // authentication is left up to the developer of the subclass
+ return new AltKerberosAuthenticationHandler() {
+ @Override
+ public AuthenticationToken alternateAuthenticate(
+ HttpServletRequest request,
+ HttpServletResponse response)
+ throws IOException, AuthenticationException {
+ return new AuthenticationToken("A", "B", getType());
+ }
+ };
+ }
+
+ @Override
+ protected String getExpectedType() {
+ return AltKerberosAuthenticationHandler.TYPE;
+ }
+
+ public void testAlternateAuthenticationAsBrowser() throws Exception {
+ HttpServletRequest request = Mockito.mock(HttpServletRequest.class);
+ HttpServletResponse response = Mockito.mock(HttpServletResponse.class);
+
+ // By default, a User-Agent without "java", "curl", "wget", or "perl" in it
+ // is considered a browser
+ Mockito.when(request.getHeader("User-Agent")).thenReturn("Some Browser");
+
+ AuthenticationToken token = handler.authenticate(request, response);
+ assertEquals("A", token.getUserName());
+ assertEquals("B", token.getName());
+ assertEquals(getExpectedType(), token.getType());
+ }
+
+ public void testNonDefaultNonBrowserUserAgentAsBrowser() throws Exception {
+ HttpServletRequest request = Mockito.mock(HttpServletRequest.class);
+ HttpServletResponse response = Mockito.mock(HttpServletResponse.class);
+
+ if (handler != null) {
+ handler.destroy();
+ handler = null;
+ }
+ handler = getNewAuthenticationHandler();
+ Properties props = getDefaultProperties();
+ props.setProperty("alt-kerberos.non-browser.user-agents", "foo, bar");
+ try {
+ handler.init(props);
+ } catch (Exception ex) {
+ handler = null;
+ throw ex;
+ }
+
+ // Pretend we're something that will not match with "foo" (or "bar")
+ Mockito.when(request.getHeader("User-Agent")).thenReturn("blah");
+ // Should use alt authentication
+ AuthenticationToken token = handler.authenticate(request, response);
+ assertEquals("A", token.getUserName());
+ assertEquals("B", token.getName());
+ assertEquals(getExpectedType(), token.getType());
+ }
+
+ public void testNonDefaultNonBrowserUserAgentAsNonBrowser() throws Exception {
+ if (handler != null) {
+ handler.destroy();
+ handler = null;
+ }
+ handler = getNewAuthenticationHandler();
+ Properties props = getDefaultProperties();
+ props.setProperty("alt-kerberos.non-browser.user-agents", "foo, bar");
+ try {
+ handler.init(props);
+ } catch (Exception ex) {
+ handler = null;
+ throw ex;
+ }
+
+ // Run the kerberos tests again
+ testRequestWithoutAuthorization();
+ testRequestWithInvalidAuthorization();
+ testRequestWithAuthorization();
+ testRequestWithInvalidKerberosAuthorization();
+ }
+}
Modified: hadoop/common/trunk/hadoop-common-project/hadoop-auth/src/test/java/org/apache/hadoop/security/authentication/server/TestKerberosAuthenticationHandler.java
URL: http://svn.apache.org/viewvc/hadoop/common/trunk/hadoop-common-project/hadoop-auth/src/test/java/org/apache/hadoop/security/authentication/server/TestKerberosAuthenticationHandler.java?rev=1418429&r1=1418428&r2=1418429&view=diff
==============================================================================
--- hadoop/common/trunk/hadoop-common-project/hadoop-auth/src/test/java/org/apache/hadoop/security/authentication/server/TestKerberosAuthenticationHandler.java
(original)
+++ hadoop/common/trunk/hadoop-common-project/hadoop-auth/src/test/java/org/apache/hadoop/security/authentication/server/TestKerberosAuthenticationHandler.java
Fri Dec 7 18:46:41 2012
@@ -28,23 +28,37 @@ import org.ietf.jgss.Oid;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
-import java.lang.reflect.Field;
import java.util.Properties;
import java.util.concurrent.Callable;
public class TestKerberosAuthenticationHandler extends TestCase {
- private KerberosAuthenticationHandler handler;
+ protected KerberosAuthenticationHandler handler;
+
+ protected KerberosAuthenticationHandler getNewAuthenticationHandler() {
+ return new KerberosAuthenticationHandler();
+ }
+
+ protected String getExpectedType() {
+ return KerberosAuthenticationHandler.TYPE;
+ }
+
+ protected Properties getDefaultProperties() {
+ Properties props = new Properties();
+ props.setProperty(KerberosAuthenticationHandler.PRINCIPAL,
+ KerberosTestUtils.getServerPrincipal());
+ props.setProperty(KerberosAuthenticationHandler.KEYTAB,
+ KerberosTestUtils.getKeytabFile());
+ props.setProperty(KerberosAuthenticationHandler.NAME_RULES,
+ "RULE:[1:$1@$0](.*@" + KerberosTestUtils.getRealm()+")s/@.*//\n");
+ return props;
+ }
@Override
protected void setUp() throws Exception {
super.setUp();
- handler = new KerberosAuthenticationHandler();
- Properties props = new Properties();
- props.setProperty(KerberosAuthenticationHandler.PRINCIPAL, KerberosTestUtils.getServerPrincipal());
- props.setProperty(KerberosAuthenticationHandler.KEYTAB, KerberosTestUtils.getKeytabFile());
- props.setProperty(KerberosAuthenticationHandler.NAME_RULES,
- "RULE:[1:$1@$0](.*@" + KerberosTestUtils.getRealm()+")s/@.*//\n");
+ handler = getNewAuthenticationHandler();
+ Properties props = getDefaultProperties();
try {
handler.init(props);
} catch (Exception ex) {
@@ -71,10 +85,8 @@ public class TestKerberosAuthenticationH
KerberosName.setRules("RULE:[1:$1@$0](.*@FOO)s/@.*//\nDEFAULT");
- handler = new KerberosAuthenticationHandler();
- Properties props = new Properties();
- props.setProperty(KerberosAuthenticationHandler.PRINCIPAL, KerberosTestUtils.getServerPrincipal());
- props.setProperty(KerberosAuthenticationHandler.KEYTAB, KerberosTestUtils.getKeytabFile());
+ handler = getNewAuthenticationHandler();
+ Properties props = getDefaultProperties();
props.setProperty(KerberosAuthenticationHandler.NAME_RULES, "RULE:[1:$1@$0](.*@BAR)s/@.*//\nDEFAULT");
try {
handler.init(props);
@@ -97,8 +109,7 @@ public class TestKerberosAuthenticationH
}
public void testType() throws Exception {
- KerberosAuthenticationHandler handler = new KerberosAuthenticationHandler();
- assertEquals(KerberosAuthenticationHandler.TYPE, handler.getType());
+ assertEquals(getExpectedType(), handler.getType());
}
public void testRequestWithoutAuthorization() throws Exception {
@@ -182,7 +193,7 @@ public class TestKerberosAuthenticationH
assertEquals(KerberosTestUtils.getClientPrincipal(), authToken.getName());
assertTrue(KerberosTestUtils.getClientPrincipal().startsWith(authToken.getUserName()));
- assertEquals(KerberosAuthenticationHandler.TYPE, authToken.getType());
+ assertEquals(getExpectedType(), authToken.getType());
} else {
Mockito.verify(response).setHeader(Mockito.eq(KerberosAuthenticator.WWW_AUTHENTICATE),
Mockito.matches(KerberosAuthenticator.NEGOTIATE
+ " .*"));
Modified: hadoop/common/trunk/hadoop-common-project/hadoop-common/CHANGES.txt
URL: http://svn.apache.org/viewvc/hadoop/common/trunk/hadoop-common-project/hadoop-common/CHANGES.txt?rev=1418429&r1=1418428&r2=1418429&view=diff
==============================================================================
--- hadoop/common/trunk/hadoop-common-project/hadoop-common/CHANGES.txt (original)
+++ hadoop/common/trunk/hadoop-common-project/hadoop-common/CHANGES.txt Fri Dec 7 18:46:41
2012
@@ -312,6 +312,8 @@ Release 2.0.3-alpha - Unreleased
HADOOP-9090. Support on-demand publish of metrics. (Mostafa Elhemali via
suresh)
+ HADOOP-9054. Add AuthenticationHandler that uses Kerberos but allows for
+ an alternate form of authentication for browsers. (rkanter via tucu)
IMPROVEMENTS
|