You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@directory.apache.org by pl...@apache.org on 2017/11/28 03:04:12 UTC

[11/15] directory-kerby git commit: Change the Maven groupId in HAS folder to org.apache.kerby.

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/a8b1c28f/has/has-common/src/main/java/org/apache/hadoop/has/common/util/HasJaasLoginUtil.java
----------------------------------------------------------------------
diff --git a/has/has-common/src/main/java/org/apache/hadoop/has/common/util/HasJaasLoginUtil.java b/has/has-common/src/main/java/org/apache/hadoop/has/common/util/HasJaasLoginUtil.java
deleted file mode 100644
index e824ea4..0000000
--- a/has/has-common/src/main/java/org/apache/hadoop/has/common/util/HasJaasLoginUtil.java
+++ /dev/null
@@ -1,261 +0,0 @@
-/**
- *  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.has.common.util;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-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.security.auth.login.LoginException;
-import java.io.File;
-import java.io.IOException;
-import java.security.Principal;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Set;
-
-/**
- * JAAS utilities for Has login.
- */
-public class HasJaasLoginUtil {
-    public static final Logger LOG = LoggerFactory.getLogger(HasJaasLoginUtil.class);
-
-    public static final boolean ENABLE_DEBUG = true;
-
-    private static String getKrb5LoginModuleName() {
-        return System.getProperty("java.vendor").contains("IBM")
-            ? "com.ibm.security.auth.module.Krb5LoginModule"
-            : "org.apache.hadoop.has.client.HasLoginModule";
-    }
-
-    /**
-     * Log a user in from a tgt ticket.
-     *
-     * @throws IOException
-     */
-    public static synchronized Subject loginUserFromTgtTicket(String hadoopSecurityHas) throws IOException {
-
-        TICKET_KERBEROS_OPTIONS.put("hadoopSecurityHas", hadoopSecurityHas);
-        Subject subject = new Subject();
-        Configuration conf = new HasJaasConf();
-        String confName = "ticket-kerberos";
-        LoginContext loginContext = null;
-        try {
-            loginContext = new LoginContext(confName, subject, null, conf);
-        } catch (LoginException e) {
-            throw new IOException("Fail to create LoginContext for " + e);
-        }
-        try {
-            loginContext.login();
-            LOG.info("Login successful for user "
-                + subject.getPrincipals().iterator().next().getName());
-        } catch (LoginException e) {
-            throw new IOException("Login failure for " + e);
-        }
-        return loginContext.getSubject();
-    }
-
-    /**
-     * Has Jaas config.
-     */
-    static class HasJaasConf extends Configuration {
-        @Override
-        public AppConfigurationEntry[] getAppConfigurationEntry(String name) {
-
-            return new AppConfigurationEntry[]{
-                TICKET_KERBEROS_LOGIN};
-        }
-    }
-
-    private static final Map<String, String> BASIC_JAAS_OPTIONS =
-        new HashMap<String, String>();
-
-    static {
-        String jaasEnvVar = System.getenv("HADOOP_JAAS_DEBUG");
-        if (jaasEnvVar != null && "true".equalsIgnoreCase(jaasEnvVar)) {
-            BASIC_JAAS_OPTIONS.put("debug", String.valueOf(ENABLE_DEBUG));
-        }
-    }
-
-    private static final Map<String, String> TICKET_KERBEROS_OPTIONS =
-        new HashMap<String, String>();
-
-    static {
-        TICKET_KERBEROS_OPTIONS.put("doNotPrompt", "true");
-        TICKET_KERBEROS_OPTIONS.put("useTgtTicket", "true");
-        TICKET_KERBEROS_OPTIONS.putAll(BASIC_JAAS_OPTIONS);
-    }
-
-    private static final AppConfigurationEntry TICKET_KERBEROS_LOGIN =
-        new AppConfigurationEntry(getKrb5LoginModuleName(),
-            AppConfigurationEntry.LoginModuleControlFlag.OPTIONAL,
-            TICKET_KERBEROS_OPTIONS);
-
-
-     public static Subject loginUsingTicketCache(
-        String principal, File cacheFile) throws IOException {
-        Set<Principal> principals = new HashSet<Principal>();
-        principals.add(new KerberosPrincipal(principal));
-
-        Subject subject = new Subject(false, principals,
-            new HashSet<Object>(), new HashSet<Object>());
-
-        Configuration conf = useTicketCache(principal, cacheFile);
-        String confName = "TicketCacheConf";
-         LoginContext loginContext = null;
-         try {
-             loginContext = new LoginContext(confName, subject, null, conf);
-         } catch (LoginException e) {
-             throw new IOException("Faill to create LoginContext for " + e);
-         }
-         try {
-             loginContext.login();
-             LOG.info("Login successful for user "
-                 + subject.getPrincipals().iterator().next().getName());
-         } catch (LoginException e) {
-             throw new IOException("Login failure for " + e);
-         }
-         return loginContext.getSubject();
-    }
-
-    public static Subject loginUsingKeytab(
-        String principal, File keytabFile) throws IOException {
-        Set<Principal> principals = new HashSet<Principal>();
-        principals.add(new KerberosPrincipal(principal));
-
-        Subject subject = new Subject(false, principals,
-            new HashSet<Object>(), new HashSet<Object>());
-
-        Configuration conf = useKeytab(principal, keytabFile);
-        String confName = "KeytabConf";
-        LoginContext loginContext = null;
-        try {
-            loginContext = new LoginContext(confName, subject, null, conf);
-        } catch (LoginException e) {
-            throw new IOException("Fail to create LoginContext for " + e);
-        }
-        try {
-            loginContext.login();
-             LOG.info("Login successful for user "
-                + subject.getPrincipals().iterator().next().getName());
-        } catch (LoginException e) {
-            throw new IOException("Login failure for " + e);
-        }
-        return loginContext.getSubject();
-    }
-
-    public static LoginContext loginUsingKeytabReturnContext(
-        String principal, File keytabFile) throws IOException {
-        Set<Principal> principals = new HashSet<Principal>();
-        principals.add(new KerberosPrincipal(principal));
-
-        Subject subject = new Subject(false, principals,
-            new HashSet<Object>(), new HashSet<Object>());
-
-        Configuration conf = useKeytab(principal, keytabFile);
-        String confName = "KeytabConf";
-        LoginContext loginContext = null;
-        try {
-            loginContext = new LoginContext(confName, subject, null, conf);
-        } catch (LoginException e) {
-            throw new IOException("Fail to create LoginContext for " + e);
-        }
-        try {
-            loginContext.login();
-            LOG.info("Login successful for user "
-                + subject.getPrincipals().iterator().next().getName());
-        } catch (LoginException e) {
-            throw new IOException("Login failure for " + e);
-        }
-        return loginContext;
-    }
-
-    public static Configuration useTicketCache(String principal,
-                                               File credentialFile) {
-        return new TicketCacheJaasConf(principal, credentialFile);
-    }
-
-    public static Configuration useKeytab(String principal, File keytabFile) {
-        return new KeytabJaasConf(principal, keytabFile);
-    }
-
-    static class TicketCacheJaasConf extends Configuration {
-        private String principal;
-        private File clientCredentialFile;
-
-        TicketCacheJaasConf(String principal, File clientCredentialFile) {
-            this.principal = principal;
-            this.clientCredentialFile = clientCredentialFile;
-        }
-
-        @Override
-        public AppConfigurationEntry[] getAppConfigurationEntry(String name) {
-            Map<String, String> options = new HashMap<String, String>();
-            options.put("principal", principal);
-            options.put("storeKey", "false");
-            options.put("doNotPrompt", "false");
-            options.put("useTicketCache", "true");
-            options.put("renewTGT", "true");
-            options.put("refreshKrb5Config", "true");
-            options.put("isInitiator", "true");
-            options.put("ticketCache", clientCredentialFile.getAbsolutePath());
-            options.putAll(BASIC_JAAS_OPTIONS);
-
-            return new AppConfigurationEntry[]{
-                new AppConfigurationEntry(getKrb5LoginModuleName(),
-                    AppConfigurationEntry.LoginModuleControlFlag.REQUIRED,
-                    options)};
-        }
-    }
-
-    static class KeytabJaasConf extends Configuration {
-        private String principal;
-        private File keytabFile;
-
-        KeytabJaasConf(String principal, File keytab) {
-            this.principal = principal;
-            this.keytabFile = keytab;
-        }
-
-        @Override
-        public AppConfigurationEntry[] getAppConfigurationEntry(String name) {
-            Map<String, String> options = new HashMap<String, String>();
-            options.put("keyTab", keytabFile.getAbsolutePath());
-            options.put("principal", principal);
-            options.put("useKeyTab", "true");
-            options.put("storeKey", "true");
-            options.put("doNotPrompt", "true");
-            options.put("renewTGT", "false");
-            options.put("refreshKrb5Config", "true");
-            options.put("isInitiator", "true");
-            options.putAll(BASIC_JAAS_OPTIONS);
-
-            return new AppConfigurationEntry[]{
-                new AppConfigurationEntry(getKrb5LoginModuleName(),
-                    AppConfigurationEntry.LoginModuleControlFlag.REQUIRED,
-                    options)};
-        }
-    }
-}

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/a8b1c28f/has/has-common/src/main/java/org/apache/hadoop/has/common/util/HasUtil.java
----------------------------------------------------------------------
diff --git a/has/has-common/src/main/java/org/apache/hadoop/has/common/util/HasUtil.java b/has/has-common/src/main/java/org/apache/hadoop/has/common/util/HasUtil.java
deleted file mode 100644
index 1d9f4b7..0000000
--- a/has/has-common/src/main/java/org/apache/hadoop/has/common/util/HasUtil.java
+++ /dev/null
@@ -1,93 +0,0 @@
-/**
- * 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.has.common.util;
-
-import org.apache.hadoop.has.common.HasConfig;
-import org.apache.hadoop.has.common.HasException;
-import org.apache.kerby.kerberos.kerb.KrbException;
-import org.apache.kerby.kerberos.kerb.crypto.EncryptionHandler;
-import org.apache.kerby.kerberos.kerb.type.base.EncryptionKey;
-import org.apache.kerby.kerberos.kerb.type.base.EncryptionType;
-
-import java.io.BufferedReader;
-import java.io.File;
-import java.io.FileNotFoundException;
-import java.io.FileOutputStream;
-import java.io.FileReader;
-import java.io.IOException;
-import java.io.PrintStream;
-
-public class HasUtil {
-
-    public static EncryptionKey getClientKey(String userName, String passPhrase,
-                                             EncryptionType type) throws KrbException {
-        EncryptionKey clientKey = EncryptionHandler.string2Key(userName,
-            passPhrase, type);
-        return clientKey;
-    }
-
-    /**
-     * Get has configuration
-     * @param hasConfFile configuration directory
-     * @return has configuration
-     * @throws KrbException e
-     */
-    public static HasConfig getHasConfig(File hasConfFile) throws HasException {
-
-        if (hasConfFile.exists()) {
-            HasConfig hasConfig = new HasConfig();
-            try {
-                hasConfig.addIniConfig(hasConfFile);
-            } catch (IOException e) {
-                throw new HasException("Can not load the has configuration file "
-                    + hasConfFile.getAbsolutePath());
-            }
-            return hasConfig;
-        }
-
-        return null;
-    }
-
-    public static void setEnableConf(File hasConfFile, String value)
-            throws HasException, IOException {
-        String oldValue = getHasConfig(hasConfFile).getEnableConf();
-        if (oldValue == null) {
-            throw new HasException("Please set enable_conf in has-server.conf.");
-        }
-        if (oldValue.equals(value)) {
-            return;
-        }
-        try {
-            BufferedReader bf = new BufferedReader(new FileReader(hasConfFile));
-            StringBuilder sb = new StringBuilder();
-            String tempString;
-            while ((tempString = bf.readLine()) != null) {
-                if (tempString.trim().startsWith("enable_conf")) {
-                    tempString = tempString.replace(oldValue, value);
-                }
-                sb.append(tempString + "\n");
-            }
-            PrintStream ps = new PrintStream(new FileOutputStream(hasConfFile));
-            ps.print(sb.toString());
-            bf.close();
-        } catch (FileNotFoundException e) {
-            throw new HasException("Can not load the has configuration file "
-                    + hasConfFile.getAbsolutePath());
-        }
-    }
-}

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/a8b1c28f/has/has-common/src/main/java/org/apache/hadoop/has/common/util/PlatformName.java
----------------------------------------------------------------------
diff --git a/has/has-common/src/main/java/org/apache/hadoop/has/common/util/PlatformName.java b/has/has-common/src/main/java/org/apache/hadoop/has/common/util/PlatformName.java
deleted file mode 100644
index 6f64c62..0000000
--- a/has/has-common/src/main/java/org/apache/hadoop/has/common/util/PlatformName.java
+++ /dev/null
@@ -1,59 +0,0 @@
-/**
- * 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.has.common.util;
-
-import org.apache.hadoop.classification.InterfaceAudience;
-import org.apache.hadoop.classification.InterfaceStability;
-
-/**
- * Borrow the class from Apache Hadoop
- */
-
-/**
- * A helper class for getting build-info of the java-vm.
- *
- */
-@InterfaceAudience.LimitedPrivate({"HBase"})
-@InterfaceStability.Unstable
-public class PlatformName {
-  /**
-   * The complete platform 'name' to identify the platform as
-   * per the java-vm.
-   */
-  public static final String PLATFORM_NAME =
-      (System.getProperty("os.name").startsWith("Windows")
-      ? System.getenv("os") : System.getProperty("os.name"))
-      + "-" + System.getProperty("os.arch")
-      + "-" + System.getProperty("sun.arch.data.model");
-
-  /**
-   * The java vendor name used in this platform.
-   */
-  public static final String JAVA_VENDOR_NAME = System.getProperty("java.vendor");
-
-  /**
-   * A public static variable to indicate the current java vendor is
-   * IBM java or not.
-   */
-  public static final boolean IBM_JAVA = JAVA_VENDOR_NAME.contains("IBM");
-
-  public static void main(String[] args) {
-    System.out.println(PLATFORM_NAME);
-  }
-}

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/a8b1c28f/has/has-common/src/main/java/org/apache/hadoop/has/common/util/StringUtils.java
----------------------------------------------------------------------
diff --git a/has/has-common/src/main/java/org/apache/hadoop/has/common/util/StringUtils.java b/has/has-common/src/main/java/org/apache/hadoop/has/common/util/StringUtils.java
deleted file mode 100644
index 2b00904..0000000
--- a/has/has-common/src/main/java/org/apache/hadoop/has/common/util/StringUtils.java
+++ /dev/null
@@ -1,55 +0,0 @@
-/**
- * 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.has.common.util;
-
-import org.apache.hadoop.classification.InterfaceAudience;
-import org.apache.hadoop.classification.InterfaceStability;
-
-import java.util.Locale;
-
-/**
- * General string utils
- */
-@InterfaceAudience.Private
-@InterfaceStability.Unstable
-public class StringUtils {
-
-  /**
-   * Converts all of the characters in this String to lower case with
-   * Locale.ENGLISH.
-   *
-   * @param str  string to be converted
-   * @return     the str, converted to lowercase.
-   */
-  public static String toLowerCase(String str) {
-    return str.toLowerCase(Locale.ENGLISH);
-  }
-
-  /**
-   * Converts all of the characters in this String to upper case with
-   * Locale.ENGLISH.
-   *
-   * @param str  string to be converted
-   * @return     the str, converted to uppercase.
-   */
-  public static String toUpperCase(String str) {
-    return str.toUpperCase(Locale.ENGLISH);
-  }
-
-}

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/a8b1c28f/has/has-common/src/main/java/org/apache/hadoop/has/common/util/URLConnectionFactory.java
----------------------------------------------------------------------
diff --git a/has/has-common/src/main/java/org/apache/hadoop/has/common/util/URLConnectionFactory.java b/has/has-common/src/main/java/org/apache/hadoop/has/common/util/URLConnectionFactory.java
deleted file mode 100644
index a818864..0000000
--- a/has/has-common/src/main/java/org/apache/hadoop/has/common/util/URLConnectionFactory.java
+++ /dev/null
@@ -1,215 +0,0 @@
-/**
- * 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.has.common.util;
-
-import com.google.common.annotations.VisibleForTesting;
-import org.apache.hadoop.classification.InterfaceStability;
-import org.apache.hadoop.has.common.HasConfig;
-import org.apache.hadoop.has.common.HasException;
-import org.apache.hadoop.has.common.spnego.AuthenticatedURL;
-import org.apache.hadoop.has.common.spnego.AuthenticationException;
-import org.apache.hadoop.has.common.spnego.KerberosHasAuthenticator;
-import org.apache.hadoop.has.common.ssl.SSLFactory;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import javax.net.ssl.HostnameVerifier;
-import javax.net.ssl.HttpsURLConnection;
-import javax.net.ssl.SSLSocketFactory;
-import java.io.IOException;
-import java.net.HttpURLConnection;
-import java.net.URL;
-import java.net.URLConnection;
-import java.security.GeneralSecurityException;
-
-/**
- * Borrow the class from Apache Hadoop
- */
-
-/**
- * Utilities for handling URLs
- */
-@InterfaceStability.Unstable
-public class URLConnectionFactory {
-  private static final Logger LOG = LoggerFactory
-      .getLogger(URLConnectionFactory.class);
-
-  /**
-   * Timeout for socket connects and reads
-   */
-   // 1 minute
-  public static final int DEFAULT_SOCKET_TIMEOUT = 60 * 1000;
-  private final ConnectionConfigurator connConfigurator;
-
-  private static final ConnectionConfigurator DEFAULT_TIMEOUT_CONN_CONFIGURATOR
-      = new ConnectionConfigurator() {
-        @Override
-        public HttpURLConnection configure(HttpURLConnection conn)
-            throws IOException {
-          URLConnectionFactory.setTimeouts(conn,
-                                           DEFAULT_SOCKET_TIMEOUT,
-                                           DEFAULT_SOCKET_TIMEOUT);
-          return conn;
-        }
-      };
-
-  /**
-   * The URLConnectionFactory that sets the default timeout and it only trusts
-   * Java's SSL certificates.
-   */
-  public static final URLConnectionFactory DEFAULT_SYSTEM_CONNECTION_FACTORY =
-      new URLConnectionFactory(DEFAULT_TIMEOUT_CONN_CONFIGURATOR);
-
-  /**
-   * Construct a new URLConnectionFactory based on the configuration. It will
-   * try to load SSL certificates when it is specified.
-   */
-  public static URLConnectionFactory newDefaultURLConnectionFactory(HasConfig conf) {
-    ConnectionConfigurator conn = null;
-    try {
-      conn = newSslConnConfigurator(DEFAULT_SOCKET_TIMEOUT, conf);
-    } catch (Exception e) {
-      LOG.debug(
-          "Cannot load customized ssl related configuration. Fallback to system-generic settings.",
-          e);
-      conn = DEFAULT_TIMEOUT_CONN_CONFIGURATOR;
-    }
-    return new URLConnectionFactory(conn);
-  }
-
-  private static ConnectionConfigurator getSSLConnectionConfiguration(
-      HasConfig conf) {
-    ConnectionConfigurator conn;
-    try {
-      conn = newSslConnConfigurator(DEFAULT_SOCKET_TIMEOUT, conf);
-    } catch (Exception e) {
-      LOG.warn(
-          "Cannot load customized ssl related configuration. Fallback to"
-              + " system-generic settings.",
-          e);
-      conn = DEFAULT_TIMEOUT_CONN_CONFIGURATOR;
-    }
-
-    return conn;
-  }
-
-  @VisibleForTesting
-  URLConnectionFactory(ConnectionConfigurator connConfigurator) {
-    this.connConfigurator = connConfigurator;
-  }
-
-  /**
-   * Create a new ConnectionConfigurator for SSL connections
-   */
-  private static ConnectionConfigurator newSslConnConfigurator(
-      final int defaultTimeout, HasConfig conf)
-      throws IOException, GeneralSecurityException, HasException {
-    final SSLFactory factory;
-    final SSLSocketFactory sf;
-    final HostnameVerifier hv;
-    final int connectTimeout;
-    final int readTimeout;
-
-    factory = new SSLFactory(SSLFactory.Mode.CLIENT, conf);
-    factory.init();
-    sf = factory.createSSLSocketFactory();
-    hv = factory.getHostnameVerifier();
-
-    connectTimeout = defaultTimeout;
-
-    readTimeout = defaultTimeout;
-
-    return new ConnectionConfigurator() {
-      @Override
-      public HttpURLConnection configure(HttpURLConnection conn)
-          throws IOException {
-        if (conn instanceof HttpsURLConnection) {
-          HttpsURLConnection c = (HttpsURLConnection) conn;
-          c.setSSLSocketFactory(sf);
-          c.setHostnameVerifier(hv);
-        }
-        URLConnectionFactory.setTimeouts(conn, connectTimeout, readTimeout);
-        return conn;
-      }
-    };
-  }
-
-  /**
-   * Opens a url with read and connect timeouts
-   *
-   * @param url
-   *          to open
-   * @return URLConnection
-   * @throws IOException
-   */
-  public URLConnection openConnection(URL url) throws IOException {
-    try {
-      return openConnection(url, false, null);
-    } catch (AuthenticationException e) {
-      // Unreachable
-      LOG.error("Open connection {} failed", url, e);
-      return null;
-    }
-  }
-
-  /**
-   * Opens a url with read and connect timeouts
-   *
-   * @param url
-   *          URL to open
-   * @param isSpnego
-   *          whether the url should be authenticated via SPNEGO
-   * @return URLConnection
-   * @throws IOException
-   * @throws AuthenticationException
-   */
-  public URLConnection openConnection(URL url, boolean isSpnego, HasConfig hasConfig)
-      throws IOException, AuthenticationException {
-    if (isSpnego && (hasConfig != null)) {
-      LOG.debug("open AuthenticatedURL connection {}", url);
-//      UserGroupInformation.getCurrentUser().checkTGTAndReloginFromKeytab();
-      final AuthenticatedURL.Token authToken = new AuthenticatedURL.Token();
-      return new AuthenticatedURL(new KerberosHasAuthenticator(hasConfig.getAdminKeytab(),
-          hasConfig.getAdminKeytabPrincipal()),
-          connConfigurator).openConnection(url, authToken);
-    } else {
-      LOG.debug("open URL connection");
-      URLConnection connection = url.openConnection();
-      if (connection instanceof HttpURLConnection) {
-        connConfigurator.configure((HttpURLConnection) connection);
-      }
-      return connection;
-    }
-  }
-
-  /**
-   * Sets timeout parameters on the given URLConnection.
-   *
-   * @param connection
-   *          URLConnection to set
-   * @param connectTimeout
-   *          the connection and read timeout of the connection.
-   */
-  private static void setTimeouts(URLConnection connection,
-                                  int connectTimeout,
-                                  int readTimeout) {
-    connection.setConnectTimeout(connectTimeout);
-    connection.setReadTimeout(readTimeout);
-  }
-}

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/a8b1c28f/has/has-common/src/main/java/org/apache/kerby/has/common/HasAdmin.java
----------------------------------------------------------------------
diff --git a/has/has-common/src/main/java/org/apache/kerby/has/common/HasAdmin.java b/has/has-common/src/main/java/org/apache/kerby/has/common/HasAdmin.java
new file mode 100644
index 0000000..30b1e35
--- /dev/null
+++ b/has/has-common/src/main/java/org/apache/kerby/has/common/HasAdmin.java
@@ -0,0 +1,140 @@
+/**
+ *  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.kerby.has.common;
+
+import java.io.File;
+import java.util.List;
+
+/**
+ * Server side admin facilities from remote, similar to MIT kadmin remote mode.
+ */
+public interface HasAdmin {
+
+    /**
+     * Get the hadmin principal name.
+     *
+     * @return The hadmin principal name.
+     */
+    String getHadminPrincipal();
+
+    /**
+     * Add principal to backend.
+     *
+     * @param principal The principal to be added into backend
+     * @throws HasException e
+     */
+    void addPrincipal(String principal) throws HasException;
+
+    /**
+     * Add principal to backend.
+     *
+     * @param principal The principal to be added into backend
+     * @param password  The password to create encryption key
+     * @throws HasException e
+     */
+    void addPrincipal(String principal, String password) throws HasException;
+
+    /**
+     * Export all the keys of the specified principal into the specified keytab
+     * file.
+     *
+     * @param keytabFile The keytab file
+     * @param principal The principal name
+     * @throws HasException e
+     */
+    void exportKeytab(File keytabFile, String principal) throws HasException;
+
+    /**
+     * Export all the keys of the specified principals into the specified keytab
+     * file.
+     *
+     * @param keytabFile The keytab file
+     * @param principals The principal names
+     * @throws HasException e
+     */
+    void exportKeytab(File keytabFile, List<String> principals) throws HasException;
+
+    /**
+     * Delete the principal in backend.
+     *
+     * @param principal The principal to be deleted from backend
+     * @throws HasException e
+     */
+    void deletePrincipal(String principal) throws HasException;
+
+    /**
+     * Rename the principal.
+     *
+     * @param oldPrincipalName The original principal name
+     * @param newPrincipalName The new principal name
+     * @throws HasException e
+     */
+    void renamePrincipal(String oldPrincipalName,
+                         String newPrincipalName) throws HasException;
+
+    /**
+     * Get all the principal names from backend.
+     *
+     * @return principal list
+     * @throws HasException e
+     */
+    List<String> getPrincipals() throws HasException;
+
+    /**
+     * Get all the principal names that meets the pattern
+     *
+     * @param globString The glob string for matching
+     * @return Principal names
+     * @throws HasException e
+     */
+    List<String> getPrincipals(String globString) throws HasException;
+
+    /**
+     * Change the password of specified principal.
+     *
+     * @param principal The principal to be updated password
+     * @param newPassword The new password
+     * @throws HasException e
+     */
+//    void changePassword(String principal, String newPassword) throws HasException;
+
+    /**
+     * Update the random keys of specified principal.
+     *
+     * @param principal The principal to be updated keys
+     * @throws HasException e
+     */
+//    void updateKeys(String principal) throws HasException;
+
+    /**
+     * Release any resources associated.
+     *
+     * @throws HasException e
+     */
+//    void release() throws HasException;
+
+    String addPrincByRole(String host, String role) throws HasException;
+
+    File getKeytabByHostAndRole(String host, String role) throws HasException;
+
+    int size() throws HasException;
+
+    void setEnableOfConf(String isEnable) throws HasException;
+}

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/a8b1c28f/has/has-common/src/main/java/org/apache/kerby/has/common/HasConfig.java
----------------------------------------------------------------------
diff --git a/has/has-common/src/main/java/org/apache/kerby/has/common/HasConfig.java b/has/has-common/src/main/java/org/apache/kerby/has/common/HasConfig.java
new file mode 100644
index 0000000..e0f3f1e
--- /dev/null
+++ b/has/has-common/src/main/java/org/apache/kerby/has/common/HasConfig.java
@@ -0,0 +1,103 @@
+/**
+ *  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.kerby.has.common;
+
+import org.apache.kerby.kerberos.kerb.common.Krb5Conf;
+
+import java.io.File;
+
+/**
+ * AK configuration API.
+ */
+public class HasConfig extends Krb5Conf {
+    private File confDir;
+
+    public void setConfDir(File dir) {
+        this.confDir = dir;
+    }
+
+    public File getConfDir() {
+        return confDir;
+    }
+
+    public String getHttpsHost() {
+        return getString(HasConfigKey.HTTPS_HOST, false, "HAS");
+    }
+
+    public String getHttpsPort() {
+        return getString(HasConfigKey.HTTPS_PORT, false, "HAS");
+    }
+
+    public String getHttpHost() {
+        return getString(HasConfigKey.HTTP_HOST, false, "HAS");
+    }
+
+    public String getHttpPort() {
+        return getString(HasConfigKey.HTTP_PORT, false, "HAS");
+    }
+
+    public String getPluginName() {
+        return getString(HasConfigKey.AUTH_TYPE, true, "PLUGIN");
+    }
+
+    public String getRealm() {
+        return getString(HasConfigKey.REALM, false, "HAS");
+    }
+
+    public String getSslServerConf() {
+        return getString(HasConfigKey.SSL_SERVER_CONF, true, "HAS");
+    }
+
+    public String getSslClientConf() {
+        return getString(HasConfigKey.SSL_CLIENT_CONF, true, "HAS");
+    }
+
+    public String getFilterAuthType() {
+        return getString(HasConfigKey.FILTER_AUTH_TYPE, true, "HAS");
+    }
+
+    public String getKerberosPrincipal() {
+        return getString(HasConfigKey.KERBEROS_PRINCIPAL, false, "HAS");
+    }
+
+    public String getKerberosKeytab() {
+        return getString(HasConfigKey.KERBEROS_KEYTAB, false, "HAS");
+    }
+
+    public String getKerberosNameRules() {
+        return getString(HasConfigKey.KERBEROS_NAME_RULES, false, "HAS");
+    }
+
+    public String getAdminKeytab() {
+        return getString(HasConfigKey.ADMIN_KEYTAB, false, "HAS");
+    }
+
+    public String getAdminKeytabPrincipal() {
+        return getString(HasConfigKey.ADMIN_KEYTAB_PRINCIPAL, false, "HAS");
+    }
+
+    public String getEnableConf() {
+        return getString(HasConfigKey.ENABLE_CONF, false, "HAS");
+    }
+
+    public String getSslClientCert() {
+        return getString(HasConfigKey.SSL_CLIENT_CERT, true, "HAS");
+    }
+}

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/a8b1c28f/has/has-common/src/main/java/org/apache/kerby/has/common/HasConfigKey.java
----------------------------------------------------------------------
diff --git a/has/has-common/src/main/java/org/apache/kerby/has/common/HasConfigKey.java b/has/has-common/src/main/java/org/apache/kerby/has/common/HasConfigKey.java
new file mode 100644
index 0000000..272ab0e
--- /dev/null
+++ b/has/has-common/src/main/java/org/apache/kerby/has/common/HasConfigKey.java
@@ -0,0 +1,61 @@
+/**
+ *  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.kerby.has.common;
+
+import org.apache.kerby.config.ConfigKey;
+
+public enum HasConfigKey implements ConfigKey {
+    HTTP_HOST,
+    HTTP_PORT,
+    HTTPS_HOST,
+    HTTPS_PORT,
+    AUTH_TYPE("RAM"),
+    REALM,
+    ENABLE_CONF,
+    SSL_SERVER_CONF("/etc/has/ssl-server.conf"),
+    SSL_CLIENT_CONF("/etc/has/ssl-client.conf"),
+    SSL_CLIENT_CERT("/etc/has/cert-signed"),
+    FILTER_AUTH_TYPE("kerberos"),
+    KERBEROS_PRINCIPAL,
+    KERBEROS_KEYTAB,
+    KERBEROS_NAME_RULES,
+    ADMIN_KEYTAB,
+    ADMIN_KEYTAB_PRINCIPAL;
+
+    private Object defaultValue;
+
+    HasConfigKey() {
+        this.defaultValue = null;
+    }
+
+    HasConfigKey(Object defaultValue) {
+        this.defaultValue = defaultValue;
+    }
+
+    @Override
+    public String getPropertyKey() {
+        return name().toLowerCase();
+    }
+
+    @Override
+    public Object getDefaultValue() {
+        return this.defaultValue;
+    }
+}

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/a8b1c28f/has/has-common/src/main/java/org/apache/kerby/has/common/HasException.java
----------------------------------------------------------------------
diff --git a/has/has-common/src/main/java/org/apache/kerby/has/common/HasException.java b/has/has-common/src/main/java/org/apache/kerby/has/common/HasException.java
new file mode 100644
index 0000000..9e5db44
--- /dev/null
+++ b/has/has-common/src/main/java/org/apache/kerby/has/common/HasException.java
@@ -0,0 +1,53 @@
+/**
+ * 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
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * 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.kerby.has.common;
+
+public class HasException extends Exception {
+
+    private static final long serialVersionUID = -1916788959202646914L;
+
+    /**
+     * Creates an {@link HasException}.
+     *
+     * @param cause original exception.
+     */
+    public HasException(Throwable cause) {
+        super(cause);
+    }
+
+    /**
+     * Creates an {@link HasException}.
+     *
+     * @param message exception message.
+     */
+    public HasException(String message) {
+        super(message);
+    }
+
+    /**
+     * Creates an {@link HasException}.
+     *
+     * @param message exception message.
+     * @param cause   original exception.
+     */
+    public HasException(String message, Throwable cause) {
+        super(message, cause);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/a8b1c28f/has/has-common/src/main/java/org/apache/kerby/has/common/spnego/AuthToken.java
----------------------------------------------------------------------
diff --git a/has/has-common/src/main/java/org/apache/kerby/has/common/spnego/AuthToken.java b/has/has-common/src/main/java/org/apache/kerby/has/common/spnego/AuthToken.java
new file mode 100644
index 0000000..bacc740
--- /dev/null
+++ b/has/has-common/src/main/java/org/apache/kerby/has/common/spnego/AuthToken.java
@@ -0,0 +1,217 @@
+/**
+ * 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.kerby.has.common.spnego;
+
+import java.security.Principal;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import java.util.StringTokenizer;
+
+/**
+ * Borrow the class from Apache hadoop
+ */
+public class AuthToken implements Principal {
+
+  /**
+   * Constant that identifies an anonymous request.
+   */
+
+  private static final String ATTR_SEPARATOR = "&";
+  private static final String USER_NAME = "u";
+  private static final String PRINCIPAL = "p";
+  private static final String EXPIRES = "e";
+  private static final String TYPE = "t";
+
+  private static final Set<String> ATTRIBUTES =
+    new HashSet<String>(Arrays.asList(USER_NAME, PRINCIPAL, EXPIRES, TYPE));
+
+  private String userName;
+  private String principal;
+  private String type;
+  private long expires;
+  private String tokenStr;
+
+  protected AuthToken() {
+    userName = null;
+    principal = null;
+    type = null;
+    expires = -1;
+    tokenStr = "ANONYMOUS";
+    generateToken();
+  }
+
+  private static final String ILLEGAL_ARG_MSG = " is NULL, empty or contains a '" + ATTR_SEPARATOR + "'";
+
+  /**
+   * Creates an authentication token.
+   *
+   * @param userName user name.
+   * @param principal principal (commonly matches the user name, with Kerberos is the full/long principal
+   * name while the userName is the short name).
+   * @param type the authentication mechanism name.
+   * (<code>System.currentTimeMillis() + validityPeriod</code>).
+   */
+  public AuthToken(String userName, String principal, String type) {
+    checkForIllegalArgument(userName, "userName");
+    checkForIllegalArgument(principal, "principal");
+    checkForIllegalArgument(type, "type");
+    this.userName = userName;
+    this.principal = principal;
+    this.type = type;
+    this.expires = -1;
+  }
+  
+  /**
+   * Check if the provided value is invalid. Throw an error if it is invalid, NOP otherwise.
+   * 
+   * @param value the value to check.
+   * @param name the parameter name to use in an error message if the value is invalid.
+   */
+  protected static void checkForIllegalArgument(String value, String name) {
+    if (value == null || value.length() == 0 || value.contains(ATTR_SEPARATOR)) {
+      throw new IllegalArgumentException(name + ILLEGAL_ARG_MSG);
+    }
+  }
+
+  /**
+   * Sets the expiration of the token.
+   *
+   * @param expires expiration time of the token in milliseconds since the epoch.
+   */
+  public void setExpires(long expires) {
+    this.expires = expires;
+      generateToken();
+  }
+
+  /**
+   * Returns true if the token has expired.
+   *
+   * @return true if the token has expired.
+   */
+  public boolean isExpired() {
+    return getExpires() != -1 && System.currentTimeMillis() > getExpires();
+  }
+
+  /**
+   * Generates the token.
+   */
+  private void generateToken() {
+    StringBuffer sb = new StringBuffer();
+    sb.append(USER_NAME).append("=").append(getUserName()).append(ATTR_SEPARATOR);
+    sb.append(PRINCIPAL).append("=").append(getName()).append(ATTR_SEPARATOR);
+    sb.append(TYPE).append("=").append(getType()).append(ATTR_SEPARATOR);
+    sb.append(EXPIRES).append("=").append(getExpires());
+    tokenStr = sb.toString();
+  }
+
+  /**
+   * Returns the user name.
+   *
+   * @return the user name.
+   */
+  public String getUserName() {
+    return userName;
+  }
+
+  /**
+   * Returns the principal name (this method name comes from the JDK {@link Principal} interface).
+   *
+   * @return the principal name.
+   */
+  @Override
+  public String getName() {
+    return principal;
+  }
+
+  /**
+   * Returns the authentication mechanism of the token.
+   *
+   * @return the authentication mechanism of the token.
+   */
+  public String getType() {
+    return type;
+  }
+
+  /**
+   * Returns the expiration time of the token.
+   *
+   * @return the expiration time of the token, in milliseconds since Epoc.
+   */
+  public long getExpires() {
+    return expires;
+  }
+
+  /**
+   * Returns the string representation of the token.
+   * <p>
+   * This string representation is parseable by the {@link #parse} method.
+   *
+   * @return the string representation of the token.
+   */
+  @Override
+  public String toString() {
+    return tokenStr;
+  }
+
+  public static AuthToken parse(String tokenStr) throws AuthenticationException {
+    if (tokenStr.length() >= 2) {
+      // strip the \" at the two ends of the tokenStr
+      if (tokenStr.charAt(0) == '\"'
+          && tokenStr.charAt(tokenStr.length() - 1) == '\"') {
+        tokenStr = tokenStr.substring(1, tokenStr.length() - 1);
+      }
+    }
+    Map<String, String> map = split(tokenStr);
+    // remove the signature part, since client doesn't care about it
+    map.remove("s");
+
+    if (!map.keySet().equals(ATTRIBUTES)) {
+      throw new AuthenticationException("Invalid token string, missing attributes");
+    }
+    long expires = Long.parseLong(map.get(EXPIRES));
+    AuthToken token = new AuthToken(map.get(USER_NAME), map.get(PRINCIPAL), map.get(TYPE));
+    token.setExpires(expires);
+    return token;
+  }
+
+  /**
+   * Splits the string representation of a token into attributes pairs.
+   *
+   * @param tokenStr string representation of a token.
+   *
+   * @return a map with the attribute pairs of the token.
+   *
+   * @throws AuthenticationException thrown if the string representation of the token could not be broken into
+   * attribute pairs.
+   */
+  private static Map<String, String> split(String tokenStr) throws AuthenticationException {
+    Map<String, String> map = new HashMap<String, String>();
+    StringTokenizer st = new StringTokenizer(tokenStr, ATTR_SEPARATOR);
+    while (st.hasMoreTokens()) {
+      String part = st.nextToken();
+      int separator = part.indexOf('=');
+      if (separator == -1) {
+        throw new AuthenticationException("Invalid authentication token");
+      }
+      String key = part.substring(0, separator);
+      String value = part.substring(separator + 1);
+      map.put(key, value);
+    }
+    return map;
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/a8b1c28f/has/has-common/src/main/java/org/apache/kerby/has/common/spnego/AuthenticatedURL.java
----------------------------------------------------------------------
diff --git a/has/has-common/src/main/java/org/apache/kerby/has/common/spnego/AuthenticatedURL.java b/has/has-common/src/main/java/org/apache/kerby/has/common/spnego/AuthenticatedURL.java
new file mode 100644
index 0000000..372c5cd
--- /dev/null
+++ b/has/has-common/src/main/java/org/apache/kerby/has/common/spnego/AuthenticatedURL.java
@@ -0,0 +1,282 @@
+/**
+ * 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.kerby.has.common.spnego;
+
+import org.apache.kerby.has.common.util.ConnectionConfigurator;
+
+import java.io.IOException;
+import java.net.HttpURLConnection;
+import java.net.URL;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Borrow the class from Apache Hadoop
+ */
+
+/**
+ * <p>
+ * The authentication mechanisms supported by default are Hadoop Simple  authentication
+ * (also known as pseudo authentication) and Kerberos SPNEGO authentication.
+ * <p>
+ * Additional authentication mechanisms can be supported via {@link Authenticator} implementations.
+ * <p>
+ * The default {@link Authenticator} is the {@link KerberosAuthenticator} class which supports
+ * automatic fallback from Kerberos SPNEGO to Hadoop Simple authentication.
+ * <p>
+ * <code>AuthenticatedURL</code> instances are not thread-safe.
+ * <p>
+ * The usage pattern of the {@link AuthenticatedURL} is:
+ * <pre>
+ *
+ * // establishing an initial connection
+ *
+ * URL url = new URL("http://foo:8080/bar");
+ * AuthenticatedURL.Token token = new AuthenticatedURL.Token();
+ * AuthenticatedURL aUrl = new AuthenticatedURL();
+ * HttpURLConnection conn = new AuthenticatedURL(url, token).openConnection();
+ * ....
+ * // use the 'conn' instance
+ * ....
+ *
+ * // establishing a follow up connection using a token from the previous connection
+ *
+ * HttpURLConnection conn = new AuthenticatedURL(url, token).openConnection();
+ * ....
+ * // use the 'conn' instance
+ * ....
+ *
+ * </pre>
+ */
+public class AuthenticatedURL {
+
+  /**
+   * Name of the HTTP cookie used for the authentication token between the client and the server.
+   */
+  public static final String AUTH_COOKIE = "hadoop.auth";
+
+  private static final String AUTH_COOKIE_EQ = AUTH_COOKIE + "=";
+
+  /**
+   * Client side authentication token.
+   */
+  public static class Token {
+
+    private String token;
+
+    /**
+     * Creates a token.
+     */
+    public Token() {
+    }
+
+    /**
+     * Creates a token using an existing string representation of the token.
+     *
+     * @param tokenStr string representation of the tokenStr.
+     */
+    public Token(String tokenStr) {
+      if (tokenStr == null) {
+        throw new IllegalArgumentException("tokenStr cannot be null");
+      }
+      set(tokenStr);
+    }
+
+    /**
+     * Returns if a token from the server has been set.
+     *
+     * @return if a token from the server has been set.
+     */
+    public boolean isSet() {
+      return token != null;
+    }
+
+    /**
+     * Sets a token.
+     *
+     * @param tokenStr string representation of the tokenStr.
+     */
+    void set(String tokenStr) {
+      token = tokenStr;
+    }
+
+    /**
+     * Returns the string representation of the token.
+     *
+     * @return the string representation of the token.
+     */
+    @Override
+    public String toString() {
+      return token;
+    }
+
+  }
+
+  private static Class<? extends Authenticator> defaultAuthenticator
+      = KerberosAuthenticator.class;
+
+  /**
+   * Sets the default {@link Authenticator} class to use when an {@link AuthenticatedURL} instance
+   * is created without specifying an authenticator.
+   *
+   * @param authenticator the authenticator class to use as default.
+   */
+  public static void setDefaultAuthenticator(Class<? extends Authenticator> authenticator) {
+    defaultAuthenticator = authenticator;
+  }
+
+  /**
+   * Returns the default {@link Authenticator} class to use when an {@link AuthenticatedURL} instance
+   * is created without specifying an authenticator.
+   *
+   * @return the authenticator class to use as default.
+   */
+  public static Class<? extends Authenticator> getDefaultAuthenticator() {
+    return defaultAuthenticator;
+  }
+
+  private Authenticator authenticator;
+  private ConnectionConfigurator connConfigurator;
+
+  /**
+   * Creates an {@link AuthenticatedURL}.
+   */
+  public AuthenticatedURL() {
+    this(null);
+  }
+
+  /**
+   * Creates an <code>AuthenticatedURL</code>.
+   *
+   * @param authenticator the {@link Authenticator} instance to use, if <code>null</code> a {@link
+   * KerberosAuthenticator} is used.
+   */
+  public AuthenticatedURL(Authenticator authenticator) {
+    this(authenticator, null);
+  }
+
+  /**
+   * Creates an <code>AuthenticatedURL</code>.
+   *
+   * @param authenticator the {@link Authenticator} instance to use, if <code>null</code> a {@link
+   * KerberosAuthenticator} is used.
+   * @param connConfigurator a connection configurator.
+   */
+  public AuthenticatedURL(Authenticator authenticator,
+                          ConnectionConfigurator connConfigurator) {
+    try {
+      this.authenticator = (authenticator != null) ? authenticator : defaultAuthenticator.newInstance();
+    } catch (Exception ex) {
+      throw new RuntimeException(ex);
+    }
+    this.connConfigurator = connConfigurator;
+    this.authenticator.setConnectionConfigurator(connConfigurator);
+  }
+
+  /**
+   * Returns the {@link Authenticator} instance used by the
+   * <code>AuthenticatedURL</code>.
+   *
+   * @return the {@link Authenticator} instance
+   */
+  protected Authenticator getAuthenticator() {
+    return authenticator;
+  }
+
+  /**
+   * Returns an authenticated {@link HttpURLConnection}.
+   *
+   * @param url the URL to connect to. Only HTTP/S URLs are supported.
+   * @param token the authentication token being used for the user.
+   *
+   * @return an authenticated {@link HttpURLConnection}.
+   *
+   * @throws IOException if an IO error occurred.
+   * @throws AuthenticationException if an authentication exception occurred.
+   */
+  public HttpURLConnection openConnection(URL url, Token token) throws IOException, AuthenticationException {
+    if (url == null) {
+      throw new IllegalArgumentException("url cannot be NULL");
+    }
+    if (!url.getProtocol().equalsIgnoreCase("http") && !url.getProtocol().equalsIgnoreCase("https")) {
+      throw new IllegalArgumentException("url must be for a HTTP or HTTPS resource");
+    }
+    if (token == null) {
+      throw new IllegalArgumentException("token cannot be NULL");
+    }
+    authenticator.authenticate(url, token);
+    HttpURLConnection conn = (HttpURLConnection) url.openConnection();
+    if (connConfigurator != null) {
+      conn = connConfigurator.configure(conn);
+    }
+    injectToken(conn, token);
+    return conn;
+  }
+
+  /**
+   * Helper method that injects an authentication token to send with a connection.
+   *
+   * @param conn connection to inject the authentication token into.
+   * @param token authentication token to inject.
+   */
+  public static void injectToken(HttpURLConnection conn, Token token) {
+    String t = token.token;
+    if (t != null) {
+      if (!t.startsWith("\"")) {
+        t = "\"" + t + "\"";
+      }
+      conn.addRequestProperty("Cookie", AUTH_COOKIE_EQ + t);
+    }
+  }
+
+  /**
+   * Helper method that extracts an authentication token received from a connection.
+   * <p>
+   * This method is used by {@link Authenticator} implementations.
+   *
+   * @param conn connection to extract the authentication token from.
+   * @param token the authentication token.
+   *
+   * @throws IOException if an IO error occurred.
+   * @throws AuthenticationException if an authentication exception occurred.
+   */
+  public static void extractToken(HttpURLConnection conn, Token token) throws IOException, AuthenticationException {
+    int respCode = conn.getResponseCode();
+    if (respCode == HttpURLConnection.HTTP_OK
+        || respCode == HttpURLConnection.HTTP_CREATED
+        || respCode == HttpURLConnection.HTTP_ACCEPTED) {
+      Map<String, List<String>> headers = conn.getHeaderFields();
+      List<String> cookies = headers.get("Set-Cookie");
+      if (cookies != null) {
+        for (String cookie : cookies) {
+          if (cookie.startsWith(AUTH_COOKIE_EQ)) {
+            String value = cookie.substring(AUTH_COOKIE_EQ.length());
+            int separator = value.indexOf(";");
+            if (separator > -1) {
+              value = value.substring(0, separator);
+            }
+            if (value.length() > 0) {
+              token.set(value);
+            }
+          }
+        }
+      }
+    } else {
+      token.set(null);
+      throw new AuthenticationException("Authentication failed, status: " + conn.getResponseCode()
+          + ", message: " + conn.getResponseMessage());
+    }
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/a8b1c28f/has/has-common/src/main/java/org/apache/kerby/has/common/spnego/AuthenticationException.java
----------------------------------------------------------------------
diff --git a/has/has-common/src/main/java/org/apache/kerby/has/common/spnego/AuthenticationException.java b/has/has-common/src/main/java/org/apache/kerby/has/common/spnego/AuthenticationException.java
new file mode 100644
index 0000000..38e5f6a
--- /dev/null
+++ b/has/has-common/src/main/java/org/apache/kerby/has/common/spnego/AuthenticationException.java
@@ -0,0 +1,54 @@
+/**
+ * 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.kerby.has.common.spnego;
+
+/**
+ * Borrow the class from Apache Hadoop
+ */
+
+/**
+ * Exception thrown when an authentication error occurrs.
+ */
+public class AuthenticationException extends Exception {
+  
+  static final long serialVersionUID = 0;
+
+  /**
+   * Creates an {@link AuthenticationException}.
+   *
+   * @param cause original exception.
+   */
+  public AuthenticationException(Throwable cause) {
+    super(cause);
+  }
+
+  /**
+   * Creates an {@link AuthenticationException}.
+   *
+   * @param msg exception message.
+   */
+  public AuthenticationException(String msg) {
+    super(msg);
+  }
+
+  /**
+   * Creates an {@link AuthenticationException}.
+   *
+   * @param msg exception message.
+   * @param cause original exception.
+   */
+  public AuthenticationException(String msg, Throwable cause) {
+    super(msg, cause);
+  }
+}

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/a8b1c28f/has/has-common/src/main/java/org/apache/kerby/has/common/spnego/Authenticator.java
----------------------------------------------------------------------
diff --git a/has/has-common/src/main/java/org/apache/kerby/has/common/spnego/Authenticator.java b/has/has-common/src/main/java/org/apache/kerby/has/common/spnego/Authenticator.java
new file mode 100644
index 0000000..a643218
--- /dev/null
+++ b/has/has-common/src/main/java/org/apache/kerby/has/common/spnego/Authenticator.java
@@ -0,0 +1,52 @@
+/**
+ * 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.kerby.has.common.spnego;
+
+import org.apache.kerby.has.common.util.ConnectionConfigurator;
+
+import java.io.IOException;
+import java.net.URL;
+
+/**
+ * Borrow the class from Apache Hadoop
+ */
+
+/**
+ * Interface for client authentication mechanisms.
+ * <p>
+ * Implementations are use-once instances, they don't need to be thread safe.
+ */
+public interface Authenticator {
+
+  /**
+   * Sets a {@link ConnectionConfigurator} instance to use for
+   * configuring connections.
+   *
+   * @param configurator the {@link ConnectionConfigurator} instance.
+   */
+  void setConnectionConfigurator(ConnectionConfigurator configurator);
+
+  /**
+   * Authenticates against a URL and returns a {@link AuthenticatedURL.Token} to be
+   * used by subsequent requests.
+   *
+   * @param url the URl to authenticate against.
+   * @param token the authentication token being used for the user.
+   *
+   * @throws IOException if an IO error occurred.
+   * @throws AuthenticationException if an authentication error occurred.
+   */
+  void authenticate(URL url, AuthenticatedURL.Token token) throws IOException, AuthenticationException;
+
+}

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/a8b1c28f/has/has-common/src/main/java/org/apache/kerby/has/common/spnego/KerberosAuthenticator.java
----------------------------------------------------------------------
diff --git a/has/has-common/src/main/java/org/apache/kerby/has/common/spnego/KerberosAuthenticator.java b/has/has-common/src/main/java/org/apache/kerby/has/common/spnego/KerberosAuthenticator.java
new file mode 100644
index 0000000..6c43832
--- /dev/null
+++ b/has/has-common/src/main/java/org/apache/kerby/has/common/spnego/KerberosAuthenticator.java
@@ -0,0 +1,359 @@
+/**
+ * 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.kerby.has.common.spnego;
+
+import org.apache.commons.codec.binary.Base64;
+import org.apache.kerby.has.common.util.ConnectionConfigurator;
+import org.ietf.jgss.GSSContext;
+import org.ietf.jgss.GSSManager;
+import org.ietf.jgss.GSSName;
+import org.ietf.jgss.Oid;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.security.auth.Subject;
+import javax.security.auth.kerberos.KerberosKey;
+import javax.security.auth.kerberos.KerberosTicket;
+import javax.security.auth.login.AppConfigurationEntry;
+import javax.security.auth.login.Configuration;
+import javax.security.auth.login.LoginContext;
+import javax.security.auth.login.LoginException;
+import java.io.IOException;
+import java.net.HttpURLConnection;
+import java.net.URL;
+import java.security.AccessControlContext;
+import java.security.AccessController;
+import java.security.PrivilegedActionException;
+import java.security.PrivilegedExceptionAction;
+import java.util.HashMap;
+import java.util.Map;
+
+import static org.apache.kerby.has.common.util.PlatformName.IBM_JAVA;
+
+/**
+ * Borrow the class from Apache Hadoop
+ */
+
+/**
+ * The {@link KerberosAuthenticator} implements the Kerberos SPNEGO authentication sequence.
+ * <p>
+ * It uses the default principal for the Kerberos cache (normally set via kinit).
+ * <p>
+ */
+public class KerberosAuthenticator implements Authenticator {
+  
+  private static final Logger LOG = LoggerFactory.getLogger(KerberosAuthenticator.class);
+
+  /**
+   * HTTP header used by the SPNEGO server endpoint during an authentication sequence.
+   */
+  public static final String WWW_AUTHENTICATE = "WWW-Authenticate";
+
+  /**
+   * HTTP header used by the SPNEGO client endpoint during an authentication sequence.
+   */
+  public static final String AUTHORIZATION = "Authorization";
+
+  /**
+   * HTTP header prefix used by the SPNEGO client/server endpoints during an authentication sequence.
+   */
+  public static final String NEGOTIATE = "Negotiate";
+
+  private static final String AUTH_HTTP_METHOD = "OPTIONS";
+
+  private static String keytabPrincipal = null;
+  private static String keytabFile = null;
+
+  /*
+  * Defines the Kerberos configuration that will be used to obtain the Kerberos principal from the
+  * Kerberos cache.
+  */
+  private static class KerberosConfiguration extends Configuration {
+
+    private static final String OS_LOGIN_MODULE_NAME;
+    private static final boolean WINDOWS = System.getProperty("os.name").startsWith("Windows");
+    private static final boolean IS_64_BIT = System.getProperty("os.arch").contains("64");
+    private static final boolean AIX = System.getProperty("os.name").equals("AIX");
+
+    /* Return the OS login module class name */
+    private static String getOSLoginModuleName() {
+      if (IBM_JAVA) {
+        if (WINDOWS) {
+          return IS_64_BIT ? "com.ibm.security.auth.module.Win64LoginModule"
+              : "com.ibm.security.auth.module.NTLoginModule";
+        } else if (AIX) {
+          return IS_64_BIT ? "com.ibm.security.auth.module.AIX64LoginModule"
+              : "com.ibm.security.auth.module.AIXLoginModule";
+        } else {
+          return "com.ibm.security.auth.module.LinuxLoginModule";
+        }
+      } else {
+        return WINDOWS ? "com.sun.security.auth.module.NTLoginModule"
+            : "com.sun.security.auth.module.UnixLoginModule";
+      }
+    }
+
+    static {
+      OS_LOGIN_MODULE_NAME = getOSLoginModuleName();
+    }
+
+    private static final AppConfigurationEntry OS_SPECIFIC_LOGIN =
+      new AppConfigurationEntry(OS_LOGIN_MODULE_NAME,
+                                AppConfigurationEntry.LoginModuleControlFlag.REQUIRED,
+                                new HashMap<String, String>());
+
+    private static final Map<String, String> KEYTAB_KERBEROS_OPTIONS
+        = new HashMap<String, String>();
+    static {
+      if (IBM_JAVA) {
+        KEYTAB_KERBEROS_OPTIONS.put("credsType", "both");
+        KEYTAB_KERBEROS_OPTIONS.put("useKeytab",
+            prependFileAuthority(keytabFile));
+      } else {
+        KEYTAB_KERBEROS_OPTIONS.put("doNotPrompt", "true");
+        KEYTAB_KERBEROS_OPTIONS.put("useKeyTab", "true");
+        KEYTAB_KERBEROS_OPTIONS.put("storeKey", "true");
+        KEYTAB_KERBEROS_OPTIONS.put("keyTab", keytabFile);
+      }
+      KEYTAB_KERBEROS_OPTIONS.put("principal", keytabPrincipal);
+      KEYTAB_KERBEROS_OPTIONS.put("refreshKrb5Config", "true");
+      KEYTAB_KERBEROS_OPTIONS.put("debug", "false");
+    }
+
+    private static final AppConfigurationEntry USER_KERBEROS_LOGIN =
+      new AppConfigurationEntry(KerberosUtil.getKrb5LoginModuleName(),
+                                AppConfigurationEntry.LoginModuleControlFlag.OPTIONAL,
+                                KEYTAB_KERBEROS_OPTIONS);
+
+    private static final AppConfigurationEntry[] USER_KERBEROS_CONF =
+      new AppConfigurationEntry[]{OS_SPECIFIC_LOGIN, USER_KERBEROS_LOGIN};
+
+    @Override
+    public AppConfigurationEntry[] getAppConfigurationEntry(String appName) {
+      return USER_KERBEROS_CONF;
+    }
+
+    private static String prependFileAuthority(String keytabPath) {
+      return keytabPath.startsWith("file://") ? keytabPath
+          : "file://" + keytabPath;
+    }
+  }
+  
+  private URL url;
+  private HttpURLConnection conn;
+  private Base64 base64;
+  private ConnectionConfigurator connConfigurator;
+
+  /**
+   * Sets a {@link ConnectionConfigurator} instance to use for
+   * configuring connections.
+   *
+   * @param configurator the {@link ConnectionConfigurator} instance.
+   */
+  @Override
+  public void setConnectionConfigurator(ConnectionConfigurator configurator) {
+    connConfigurator = configurator;
+  }
+
+  /**
+   * Performs SPNEGO authentication against the specified URL.
+   * <p>
+   * If a token is given it does a NOP and returns the given token.
+   * <p>
+   * If no token is given, it will perform the SPNEGO authentication sequence using an
+   * HTTP <code>OPTIONS</code> request.
+   *
+   * @param url the URl to authenticate against.
+   * @param token the authentication token being used for the user.
+   *
+   * @throws IOException if an IO error occurred.
+   * @throws AuthenticationException if an authentication error occurred.
+   */
+  @Override
+  public void authenticate(URL url, AuthenticatedURL.Token token)
+    throws IOException, AuthenticationException {
+
+    if (!token.isSet()) {
+      this.url = url;
+      base64 = new Base64(0);
+      conn = (HttpURLConnection) url.openConnection();
+      if (connConfigurator != null) {
+        conn = connConfigurator.configure(conn);
+      }
+      conn.setRequestMethod(AUTH_HTTP_METHOD);
+      conn.connect();
+      
+      boolean needFallback = false;
+      if (conn.getResponseCode() == HttpURLConnection.HTTP_OK) {
+        LOG.debug("JDK performed authentication on our behalf.");
+        // If the JDK already did the SPNEGO back-and-forth for
+        // us, just pull out the token.
+        AuthenticatedURL.extractToken(conn, token);
+        if (isTokenKerberos(token)) {
+          return;
+        }
+        needFallback = true;
+      }
+      if (!needFallback && isNegotiate()) {
+        LOG.debug("Performing our own SPNEGO sequence.");
+        doSpnegoSequence(token);
+      } else {
+        throw new IOException("Should perform our own SPNEGO sequence");
+      }
+    }
+  }
+
+  public void setKeyTab(String keytabFile, String keytabPrincipal) {
+    this.keytabFile = keytabFile;
+    this.keytabPrincipal = keytabPrincipal;
+  }
+
+  /*
+   * Check if the passed token is of type "kerberos" or "kerberos-dt"
+   */
+  private boolean isTokenKerberos(AuthenticatedURL.Token token)
+      throws AuthenticationException {
+    if (token.isSet()) {
+      AuthToken aToken = AuthToken.parse(token.toString());
+      if (aToken.getType().equals("kerberos")
+          || aToken.getType().equals("kerberos-dt")) {
+        return true;
+      }
+    }
+    return false;
+  }
+
+  /*
+  * Indicates if the response is starting a SPNEGO negotiation.
+  */
+  private boolean isNegotiate() throws IOException {
+    boolean negotiate = false;
+    if (conn.getResponseCode() == HttpURLConnection.HTTP_UNAUTHORIZED) {
+      String authHeader = conn.getHeaderField(WWW_AUTHENTICATE);
+      negotiate = authHeader != null && authHeader.trim().startsWith(NEGOTIATE);
+    }
+    return negotiate;
+  }
+
+  /**
+   * Implements the SPNEGO authentication sequence interaction using the current default principal
+   * in the Kerberos cache (normally set via kinit).
+   *
+   * @param token the authentication token being used for the user.
+   *
+   * @throws IOException if an IO error occurred.
+   * @throws AuthenticationException if an authentication error occurred.
+   */
+  private void doSpnegoSequence(AuthenticatedURL.Token token) throws IOException, AuthenticationException {
+    try {
+      AccessControlContext context = AccessController.getContext();
+      Subject subject = Subject.getSubject(context);
+      if (subject == null
+          || (subject.getPrivateCredentials(KerberosKey.class).isEmpty()
+              && subject.getPrivateCredentials(KerberosTicket.class).isEmpty())) {
+        LOG.debug("No subject in context, logging in");
+        subject = new Subject();
+        LoginContext login = new LoginContext("", subject,
+            null, new KerberosConfiguration());
+        login.login();
+      }
+
+      if (LOG.isDebugEnabled()) {
+        LOG.debug("Using subject: " + subject);
+      }
+      Subject.doAs(subject, new PrivilegedExceptionAction<Void>() {
+
+        @Override
+        public Void run() throws Exception {
+          GSSContext gssContext = null;
+          try {
+            GSSManager gssManager = GSSManager.getInstance();
+            String servicePrincipal = KerberosUtil.getServicePrincipal("HTTP",
+                KerberosAuthenticator.this.url.getHost());
+            LOG.info("service principal is:" + servicePrincipal);
+            Oid oid = KerberosUtil.getOidInstance("NT_GSS_KRB5_PRINCIPAL");
+            GSSName serviceName = gssManager.createName(servicePrincipal,
+                                                        oid);
+            oid = KerberosUtil.getOidInstance("GSS_KRB5_MECH_OID");
+            gssContext = gssManager.createContext(serviceName, oid, null,
+                                                  GSSContext.DEFAULT_LIFETIME);
+            gssContext.requestCredDeleg(true);
+            gssContext.requestMutualAuth(true);
+
+            byte[] inToken = new byte[0];
+            byte[] outToken;
+            boolean established = false;
+
+            // Loop while the context is still not established
+            while (!established) {
+              outToken = gssContext.initSecContext(inToken, 0, inToken.length);
+              if (outToken != null) {
+                sendToken(outToken);
+              }
+
+              if (!gssContext.isEstablished()) {
+                inToken = readToken();
+              } else {
+                established = true;
+              }
+            }
+          } finally {
+            if (gssContext != null) {
+              gssContext.dispose();
+              gssContext = null;
+            }
+          }
+          return null;
+        }
+      });
+    } catch (PrivilegedActionException ex) {
+      throw new AuthenticationException(ex.getException());
+    } catch (LoginException ex) {
+      throw new AuthenticationException(ex);
+    }
+    AuthenticatedURL.extractToken(conn, token);
+  }
+
+  /*
+  * Sends the Kerberos token to the server.
+  */
+  private void sendToken(byte[] outToken) throws IOException {
+    String token = base64.encodeToString(outToken);
+    conn = (HttpURLConnection) url.openConnection();
+    if (connConfigurator != null) {
+      conn = connConfigurator.configure(conn);
+    }
+    conn.setRequestMethod(AUTH_HTTP_METHOD);
+    conn.setRequestProperty(AUTHORIZATION, NEGOTIATE + " " + token);
+    conn.connect();
+  }
+
+  /*
+  * Retrieves the Kerberos token returned by the server.
+  */
+  private byte[] readToken() throws IOException, AuthenticationException {
+    int status = conn.getResponseCode();
+    if (status == HttpURLConnection.HTTP_OK || status == HttpURLConnection.HTTP_UNAUTHORIZED) {
+      String authHeader = conn.getHeaderField(WWW_AUTHENTICATE);
+      if (authHeader == null || !authHeader.trim().startsWith(NEGOTIATE)) {
+        throw new AuthenticationException("Invalid SPNEGO sequence, '" + WWW_AUTHENTICATE
+            + "' header incorrect: " + authHeader);
+      }
+      String negotiation = authHeader.trim().substring((NEGOTIATE + " ").length()).trim();
+      return base64.decode(negotiation);
+    }
+    throw new AuthenticationException("Invalid SPNEGO sequence, status code: " + status);
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/a8b1c28f/has/has-common/src/main/java/org/apache/kerby/has/common/spnego/KerberosHasAuthenticator.java
----------------------------------------------------------------------
diff --git a/has/has-common/src/main/java/org/apache/kerby/has/common/spnego/KerberosHasAuthenticator.java b/has/has-common/src/main/java/org/apache/kerby/has/common/spnego/KerberosHasAuthenticator.java
new file mode 100644
index 0000000..da598a3
--- /dev/null
+++ b/has/has-common/src/main/java/org/apache/kerby/has/common/spnego/KerberosHasAuthenticator.java
@@ -0,0 +1,25 @@
+/**
+ * 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
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * 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.kerby.has.common.spnego;
+
+public class KerberosHasAuthenticator extends KerberosAuthenticator {
+
+    public KerberosHasAuthenticator(String keytabFile, String keytabPrincipal) {
+        setKeyTab(keytabFile, keytabPrincipal);
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/a8b1c28f/has/has-common/src/main/java/org/apache/kerby/has/common/spnego/KerberosUtil.java
----------------------------------------------------------------------
diff --git a/has/has-common/src/main/java/org/apache/kerby/has/common/spnego/KerberosUtil.java b/has/has-common/src/main/java/org/apache/kerby/has/common/spnego/KerberosUtil.java
new file mode 100644
index 0000000..062b6a1
--- /dev/null
+++ b/has/has-common/src/main/java/org/apache/kerby/has/common/spnego/KerberosUtil.java
@@ -0,0 +1,262 @@
+/**
+ * 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.kerby.has.common.spnego;
+
+import java.io.File;
+import java.io.IOException;
+import java.lang.reflect.Field;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Locale;
+import java.util.Set;
+import java.util.regex.Pattern;
+
+import org.apache.kerby.kerberos.kerb.keytab.Keytab;
+import org.apache.kerby.kerberos.kerb.type.base.PrincipalName;
+import org.ietf.jgss.GSSException;
+import org.ietf.jgss.Oid;
+
+import javax.security.auth.Subject;
+import javax.security.auth.kerberos.KerberosTicket;
+import javax.security.auth.kerberos.KeyTab;
+
+import static org.apache.kerby.has.common.util.PlatformName.IBM_JAVA;
+
+/**
+ * Borrow the class from Apache Hadoop
+ */
+
+public class KerberosUtil {
+
+  /* Return the Kerberos login module name */
+  public static String getKrb5LoginModuleName() {
+    return (IBM_JAVA)
+      ? "com.ibm.security.auth.module.Krb5LoginModule"
+      : "com.sun.security.auth.module.Krb5LoginModule";
+  }
+
+  public static Oid getOidInstance(String oidName)
+      throws ClassNotFoundException, GSSException, NoSuchFieldException,
+      IllegalAccessException {
+    Class<?> oidClass;
+    if (IBM_JAVA) {
+      if ("NT_GSS_KRB5_PRINCIPAL".equals(oidName)) {
+        // IBM JDK GSSUtil class does not have field for krb5 principal oid
+        return new Oid("1.2.840.113554.1.2.2.1");
+      }
+      oidClass = Class.forName("com.ibm.security.jgss.GSSUtil");
+    } else {
+      oidClass = Class.forName("sun.security.jgss.GSSUtil");
+    }
+    Field oidField = oidClass.getDeclaredField(oidName);
+    return (Oid) oidField.get(oidClass);
+  }
+
+  public static String getDefaultRealm() 
+      throws ClassNotFoundException, NoSuchMethodException, 
+      IllegalArgumentException, IllegalAccessException, 
+      InvocationTargetException {
+    Object kerbConf;
+    Class<?> classRef;
+    Method getInstanceMethod;
+    Method getDefaultRealmMethod;
+    if (IBM_JAVA) {
+      classRef = Class.forName("com.ibm.security.krb5.internal.Config");
+    } else {
+      classRef = Class.forName("sun.security.krb5.Config");
+    }
+    getInstanceMethod = classRef.getMethod("getInstance", new Class[0]);
+    kerbConf = getInstanceMethod.invoke(classRef, new Object[0]);
+    getDefaultRealmMethod = classRef.getDeclaredMethod("getDefaultRealm",
+        new Class[0]);
+    return (String) getDefaultRealmMethod.invoke(kerbConf, new Object[0]);
+  }
+
+  public static String getDefaultRealmProtected() {
+    String realmString = null;
+    try {
+      realmString = getDefaultRealm();
+    } catch (RuntimeException rte) {
+      //silently catch everything
+    } catch (Exception e) {
+      //silently return null
+    }
+    return realmString;
+  }
+
+  /*
+   * For a Service Host Principal specification, map the host's domain
+   * to kerberos realm, as specified by krb5.conf [domain_realm] mappings.
+   * Unfortunately the mapping routines are private to the security.krb5
+   * package, so have to construct a PrincipalName instance to derive the realm.
+   *
+   * Many things can go wrong with Kerberos configuration, and this is not
+   * the place to be throwing exceptions to help debug them.  Nor do we choose
+   * to make potentially voluminous logs on every call to a communications API.
+   * So we simply swallow all exceptions from the underlying libraries and
+   * return null if we can't get a good value for the realmString.
+   *
+   * @param shortprinc A service principal name with host fqdn as instance, e.g.
+   *     "HTTP/myhost.mydomain"
+   * @return String value of Kerberos realm, mapped from host fqdn
+   *     May be default realm, or may be null.
+   */
+  public static String getDomainRealm(String shortprinc) {
+    Class<?> classRef;
+    Object principalName; //of type sun.security.krb5.PrincipalName or IBM equiv
+    String realmString = null;
+    try {
+      if (IBM_JAVA) {
+        classRef = Class.forName("com.ibm.security.krb5.PrincipalName");
+      } else {
+        classRef = Class.forName("sun.security.krb5.PrincipalName");
+      }
+      int tKrbNtSrvHst = classRef.getField("KRB_NT_SRV_HST").getInt(null);
+      principalName = classRef.getConstructor(String.class, int.class).
+          newInstance(shortprinc, tKrbNtSrvHst);
+      realmString = (String) classRef.getMethod("getRealmString", new Class[0]).
+          invoke(principalName, new Object[0]);
+    } catch (RuntimeException rte) {
+      //silently catch everything
+    } catch (Exception e) {
+      //silently return default realm (which may itself be null)
+    }
+    if (null == realmString || realmString.equals("")) {
+      return getDefaultRealmProtected();
+    } else {
+      return realmString;
+    }
+  }
+
+  /* Return fqdn of the current host */
+  static String getLocalHostName() throws UnknownHostException {
+    return InetAddress.getLocalHost().getCanonicalHostName();
+  }
+  
+  /**
+   * Create Kerberos principal for a given service and hostname,
+   * inferring realm from the fqdn of the hostname. It converts
+   * hostname to lower case. If hostname is null or "0.0.0.0", it uses
+   * dynamically looked-up fqdn of the current host instead.
+   * If domain_realm mappings are inadequately specified, it will
+   * use default_realm, per usual Kerberos behavior.
+   * If default_realm also gives a null value, then a principal
+   * without realm will be returned, which by Kerberos definitions is
+   * just another way to specify default realm.
+   *
+   * @param service
+   *          Service for which you want to generate the principal.
+   * @param hostname
+   *          Fully-qualified domain name.
+   * @return Converted Kerberos principal name.
+   * @throws UnknownHostException
+   *           If no IP address for the local host could be found.
+   */
+  public static final String getServicePrincipal(String service,
+      String hostname)
+      throws UnknownHostException {
+    String fqdn = hostname;
+    String shortprinc = null;
+    String realmString = null;
+    if (null == fqdn || fqdn.equals("") || fqdn.equals("0.0.0.0")) {
+      fqdn = getLocalHostName();
+    }
+    // convert hostname to lowercase as kerberos does not work with hostnames
+    // with uppercase characters.
+    fqdn = fqdn.toLowerCase(Locale.US);
+    shortprinc = service + "/" + fqdn;
+    // Obtain the realm name inferred from the domain of the host
+    realmString = getDomainRealm(shortprinc);
+    if (null == realmString || realmString.equals("")) {
+      return shortprinc;
+    } else {
+      return shortprinc + "@" + realmString;
+    }
+  }
+
+  /**
+   * Get all the unique principals present in the keytabfile.
+   * 
+   * @param keytabFileName 
+   *          Name of the keytab file to be read.
+   * @return list of unique principals in the keytab.
+   * @throws IOException 
+   *          If keytab entries cannot be read from the file.
+   */
+  static final String[] getPrincipalNames(String keytabFileName) throws IOException {
+    Keytab keytab = Keytab.loadKeytab(new File(keytabFileName));
+    Set<String> principals = new HashSet<String>();
+    List<PrincipalName> entries = keytab.getPrincipals();
+    for (PrincipalName entry : entries) {
+      principals.add(entry.getName().replace("\\", "/"));
+    }
+    return principals.toArray(new String[0]);
+  }
+
+  /**
+   * Get all the unique principals from keytabfile which matches a pattern.
+   * 
+   * @param keytab Name of the keytab file to be read.
+   * @param pattern pattern to be matched.
+   * @return list of unique principals which matches the pattern.
+   * @throws IOException if cannot get the principal name
+   */
+  public static final String[] getPrincipalNames(String keytab,
+      Pattern pattern) throws IOException {
+    String[] principals = getPrincipalNames(keytab);
+    if (principals.length != 0) {
+      List<String> matchingPrincipals = new ArrayList<String>();
+      for (String principal : principals) {
+        if (pattern.matcher(principal).matches()) {
+          matchingPrincipals.add(principal);
+        }
+      }
+      principals = matchingPrincipals.toArray(new String[0]);
+    }
+    return principals;
+  }
+
+  /**
+   * Check if the subject contains Kerberos keytab related objects.
+   * The Kerberos keytab object attached in subject has been changed
+   * from KerberosKey (JDK 7) to KeyTab (JDK 8)
+   *
+   *
+   * @param subject subject to be checked
+   * @return true if the subject contains Kerberos keytab
+   */
+  public static boolean hasKerberosKeyTab(Subject subject) {
+    return !subject.getPrivateCredentials(KeyTab.class).isEmpty();
+  }
+
+  /**
+   * Check if the subject contains Kerberos ticket.
+   *
+   *
+   * @param subject subject to be checked
+   * @return true if the subject contains Kerberos ticket
+   */
+  public static boolean hasKerberosTicket(Subject subject) {
+    return !subject.getPrivateCredentials(KerberosTicket.class).isEmpty();
+  }
+}