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;
-
-}