org.apache.hadoop.security.token.delegation.web.TestWebDelegationToken.java Source code

Java tutorial

Introduction

Here is the source code for org.apache.hadoop.security.token.delegation.web.TestWebDelegationToken.java

Source

/**
 * 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.token.delegation.web;

import org.apache.commons.io.IOUtils;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.minikdc.MiniKdc;
import org.apache.hadoop.security.UserGroupInformation;
import org.apache.hadoop.security.authentication.client.AuthenticationException;
import org.apache.hadoop.security.authentication.client.KerberosAuthenticator;
import org.apache.hadoop.security.authentication.server.AuthenticationFilter;
import org.apache.hadoop.security.authentication.server.AuthenticationHandler;
import org.apache.hadoop.security.authentication.server.AuthenticationToken;
import org.apache.hadoop.security.authentication.server.KerberosAuthenticationHandler;
import org.apache.hadoop.security.authentication.server.PseudoAuthenticationHandler;
import org.apache.hadoop.security.authentication.util.KerberosUtil;
import org.apache.hadoop.security.token.delegation.AbstractDelegationTokenSecretManager;
import org.codehaus.jackson.map.ObjectMapper;
import org.apache.hadoop.test.GenericTestUtils;
import org.apache.log4j.Level;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.mortbay.jetty.AbstractConnector;
import org.mortbay.jetty.Connector;
import org.mortbay.jetty.Server;
import org.mortbay.jetty.servlet.Context;
import org.mortbay.jetty.servlet.FilterHolder;
import org.mortbay.jetty.servlet.ServletHolder;

import javax.security.auth.Subject;
import javax.security.auth.kerberos.KerberosPrincipal;
import javax.security.auth.login.AppConfigurationEntry;
import javax.security.auth.login.Configuration;
import javax.security.auth.login.LoginContext;
import javax.servlet.Filter;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import java.io.ByteArrayInputStream;
import java.io.DataInputStream;
import java.io.File;
import java.io.IOException;
import java.io.Writer;
import java.net.HttpURLConnection;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.URL;
import java.security.Principal;
import java.security.PrivilegedActionException;
import java.security.PrivilegedExceptionAction;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.Callable;

public class TestWebDelegationToken {
    private static final String OK_USER = "ok-user";
    private static final String FAIL_USER = "fail-user";
    private static final String FOO_USER = "foo";

    private Server jetty;

    public static class DummyAuthenticationHandler implements AuthenticationHandler {
        @Override
        public String getType() {
            return "dummy";
        }

        @Override
        public void init(Properties config) throws ServletException {
        }

        @Override
        public void destroy() {
        }

        @Override
        public boolean managementOperation(AuthenticationToken token, HttpServletRequest request,
                HttpServletResponse response) throws IOException, AuthenticationException {
            return false;
        }

        @Override
        public AuthenticationToken authenticate(HttpServletRequest request, HttpServletResponse response)
                throws IOException, AuthenticationException {
            AuthenticationToken token = null;
            if (request.getParameter("authenticated") != null) {
                token = new AuthenticationToken(request.getParameter("authenticated"), "U", "test");
            } else {
                response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
                response.setHeader(KerberosAuthenticator.WWW_AUTHENTICATE, "dummy");
            }
            return token;
        }
    }

    public static class DummyDelegationTokenAuthenticationHandler extends DelegationTokenAuthenticationHandler {
        public DummyDelegationTokenAuthenticationHandler() {
            super(new DummyAuthenticationHandler());
        }

        @Override
        public void init(Properties config) throws ServletException {
            Properties conf = new Properties(config);
            conf.setProperty(TOKEN_KIND, "token-kind");
            initTokenManager(conf);
        }
    }

    public static class AFilter extends DelegationTokenAuthenticationFilter {

        @Override
        protected Properties getConfiguration(String configPrefix, FilterConfig filterConfig) {
            Properties conf = new Properties();
            conf.setProperty(AUTH_TYPE, DummyDelegationTokenAuthenticationHandler.class.getName());
            return conf;
        }
    }

    public static class PingServlet extends HttpServlet {

        @Override
        protected void doGet(HttpServletRequest req, HttpServletResponse resp)
                throws ServletException, IOException {
            resp.setStatus(HttpServletResponse.SC_OK);
            resp.getWriter().write("ping");
            if (req.getHeader(DelegationTokenAuthenticator.DELEGATION_TOKEN_HEADER) != null) {
                resp.setHeader("UsingHeader", "true");
            }
            if (req.getQueryString() != null
                    && req.getQueryString().contains(DelegationTokenAuthenticator.DELEGATION_PARAM + "=")) {
                resp.setHeader("UsingQueryString", "true");
            }
        }

        @Override
        protected void doPost(HttpServletRequest req, HttpServletResponse resp)
                throws ServletException, IOException {
            Writer writer = resp.getWriter();
            writer.write("ping: ");
            IOUtils.copy(req.getReader(), writer);
            resp.setStatus(HttpServletResponse.SC_OK);
        }
    }

    protected Server createJettyServer() {
        try {
            jetty = new Server(0);
            jetty.getConnectors()[0].setHost("localhost");
            return jetty;
        } catch (Exception ex) {
            throw new RuntimeException("Could not setup Jetty: " + ex.getMessage(), ex);
        }
    }

    protected String getJettyURL() {
        Connector c = jetty.getConnectors()[0];
        return "http://" + c.getHost() + ":" + c.getLocalPort();
    }

    @Before
    public void setUp() throws Exception {
        // resetting hadoop security to simple
        org.apache.hadoop.conf.Configuration conf = new org.apache.hadoop.conf.Configuration();
        UserGroupInformation.setConfiguration(conf);

        jetty = createJettyServer();
        GenericTestUtils.setLogLevel(KerberosAuthenticationHandler.LOG, Level.TRACE);
    }

    @After
    public void cleanUp() throws Exception {
        jetty.stop();

        // resetting hadoop security to simple
        org.apache.hadoop.conf.Configuration conf = new org.apache.hadoop.conf.Configuration();
        UserGroupInformation.setConfiguration(conf);
    }

    protected Server getJetty() {
        return jetty;
    }

    @Test
    public void testRawHttpCalls() throws Exception {
        final Server jetty = createJettyServer();
        Context context = new Context();
        context.setContextPath("/foo");
        jetty.setHandler(context);
        context.addFilter(new FilterHolder(AFilter.class), "/*", 0);
        context.addServlet(new ServletHolder(PingServlet.class), "/bar");
        try {
            jetty.start();
            URL nonAuthURL = new URL(getJettyURL() + "/foo/bar");
            URL authURL = new URL(getJettyURL() + "/foo/bar?authenticated=foo");

            // unauthenticated access to URL
            HttpURLConnection conn = (HttpURLConnection) nonAuthURL.openConnection();
            Assert.assertEquals(HttpURLConnection.HTTP_UNAUTHORIZED, conn.getResponseCode());

            // authenticated access to URL
            conn = (HttpURLConnection) authURL.openConnection();
            Assert.assertEquals(HttpURLConnection.HTTP_OK, conn.getResponseCode());

            // unauthenticated access to get delegation token
            URL url = new URL(nonAuthURL.toExternalForm() + "?op=GETDELEGATIONTOKEN");
            conn = (HttpURLConnection) url.openConnection();
            Assert.assertEquals(HttpURLConnection.HTTP_UNAUTHORIZED, conn.getResponseCode());

            // authenticated access to get delegation token
            url = new URL(authURL.toExternalForm() + "&op=GETDELEGATIONTOKEN&renewer=foo");
            conn = (HttpURLConnection) url.openConnection();
            Assert.assertEquals(HttpURLConnection.HTTP_OK, conn.getResponseCode());
            ObjectMapper mapper = new ObjectMapper();
            Map map = mapper.readValue(conn.getInputStream(), Map.class);
            String dt = (String) ((Map) map.get("Token")).get("urlString");
            Assert.assertNotNull(dt);

            // delegation token access to URL
            url = new URL(nonAuthURL.toExternalForm() + "?delegation=" + dt);
            conn = (HttpURLConnection) url.openConnection();
            Assert.assertEquals(HttpURLConnection.HTTP_OK, conn.getResponseCode());

            // delegation token and authenticated access to URL
            url = new URL(authURL.toExternalForm() + "&delegation=" + dt);
            conn = (HttpURLConnection) url.openConnection();
            Assert.assertEquals(HttpURLConnection.HTTP_OK, conn.getResponseCode());

            // renewew delegation token, unauthenticated access to URL
            url = new URL(nonAuthURL.toExternalForm() + "?op=RENEWDELEGATIONTOKEN&token=" + dt);
            conn = (HttpURLConnection) url.openConnection();
            conn.setRequestMethod("PUT");
            Assert.assertEquals(HttpURLConnection.HTTP_UNAUTHORIZED, conn.getResponseCode());

            // renewew delegation token, authenticated access to URL
            url = new URL(authURL.toExternalForm() + "&op=RENEWDELEGATIONTOKEN&token=" + dt);
            conn = (HttpURLConnection) url.openConnection();
            conn.setRequestMethod("PUT");
            Assert.assertEquals(HttpURLConnection.HTTP_OK, conn.getResponseCode());

            // renewew delegation token, authenticated access to URL, not renewer
            url = new URL(getJettyURL() + "/foo/bar?authenticated=bar&op=RENEWDELEGATIONTOKEN&token=" + dt);
            conn = (HttpURLConnection) url.openConnection();
            conn.setRequestMethod("PUT");
            Assert.assertEquals(HttpURLConnection.HTTP_FORBIDDEN, conn.getResponseCode());

            // cancel delegation token, nonauthenticated access to URL
            url = new URL(nonAuthURL.toExternalForm() + "?op=CANCELDELEGATIONTOKEN&token=" + dt);
            conn = (HttpURLConnection) url.openConnection();
            conn.setRequestMethod("PUT");
            Assert.assertEquals(HttpURLConnection.HTTP_OK, conn.getResponseCode());

            // cancel canceled delegation token, nonauthenticated access to URL
            url = new URL(nonAuthURL.toExternalForm() + "?op=CANCELDELEGATIONTOKEN&token=" + dt);
            conn = (HttpURLConnection) url.openConnection();
            conn.setRequestMethod("PUT");
            Assert.assertEquals(HttpURLConnection.HTTP_NOT_FOUND, conn.getResponseCode());

            // get new delegation token
            url = new URL(authURL.toExternalForm() + "&op=GETDELEGATIONTOKEN&renewer=foo");
            conn = (HttpURLConnection) url.openConnection();
            Assert.assertEquals(HttpURLConnection.HTTP_OK, conn.getResponseCode());
            mapper = new ObjectMapper();
            map = mapper.readValue(conn.getInputStream(), Map.class);
            dt = (String) ((Map) map.get("Token")).get("urlString");
            Assert.assertNotNull(dt);

            // cancel delegation token, authenticated access to URL
            url = new URL(authURL.toExternalForm() + "&op=CANCELDELEGATIONTOKEN&token=" + dt);
            conn = (HttpURLConnection) url.openConnection();
            conn.setRequestMethod("PUT");
            Assert.assertEquals(HttpURLConnection.HTTP_OK, conn.getResponseCode());
        } finally {
            jetty.stop();
        }
    }

    @Test
    public void testDelegationTokenAuthenticatorCallsWithHeader() throws Exception {
        testDelegationTokenAuthenticatorCalls(false);
    }

    @Test
    public void testDelegationTokenAuthenticatorCallsWithQueryString() throws Exception {
        testDelegationTokenAuthenticatorCalls(true);
    }

    private void testDelegationTokenAuthenticatorCalls(final boolean useQS) throws Exception {
        final Server jetty = createJettyServer();
        Context context = new Context();
        context.setContextPath("/foo");
        jetty.setHandler(context);
        context.addFilter(new FilterHolder(AFilter.class), "/*", 0);
        context.addServlet(new ServletHolder(PingServlet.class), "/bar");

        try {
            jetty.start();
            final URL nonAuthURL = new URL(getJettyURL() + "/foo/bar");
            URL authURL = new URL(getJettyURL() + "/foo/bar?authenticated=foo");
            URL authURL2 = new URL(getJettyURL() + "/foo/bar?authenticated=bar");

            DelegationTokenAuthenticatedURL.Token token = new DelegationTokenAuthenticatedURL.Token();
            final DelegationTokenAuthenticatedURL aUrl = new DelegationTokenAuthenticatedURL();
            aUrl.setUseQueryStringForDelegationToken(useQS);

            try {
                aUrl.getDelegationToken(nonAuthURL, token, FOO_USER);
                Assert.fail();
            } catch (Exception ex) {
                Assert.assertTrue(ex.getMessage().contains("401"));
            }

            aUrl.getDelegationToken(authURL, token, FOO_USER);
            Assert.assertNotNull(token.getDelegationToken());
            Assert.assertEquals(new Text("token-kind"), token.getDelegationToken().getKind());

            aUrl.renewDelegationToken(authURL, token);

            try {
                aUrl.renewDelegationToken(nonAuthURL, token);
                Assert.fail();
            } catch (Exception ex) {
                Assert.assertTrue(ex.getMessage().contains("401"));
            }

            aUrl.getDelegationToken(authURL, token, FOO_USER);

            try {
                aUrl.renewDelegationToken(authURL2, token);
                Assert.fail();
            } catch (Exception ex) {
                Assert.assertTrue(ex.getMessage().contains("403"));
            }

            aUrl.getDelegationToken(authURL, token, FOO_USER);

            aUrl.cancelDelegationToken(authURL, token);

            aUrl.getDelegationToken(authURL, token, FOO_USER);

            aUrl.cancelDelegationToken(nonAuthURL, token);

            aUrl.getDelegationToken(authURL, token, FOO_USER);

            try {
                aUrl.renewDelegationToken(nonAuthURL, token);
            } catch (Exception ex) {
                Assert.assertTrue(ex.getMessage().contains("401"));
            }

            aUrl.getDelegationToken(authURL, token, "foo");

            UserGroupInformation ugi = UserGroupInformation.getCurrentUser();
            ugi.addToken(token.getDelegationToken());
            ugi.doAs(new PrivilegedExceptionAction<Void>() {
                @Override
                public Void run() throws Exception {
                    HttpURLConnection conn = aUrl.openConnection(nonAuthURL,
                            new DelegationTokenAuthenticatedURL.Token());
                    Assert.assertEquals(HttpServletResponse.SC_OK, conn.getResponseCode());
                    if (useQS) {
                        Assert.assertNull(conn.getHeaderField("UsingHeader"));
                        Assert.assertNotNull(conn.getHeaderField("UsingQueryString"));
                    } else {
                        Assert.assertNotNull(conn.getHeaderField("UsingHeader"));
                        Assert.assertNull(conn.getHeaderField("UsingQueryString"));
                    }
                    return null;
                }
            });

        } finally {
            jetty.stop();
        }
    }

    private static class DummyDelegationTokenSecretManager
            extends AbstractDelegationTokenSecretManager<DelegationTokenIdentifier> {

        public DummyDelegationTokenSecretManager() {
            super(10000, 10000, 10000, 10000);
        }

        @Override
        public DelegationTokenIdentifier createIdentifier() {
            return new DelegationTokenIdentifier(new Text("fooKind"));
        }

    }

    @Test
    public void testExternalDelegationTokenSecretManager() throws Exception {
        DummyDelegationTokenSecretManager secretMgr = new DummyDelegationTokenSecretManager();
        final Server jetty = createJettyServer();
        Context context = new Context();
        context.setContextPath("/foo");
        jetty.setHandler(context);
        context.addFilter(new FilterHolder(AFilter.class), "/*", 0);
        context.addServlet(new ServletHolder(PingServlet.class), "/bar");
        try {
            secretMgr.startThreads();
            context.setAttribute(DelegationTokenAuthenticationFilter.DELEGATION_TOKEN_SECRET_MANAGER_ATTR,
                    secretMgr);
            jetty.start();
            URL authURL = new URL(getJettyURL() + "/foo/bar?authenticated=foo");

            DelegationTokenAuthenticatedURL.Token token = new DelegationTokenAuthenticatedURL.Token();
            DelegationTokenAuthenticatedURL aUrl = new DelegationTokenAuthenticatedURL();

            aUrl.getDelegationToken(authURL, token, FOO_USER);
            Assert.assertNotNull(token.getDelegationToken());
            Assert.assertEquals(new Text("fooKind"), token.getDelegationToken().getKind());

        } finally {
            jetty.stop();
            secretMgr.stopThreads();
        }
    }

    public static class NoDTFilter extends AuthenticationFilter {

        @Override
        protected Properties getConfiguration(String configPrefix, FilterConfig filterConfig) {
            Properties conf = new Properties();
            conf.setProperty(AUTH_TYPE, PseudoAuthenticationHandler.TYPE);
            return conf;
        }
    }

    public static class NoDTHandlerDTAFilter extends DelegationTokenAuthenticationFilter {

        @Override
        protected Properties getConfiguration(String configPrefix, FilterConfig filterConfig) {
            Properties conf = new Properties();
            conf.setProperty(AUTH_TYPE, PseudoAuthenticationHandler.TYPE);
            return conf;
        }
    }

    public static class UserServlet extends HttpServlet {

        @Override
        protected void doGet(HttpServletRequest req, HttpServletResponse resp)
                throws ServletException, IOException {
            resp.setStatus(HttpServletResponse.SC_OK);
            resp.getWriter().write(req.getUserPrincipal().getName());
        }
    }

    @Test
    public void testDelegationTokenAuthenticationURLWithNoDTFilter() throws Exception {
        testDelegationTokenAuthenticatedURLWithNoDT(NoDTFilter.class);
    }

    @Test
    public void testDelegationTokenAuthenticationURLWithNoDTHandler() throws Exception {
        testDelegationTokenAuthenticatedURLWithNoDT(NoDTHandlerDTAFilter.class);
    }

    // we are, also, implicitly testing  KerberosDelegationTokenAuthenticator
    // fallback here
    private void testDelegationTokenAuthenticatedURLWithNoDT(Class<? extends Filter> filterClass) throws Exception {
        final Server jetty = createJettyServer();
        Context context = new Context();
        context.setContextPath("/foo");
        jetty.setHandler(context);
        context.addFilter(new FilterHolder(filterClass), "/*", 0);
        context.addServlet(new ServletHolder(UserServlet.class), "/bar");

        try {
            jetty.start();
            final URL url = new URL(getJettyURL() + "/foo/bar");

            UserGroupInformation ugi = UserGroupInformation.createRemoteUser(FOO_USER);
            ugi.doAs(new PrivilegedExceptionAction<Void>() {
                @Override
                public Void run() throws Exception {
                    DelegationTokenAuthenticatedURL.Token token = new DelegationTokenAuthenticatedURL.Token();
                    DelegationTokenAuthenticatedURL aUrl = new DelegationTokenAuthenticatedURL();
                    HttpURLConnection conn = aUrl.openConnection(url, token);
                    Assert.assertEquals(HttpURLConnection.HTTP_OK, conn.getResponseCode());
                    List<String> ret = IOUtils.readLines(conn.getInputStream());
                    Assert.assertEquals(1, ret.size());
                    Assert.assertEquals(FOO_USER, ret.get(0));

                    try {
                        aUrl.getDelegationToken(url, token, FOO_USER);
                        Assert.fail();
                    } catch (AuthenticationException ex) {
                        Assert.assertTrue(ex.getMessage().contains("delegation token operation"));
                    }
                    return null;
                }
            });
        } finally {
            jetty.stop();
        }
    }

    public static class PseudoDTAFilter extends DelegationTokenAuthenticationFilter {

        @Override
        protected Properties getConfiguration(String configPrefix, FilterConfig filterConfig) {
            Properties conf = new Properties();
            conf.setProperty(AUTH_TYPE, PseudoDelegationTokenAuthenticationHandler.class.getName());
            conf.setProperty(DelegationTokenAuthenticationHandler.TOKEN_KIND, "token-kind");
            return conf;
        }

        @Override
        protected org.apache.hadoop.conf.Configuration getProxyuserConfiguration(FilterConfig filterConfig)
                throws ServletException {
            org.apache.hadoop.conf.Configuration conf = new org.apache.hadoop.conf.Configuration(false);
            conf.set("proxyuser.foo.users", OK_USER);
            conf.set("proxyuser.foo.hosts", "localhost");
            return conf;
        }
    }

    @Test
    public void testFallbackToPseudoDelegationTokenAuthenticator() throws Exception {
        final Server jetty = createJettyServer();
        Context context = new Context();
        context.setContextPath("/foo");
        jetty.setHandler(context);
        context.addFilter(new FilterHolder(PseudoDTAFilter.class), "/*", 0);
        context.addServlet(new ServletHolder(UserServlet.class), "/bar");

        try {
            jetty.start();
            final URL url = new URL(getJettyURL() + "/foo/bar");

            UserGroupInformation ugi = UserGroupInformation.createRemoteUser(FOO_USER);
            ugi.doAs(new PrivilegedExceptionAction<Void>() {
                @Override
                public Void run() throws Exception {
                    DelegationTokenAuthenticatedURL.Token token = new DelegationTokenAuthenticatedURL.Token();
                    DelegationTokenAuthenticatedURL aUrl = new DelegationTokenAuthenticatedURL();
                    HttpURLConnection conn = aUrl.openConnection(url, token);
                    Assert.assertEquals(HttpURLConnection.HTTP_OK, conn.getResponseCode());
                    List<String> ret = IOUtils.readLines(conn.getInputStream());
                    Assert.assertEquals(1, ret.size());
                    Assert.assertEquals(FOO_USER, ret.get(0));

                    aUrl.getDelegationToken(url, token, FOO_USER);
                    Assert.assertNotNull(token.getDelegationToken());
                    Assert.assertEquals(new Text("token-kind"), token.getDelegationToken().getKind());
                    return null;
                }
            });
        } finally {
            jetty.stop();
        }
    }

    public static class KDTAFilter extends DelegationTokenAuthenticationFilter {
        static String keytabFile;

        @Override
        protected Properties getConfiguration(String configPrefix, FilterConfig filterConfig) {
            Properties conf = new Properties();
            conf.setProperty(AUTH_TYPE, KerberosDelegationTokenAuthenticationHandler.class.getName());
            conf.setProperty(KerberosAuthenticationHandler.KEYTAB, keytabFile);
            conf.setProperty(KerberosAuthenticationHandler.PRINCIPAL, "HTTP/localhost");
            conf.setProperty(KerberosDelegationTokenAuthenticationHandler.TOKEN_KIND, "token-kind");
            return conf;
        }

        @Override
        protected org.apache.hadoop.conf.Configuration getProxyuserConfiguration(FilterConfig filterConfig)
                throws ServletException {
            org.apache.hadoop.conf.Configuration conf = new org.apache.hadoop.conf.Configuration(false);
            conf.set("proxyuser.client.users", OK_USER);
            conf.set("proxyuser.client.hosts", "127.0.0.1");
            return conf;
        }
    }

    private static class KerberosConfiguration extends Configuration {
        private String principal;
        private String keytab;

        public KerberosConfiguration(String principal, String keytab) {
            this.principal = principal;
            this.keytab = keytab;
        }

        @Override
        public AppConfigurationEntry[] getAppConfigurationEntry(String name) {
            Map<String, String> options = new HashMap<String, String>();
            options.put("principal", principal);
            options.put("keyTab", keytab);
            options.put("useKeyTab", "true");
            options.put("storeKey", "true");
            options.put("doNotPrompt", "true");
            options.put("useTicketCache", "true");
            options.put("renewTGT", "true");
            options.put("refreshKrb5Config", "true");
            options.put("isInitiator", "true");
            String ticketCache = System.getenv("KRB5CCNAME");
            if (ticketCache != null) {
                options.put("ticketCache", ticketCache);
            }
            options.put("debug", "true");

            return new AppConfigurationEntry[] { new AppConfigurationEntry(KerberosUtil.getKrb5LoginModuleName(),
                    AppConfigurationEntry.LoginModuleControlFlag.REQUIRED, options), };
        }
    }

    public static <T> T doAsKerberosUser(String principal, String keytab, final Callable<T> callable)
            throws Exception {
        LoginContext loginContext = null;
        try {
            Set<Principal> principals = new HashSet<Principal>();
            principals.add(new KerberosPrincipal(principal));
            Subject subject = new Subject(false, principals, new HashSet<Object>(), new HashSet<Object>());
            loginContext = new LoginContext("", subject, null, new KerberosConfiguration(principal, keytab));
            loginContext.login();
            subject = loginContext.getSubject();
            return Subject.doAs(subject, new PrivilegedExceptionAction<T>() {
                @Override
                public T run() throws Exception {
                    return callable.call();
                }
            });
        } catch (PrivilegedActionException ex) {
            throw ex.getException();
        } finally {
            if (loginContext != null) {
                loginContext.logout();
            }
        }
    }

    @Test
    public void testKerberosDelegationTokenAuthenticator() throws Exception {
        testKerberosDelegationTokenAuthenticator(false);
    }

    @Test
    public void testKerberosDelegationTokenAuthenticatorWithDoAs() throws Exception {
        testKerberosDelegationTokenAuthenticator(true);
    }

    private void testKerberosDelegationTokenAuthenticator(final boolean doAs) throws Exception {
        final String doAsUser = doAs ? OK_USER : null;

        // setting hadoop security to kerberos
        org.apache.hadoop.conf.Configuration conf = new org.apache.hadoop.conf.Configuration();
        conf.set("hadoop.security.authentication", "kerberos");
        UserGroupInformation.setConfiguration(conf);

        File testDir = new File("target/" + UUID.randomUUID().toString());
        Assert.assertTrue(testDir.mkdirs());
        MiniKdc kdc = new MiniKdc(MiniKdc.createConf(), testDir);
        final Server jetty = createJettyServer();
        Context context = new Context();
        context.setContextPath("/foo");
        jetty.setHandler(context);
        ((AbstractConnector) jetty.getConnectors()[0]).setResolveNames(true);
        context.addFilter(new FilterHolder(KDTAFilter.class), "/*", 0);
        context.addServlet(new ServletHolder(UserServlet.class), "/bar");
        try {
            kdc.start();
            File keytabFile = new File(testDir, "test.keytab");
            kdc.createPrincipal(keytabFile, "client", "HTTP/localhost");
            KDTAFilter.keytabFile = keytabFile.getAbsolutePath();
            jetty.start();

            final DelegationTokenAuthenticatedURL.Token token = new DelegationTokenAuthenticatedURL.Token();
            final DelegationTokenAuthenticatedURL aUrl = new DelegationTokenAuthenticatedURL();
            final URL url = new URL(getJettyURL() + "/foo/bar");

            try {
                aUrl.getDelegationToken(url, token, FOO_USER, doAsUser);
                Assert.fail();
            } catch (AuthenticationException ex) {
                Assert.assertTrue(ex.getMessage().contains("GSSException"));
            }

            doAsKerberosUser("client", keytabFile.getAbsolutePath(), new Callable<Void>() {
                @Override
                public Void call() throws Exception {
                    aUrl.getDelegationToken(url, token, doAs ? doAsUser : "client", doAsUser);
                    Assert.assertNotNull(token.getDelegationToken());
                    Assert.assertEquals(new Text("token-kind"), token.getDelegationToken().getKind());
                    // Make sure the token belongs to the right owner
                    ByteArrayInputStream buf = new ByteArrayInputStream(token.getDelegationToken().getIdentifier());
                    DataInputStream dis = new DataInputStream(buf);
                    DelegationTokenIdentifier id = new DelegationTokenIdentifier(new Text("token-kind"));
                    id.readFields(dis);
                    dis.close();
                    Assert.assertEquals(doAs ? new Text(OK_USER) : new Text("client"), id.getOwner());
                    if (doAs) {
                        Assert.assertEquals(new Text("client"), id.getRealUser());
                    }

                    aUrl.renewDelegationToken(url, token, doAsUser);
                    Assert.assertNotNull(token.getDelegationToken());

                    aUrl.getDelegationToken(url, token, FOO_USER, doAsUser);
                    Assert.assertNotNull(token.getDelegationToken());

                    try {
                        aUrl.renewDelegationToken(url, token, doAsUser);
                        Assert.fail();
                    } catch (Exception ex) {
                        Assert.assertTrue(ex.getMessage().contains("403"));
                    }

                    aUrl.getDelegationToken(url, token, FOO_USER, doAsUser);

                    aUrl.cancelDelegationToken(url, token, doAsUser);
                    Assert.assertNull(token.getDelegationToken());

                    return null;
                }
            });
        } finally {
            jetty.stop();
            kdc.stop();
        }
    }

    @Test
    public void testProxyUser() throws Exception {
        final Server jetty = createJettyServer();
        Context context = new Context();
        context.setContextPath("/foo");
        jetty.setHandler(context);
        context.addFilter(new FilterHolder(PseudoDTAFilter.class), "/*", 0);
        context.addServlet(new ServletHolder(UserServlet.class), "/bar");

        try {
            jetty.start();
            final URL url = new URL(getJettyURL() + "/foo/bar");

            // proxyuser using raw HTTP, verifying doAs is case insensitive
            String strUrl = String.format("%s?user.name=%s&doas=%s", url.toExternalForm(), FOO_USER, OK_USER);
            HttpURLConnection conn = (HttpURLConnection) new URL(strUrl).openConnection();
            Assert.assertEquals(HttpURLConnection.HTTP_OK, conn.getResponseCode());
            List<String> ret = IOUtils.readLines(conn.getInputStream());
            Assert.assertEquals(1, ret.size());
            Assert.assertEquals(OK_USER, ret.get(0));
            strUrl = String.format("%s?user.name=%s&DOAS=%s", url.toExternalForm(), FOO_USER, OK_USER);
            conn = (HttpURLConnection) new URL(strUrl).openConnection();
            Assert.assertEquals(HttpURLConnection.HTTP_OK, conn.getResponseCode());
            ret = IOUtils.readLines(conn.getInputStream());
            Assert.assertEquals(1, ret.size());
            Assert.assertEquals(OK_USER, ret.get(0));

            UserGroupInformation ugi = UserGroupInformation.createRemoteUser(FOO_USER);
            ugi.doAs(new PrivilegedExceptionAction<Void>() {
                @Override
                public Void run() throws Exception {
                    DelegationTokenAuthenticatedURL.Token token = new DelegationTokenAuthenticatedURL.Token();
                    DelegationTokenAuthenticatedURL aUrl = new DelegationTokenAuthenticatedURL();

                    // proxyuser using authentication handler authentication
                    HttpURLConnection conn = aUrl.openConnection(url, token, OK_USER);
                    Assert.assertEquals(HttpURLConnection.HTTP_OK, conn.getResponseCode());
                    List<String> ret = IOUtils.readLines(conn.getInputStream());
                    Assert.assertEquals(1, ret.size());
                    Assert.assertEquals(OK_USER, ret.get(0));

                    // unauthorized proxy user using authentication handler authentication
                    conn = aUrl.openConnection(url, token, FAIL_USER);
                    Assert.assertEquals(HttpURLConnection.HTTP_FORBIDDEN, conn.getResponseCode());

                    // proxy using delegation token authentication
                    aUrl.getDelegationToken(url, token, FOO_USER);

                    UserGroupInformation ugi = UserGroupInformation.getCurrentUser();
                    ugi.addToken(token.getDelegationToken());
                    token = new DelegationTokenAuthenticatedURL.Token();

                    // requests using delegation token as auth do not honor doAs
                    conn = aUrl.openConnection(url, token, OK_USER);
                    Assert.assertEquals(HttpURLConnection.HTTP_OK, conn.getResponseCode());
                    ret = IOUtils.readLines(conn.getInputStream());
                    Assert.assertEquals(1, ret.size());
                    Assert.assertEquals(FOO_USER, ret.get(0));

                    return null;
                }
            });
        } finally {
            jetty.stop();
        }
    }

    public static class UGIServlet extends HttpServlet {

        @Override
        protected void doGet(HttpServletRequest req, HttpServletResponse resp)
                throws ServletException, IOException {
            UserGroupInformation ugi = HttpUserGroupInformation.get();
            if (ugi != null) {
                String ret = "remoteuser=" + req.getRemoteUser() + ":ugi=" + ugi.getShortUserName();
                if (ugi.getAuthenticationMethod() == UserGroupInformation.AuthenticationMethod.PROXY) {
                    ret = "realugi=" + ugi.getRealUser().getShortUserName() + ":" + ret;
                }
                resp.setStatus(HttpServletResponse.SC_OK);
                resp.getWriter().write(ret);
            } else {
                resp.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
            }
        }
    }

    @Test
    public void testHttpUGI() throws Exception {
        final Server jetty = createJettyServer();
        Context context = new Context();
        context.setContextPath("/foo");
        jetty.setHandler(context);
        context.addFilter(new FilterHolder(PseudoDTAFilter.class), "/*", 0);
        context.addServlet(new ServletHolder(UGIServlet.class), "/bar");

        try {
            jetty.start();
            final URL url = new URL(getJettyURL() + "/foo/bar");

            UserGroupInformation ugi = UserGroupInformation.createRemoteUser(FOO_USER);
            ugi.doAs(new PrivilegedExceptionAction<Void>() {
                @Override
                public Void run() throws Exception {
                    DelegationTokenAuthenticatedURL.Token token = new DelegationTokenAuthenticatedURL.Token();
                    DelegationTokenAuthenticatedURL aUrl = new DelegationTokenAuthenticatedURL();

                    // user foo
                    HttpURLConnection conn = aUrl.openConnection(url, token);
                    Assert.assertEquals(HttpURLConnection.HTTP_OK, conn.getResponseCode());
                    List<String> ret = IOUtils.readLines(conn.getInputStream());
                    Assert.assertEquals(1, ret.size());
                    Assert.assertEquals("remoteuser=" + FOO_USER + ":ugi=" + FOO_USER, ret.get(0));

                    // user ok-user via proxyuser foo
                    conn = aUrl.openConnection(url, token, OK_USER);
                    Assert.assertEquals(HttpURLConnection.HTTP_OK, conn.getResponseCode());
                    ret = IOUtils.readLines(conn.getInputStream());
                    Assert.assertEquals(1, ret.size());
                    Assert.assertEquals("realugi=" + FOO_USER + ":remoteuser=" + OK_USER + ":ugi=" + OK_USER,
                            ret.get(0));

                    return null;
                }
            });
        } finally {
            jetty.stop();
        }
    }

    public static class IpAddressBasedPseudoDTAFilter extends PseudoDTAFilter {
        @Override
        protected org.apache.hadoop.conf.Configuration getProxyuserConfiguration(FilterConfig filterConfig)
                throws ServletException {
            org.apache.hadoop.conf.Configuration configuration = super.getProxyuserConfiguration(filterConfig);
            configuration.set("proxyuser.foo.hosts", "127.0.0.1");
            return configuration;
        }
    }

    @Test
    public void testIpaddressCheck() throws Exception {
        final Server jetty = createJettyServer();
        ((AbstractConnector) jetty.getConnectors()[0]).setResolveNames(true);
        Context context = new Context();
        context.setContextPath("/foo");
        jetty.setHandler(context);

        context.addFilter(new FilterHolder(IpAddressBasedPseudoDTAFilter.class), "/*", 0);
        context.addServlet(new ServletHolder(UGIServlet.class), "/bar");

        try {
            jetty.start();
            final URL url = new URL(getJettyURL() + "/foo/bar");

            UserGroupInformation ugi = UserGroupInformation.createRemoteUser(FOO_USER);
            ugi.doAs(new PrivilegedExceptionAction<Void>() {
                @Override
                public Void run() throws Exception {
                    DelegationTokenAuthenticatedURL.Token token = new DelegationTokenAuthenticatedURL.Token();
                    DelegationTokenAuthenticatedURL aUrl = new DelegationTokenAuthenticatedURL();

                    // user ok-user via proxyuser foo
                    HttpURLConnection conn = aUrl.openConnection(url, token, OK_USER);
                    Assert.assertEquals(HttpURLConnection.HTTP_OK, conn.getResponseCode());
                    List<String> ret = IOUtils.readLines(conn.getInputStream());
                    Assert.assertEquals(1, ret.size());
                    Assert.assertEquals("realugi=" + FOO_USER + ":remoteuser=" + OK_USER + ":ugi=" + OK_USER,
                            ret.get(0));

                    return null;
                }
            });
        } finally {
            jetty.stop();
        }
    }

}