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:14 UTC

[13/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-client/src/main/java/org/apache/kerby/has/client/HasClient.java
----------------------------------------------------------------------
diff --git a/has/has-client/src/main/java/org/apache/kerby/has/client/HasClient.java b/has/has-client/src/main/java/org/apache/kerby/has/client/HasClient.java
new file mode 100755
index 0000000..759c922
--- /dev/null
+++ b/has/has-client/src/main/java/org/apache/kerby/has/client/HasClient.java
@@ -0,0 +1,677 @@
+/**
+ * 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.client;
+
+import com.sun.jersey.api.client.Client;
+import com.sun.jersey.api.client.ClientHandlerException;
+import com.sun.jersey.api.client.ClientResponse;
+import com.sun.jersey.api.client.WebResource;
+import org.apache.commons.codec.binary.Base64;
+import org.apache.commons.text.CharacterPredicates;
+import org.apache.commons.text.RandomStringGenerator;
+import org.apache.kerby.has.common.HasConfig;
+import org.apache.kerby.has.common.HasConfigKey;
+import org.apache.kerby.has.common.HasException;
+import org.apache.kerby.has.common.ssl.SSLFactory;
+import org.apache.kerby.has.common.util.HasUtil;
+import org.apache.kerby.has.common.util.URLConnectionFactory;
+import org.apache.kerby.kerberos.kerb.KrbCodec;
+import org.apache.kerby.kerberos.kerb.KrbException;
+import org.apache.kerby.kerberos.kerb.KrbRuntime;
+import org.apache.kerby.kerberos.kerb.crypto.EncryptionHandler;
+import org.apache.kerby.kerberos.kerb.provider.TokenEncoder;
+import org.apache.kerby.kerberos.kerb.type.base.AuthToken;
+import org.apache.kerby.kerberos.kerb.type.base.EncryptedData;
+import org.apache.kerby.kerberos.kerb.type.base.EncryptionKey;
+import org.apache.kerby.kerberos.kerb.type.base.KeyUsage;
+import org.apache.kerby.kerberos.kerb.type.base.KrbError;
+import org.apache.kerby.kerberos.kerb.type.base.KrbMessage;
+import org.apache.kerby.kerberos.kerb.type.base.KrbMessageType;
+import org.apache.kerby.kerberos.kerb.type.base.PrincipalName;
+import org.apache.kerby.kerberos.kerb.type.kdc.EncAsRepPart;
+import org.apache.kerby.kerberos.kerb.type.kdc.EncKdcRepPart;
+import org.apache.kerby.kerberos.kerb.type.kdc.KdcRep;
+import org.apache.kerby.kerberos.kerb.type.ticket.TgtTicket;
+import org.apache.kerby.util.IOUtil;
+import org.codehaus.jettison.json.JSONException;
+import org.codehaus.jettison.json.JSONObject;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.PrintStream;
+import java.net.HttpURLConnection;
+import java.net.MalformedURLException;
+import java.net.ProtocolException;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.nio.ByteBuffer;
+import java.security.GeneralSecurityException;
+import java.security.KeyStore;
+import java.security.PublicKey;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactory;
+import java.security.cert.X509Certificate;
+import java.util.Date;
+
+/**
+ * HAS client
+ */
+public class HasClient {
+
+    public static final Logger LOG = LoggerFactory.getLogger(HasClient.class);
+
+    public static final String JAVA_SECURITY_KRB5_CONF = "java.security.krb5.conf";
+    public static final String HAS_HTTP_PORT_DEFAULT = "9870";
+    public static final String HAS_CONFIG_DEFAULT = "/etc/has/has-client.conf";
+    public static final String CA_ROOT_DEFAULT = "/etc/has/ca-root.pem";
+
+    private String hadoopSecurityHas = null;
+    private String type;
+    private File clientConfigFolder;
+
+
+    public HasClient() { }
+
+    /**
+     * Create an instance of the HasClient.
+     *
+     * @param hadoopSecurityHas the has config
+     */
+    public HasClient(String hadoopSecurityHas) {
+        this.hadoopSecurityHas = hadoopSecurityHas;
+    }
+
+
+    public TgtTicket requestTgt() throws HasException {
+        HasConfig config;
+        if (hadoopSecurityHas == null) {
+            String hasClientConf = System.getenv("HAS_CLIENT_CONF");
+            if (hasClientConf == null) {
+                hasClientConf = HAS_CONFIG_DEFAULT;
+            }
+            LOG.debug("has-client conf path: " + hasClientConf);
+            File confFile = new File(hasClientConf);
+            if (!confFile.exists()) {
+                throw new HasException("The HAS client config file: " + hasClientConf
+                    + " does not exist.");
+            }
+            try {
+                config = HasUtil.getHasConfig(confFile);
+            } catch (HasException e) {
+                LOG.error("Failed to get has client config: " + e.getMessage());
+                throw new HasException("Failed to get has client config: " + e);
+            }
+        } else {
+            config = new HasConfig();
+            String[] urls = hadoopSecurityHas.split(";");
+            String host = "";
+            int port = 0;
+            try {
+                for (String url : urls) {
+                    URI uri = new URI(url.trim());
+
+                    // parse host
+                    host = host + uri.getHost() + ",";
+
+                    // parse port
+                    if (port == 0) {
+                        port = uri.getPort();
+                    } else {
+                        if (port != uri.getPort()) {
+                            throw new HasException("Invalid port: not even.");
+                        }
+                    }
+
+                    // We will get the auth type from env first
+                    type = System.getenv("auth_type");
+                    // parse host
+                    if (type == null) {
+                        String[] strs = uri.getQuery().split("=");
+                        if (strs[0].equals("auth_type")) {
+                            type = strs[1];
+                        } else {
+                            LOG.warn("No auth type in conf.");
+                        }
+                    }
+                }
+                if (host == null || port == 0) {
+                    throw new HasException("host is null.");
+                } else {
+                    host = host.substring(0, host.length() - 1);
+                    config.setString(HasConfigKey.HTTPS_HOST, host);
+                    config.setInt(HasConfigKey.HTTPS_PORT, port);
+                    config.setString(HasConfigKey.AUTH_TYPE, type);
+                }
+            } catch (URISyntaxException e) {
+                LOG.error("Errors occurred when getting web url. " + e.getMessage());
+                throw new HasException(
+                    "Errors occurred when getting web url. " + e.getMessage());
+            }
+        }
+        if (config == null) {
+            throw new HasException("Failed to get HAS client config.");
+        }
+        clientConfigFolder = new File("/etc/has/" + config.getHttpsHost());
+        if (!clientConfigFolder.exists()) {
+            clientConfigFolder.mkdirs();
+        }
+
+        // get and set ssl-client/trustStore first
+        String sslClientConfPath = clientConfigFolder + "/ssl-client.conf";
+        loadSslClientConf(config, sslClientConfPath);
+        config.setString(HasConfigKey.SSL_CLIENT_CONF, sslClientConfPath);
+
+        createKrb5Conf(config);
+
+        HasClientPlugin plugin;
+        try {
+            plugin = getClientTokenPlugin(config);
+        } catch (HasException e) {
+            LOG.error("Failed to get client token plugin from config: " + e.getMessage());
+            throw new HasException(
+                "Failed to get client token plugin from config: " + e.getMessage());
+        }
+        AuthToken authToken;
+        try {
+            authToken = plugin.login(config);
+        } catch (HasLoginException e) {
+            LOG.error("Plugin login failed: " + e.getMessage());
+            throw new HasException(
+                "Plugin login failed: " + e.getMessage());
+        }
+        type = plugin.getLoginType();
+
+        LOG.info("The plugin type is: " + type);
+
+        return requestTgt(authToken, type, config);
+    }
+
+    private void createKrb5Conf(HasConfig config) throws HasException {
+        HasAdminClient hasAdminClient = new HasAdminClient(config);
+        File krb5Conf = new File(clientConfigFolder + "/krb5.conf");
+        if (!krb5Conf.exists()) {
+            String content = hasAdminClient.getKrb5conf();
+            if (content == null) {
+                LOG.error("Failed to get krb5.conf.");
+                throw new HasException("Failed to get krb5.conf.");
+            }
+            try {
+                PrintStream ps = new PrintStream(new FileOutputStream(krb5Conf));
+                ps.println(content);
+                LOG.info("krb5.conf has saved in : " + krb5Conf.getAbsolutePath());
+            } catch (FileNotFoundException e) {
+                LOG.error(e.getMessage());
+                throw new HasException(e);
+            }
+        }
+        System.setProperty(JAVA_SECURITY_KRB5_CONF, krb5Conf.getAbsolutePath());
+    }
+
+
+    private HasClientPlugin getClientTokenPlugin(HasConfig config) throws HasException {
+        String pluginName = config.getPluginName();
+        LOG.info("The plugin name getting from config is: " + pluginName);
+        HasClientPlugin clientPlugin;
+        if (pluginName != null) {
+            clientPlugin = HasClientPluginRegistry.createPlugin(pluginName);
+        } else {
+            throw new HasException("Please set the plugin name in has client conf");
+        }
+        if (clientPlugin == null) {
+            throw new HasException("Failed to create client plugin: " + pluginName);
+        }
+        LOG.info("The plugin class is: " + clientPlugin);
+
+        return clientPlugin;
+    }
+
+    /**
+     * Request a TGT with user token, plugin type and has config.
+     * @param authToken
+     * @param type
+     * @param config
+     * @return TGT
+     * @throws HasException e
+     */
+    public TgtTicket requestTgt(AuthToken authToken, String type, HasConfig config)
+        throws HasException {
+        TokenEncoder tokenEncoder = KrbRuntime.getTokenProvider("JWT").createTokenEncoder();
+
+        String tokenString;
+        try {
+            tokenString = tokenEncoder.encodeAsString(authToken);
+        } catch (KrbException e) {
+            LOG.debug("Failed to decode the auth token.");
+            throw new HasException("Failed to decode the auth token." + e.getMessage());
+        }
+
+        JSONObject json = null;
+        int responseStatus = 0;
+        boolean success = false;
+        if ((config.getHttpsPort() != null) && (config.getHttpsHost() != null)) {
+            String sslClientConfPath = clientConfigFolder + "/ssl-client.conf";
+            config.setString(SSLFactory.SSL_HOSTNAME_VERIFIER_KEY, "ALLOW_ALL");
+            config.setString(SSLFactory.SSL_CLIENT_CONF_KEY, sslClientConfPath);
+            config.setBoolean(SSLFactory.SSL_REQUIRE_CLIENT_CERT_KEY, false);
+
+            URLConnectionFactory connectionFactory = URLConnectionFactory
+                .newDefaultURLConnectionFactory(config);
+
+            URL url;
+            String[] hosts = config.getHttpsHost().split(",");
+            for (String host : hosts) {
+                try {
+                    url = new URL("https://" + host.trim() + ":" + config.getHttpsPort()
+                        + "/has/v1?type=" + type + "&authToken=" + tokenString);
+                } catch (MalformedURLException e) {
+                    LOG.warn("Failed to get url. " + e.toString());
+                    continue;
+                }
+                HttpURLConnection conn;
+                try {
+                    conn = (HttpURLConnection) connectionFactory.openConnection(url);
+                } catch (IOException e) {
+                    LOG.warn("Failed to open connection. " + e.toString());
+                    continue;
+                }
+
+                conn.setRequestProperty("Content-Type", "application/json; charset=UTF-8");
+                try {
+                    conn.setRequestMethod("PUT");
+                } catch (ProtocolException e) {
+                    LOG.warn("Failed to set request method. " + e.toString());
+                    continue;
+                }
+                conn.setDoOutput(true);
+                conn.setDoInput(true);
+
+                try {
+                    conn.connect();
+
+                    responseStatus = conn.getResponseCode();
+                    switch (responseStatus) {
+                        case 200:
+                        case 201:
+                            BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream()));
+                            StringBuilder sb = new StringBuilder();
+                            String line;
+                            while ((line = br.readLine()) != null) {
+                                sb.append(line + "\n");
+                            }
+                            br.close();
+
+                            json = new JSONObject(sb.toString());
+                    }
+
+                } catch (IOException | JSONException e) {
+                    LOG.warn("ERROR! " + e.toString());
+                    continue;
+                }
+
+                if (responseStatus == 200 || responseStatus == 201) {
+                    success = true;
+                    break;
+                }
+            }
+            if (!success) {
+                throw new HasException("Failed : HTTP error code : "
+                    + responseStatus);
+            }
+        } else {
+            WebResource webResource;
+            Client client = Client.create();
+            String[] hosts = config.getHttpHost().split(",");
+            for (String host : hosts) {
+                webResource = client
+                    .resource("http://" + host.trim() + ":" + config.getHttpPort()
+                        + "/has/v1?type=" + type + "&authToken="
+                        + tokenString);
+                try {
+                    ClientResponse response = webResource.accept("application/json")
+                        .put(ClientResponse.class);
+
+                    if (response.getStatus() != 200) {
+                        LOG.warn("WARN! " + response.getEntity(String.class));
+                        responseStatus = response.getStatus();
+                        continue;
+                    }
+                    json = response.getEntity(JSONObject.class);
+                } catch (ClientHandlerException e) {
+                    LOG.warn("WARN! " + e.toString());
+                    continue;
+                }
+                success = true;
+                break;
+            }
+            if (!success) {
+                throw new HasException("Failed : HTTP error code : "
+                    + responseStatus);
+            }
+        }
+
+        LOG.debug("Return from Server .... \n");
+
+        try {
+            return handleResponse(json, (String) authToken.getAttributes().get("passPhrase"));
+        } catch (HasException e) {
+            LOG.debug("Failed to handle response when requesting tgt ticket in client."
+                + e.getMessage());
+            throw new HasException(e);
+        }
+    }
+
+    private File loadSslClientConf(HasConfig config, String sslClientConfPath) throws HasException {
+        File sslClientConf = new File(sslClientConfPath);
+        if (!sslClientConf.exists()) {
+            String httpHost = config.getHttpHost();
+            String httpPort = config.getHttpPort();
+            if (httpHost == null) {
+                LOG.info("Can't find the http host in config, the https host will be used.");
+                httpHost = config.getHttpsHost();
+            }
+            if (httpPort == null) {
+                LOG.info("Can't find the http port in config, the default http port will be used.");
+                httpPort = HAS_HTTP_PORT_DEFAULT;
+            }
+            X509Certificate certificate = getCertificate(httpHost, httpPort);
+            if (verifyCertificate(certificate)) {
+                String password = createTrustStore(config.getHttpsHost(), certificate);
+                createClientSSLConfig(password);
+            } else {
+                throw new HasException("The certificate from HAS server is invalid.");
+            }
+        }
+        return sslClientConf;
+    }
+
+    public KrbMessage getKrbMessage(JSONObject json) throws HasException {
+
+        LOG.debug("Starting to get the message from has server.");
+
+        try {
+            boolean success = json.getBoolean("success");
+            if (!success) {
+                throw new HasException("Failed: " + json.getString("krbMessage"));
+            }
+        } catch (JSONException e) {
+            LOG.debug("Failed to get message." + e);
+            throw new HasException("Failed to get message." + e);
+        }
+
+        String typeString;
+        try {
+            typeString = json.getString("type");
+        } catch (JSONException e) {
+            LOG.debug("Failed to get message." + e);
+            throw new HasException("Failed to get message." + e);
+        }
+
+        if (typeString != null && typeString.equals(type)) {
+            LOG.debug("The message type is " + type);
+            String krbMessageString = null;
+            try {
+                krbMessageString = json.getString("krbMessage");
+            } catch (JSONException e) {
+                LOG.debug("Failed to get the krbMessage. " + e);
+            }
+            Base64 base64 = new Base64(0);
+            byte[] krbMessage = base64.decode(krbMessageString);
+            ByteBuffer byteBuffer = ByteBuffer.wrap(krbMessage);
+            KrbMessage kdcRep;
+            try {
+                kdcRep = KrbCodec.decodeMessage(byteBuffer);
+            } catch (IOException e) {
+                throw new HasException("Krb decoding message failed", e);
+            }
+            return kdcRep;
+        } else {
+            throw new HasException("Can't get the right message from server.");
+        }
+    }
+
+    public TgtTicket handleResponse(JSONObject json, String passPhrase)
+        throws HasException {
+        KrbMessage kdcRep = getKrbMessage(json);
+
+        KrbMessageType messageType = kdcRep.getMsgType();
+        if (messageType == KrbMessageType.AS_REP) {
+            return processResponse((KdcRep) kdcRep, passPhrase);
+        } else if (messageType == KrbMessageType.KRB_ERROR) {
+            KrbError error = (KrbError) kdcRep;
+            LOG.error("KDC server response with message: "
+                + error.getErrorCode().getMessage());
+
+            throw new HasException(error.getEtext());
+        }
+        return null;
+    }
+
+    public TgtTicket processResponse(KdcRep kdcRep, String passPhrase)
+        throws HasException {
+
+        PrincipalName clientPrincipal = kdcRep.getCname();
+        String clientRealm = kdcRep.getCrealm();
+        clientPrincipal.setRealm(clientRealm);
+
+        // Get the client to decrypt the EncryptedData
+        EncryptionKey clientKey = null;
+        try {
+            clientKey = HasUtil.getClientKey(clientPrincipal.getName(),
+                passPhrase,
+                kdcRep.getEncryptedEncPart().getEType());
+        } catch (KrbException e) {
+            throw new HasException("Could not generate key. " + e.getMessage());
+        }
+
+        byte[] decryptedData = decryptWithClientKey(kdcRep.getEncryptedEncPart(),
+            KeyUsage.AS_REP_ENCPART, clientKey);
+        if ((decryptedData[0] & 0x1f) == 26) {
+            decryptedData[0] = (byte) (decryptedData[0] - 1);
+        }
+        EncKdcRepPart encKdcRepPart = new EncAsRepPart();
+        try {
+            encKdcRepPart.decode(decryptedData);
+        } catch (IOException e) {
+            throw new HasException("Failed to decode EncAsRepPart", e);
+        }
+        kdcRep.setEncPart(encKdcRepPart);
+
+//        if (getChosenNonce() != encKdcRepPart.getNonce()) {
+//            throw new KrbException("Nonce didn't match");
+//        }
+
+//        PrincipalName returnedServerPrincipal = encKdcRepPart.getSname();
+//        returnedServerPrincipal.setRealm(encKdcRepPart.getSrealm());
+//        PrincipalName requestedServerPrincipal = getServerPrincipal();
+//        if (requestedServerPrincipal.getRealm() == null) {
+//            requestedServerPrincipal.setRealm(getContext().getKrbSetting().getKdcRealm());
+//        }
+//        if (!returnedServerPrincipal.equals(requestedServerPrincipal)) {
+//            throw new KrbException(KrbErrorCode.KDC_ERR_SERVER_NOMATCH);
+//        }
+
+//        HostAddresses hostAddresses = getHostAddresses();
+//        if (hostAddresses != null) {
+//            List<HostAddress> requestHosts = hostAddresses.getElements();
+//            if (!requestHosts.isEmpty()) {
+//                List<HostAddress> responseHosts = encKdcRepPart.getCaddr().getElements();
+//                for (HostAddress h : requestHosts) {
+//                    if (!responseHosts.contains(h)) {
+//                        throw new KrbException("Unexpected client host");
+//                    }
+//                }
+//            }
+//        }
+
+        TgtTicket tgtTicket = getTicket(kdcRep);
+        LOG.info("Ticket expire time: " + tgtTicket.getEncKdcRepPart().getEndTime());
+        return tgtTicket;
+
+    }
+
+    protected byte[] decryptWithClientKey(EncryptedData data,
+                                          KeyUsage usage,
+                                          EncryptionKey clientKey) throws HasException {
+        if (clientKey == null) {
+            throw new HasException("Client key isn't available");
+        }
+        try {
+            return EncryptionHandler.decrypt(data, clientKey, usage);
+        } catch (KrbException e) {
+            throw new HasException("Errors occurred when decrypting the data." + e.getMessage());
+        }
+    }
+
+    /**
+     * Get the tgt ticket from KdcRep
+     *
+     * @param kdcRep
+     */
+    public TgtTicket getTicket(KdcRep kdcRep) {
+        TgtTicket tgtTicket = new TgtTicket(kdcRep.getTicket(),
+            (EncAsRepPart) kdcRep.getEncPart(), kdcRep.getCname());
+        return tgtTicket;
+    }
+
+    /**
+     * Get certificate from HAS server.
+     *
+     */
+    private X509Certificate getCertificate(String host, String port) throws HasException {
+        X509Certificate certificate;
+        Client client = Client.create();
+        WebResource webResource = client.resource("http://" + host + ":" + port + "/has/v1/getcert");
+        ClientResponse response = webResource.get(ClientResponse.class);
+        if (response.getStatus() != 200) {
+            throw new HasException(response.getEntity(String.class));
+        }
+        try {
+            CertificateFactory factory = CertificateFactory.getInstance("X.509");
+            InputStream in = response.getEntityInputStream();
+            certificate = (X509Certificate) factory.generateCertificate(in);
+        } catch (CertificateException e) {
+            throw new HasException("Failed to get certificate from HAS server", e);
+        }
+
+        return certificate;
+    }
+
+    /**
+     * Verify certificate.
+     */
+    private boolean verifyCertificate(X509Certificate certificate) throws HasException {
+        // Check if certificate is expired
+        try {
+            Date date = new Date();
+            certificate.checkValidity(date);
+        } catch (GeneralSecurityException e) {
+            return false;
+        }
+
+        // Get certificate from ca root
+        X509Certificate caRoot;
+        try {
+            //Get the ca root path from env, client should export it.
+            String caRootPath = System.getenv("CA_ROOT");
+            if (caRootPath == null) {
+                caRootPath = CA_ROOT_DEFAULT;
+            }
+            File caRootFile;
+            if (caRootPath != null) {
+                caRootFile = new File(caRootPath);
+                if (!caRootFile.exists()) {
+                    throw new HasException("CA_ROOT: " + caRootPath + " not exist.");
+                }
+            } else {
+                throw new HasException("Please set the CA_ROOT.");
+            }
+
+            CertificateFactory factory = CertificateFactory.getInstance("X.509");
+            FileInputStream in = new FileInputStream(caRootFile);
+            caRoot = (X509Certificate) factory.generateCertificate(in);
+        } catch (CertificateException | FileNotFoundException e) {
+            throw new HasException("Failed to get certificate from ca root file", e);
+        }
+
+        // Verify certificate with root certificate
+        try {
+            PublicKey publicKey = caRoot.getPublicKey();
+            certificate.verify(publicKey);
+        } catch (GeneralSecurityException e) {
+            return false;
+        }
+
+        return true;
+    }
+
+    /**
+     * Create and save truststore file based on certificate.
+     *
+     */
+    private String createTrustStore(String host, X509Certificate certificate) throws HasException {
+        KeyStore trustStore;
+
+        // Create password
+        RandomStringGenerator generator = new RandomStringGenerator.Builder()
+            .withinRange('a', 'z')
+            .filteredBy(CharacterPredicates.LETTERS, CharacterPredicates.DIGITS)
+            .build();
+        String password = generator.generate(15);
+
+        File trustStoreFile = new File(clientConfigFolder + "/truststore.jks");
+        try {
+            trustStore = KeyStore.getInstance("jks");
+            trustStore.load(null, null);
+            trustStore.setCertificateEntry(host, certificate);
+            FileOutputStream out = new FileOutputStream(trustStoreFile);
+            trustStore.store(out, password.toCharArray());
+            out.close();
+        } catch (IOException | GeneralSecurityException e) {
+            throw new HasException("Failed to create and save truststore file", e);
+        }
+        return password;
+    }
+
+    /**
+     * Create ssl configuration file for client.
+     *
+     */
+    private void createClientSSLConfig(String password) throws HasException {
+        String resourcePath = "/ssl-client.conf.template";
+        InputStream templateResource = getClass().getResourceAsStream(resourcePath);
+        try {
+            String content = IOUtil.readInput(templateResource);
+            content = content.replaceAll("_location_", clientConfigFolder.getAbsolutePath()
+                + "/truststore.jks");
+            content = content.replaceAll("_password_", password);
+
+            IOUtil.writeFile(content, new File(clientConfigFolder + "/ssl-client.conf"));
+        } catch (IOException e) {
+            throw new HasException("Failed to create client ssl configuration file", e);
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/a8b1c28f/has/has-client/src/main/java/org/apache/kerby/has/client/HasClientPlugin.java
----------------------------------------------------------------------
diff --git a/has/has-client/src/main/java/org/apache/kerby/has/client/HasClientPlugin.java b/has/has-client/src/main/java/org/apache/kerby/has/client/HasClientPlugin.java
new file mode 100644
index 0000000..03b04b6
--- /dev/null
+++ b/has/has-client/src/main/java/org/apache/kerby/has/client/HasClientPlugin.java
@@ -0,0 +1,42 @@
+/**
+ * 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.client;
+
+import org.apache.kerby.has.common.HasConfig;
+import org.apache.kerby.kerberos.kerb.type.base.AuthToken;
+
+public interface HasClientPlugin {
+
+    /**
+     * Get the login module type ID, used to distinguish this module from others.
+     * Should correspond to the server side module.
+     *
+     * @return login type
+     */
+    String getLoginType();
+
+    /**
+     * Perform all the client side login logics, the results wrapped in an AuthToken,
+     * will be validated by HAS server.
+     *
+     * @param conf token plugin config
+     * @return user auth token
+     */
+    AuthToken login(HasConfig conf) throws HasLoginException;
+}

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/a8b1c28f/has/has-client/src/main/java/org/apache/kerby/has/client/HasClientPluginRegistry.java
----------------------------------------------------------------------
diff --git a/has/has-client/src/main/java/org/apache/kerby/has/client/HasClientPluginRegistry.java b/has/has-client/src/main/java/org/apache/kerby/has/client/HasClientPluginRegistry.java
new file mode 100644
index 0000000..45cd193
--- /dev/null
+++ b/has/has-client/src/main/java/org/apache/kerby/has/client/HasClientPluginRegistry.java
@@ -0,0 +1,63 @@
+/**
+ * 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.client;
+
+import org.apache.kerby.has.common.HasException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.Collections;
+import java.util.Map;
+import java.util.ServiceLoader;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+
+public class HasClientPluginRegistry {
+    static final Logger LOG = LoggerFactory.getLogger(HasClientPluginRegistry.class);
+
+    private static Map<String, Class> allPlugins = new ConcurrentHashMap<>();
+
+    static {
+        ServiceLoader<HasClientPlugin> plugins = ServiceLoader.load(HasClientPlugin.class);
+
+        for (HasClientPlugin plugin : plugins) {
+            allPlugins.put(plugin.getLoginType(), plugin.getClass());
+        }
+    }
+
+    public static Set<String> registeredPlugins() {
+        return Collections.unmodifiableSet(allPlugins.keySet());
+    }
+
+    public static boolean registeredPlugin(String name) {
+        return allPlugins.containsKey(name);
+    }
+
+    public static HasClientPlugin createPlugin(String name) throws HasException {
+        if (!registeredPlugin(name)) {
+            throw new HasException("Unregistered plugin " + name);
+        }
+        try {
+            HasClientPlugin clientPlugin = (HasClientPlugin) allPlugins.get(name).newInstance();
+            return clientPlugin;
+        } catch (Exception e) {
+            LOG.error("Create {} plugin failed", name, e);
+            throw new HasException(e.getMessage());
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/a8b1c28f/has/has-client/src/main/java/org/apache/kerby/has/client/HasLoginException.java
----------------------------------------------------------------------
diff --git a/has/has-client/src/main/java/org/apache/kerby/has/client/HasLoginException.java b/has/has-client/src/main/java/org/apache/kerby/has/client/HasLoginException.java
new file mode 100644
index 0000000..2157537
--- /dev/null
+++ b/has/has-client/src/main/java/org/apache/kerby/has/client/HasLoginException.java
@@ -0,0 +1,37 @@
+/**
+ * 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.client;
+
+import org.apache.kerby.has.common.HasException;
+
+public class HasLoginException extends HasException {
+    private static final long serialVersionUID = 4140429098192628252L;
+
+    public HasLoginException(Throwable cause) {
+        super(cause);
+    }
+
+    public HasLoginException(String message) {
+        super(message);
+    }
+
+    public HasLoginException(String message, Throwable cause) {
+        super(message, cause);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/a8b1c28f/has/has-client/src/main/java/org/apache/kerby/has/client/HasLoginModule.java
----------------------------------------------------------------------
diff --git a/has/has-client/src/main/java/org/apache/kerby/has/client/HasLoginModule.java b/has/has-client/src/main/java/org/apache/kerby/has/client/HasLoginModule.java
new file mode 100644
index 0000000..91f3e35
--- /dev/null
+++ b/has/has-client/src/main/java/org/apache/kerby/has/client/HasLoginModule.java
@@ -0,0 +1,491 @@
+/**
+ * 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.client;
+
+import com.sun.security.auth.module.Krb5LoginModule;
+import org.apache.kerby.has.common.HasException;
+import org.apache.kerby.kerberos.kerb.ccache.Credential;
+import org.apache.kerby.kerberos.kerb.type.ticket.TgtTicket;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import sun.security.jgss.krb5.Krb5Util;
+import sun.security.krb5.Credentials;
+import sun.security.krb5.KrbException;
+import sun.security.krb5.PrincipalName;
+
+import javax.security.auth.DestroyFailedException;
+import javax.security.auth.Subject;
+import javax.security.auth.callback.CallbackHandler;
+import javax.security.auth.kerberos.KerberosPrincipal;
+import javax.security.auth.kerberos.KerberosTicket;
+import javax.security.auth.login.LoginException;
+import javax.security.auth.spi.LoginModule;
+import java.io.IOException;
+import java.util.Date;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Login with tgt ticket
+ * The client's TGT will be retrieved from the API of HasClient
+ */
+//CHECKSTYLE.OFF
+public class HasLoginModule implements LoginModule {
+
+    public static final Logger LOG = LoggerFactory.getLogger(HasLoginModule.class);
+
+    Krb5LoginModule krb5LoginModule;
+
+    // initial state
+    private Subject subject;
+    private CallbackHandler callbackHandler;
+    private Map<String, Object> sharedState;
+    private Map<String, ?> options;
+
+    // configurable option
+    private boolean debug = false;
+    private boolean doNotPrompt = false;
+    private boolean useTgtTicket = false;
+    private String hadoopSecurityHas = null;
+    private String princName = null;
+
+    private boolean refreshKrb5Config = false;
+
+    // specify if initiator.
+    // perform authentication exchange if initiator
+    private boolean isInitiator = true;
+
+    // the authentication status
+    private boolean succeeded = false;
+    private boolean commitSucceeded = false;
+
+    private Credentials cred = null;
+
+    private PrincipalName principal = null;
+    private KerberosPrincipal kerbClientPrinc = null;
+    private KerberosTicket kerbTicket = null;
+    private StringBuffer krb5PrincName = null;
+    private boolean unboundServer = false;
+
+    /**
+     * Initialize this <code>LoginModule</code>.
+     * <p>
+     * <p>
+     *
+     * @param subject         the <code>Subject</code> to be authenticated. <p>
+     * @param callbackHandler a <code>CallbackHandler</code> for
+     *                        communication with the end user (prompting for
+     *                        usernames and passwords, for example). <p>
+     * @param sharedState     shared <code>LoginModule</code> state. <p>
+     * @param options         options specified in the login
+     *                        <code>Configuration</code> for this particular
+     *                        <code>LoginModule</code>.
+     */
+    public void initialize(Subject subject,
+                           CallbackHandler callbackHandler,
+                           Map<String, ?> sharedState,
+                           Map<String, ?> options) {
+
+        this.subject = subject;
+        this.callbackHandler = callbackHandler;
+        this.sharedState = (Map<String, Object>) sharedState;
+        this.options = options;
+
+        // initialize any configured options
+        useTgtTicket = "true".equalsIgnoreCase((String) options.get("useTgtTicket"));
+
+        if (useTgtTicket) {
+            debug = "true".equalsIgnoreCase((String) options.get("debug"));
+            doNotPrompt = "true".equalsIgnoreCase((String) options.get("doNotPrompt"));
+            useTgtTicket = "true".equalsIgnoreCase((String) options.get("useTgtTicket"));
+            hadoopSecurityHas = (String) options.get("hadoopSecurityHas");
+            princName = (String) options.get("principal");
+            refreshKrb5Config =
+                "true".equalsIgnoreCase((String) options.get("refreshKrb5Config"));
+
+            // check isInitiator value
+            String isInitiatorValue = ((String) options.get("isInitiator"));
+            if (isInitiatorValue != null) {
+                // use default, if value not set
+                isInitiator = "true".equalsIgnoreCase(isInitiatorValue);
+            }
+
+            if (debug) {
+                System.out.print("Debug is  " + debug
+                    + " doNotPrompt " + doNotPrompt
+                    + " isInitiator " + isInitiator
+                    + " refreshKrb5Config is " + refreshKrb5Config
+                    + " principal is " + princName + "\n");
+            }
+        } else {
+            krb5LoginModule = new Krb5LoginModule();
+            krb5LoginModule.initialize(subject, callbackHandler, sharedState, options);
+        }
+    }
+
+    /**
+     * Authenticate the user
+     * <p>
+     * <p>
+     *
+     * @return true in all cases since this <code>LoginModule</code>
+     * should not be ignored.
+     * @throws LoginException       if this <code>LoginModule</code>
+     *                              is unable to perform the authentication.
+     */
+    public boolean login() throws LoginException {
+
+        if (useTgtTicket) {
+            if (refreshKrb5Config) {
+                try {
+                    if (debug) {
+                        System.out.println("Refreshing Kerberos configuration");
+                    }
+                    sun.security.krb5.Config.refresh();
+                } catch (KrbException ke) {
+                    LoginException le = new LoginException(ke.getMessage());
+                    le.initCause(ke);
+                    throw le;
+                }
+            }
+            String principalProperty = System.getProperty("sun.security.krb5.principal");
+            if (principalProperty != null) {
+                krb5PrincName = new StringBuffer(principalProperty);
+            } else {
+                if (princName != null) {
+                    krb5PrincName = new StringBuffer(princName);
+                }
+            }
+
+            validateConfiguration();
+
+            if (krb5PrincName != null && krb5PrincName.toString().equals("*")) {
+                unboundServer = true;
+            }
+
+            // attempt the authentication by getting the username and pwd
+            // by prompting or configuration i.e. not from shared state
+
+            try {
+                attemptAuthentication(false);
+                succeeded = true;
+                cleanState();
+                return true;
+            } catch (LoginException e) {
+                // authentication failed -- clean out state
+                if (debug) {
+                    System.out.println("\t\t[HasLoginModule] "
+                        + "authentication failed \n"
+                        + e.getMessage());
+                }
+                succeeded = false;
+                cleanState();
+                throw e;
+            }
+        } else {
+            succeeded = krb5LoginModule.login();
+            return succeeded;
+        }
+    }
+
+    /**
+     * Process the configuration options
+     * Get the TGT from Has Client
+     */
+
+    private void attemptAuthentication(boolean getPasswdFromSharedState)
+        throws LoginException {
+
+        /*
+         * Check the creds cache to see whether
+         * we have TGT for this client principal
+         */
+        if (krb5PrincName != null) {
+            try {
+                principal = new PrincipalName(krb5PrincName.toString(),
+                        PrincipalName.KRB_NT_PRINCIPAL);
+            } catch (KrbException e) {
+                LoginException le = new LoginException(e.getMessage());
+                le.initCause(e);
+                throw le;
+            }
+        }
+
+        try {
+            if (useTgtTicket) {
+                if (debug) {
+                    System.out.println("use tgt ticket to login, acquire TGT TICKET...");
+                }
+
+                HasClient hasClient = new HasClient(hadoopSecurityHas);
+                TgtTicket tgtTicket = null;
+                try {
+                    tgtTicket = hasClient.requestTgt();
+                } catch (HasException e) {
+                    LoginException le = new LoginException(e.getMessage());
+                    le.initCause(e);
+                    throw le;
+                }
+                Credential credential = new Credential(tgtTicket);
+                boolean[] flags = new boolean[7];
+                int flag = credential.getTicketFlags().getFlags();
+                for (int i = 6; i >= 0; i--) {
+                    flags[i] = (flag & (1 << i)) != 0;
+                }
+                Date startTime = null;
+                if (credential.getStartTime() != null) {
+                    startTime = credential.getStartTime().getValue();
+                }
+                cred = new Credentials(credential.getTicket().encode(),
+                    credential.getClientName().getName(),
+                    credential.getServerName().getName(),
+                    credential.getKey().getKeyData(),
+                    credential.getKey().getKeyType().getValue(),
+                    flags,
+                    credential.getAuthTime().getValue(),
+                    startTime,
+                    credential.getEndTime().getValue(),
+                    credential.getRenewTill().getValue(),
+                    null);
+
+                if (cred != null) {
+                    // get the principal name from the ticket cache
+                    if (principal == null) {
+                        principal = cred.getClient();
+                    }
+                }
+                if (debug) {
+                    System.out.println("Principal is " + principal);
+                    if (cred == null) {
+                        System.out.println("null credentials from TGT Ticket");
+                    }
+                }
+            }
+        } catch (KrbException e) {
+            LoginException le = new LoginException(e.getMessage());
+            le.initCause(e);
+            throw le;
+        } catch (IOException ioe) {
+            LoginException ie = new LoginException(ioe.getMessage());
+            ie.initCause(ioe);
+            throw ie;
+        }
+    }
+
+    private void validateConfiguration() throws LoginException {
+        if (doNotPrompt && !useTgtTicket) {
+            throw new LoginException("Configuration Error"
+                + " - either doNotPrompt should be "
+                + " false or"
+                + " useTgtTicket"
+                + " should be true");
+        }
+
+        if (krb5PrincName != null && krb5PrincName.toString().equals("*")) {
+            if (isInitiator) {
+                throw new LoginException("Configuration Error"
+                        + " - principal cannot be * when isInitiator is true");
+            }
+        }
+    }
+
+    /**
+     * <p> This method is called if the LoginContext's
+     * overall authentication succeeded
+     *
+     * @return true if this LoginModule's own login and commit
+     * attempts succeeded, or false otherwise.
+     * @throws LoginException if the commit fails.
+     */
+
+    public boolean commit() throws LoginException {
+        if (debug) {
+            System.out.println("Login success? " + succeeded);
+        }
+
+        if (useTgtTicket) {
+        /*
+         * Let us add the Krb5 Creds to the Subject's
+         * private credentials. The credentials are of type
+         * KerberosKey or KerberosTicket
+         */
+            if (succeeded == false) {
+                return false;
+            } else {
+
+                if (isInitiator && (cred == null)) {
+                    succeeded = false;
+                    throw new LoginException("Null Client Credential");
+                }
+
+                if (subject.isReadOnly()) {
+                    cleanKerberosCred();
+                    throw new LoginException("Subject is Readonly");
+                }
+
+            /*
+             * Add the Principal (authenticated identity)
+             * to the Subject's principal set and
+             * add the credentials (TGT or Service key) to the
+             * Subject's private credentials
+             */
+
+                Set<Object> privCredSet = subject.getPrivateCredentials();
+                Set<java.security.Principal> princSet = subject.getPrincipals();
+                kerbClientPrinc = new KerberosPrincipal(principal.getName());
+
+                // create Kerberos Ticket
+                if (isInitiator) {
+                    kerbTicket = Krb5Util.credsToTicket(cred);
+                }
+
+                // Let us add the kerbClientPrinc,kerbTicket
+
+                // We won't add "*" as a KerberosPrincipal
+                if (!unboundServer
+                    && !princSet.contains(kerbClientPrinc)) {
+                    princSet.add(kerbClientPrinc);
+                }
+
+                // add the TGT
+                if (kerbTicket != null) {
+                    if (!privCredSet.contains(kerbTicket)) {
+                        privCredSet.add(kerbTicket);
+                    }
+                }
+            }
+            commitSucceeded = true;
+            if (debug) {
+                System.out.println("Commit Succeeded \n");
+            }
+            return true;
+        } else {
+            return krb5LoginModule.commit();
+        }
+    }
+
+    /**
+     * <p> This method is called if the LoginContext's
+     * overall authentication failed.
+     *
+     * @return false if this LoginModule's own login and/or commit attempts
+     * failed, and true otherwise.
+     * @throws LoginException if the abort fails.
+     */
+
+    public boolean abort() throws LoginException {
+        if (useTgtTicket) {
+            if (succeeded == false) {
+                return false;
+            } else if (succeeded == true && commitSucceeded == false) {
+                // login succeeded but overall authentication failed
+                succeeded = false;
+                cleanKerberosCred();
+            } else {
+                // overall authentication succeeded and commit succeeded,
+                // but someone else's commit failed
+                logout();
+            }
+            return true;
+        } else {
+            return krb5LoginModule.abort();
+        }
+    }
+
+    /**
+     * Logout the user.
+     * <p>
+     * <p> This method removes the <code>Krb5Principal</code>
+     * that was added by the <code>commit</code> method.
+     * <p>
+     * <p>
+     *
+     * @return true in all cases since this <code>LoginModule</code>
+     * should not be ignored.
+     * @throws LoginException if the logout fails.
+     */
+    public boolean logout() throws LoginException {
+
+        if (useTgtTicket) {
+            if (debug) {
+                System.out.println("\t\t[Krb5LoginModule]: "
+                    + "Entering logout");
+            }
+
+            if (subject.isReadOnly()) {
+                cleanKerberosCred();
+                throw new LoginException("Subject is Readonly");
+            }
+
+            subject.getPrincipals().remove(kerbClientPrinc);
+            // Let us remove all Kerberos credentials stored in the Subject
+            Iterator<Object> it = subject.getPrivateCredentials().iterator();
+            while (it.hasNext()) {
+                Object o = it.next();
+                if (o instanceof KerberosTicket) {
+                    it.remove();
+                }
+            }
+            // clean the kerberos ticket and keys
+            cleanKerberosCred();
+
+            succeeded = false;
+            commitSucceeded = false;
+            if (debug) {
+                System.out.println("\t\t[HasLoginModule]: "
+                    + "logged out Subject");
+            }
+            return true;
+        } else {
+            return krb5LoginModule.logout();
+        }
+    }
+
+    /**
+     * Clean Kerberos credentials
+     */
+    private void cleanKerberosCred() throws LoginException {
+        // Clean the ticket and server key
+        try {
+            if (kerbTicket != null) {
+                kerbTicket.destroy();
+            }
+        } catch (DestroyFailedException e) {
+            throw new LoginException("Destroy Failed on Kerberos Private Credentials");
+        }
+        kerbTicket = null;
+        kerbClientPrinc = null;
+    }
+
+    /**
+     * Clean out the state
+     */
+    private void cleanState() {
+
+        if (!succeeded) {
+            // remove temp results for the next try
+            principal = null;
+        }
+        if (krb5PrincName != null && krb5PrincName.length() != 0) {
+            krb5PrincName.delete(0, krb5PrincName.length());
+        }
+        krb5PrincName = null;
+    }
+}

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/a8b1c28f/has/has-common/pom.xml
----------------------------------------------------------------------
diff --git a/has/has-common/pom.xml b/has/has-common/pom.xml
index 3046871..47e3147 100644
--- a/has/has-common/pom.xml
+++ b/has/has-common/pom.xml
@@ -5,7 +5,7 @@
   <modelVersion>4.0.0</modelVersion>
 
   <parent>
-    <groupId>org.apache.hadoop</groupId>
+    <groupId>org.apache.kerby</groupId>
     <artifactId>has-project</artifactId>
     <version>1.0.0-SNAPSHOT</version>
   </parent>
@@ -34,7 +34,7 @@
     <dependency>
       <groupId>org.apache.hadoop</groupId>
       <artifactId>hadoop-annotations</artifactId>
-      <version>3.0.0-alpha2</version>
+      <version>${hadoop.version}</version>
     </dependency>
     <dependency>
       <groupId>commons-codec</groupId>

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/a8b1c28f/has/has-common/src/main/java/org/apache/hadoop/has/common/HasAdmin.java
----------------------------------------------------------------------
diff --git a/has/has-common/src/main/java/org/apache/hadoop/has/common/HasAdmin.java b/has/has-common/src/main/java/org/apache/hadoop/has/common/HasAdmin.java
deleted file mode 100644
index 94dc5df..0000000
--- a/has/has-common/src/main/java/org/apache/hadoop/has/common/HasAdmin.java
+++ /dev/null
@@ -1,140 +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;
-
-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/hadoop/has/common/HasConfig.java
----------------------------------------------------------------------
diff --git a/has/has-common/src/main/java/org/apache/hadoop/has/common/HasConfig.java b/has/has-common/src/main/java/org/apache/hadoop/has/common/HasConfig.java
deleted file mode 100644
index 3fc0998..0000000
--- a/has/has-common/src/main/java/org/apache/hadoop/has/common/HasConfig.java
+++ /dev/null
@@ -1,103 +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;
-
-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/hadoop/has/common/HasConfigKey.java
----------------------------------------------------------------------
diff --git a/has/has-common/src/main/java/org/apache/hadoop/has/common/HasConfigKey.java b/has/has-common/src/main/java/org/apache/hadoop/has/common/HasConfigKey.java
deleted file mode 100644
index 07db8d4..0000000
--- a/has/has-common/src/main/java/org/apache/hadoop/has/common/HasConfigKey.java
+++ /dev/null
@@ -1,61 +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;
-
-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/hadoop/has/common/HasException.java
----------------------------------------------------------------------
diff --git a/has/has-common/src/main/java/org/apache/hadoop/has/common/HasException.java b/has/has-common/src/main/java/org/apache/hadoop/has/common/HasException.java
deleted file mode 100644
index f8fc3b3..0000000
--- a/has/has-common/src/main/java/org/apache/hadoop/has/common/HasException.java
+++ /dev/null
@@ -1,53 +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
- * <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.hadoop.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/hadoop/has/common/spnego/AuthToken.java
----------------------------------------------------------------------
diff --git a/has/has-common/src/main/java/org/apache/hadoop/has/common/spnego/AuthToken.java b/has/has-common/src/main/java/org/apache/hadoop/has/common/spnego/AuthToken.java
deleted file mode 100644
index c7a18da..0000000
--- a/has/has-common/src/main/java/org/apache/hadoop/has/common/spnego/AuthToken.java
+++ /dev/null
@@ -1,217 +0,0 @@
-/**
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License. See accompanying LICENSE file.
- */
-package org.apache.hadoop.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/hadoop/has/common/spnego/AuthenticatedURL.java
----------------------------------------------------------------------
diff --git a/has/has-common/src/main/java/org/apache/hadoop/has/common/spnego/AuthenticatedURL.java b/has/has-common/src/main/java/org/apache/hadoop/has/common/spnego/AuthenticatedURL.java
deleted file mode 100644
index ccd7ea4..0000000
--- a/has/has-common/src/main/java/org/apache/hadoop/has/common/spnego/AuthenticatedURL.java
+++ /dev/null
@@ -1,282 +0,0 @@
-/**
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License. See accompanying LICENSE file.
- */
-package org.apache.hadoop.has.common.spnego;
-
-import org.apache.hadoop.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/hadoop/has/common/spnego/AuthenticationException.java
----------------------------------------------------------------------
diff --git a/has/has-common/src/main/java/org/apache/hadoop/has/common/spnego/AuthenticationException.java b/has/has-common/src/main/java/org/apache/hadoop/has/common/spnego/AuthenticationException.java
deleted file mode 100644
index 62a5d38..0000000
--- a/has/has-common/src/main/java/org/apache/hadoop/has/common/spnego/AuthenticationException.java
+++ /dev/null
@@ -1,54 +0,0 @@
-/**
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License. See accompanying LICENSE file.
- */
-package org.apache.hadoop.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/hadoop/has/common/spnego/Authenticator.java
----------------------------------------------------------------------
diff --git a/has/has-common/src/main/java/org/apache/hadoop/has/common/spnego/Authenticator.java b/has/has-common/src/main/java/org/apache/hadoop/has/common/spnego/Authenticator.java
deleted file mode 100644
index 91eb1a0..0000000
--- a/has/has-common/src/main/java/org/apache/hadoop/has/common/spnego/Authenticator.java
+++ /dev/null
@@ -1,52 +0,0 @@
-/**
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License. See accompanying LICENSE file.
- */
-package org.apache.hadoop.has.common.spnego;
-
-import org.apache.hadoop.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;
-
-}