You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@directory.apache.org by pl...@apache.org on 2017/11/28 03:04:12 UTC
[11/15] directory-kerby git commit: Change the Maven groupId in HAS
folder to org.apache.kerby.
http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/a8b1c28f/has/has-common/src/main/java/org/apache/hadoop/has/common/util/HasJaasLoginUtil.java
----------------------------------------------------------------------
diff --git a/has/has-common/src/main/java/org/apache/hadoop/has/common/util/HasJaasLoginUtil.java b/has/has-common/src/main/java/org/apache/hadoop/has/common/util/HasJaasLoginUtil.java
deleted file mode 100644
index e824ea4..0000000
--- a/has/has-common/src/main/java/org/apache/hadoop/has/common/util/HasJaasLoginUtil.java
+++ /dev/null
@@ -1,261 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-package org.apache.hadoop.has.common.util;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import javax.security.auth.Subject;
-import javax.security.auth.kerberos.KerberosPrincipal;
-import javax.security.auth.login.AppConfigurationEntry;
-import javax.security.auth.login.Configuration;
-import javax.security.auth.login.LoginContext;
-import javax.security.auth.login.LoginException;
-import java.io.File;
-import java.io.IOException;
-import java.security.Principal;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Set;
-
-/**
- * JAAS utilities for Has login.
- */
-public class HasJaasLoginUtil {
- public static final Logger LOG = LoggerFactory.getLogger(HasJaasLoginUtil.class);
-
- public static final boolean ENABLE_DEBUG = true;
-
- private static String getKrb5LoginModuleName() {
- return System.getProperty("java.vendor").contains("IBM")
- ? "com.ibm.security.auth.module.Krb5LoginModule"
- : "org.apache.hadoop.has.client.HasLoginModule";
- }
-
- /**
- * Log a user in from a tgt ticket.
- *
- * @throws IOException
- */
- public static synchronized Subject loginUserFromTgtTicket(String hadoopSecurityHas) throws IOException {
-
- TICKET_KERBEROS_OPTIONS.put("hadoopSecurityHas", hadoopSecurityHas);
- Subject subject = new Subject();
- Configuration conf = new HasJaasConf();
- String confName = "ticket-kerberos";
- LoginContext loginContext = null;
- try {
- loginContext = new LoginContext(confName, subject, null, conf);
- } catch (LoginException e) {
- throw new IOException("Fail to create LoginContext for " + e);
- }
- try {
- loginContext.login();
- LOG.info("Login successful for user "
- + subject.getPrincipals().iterator().next().getName());
- } catch (LoginException e) {
- throw new IOException("Login failure for " + e);
- }
- return loginContext.getSubject();
- }
-
- /**
- * Has Jaas config.
- */
- static class HasJaasConf extends Configuration {
- @Override
- public AppConfigurationEntry[] getAppConfigurationEntry(String name) {
-
- return new AppConfigurationEntry[]{
- TICKET_KERBEROS_LOGIN};
- }
- }
-
- private static final Map<String, String> BASIC_JAAS_OPTIONS =
- new HashMap<String, String>();
-
- static {
- String jaasEnvVar = System.getenv("HADOOP_JAAS_DEBUG");
- if (jaasEnvVar != null && "true".equalsIgnoreCase(jaasEnvVar)) {
- BASIC_JAAS_OPTIONS.put("debug", String.valueOf(ENABLE_DEBUG));
- }
- }
-
- private static final Map<String, String> TICKET_KERBEROS_OPTIONS =
- new HashMap<String, String>();
-
- static {
- TICKET_KERBEROS_OPTIONS.put("doNotPrompt", "true");
- TICKET_KERBEROS_OPTIONS.put("useTgtTicket", "true");
- TICKET_KERBEROS_OPTIONS.putAll(BASIC_JAAS_OPTIONS);
- }
-
- private static final AppConfigurationEntry TICKET_KERBEROS_LOGIN =
- new AppConfigurationEntry(getKrb5LoginModuleName(),
- AppConfigurationEntry.LoginModuleControlFlag.OPTIONAL,
- TICKET_KERBEROS_OPTIONS);
-
-
- public static Subject loginUsingTicketCache(
- String principal, File cacheFile) throws IOException {
- Set<Principal> principals = new HashSet<Principal>();
- principals.add(new KerberosPrincipal(principal));
-
- Subject subject = new Subject(false, principals,
- new HashSet<Object>(), new HashSet<Object>());
-
- Configuration conf = useTicketCache(principal, cacheFile);
- String confName = "TicketCacheConf";
- LoginContext loginContext = null;
- try {
- loginContext = new LoginContext(confName, subject, null, conf);
- } catch (LoginException e) {
- throw new IOException("Faill to create LoginContext for " + e);
- }
- try {
- loginContext.login();
- LOG.info("Login successful for user "
- + subject.getPrincipals().iterator().next().getName());
- } catch (LoginException e) {
- throw new IOException("Login failure for " + e);
- }
- return loginContext.getSubject();
- }
-
- public static Subject loginUsingKeytab(
- String principal, File keytabFile) throws IOException {
- Set<Principal> principals = new HashSet<Principal>();
- principals.add(new KerberosPrincipal(principal));
-
- Subject subject = new Subject(false, principals,
- new HashSet<Object>(), new HashSet<Object>());
-
- Configuration conf = useKeytab(principal, keytabFile);
- String confName = "KeytabConf";
- LoginContext loginContext = null;
- try {
- loginContext = new LoginContext(confName, subject, null, conf);
- } catch (LoginException e) {
- throw new IOException("Fail to create LoginContext for " + e);
- }
- try {
- loginContext.login();
- LOG.info("Login successful for user "
- + subject.getPrincipals().iterator().next().getName());
- } catch (LoginException e) {
- throw new IOException("Login failure for " + e);
- }
- return loginContext.getSubject();
- }
-
- public static LoginContext loginUsingKeytabReturnContext(
- String principal, File keytabFile) throws IOException {
- Set<Principal> principals = new HashSet<Principal>();
- principals.add(new KerberosPrincipal(principal));
-
- Subject subject = new Subject(false, principals,
- new HashSet<Object>(), new HashSet<Object>());
-
- Configuration conf = useKeytab(principal, keytabFile);
- String confName = "KeytabConf";
- LoginContext loginContext = null;
- try {
- loginContext = new LoginContext(confName, subject, null, conf);
- } catch (LoginException e) {
- throw new IOException("Fail to create LoginContext for " + e);
- }
- try {
- loginContext.login();
- LOG.info("Login successful for user "
- + subject.getPrincipals().iterator().next().getName());
- } catch (LoginException e) {
- throw new IOException("Login failure for " + e);
- }
- return loginContext;
- }
-
- public static Configuration useTicketCache(String principal,
- File credentialFile) {
- return new TicketCacheJaasConf(principal, credentialFile);
- }
-
- public static Configuration useKeytab(String principal, File keytabFile) {
- return new KeytabJaasConf(principal, keytabFile);
- }
-
- static class TicketCacheJaasConf extends Configuration {
- private String principal;
- private File clientCredentialFile;
-
- TicketCacheJaasConf(String principal, File clientCredentialFile) {
- this.principal = principal;
- this.clientCredentialFile = clientCredentialFile;
- }
-
- @Override
- public AppConfigurationEntry[] getAppConfigurationEntry(String name) {
- Map<String, String> options = new HashMap<String, String>();
- options.put("principal", principal);
- options.put("storeKey", "false");
- options.put("doNotPrompt", "false");
- options.put("useTicketCache", "true");
- options.put("renewTGT", "true");
- options.put("refreshKrb5Config", "true");
- options.put("isInitiator", "true");
- options.put("ticketCache", clientCredentialFile.getAbsolutePath());
- options.putAll(BASIC_JAAS_OPTIONS);
-
- return new AppConfigurationEntry[]{
- new AppConfigurationEntry(getKrb5LoginModuleName(),
- AppConfigurationEntry.LoginModuleControlFlag.REQUIRED,
- options)};
- }
- }
-
- static class KeytabJaasConf extends Configuration {
- private String principal;
- private File keytabFile;
-
- KeytabJaasConf(String principal, File keytab) {
- this.principal = principal;
- this.keytabFile = keytab;
- }
-
- @Override
- public AppConfigurationEntry[] getAppConfigurationEntry(String name) {
- Map<String, String> options = new HashMap<String, String>();
- options.put("keyTab", keytabFile.getAbsolutePath());
- options.put("principal", principal);
- options.put("useKeyTab", "true");
- options.put("storeKey", "true");
- options.put("doNotPrompt", "true");
- options.put("renewTGT", "false");
- options.put("refreshKrb5Config", "true");
- options.put("isInitiator", "true");
- options.putAll(BASIC_JAAS_OPTIONS);
-
- return new AppConfigurationEntry[]{
- new AppConfigurationEntry(getKrb5LoginModuleName(),
- AppConfigurationEntry.LoginModuleControlFlag.REQUIRED,
- options)};
- }
- }
-}
http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/a8b1c28f/has/has-common/src/main/java/org/apache/hadoop/has/common/util/HasUtil.java
----------------------------------------------------------------------
diff --git a/has/has-common/src/main/java/org/apache/hadoop/has/common/util/HasUtil.java b/has/has-common/src/main/java/org/apache/hadoop/has/common/util/HasUtil.java
deleted file mode 100644
index 1d9f4b7..0000000
--- a/has/has-common/src/main/java/org/apache/hadoop/has/common/util/HasUtil.java
+++ /dev/null
@@ -1,93 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.hadoop.has.common.util;
-
-import org.apache.hadoop.has.common.HasConfig;
-import org.apache.hadoop.has.common.HasException;
-import org.apache.kerby.kerberos.kerb.KrbException;
-import org.apache.kerby.kerberos.kerb.crypto.EncryptionHandler;
-import org.apache.kerby.kerberos.kerb.type.base.EncryptionKey;
-import org.apache.kerby.kerberos.kerb.type.base.EncryptionType;
-
-import java.io.BufferedReader;
-import java.io.File;
-import java.io.FileNotFoundException;
-import java.io.FileOutputStream;
-import java.io.FileReader;
-import java.io.IOException;
-import java.io.PrintStream;
-
-public class HasUtil {
-
- public static EncryptionKey getClientKey(String userName, String passPhrase,
- EncryptionType type) throws KrbException {
- EncryptionKey clientKey = EncryptionHandler.string2Key(userName,
- passPhrase, type);
- return clientKey;
- }
-
- /**
- * Get has configuration
- * @param hasConfFile configuration directory
- * @return has configuration
- * @throws KrbException e
- */
- public static HasConfig getHasConfig(File hasConfFile) throws HasException {
-
- if (hasConfFile.exists()) {
- HasConfig hasConfig = new HasConfig();
- try {
- hasConfig.addIniConfig(hasConfFile);
- } catch (IOException e) {
- throw new HasException("Can not load the has configuration file "
- + hasConfFile.getAbsolutePath());
- }
- return hasConfig;
- }
-
- return null;
- }
-
- public static void setEnableConf(File hasConfFile, String value)
- throws HasException, IOException {
- String oldValue = getHasConfig(hasConfFile).getEnableConf();
- if (oldValue == null) {
- throw new HasException("Please set enable_conf in has-server.conf.");
- }
- if (oldValue.equals(value)) {
- return;
- }
- try {
- BufferedReader bf = new BufferedReader(new FileReader(hasConfFile));
- StringBuilder sb = new StringBuilder();
- String tempString;
- while ((tempString = bf.readLine()) != null) {
- if (tempString.trim().startsWith("enable_conf")) {
- tempString = tempString.replace(oldValue, value);
- }
- sb.append(tempString + "\n");
- }
- PrintStream ps = new PrintStream(new FileOutputStream(hasConfFile));
- ps.print(sb.toString());
- bf.close();
- } catch (FileNotFoundException e) {
- throw new HasException("Can not load the has configuration file "
- + hasConfFile.getAbsolutePath());
- }
- }
-}
http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/a8b1c28f/has/has-common/src/main/java/org/apache/hadoop/has/common/util/PlatformName.java
----------------------------------------------------------------------
diff --git a/has/has-common/src/main/java/org/apache/hadoop/has/common/util/PlatformName.java b/has/has-common/src/main/java/org/apache/hadoop/has/common/util/PlatformName.java
deleted file mode 100644
index 6f64c62..0000000
--- a/has/has-common/src/main/java/org/apache/hadoop/has/common/util/PlatformName.java
+++ /dev/null
@@ -1,59 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.hadoop.has.common.util;
-
-import org.apache.hadoop.classification.InterfaceAudience;
-import org.apache.hadoop.classification.InterfaceStability;
-
-/**
- * Borrow the class from Apache Hadoop
- */
-
-/**
- * A helper class for getting build-info of the java-vm.
- *
- */
-@InterfaceAudience.LimitedPrivate({"HBase"})
-@InterfaceStability.Unstable
-public class PlatformName {
- /**
- * The complete platform 'name' to identify the platform as
- * per the java-vm.
- */
- public static final String PLATFORM_NAME =
- (System.getProperty("os.name").startsWith("Windows")
- ? System.getenv("os") : System.getProperty("os.name"))
- + "-" + System.getProperty("os.arch")
- + "-" + System.getProperty("sun.arch.data.model");
-
- /**
- * The java vendor name used in this platform.
- */
- public static final String JAVA_VENDOR_NAME = System.getProperty("java.vendor");
-
- /**
- * A public static variable to indicate the current java vendor is
- * IBM java or not.
- */
- public static final boolean IBM_JAVA = JAVA_VENDOR_NAME.contains("IBM");
-
- public static void main(String[] args) {
- System.out.println(PLATFORM_NAME);
- }
-}
http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/a8b1c28f/has/has-common/src/main/java/org/apache/hadoop/has/common/util/StringUtils.java
----------------------------------------------------------------------
diff --git a/has/has-common/src/main/java/org/apache/hadoop/has/common/util/StringUtils.java b/has/has-common/src/main/java/org/apache/hadoop/has/common/util/StringUtils.java
deleted file mode 100644
index 2b00904..0000000
--- a/has/has-common/src/main/java/org/apache/hadoop/has/common/util/StringUtils.java
+++ /dev/null
@@ -1,55 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.hadoop.has.common.util;
-
-import org.apache.hadoop.classification.InterfaceAudience;
-import org.apache.hadoop.classification.InterfaceStability;
-
-import java.util.Locale;
-
-/**
- * General string utils
- */
-@InterfaceAudience.Private
-@InterfaceStability.Unstable
-public class StringUtils {
-
- /**
- * Converts all of the characters in this String to lower case with
- * Locale.ENGLISH.
- *
- * @param str string to be converted
- * @return the str, converted to lowercase.
- */
- public static String toLowerCase(String str) {
- return str.toLowerCase(Locale.ENGLISH);
- }
-
- /**
- * Converts all of the characters in this String to upper case with
- * Locale.ENGLISH.
- *
- * @param str string to be converted
- * @return the str, converted to uppercase.
- */
- public static String toUpperCase(String str) {
- return str.toUpperCase(Locale.ENGLISH);
- }
-
-}
http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/a8b1c28f/has/has-common/src/main/java/org/apache/hadoop/has/common/util/URLConnectionFactory.java
----------------------------------------------------------------------
diff --git a/has/has-common/src/main/java/org/apache/hadoop/has/common/util/URLConnectionFactory.java b/has/has-common/src/main/java/org/apache/hadoop/has/common/util/URLConnectionFactory.java
deleted file mode 100644
index a818864..0000000
--- a/has/has-common/src/main/java/org/apache/hadoop/has/common/util/URLConnectionFactory.java
+++ /dev/null
@@ -1,215 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.hadoop.has.common.util;
-
-import com.google.common.annotations.VisibleForTesting;
-import org.apache.hadoop.classification.InterfaceStability;
-import org.apache.hadoop.has.common.HasConfig;
-import org.apache.hadoop.has.common.HasException;
-import org.apache.hadoop.has.common.spnego.AuthenticatedURL;
-import org.apache.hadoop.has.common.spnego.AuthenticationException;
-import org.apache.hadoop.has.common.spnego.KerberosHasAuthenticator;
-import org.apache.hadoop.has.common.ssl.SSLFactory;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import javax.net.ssl.HostnameVerifier;
-import javax.net.ssl.HttpsURLConnection;
-import javax.net.ssl.SSLSocketFactory;
-import java.io.IOException;
-import java.net.HttpURLConnection;
-import java.net.URL;
-import java.net.URLConnection;
-import java.security.GeneralSecurityException;
-
-/**
- * Borrow the class from Apache Hadoop
- */
-
-/**
- * Utilities for handling URLs
- */
-@InterfaceStability.Unstable
-public class URLConnectionFactory {
- private static final Logger LOG = LoggerFactory
- .getLogger(URLConnectionFactory.class);
-
- /**
- * Timeout for socket connects and reads
- */
- // 1 minute
- public static final int DEFAULT_SOCKET_TIMEOUT = 60 * 1000;
- private final ConnectionConfigurator connConfigurator;
-
- private static final ConnectionConfigurator DEFAULT_TIMEOUT_CONN_CONFIGURATOR
- = new ConnectionConfigurator() {
- @Override
- public HttpURLConnection configure(HttpURLConnection conn)
- throws IOException {
- URLConnectionFactory.setTimeouts(conn,
- DEFAULT_SOCKET_TIMEOUT,
- DEFAULT_SOCKET_TIMEOUT);
- return conn;
- }
- };
-
- /**
- * The URLConnectionFactory that sets the default timeout and it only trusts
- * Java's SSL certificates.
- */
- public static final URLConnectionFactory DEFAULT_SYSTEM_CONNECTION_FACTORY =
- new URLConnectionFactory(DEFAULT_TIMEOUT_CONN_CONFIGURATOR);
-
- /**
- * Construct a new URLConnectionFactory based on the configuration. It will
- * try to load SSL certificates when it is specified.
- */
- public static URLConnectionFactory newDefaultURLConnectionFactory(HasConfig conf) {
- ConnectionConfigurator conn = null;
- try {
- conn = newSslConnConfigurator(DEFAULT_SOCKET_TIMEOUT, conf);
- } catch (Exception e) {
- LOG.debug(
- "Cannot load customized ssl related configuration. Fallback to system-generic settings.",
- e);
- conn = DEFAULT_TIMEOUT_CONN_CONFIGURATOR;
- }
- return new URLConnectionFactory(conn);
- }
-
- private static ConnectionConfigurator getSSLConnectionConfiguration(
- HasConfig conf) {
- ConnectionConfigurator conn;
- try {
- conn = newSslConnConfigurator(DEFAULT_SOCKET_TIMEOUT, conf);
- } catch (Exception e) {
- LOG.warn(
- "Cannot load customized ssl related configuration. Fallback to"
- + " system-generic settings.",
- e);
- conn = DEFAULT_TIMEOUT_CONN_CONFIGURATOR;
- }
-
- return conn;
- }
-
- @VisibleForTesting
- URLConnectionFactory(ConnectionConfigurator connConfigurator) {
- this.connConfigurator = connConfigurator;
- }
-
- /**
- * Create a new ConnectionConfigurator for SSL connections
- */
- private static ConnectionConfigurator newSslConnConfigurator(
- final int defaultTimeout, HasConfig conf)
- throws IOException, GeneralSecurityException, HasException {
- final SSLFactory factory;
- final SSLSocketFactory sf;
- final HostnameVerifier hv;
- final int connectTimeout;
- final int readTimeout;
-
- factory = new SSLFactory(SSLFactory.Mode.CLIENT, conf);
- factory.init();
- sf = factory.createSSLSocketFactory();
- hv = factory.getHostnameVerifier();
-
- connectTimeout = defaultTimeout;
-
- readTimeout = defaultTimeout;
-
- return new ConnectionConfigurator() {
- @Override
- public HttpURLConnection configure(HttpURLConnection conn)
- throws IOException {
- if (conn instanceof HttpsURLConnection) {
- HttpsURLConnection c = (HttpsURLConnection) conn;
- c.setSSLSocketFactory(sf);
- c.setHostnameVerifier(hv);
- }
- URLConnectionFactory.setTimeouts(conn, connectTimeout, readTimeout);
- return conn;
- }
- };
- }
-
- /**
- * Opens a url with read and connect timeouts
- *
- * @param url
- * to open
- * @return URLConnection
- * @throws IOException
- */
- public URLConnection openConnection(URL url) throws IOException {
- try {
- return openConnection(url, false, null);
- } catch (AuthenticationException e) {
- // Unreachable
- LOG.error("Open connection {} failed", url, e);
- return null;
- }
- }
-
- /**
- * Opens a url with read and connect timeouts
- *
- * @param url
- * URL to open
- * @param isSpnego
- * whether the url should be authenticated via SPNEGO
- * @return URLConnection
- * @throws IOException
- * @throws AuthenticationException
- */
- public URLConnection openConnection(URL url, boolean isSpnego, HasConfig hasConfig)
- throws IOException, AuthenticationException {
- if (isSpnego && (hasConfig != null)) {
- LOG.debug("open AuthenticatedURL connection {}", url);
-// UserGroupInformation.getCurrentUser().checkTGTAndReloginFromKeytab();
- final AuthenticatedURL.Token authToken = new AuthenticatedURL.Token();
- return new AuthenticatedURL(new KerberosHasAuthenticator(hasConfig.getAdminKeytab(),
- hasConfig.getAdminKeytabPrincipal()),
- connConfigurator).openConnection(url, authToken);
- } else {
- LOG.debug("open URL connection");
- URLConnection connection = url.openConnection();
- if (connection instanceof HttpURLConnection) {
- connConfigurator.configure((HttpURLConnection) connection);
- }
- return connection;
- }
- }
-
- /**
- * Sets timeout parameters on the given URLConnection.
- *
- * @param connection
- * URLConnection to set
- * @param connectTimeout
- * the connection and read timeout of the connection.
- */
- private static void setTimeouts(URLConnection connection,
- int connectTimeout,
- int readTimeout) {
- connection.setConnectTimeout(connectTimeout);
- connection.setReadTimeout(readTimeout);
- }
-}
http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/a8b1c28f/has/has-common/src/main/java/org/apache/kerby/has/common/HasAdmin.java
----------------------------------------------------------------------
diff --git a/has/has-common/src/main/java/org/apache/kerby/has/common/HasAdmin.java b/has/has-common/src/main/java/org/apache/kerby/has/common/HasAdmin.java
new file mode 100644
index 0000000..30b1e35
--- /dev/null
+++ b/has/has-common/src/main/java/org/apache/kerby/has/common/HasAdmin.java
@@ -0,0 +1,140 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.kerby.has.common;
+
+import java.io.File;
+import java.util.List;
+
+/**
+ * Server side admin facilities from remote, similar to MIT kadmin remote mode.
+ */
+public interface HasAdmin {
+
+ /**
+ * Get the hadmin principal name.
+ *
+ * @return The hadmin principal name.
+ */
+ String getHadminPrincipal();
+
+ /**
+ * Add principal to backend.
+ *
+ * @param principal The principal to be added into backend
+ * @throws HasException e
+ */
+ void addPrincipal(String principal) throws HasException;
+
+ /**
+ * Add principal to backend.
+ *
+ * @param principal The principal to be added into backend
+ * @param password The password to create encryption key
+ * @throws HasException e
+ */
+ void addPrincipal(String principal, String password) throws HasException;
+
+ /**
+ * Export all the keys of the specified principal into the specified keytab
+ * file.
+ *
+ * @param keytabFile The keytab file
+ * @param principal The principal name
+ * @throws HasException e
+ */
+ void exportKeytab(File keytabFile, String principal) throws HasException;
+
+ /**
+ * Export all the keys of the specified principals into the specified keytab
+ * file.
+ *
+ * @param keytabFile The keytab file
+ * @param principals The principal names
+ * @throws HasException e
+ */
+ void exportKeytab(File keytabFile, List<String> principals) throws HasException;
+
+ /**
+ * Delete the principal in backend.
+ *
+ * @param principal The principal to be deleted from backend
+ * @throws HasException e
+ */
+ void deletePrincipal(String principal) throws HasException;
+
+ /**
+ * Rename the principal.
+ *
+ * @param oldPrincipalName The original principal name
+ * @param newPrincipalName The new principal name
+ * @throws HasException e
+ */
+ void renamePrincipal(String oldPrincipalName,
+ String newPrincipalName) throws HasException;
+
+ /**
+ * Get all the principal names from backend.
+ *
+ * @return principal list
+ * @throws HasException e
+ */
+ List<String> getPrincipals() throws HasException;
+
+ /**
+ * Get all the principal names that meets the pattern
+ *
+ * @param globString The glob string for matching
+ * @return Principal names
+ * @throws HasException e
+ */
+ List<String> getPrincipals(String globString) throws HasException;
+
+ /**
+ * Change the password of specified principal.
+ *
+ * @param principal The principal to be updated password
+ * @param newPassword The new password
+ * @throws HasException e
+ */
+// void changePassword(String principal, String newPassword) throws HasException;
+
+ /**
+ * Update the random keys of specified principal.
+ *
+ * @param principal The principal to be updated keys
+ * @throws HasException e
+ */
+// void updateKeys(String principal) throws HasException;
+
+ /**
+ * Release any resources associated.
+ *
+ * @throws HasException e
+ */
+// void release() throws HasException;
+
+ String addPrincByRole(String host, String role) throws HasException;
+
+ File getKeytabByHostAndRole(String host, String role) throws HasException;
+
+ int size() throws HasException;
+
+ void setEnableOfConf(String isEnable) throws HasException;
+}
http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/a8b1c28f/has/has-common/src/main/java/org/apache/kerby/has/common/HasConfig.java
----------------------------------------------------------------------
diff --git a/has/has-common/src/main/java/org/apache/kerby/has/common/HasConfig.java b/has/has-common/src/main/java/org/apache/kerby/has/common/HasConfig.java
new file mode 100644
index 0000000..e0f3f1e
--- /dev/null
+++ b/has/has-common/src/main/java/org/apache/kerby/has/common/HasConfig.java
@@ -0,0 +1,103 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.kerby.has.common;
+
+import org.apache.kerby.kerberos.kerb.common.Krb5Conf;
+
+import java.io.File;
+
+/**
+ * AK configuration API.
+ */
+public class HasConfig extends Krb5Conf {
+ private File confDir;
+
+ public void setConfDir(File dir) {
+ this.confDir = dir;
+ }
+
+ public File getConfDir() {
+ return confDir;
+ }
+
+ public String getHttpsHost() {
+ return getString(HasConfigKey.HTTPS_HOST, false, "HAS");
+ }
+
+ public String getHttpsPort() {
+ return getString(HasConfigKey.HTTPS_PORT, false, "HAS");
+ }
+
+ public String getHttpHost() {
+ return getString(HasConfigKey.HTTP_HOST, false, "HAS");
+ }
+
+ public String getHttpPort() {
+ return getString(HasConfigKey.HTTP_PORT, false, "HAS");
+ }
+
+ public String getPluginName() {
+ return getString(HasConfigKey.AUTH_TYPE, true, "PLUGIN");
+ }
+
+ public String getRealm() {
+ return getString(HasConfigKey.REALM, false, "HAS");
+ }
+
+ public String getSslServerConf() {
+ return getString(HasConfigKey.SSL_SERVER_CONF, true, "HAS");
+ }
+
+ public String getSslClientConf() {
+ return getString(HasConfigKey.SSL_CLIENT_CONF, true, "HAS");
+ }
+
+ public String getFilterAuthType() {
+ return getString(HasConfigKey.FILTER_AUTH_TYPE, true, "HAS");
+ }
+
+ public String getKerberosPrincipal() {
+ return getString(HasConfigKey.KERBEROS_PRINCIPAL, false, "HAS");
+ }
+
+ public String getKerberosKeytab() {
+ return getString(HasConfigKey.KERBEROS_KEYTAB, false, "HAS");
+ }
+
+ public String getKerberosNameRules() {
+ return getString(HasConfigKey.KERBEROS_NAME_RULES, false, "HAS");
+ }
+
+ public String getAdminKeytab() {
+ return getString(HasConfigKey.ADMIN_KEYTAB, false, "HAS");
+ }
+
+ public String getAdminKeytabPrincipal() {
+ return getString(HasConfigKey.ADMIN_KEYTAB_PRINCIPAL, false, "HAS");
+ }
+
+ public String getEnableConf() {
+ return getString(HasConfigKey.ENABLE_CONF, false, "HAS");
+ }
+
+ public String getSslClientCert() {
+ return getString(HasConfigKey.SSL_CLIENT_CERT, true, "HAS");
+ }
+}
http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/a8b1c28f/has/has-common/src/main/java/org/apache/kerby/has/common/HasConfigKey.java
----------------------------------------------------------------------
diff --git a/has/has-common/src/main/java/org/apache/kerby/has/common/HasConfigKey.java b/has/has-common/src/main/java/org/apache/kerby/has/common/HasConfigKey.java
new file mode 100644
index 0000000..272ab0e
--- /dev/null
+++ b/has/has-common/src/main/java/org/apache/kerby/has/common/HasConfigKey.java
@@ -0,0 +1,61 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.kerby.has.common;
+
+import org.apache.kerby.config.ConfigKey;
+
+public enum HasConfigKey implements ConfigKey {
+ HTTP_HOST,
+ HTTP_PORT,
+ HTTPS_HOST,
+ HTTPS_PORT,
+ AUTH_TYPE("RAM"),
+ REALM,
+ ENABLE_CONF,
+ SSL_SERVER_CONF("/etc/has/ssl-server.conf"),
+ SSL_CLIENT_CONF("/etc/has/ssl-client.conf"),
+ SSL_CLIENT_CERT("/etc/has/cert-signed"),
+ FILTER_AUTH_TYPE("kerberos"),
+ KERBEROS_PRINCIPAL,
+ KERBEROS_KEYTAB,
+ KERBEROS_NAME_RULES,
+ ADMIN_KEYTAB,
+ ADMIN_KEYTAB_PRINCIPAL;
+
+ private Object defaultValue;
+
+ HasConfigKey() {
+ this.defaultValue = null;
+ }
+
+ HasConfigKey(Object defaultValue) {
+ this.defaultValue = defaultValue;
+ }
+
+ @Override
+ public String getPropertyKey() {
+ return name().toLowerCase();
+ }
+
+ @Override
+ public Object getDefaultValue() {
+ return this.defaultValue;
+ }
+}
http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/a8b1c28f/has/has-common/src/main/java/org/apache/kerby/has/common/HasException.java
----------------------------------------------------------------------
diff --git a/has/has-common/src/main/java/org/apache/kerby/has/common/HasException.java b/has/has-common/src/main/java/org/apache/kerby/has/common/HasException.java
new file mode 100644
index 0000000..9e5db44
--- /dev/null
+++ b/has/has-common/src/main/java/org/apache/kerby/has/common/HasException.java
@@ -0,0 +1,53 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.kerby.has.common;
+
+public class HasException extends Exception {
+
+ private static final long serialVersionUID = -1916788959202646914L;
+
+ /**
+ * Creates an {@link HasException}.
+ *
+ * @param cause original exception.
+ */
+ public HasException(Throwable cause) {
+ super(cause);
+ }
+
+ /**
+ * Creates an {@link HasException}.
+ *
+ * @param message exception message.
+ */
+ public HasException(String message) {
+ super(message);
+ }
+
+ /**
+ * Creates an {@link HasException}.
+ *
+ * @param message exception message.
+ * @param cause original exception.
+ */
+ public HasException(String message, Throwable cause) {
+ super(message, cause);
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/a8b1c28f/has/has-common/src/main/java/org/apache/kerby/has/common/spnego/AuthToken.java
----------------------------------------------------------------------
diff --git a/has/has-common/src/main/java/org/apache/kerby/has/common/spnego/AuthToken.java b/has/has-common/src/main/java/org/apache/kerby/has/common/spnego/AuthToken.java
new file mode 100644
index 0000000..bacc740
--- /dev/null
+++ b/has/has-common/src/main/java/org/apache/kerby/has/common/spnego/AuthToken.java
@@ -0,0 +1,217 @@
+/**
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License. See accompanying LICENSE file.
+ */
+package org.apache.kerby.has.common.spnego;
+
+import java.security.Principal;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import java.util.StringTokenizer;
+
+/**
+ * Borrow the class from Apache hadoop
+ */
+public class AuthToken implements Principal {
+
+ /**
+ * Constant that identifies an anonymous request.
+ */
+
+ private static final String ATTR_SEPARATOR = "&";
+ private static final String USER_NAME = "u";
+ private static final String PRINCIPAL = "p";
+ private static final String EXPIRES = "e";
+ private static final String TYPE = "t";
+
+ private static final Set<String> ATTRIBUTES =
+ new HashSet<String>(Arrays.asList(USER_NAME, PRINCIPAL, EXPIRES, TYPE));
+
+ private String userName;
+ private String principal;
+ private String type;
+ private long expires;
+ private String tokenStr;
+
+ protected AuthToken() {
+ userName = null;
+ principal = null;
+ type = null;
+ expires = -1;
+ tokenStr = "ANONYMOUS";
+ generateToken();
+ }
+
+ private static final String ILLEGAL_ARG_MSG = " is NULL, empty or contains a '" + ATTR_SEPARATOR + "'";
+
+ /**
+ * Creates an authentication token.
+ *
+ * @param userName user name.
+ * @param principal principal (commonly matches the user name, with Kerberos is the full/long principal
+ * name while the userName is the short name).
+ * @param type the authentication mechanism name.
+ * (<code>System.currentTimeMillis() + validityPeriod</code>).
+ */
+ public AuthToken(String userName, String principal, String type) {
+ checkForIllegalArgument(userName, "userName");
+ checkForIllegalArgument(principal, "principal");
+ checkForIllegalArgument(type, "type");
+ this.userName = userName;
+ this.principal = principal;
+ this.type = type;
+ this.expires = -1;
+ }
+
+ /**
+ * Check if the provided value is invalid. Throw an error if it is invalid, NOP otherwise.
+ *
+ * @param value the value to check.
+ * @param name the parameter name to use in an error message if the value is invalid.
+ */
+ protected static void checkForIllegalArgument(String value, String name) {
+ if (value == null || value.length() == 0 || value.contains(ATTR_SEPARATOR)) {
+ throw new IllegalArgumentException(name + ILLEGAL_ARG_MSG);
+ }
+ }
+
+ /**
+ * Sets the expiration of the token.
+ *
+ * @param expires expiration time of the token in milliseconds since the epoch.
+ */
+ public void setExpires(long expires) {
+ this.expires = expires;
+ generateToken();
+ }
+
+ /**
+ * Returns true if the token has expired.
+ *
+ * @return true if the token has expired.
+ */
+ public boolean isExpired() {
+ return getExpires() != -1 && System.currentTimeMillis() > getExpires();
+ }
+
+ /**
+ * Generates the token.
+ */
+ private void generateToken() {
+ StringBuffer sb = new StringBuffer();
+ sb.append(USER_NAME).append("=").append(getUserName()).append(ATTR_SEPARATOR);
+ sb.append(PRINCIPAL).append("=").append(getName()).append(ATTR_SEPARATOR);
+ sb.append(TYPE).append("=").append(getType()).append(ATTR_SEPARATOR);
+ sb.append(EXPIRES).append("=").append(getExpires());
+ tokenStr = sb.toString();
+ }
+
+ /**
+ * Returns the user name.
+ *
+ * @return the user name.
+ */
+ public String getUserName() {
+ return userName;
+ }
+
+ /**
+ * Returns the principal name (this method name comes from the JDK {@link Principal} interface).
+ *
+ * @return the principal name.
+ */
+ @Override
+ public String getName() {
+ return principal;
+ }
+
+ /**
+ * Returns the authentication mechanism of the token.
+ *
+ * @return the authentication mechanism of the token.
+ */
+ public String getType() {
+ return type;
+ }
+
+ /**
+ * Returns the expiration time of the token.
+ *
+ * @return the expiration time of the token, in milliseconds since Epoc.
+ */
+ public long getExpires() {
+ return expires;
+ }
+
+ /**
+ * Returns the string representation of the token.
+ * <p>
+ * This string representation is parseable by the {@link #parse} method.
+ *
+ * @return the string representation of the token.
+ */
+ @Override
+ public String toString() {
+ return tokenStr;
+ }
+
+ public static AuthToken parse(String tokenStr) throws AuthenticationException {
+ if (tokenStr.length() >= 2) {
+ // strip the \" at the two ends of the tokenStr
+ if (tokenStr.charAt(0) == '\"'
+ && tokenStr.charAt(tokenStr.length() - 1) == '\"') {
+ tokenStr = tokenStr.substring(1, tokenStr.length() - 1);
+ }
+ }
+ Map<String, String> map = split(tokenStr);
+ // remove the signature part, since client doesn't care about it
+ map.remove("s");
+
+ if (!map.keySet().equals(ATTRIBUTES)) {
+ throw new AuthenticationException("Invalid token string, missing attributes");
+ }
+ long expires = Long.parseLong(map.get(EXPIRES));
+ AuthToken token = new AuthToken(map.get(USER_NAME), map.get(PRINCIPAL), map.get(TYPE));
+ token.setExpires(expires);
+ return token;
+ }
+
+ /**
+ * Splits the string representation of a token into attributes pairs.
+ *
+ * @param tokenStr string representation of a token.
+ *
+ * @return a map with the attribute pairs of the token.
+ *
+ * @throws AuthenticationException thrown if the string representation of the token could not be broken into
+ * attribute pairs.
+ */
+ private static Map<String, String> split(String tokenStr) throws AuthenticationException {
+ Map<String, String> map = new HashMap<String, String>();
+ StringTokenizer st = new StringTokenizer(tokenStr, ATTR_SEPARATOR);
+ while (st.hasMoreTokens()) {
+ String part = st.nextToken();
+ int separator = part.indexOf('=');
+ if (separator == -1) {
+ throw new AuthenticationException("Invalid authentication token");
+ }
+ String key = part.substring(0, separator);
+ String value = part.substring(separator + 1);
+ map.put(key, value);
+ }
+ return map;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/a8b1c28f/has/has-common/src/main/java/org/apache/kerby/has/common/spnego/AuthenticatedURL.java
----------------------------------------------------------------------
diff --git a/has/has-common/src/main/java/org/apache/kerby/has/common/spnego/AuthenticatedURL.java b/has/has-common/src/main/java/org/apache/kerby/has/common/spnego/AuthenticatedURL.java
new file mode 100644
index 0000000..372c5cd
--- /dev/null
+++ b/has/has-common/src/main/java/org/apache/kerby/has/common/spnego/AuthenticatedURL.java
@@ -0,0 +1,282 @@
+/**
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License. See accompanying LICENSE file.
+ */
+package org.apache.kerby.has.common.spnego;
+
+import org.apache.kerby.has.common.util.ConnectionConfigurator;
+
+import java.io.IOException;
+import java.net.HttpURLConnection;
+import java.net.URL;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Borrow the class from Apache Hadoop
+ */
+
+/**
+ * <p>
+ * The authentication mechanisms supported by default are Hadoop Simple authentication
+ * (also known as pseudo authentication) and Kerberos SPNEGO authentication.
+ * <p>
+ * Additional authentication mechanisms can be supported via {@link Authenticator} implementations.
+ * <p>
+ * The default {@link Authenticator} is the {@link KerberosAuthenticator} class which supports
+ * automatic fallback from Kerberos SPNEGO to Hadoop Simple authentication.
+ * <p>
+ * <code>AuthenticatedURL</code> instances are not thread-safe.
+ * <p>
+ * The usage pattern of the {@link AuthenticatedURL} is:
+ * <pre>
+ *
+ * // establishing an initial connection
+ *
+ * URL url = new URL("http://foo:8080/bar");
+ * AuthenticatedURL.Token token = new AuthenticatedURL.Token();
+ * AuthenticatedURL aUrl = new AuthenticatedURL();
+ * HttpURLConnection conn = new AuthenticatedURL(url, token).openConnection();
+ * ....
+ * // use the 'conn' instance
+ * ....
+ *
+ * // establishing a follow up connection using a token from the previous connection
+ *
+ * HttpURLConnection conn = new AuthenticatedURL(url, token).openConnection();
+ * ....
+ * // use the 'conn' instance
+ * ....
+ *
+ * </pre>
+ */
+public class AuthenticatedURL {
+
+ /**
+ * Name of the HTTP cookie used for the authentication token between the client and the server.
+ */
+ public static final String AUTH_COOKIE = "hadoop.auth";
+
+ private static final String AUTH_COOKIE_EQ = AUTH_COOKIE + "=";
+
+ /**
+ * Client side authentication token.
+ */
+ public static class Token {
+
+ private String token;
+
+ /**
+ * Creates a token.
+ */
+ public Token() {
+ }
+
+ /**
+ * Creates a token using an existing string representation of the token.
+ *
+ * @param tokenStr string representation of the tokenStr.
+ */
+ public Token(String tokenStr) {
+ if (tokenStr == null) {
+ throw new IllegalArgumentException("tokenStr cannot be null");
+ }
+ set(tokenStr);
+ }
+
+ /**
+ * Returns if a token from the server has been set.
+ *
+ * @return if a token from the server has been set.
+ */
+ public boolean isSet() {
+ return token != null;
+ }
+
+ /**
+ * Sets a token.
+ *
+ * @param tokenStr string representation of the tokenStr.
+ */
+ void set(String tokenStr) {
+ token = tokenStr;
+ }
+
+ /**
+ * Returns the string representation of the token.
+ *
+ * @return the string representation of the token.
+ */
+ @Override
+ public String toString() {
+ return token;
+ }
+
+ }
+
+ private static Class<? extends Authenticator> defaultAuthenticator
+ = KerberosAuthenticator.class;
+
+ /**
+ * Sets the default {@link Authenticator} class to use when an {@link AuthenticatedURL} instance
+ * is created without specifying an authenticator.
+ *
+ * @param authenticator the authenticator class to use as default.
+ */
+ public static void setDefaultAuthenticator(Class<? extends Authenticator> authenticator) {
+ defaultAuthenticator = authenticator;
+ }
+
+ /**
+ * Returns the default {@link Authenticator} class to use when an {@link AuthenticatedURL} instance
+ * is created without specifying an authenticator.
+ *
+ * @return the authenticator class to use as default.
+ */
+ public static Class<? extends Authenticator> getDefaultAuthenticator() {
+ return defaultAuthenticator;
+ }
+
+ private Authenticator authenticator;
+ private ConnectionConfigurator connConfigurator;
+
+ /**
+ * Creates an {@link AuthenticatedURL}.
+ */
+ public AuthenticatedURL() {
+ this(null);
+ }
+
+ /**
+ * Creates an <code>AuthenticatedURL</code>.
+ *
+ * @param authenticator the {@link Authenticator} instance to use, if <code>null</code> a {@link
+ * KerberosAuthenticator} is used.
+ */
+ public AuthenticatedURL(Authenticator authenticator) {
+ this(authenticator, null);
+ }
+
+ /**
+ * Creates an <code>AuthenticatedURL</code>.
+ *
+ * @param authenticator the {@link Authenticator} instance to use, if <code>null</code> a {@link
+ * KerberosAuthenticator} is used.
+ * @param connConfigurator a connection configurator.
+ */
+ public AuthenticatedURL(Authenticator authenticator,
+ ConnectionConfigurator connConfigurator) {
+ try {
+ this.authenticator = (authenticator != null) ? authenticator : defaultAuthenticator.newInstance();
+ } catch (Exception ex) {
+ throw new RuntimeException(ex);
+ }
+ this.connConfigurator = connConfigurator;
+ this.authenticator.setConnectionConfigurator(connConfigurator);
+ }
+
+ /**
+ * Returns the {@link Authenticator} instance used by the
+ * <code>AuthenticatedURL</code>.
+ *
+ * @return the {@link Authenticator} instance
+ */
+ protected Authenticator getAuthenticator() {
+ return authenticator;
+ }
+
+ /**
+ * Returns an authenticated {@link HttpURLConnection}.
+ *
+ * @param url the URL to connect to. Only HTTP/S URLs are supported.
+ * @param token the authentication token being used for the user.
+ *
+ * @return an authenticated {@link HttpURLConnection}.
+ *
+ * @throws IOException if an IO error occurred.
+ * @throws AuthenticationException if an authentication exception occurred.
+ */
+ public HttpURLConnection openConnection(URL url, Token token) throws IOException, AuthenticationException {
+ if (url == null) {
+ throw new IllegalArgumentException("url cannot be NULL");
+ }
+ if (!url.getProtocol().equalsIgnoreCase("http") && !url.getProtocol().equalsIgnoreCase("https")) {
+ throw new IllegalArgumentException("url must be for a HTTP or HTTPS resource");
+ }
+ if (token == null) {
+ throw new IllegalArgumentException("token cannot be NULL");
+ }
+ authenticator.authenticate(url, token);
+ HttpURLConnection conn = (HttpURLConnection) url.openConnection();
+ if (connConfigurator != null) {
+ conn = connConfigurator.configure(conn);
+ }
+ injectToken(conn, token);
+ return conn;
+ }
+
+ /**
+ * Helper method that injects an authentication token to send with a connection.
+ *
+ * @param conn connection to inject the authentication token into.
+ * @param token authentication token to inject.
+ */
+ public static void injectToken(HttpURLConnection conn, Token token) {
+ String t = token.token;
+ if (t != null) {
+ if (!t.startsWith("\"")) {
+ t = "\"" + t + "\"";
+ }
+ conn.addRequestProperty("Cookie", AUTH_COOKIE_EQ + t);
+ }
+ }
+
+ /**
+ * Helper method that extracts an authentication token received from a connection.
+ * <p>
+ * This method is used by {@link Authenticator} implementations.
+ *
+ * @param conn connection to extract the authentication token from.
+ * @param token the authentication token.
+ *
+ * @throws IOException if an IO error occurred.
+ * @throws AuthenticationException if an authentication exception occurred.
+ */
+ public static void extractToken(HttpURLConnection conn, Token token) throws IOException, AuthenticationException {
+ int respCode = conn.getResponseCode();
+ if (respCode == HttpURLConnection.HTTP_OK
+ || respCode == HttpURLConnection.HTTP_CREATED
+ || respCode == HttpURLConnection.HTTP_ACCEPTED) {
+ Map<String, List<String>> headers = conn.getHeaderFields();
+ List<String> cookies = headers.get("Set-Cookie");
+ if (cookies != null) {
+ for (String cookie : cookies) {
+ if (cookie.startsWith(AUTH_COOKIE_EQ)) {
+ String value = cookie.substring(AUTH_COOKIE_EQ.length());
+ int separator = value.indexOf(";");
+ if (separator > -1) {
+ value = value.substring(0, separator);
+ }
+ if (value.length() > 0) {
+ token.set(value);
+ }
+ }
+ }
+ }
+ } else {
+ token.set(null);
+ throw new AuthenticationException("Authentication failed, status: " + conn.getResponseCode()
+ + ", message: " + conn.getResponseMessage());
+ }
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/a8b1c28f/has/has-common/src/main/java/org/apache/kerby/has/common/spnego/AuthenticationException.java
----------------------------------------------------------------------
diff --git a/has/has-common/src/main/java/org/apache/kerby/has/common/spnego/AuthenticationException.java b/has/has-common/src/main/java/org/apache/kerby/has/common/spnego/AuthenticationException.java
new file mode 100644
index 0000000..38e5f6a
--- /dev/null
+++ b/has/has-common/src/main/java/org/apache/kerby/has/common/spnego/AuthenticationException.java
@@ -0,0 +1,54 @@
+/**
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License. See accompanying LICENSE file.
+ */
+package org.apache.kerby.has.common.spnego;
+
+/**
+ * Borrow the class from Apache Hadoop
+ */
+
+/**
+ * Exception thrown when an authentication error occurrs.
+ */
+public class AuthenticationException extends Exception {
+
+ static final long serialVersionUID = 0;
+
+ /**
+ * Creates an {@link AuthenticationException}.
+ *
+ * @param cause original exception.
+ */
+ public AuthenticationException(Throwable cause) {
+ super(cause);
+ }
+
+ /**
+ * Creates an {@link AuthenticationException}.
+ *
+ * @param msg exception message.
+ */
+ public AuthenticationException(String msg) {
+ super(msg);
+ }
+
+ /**
+ * Creates an {@link AuthenticationException}.
+ *
+ * @param msg exception message.
+ * @param cause original exception.
+ */
+ public AuthenticationException(String msg, Throwable cause) {
+ super(msg, cause);
+ }
+}
http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/a8b1c28f/has/has-common/src/main/java/org/apache/kerby/has/common/spnego/Authenticator.java
----------------------------------------------------------------------
diff --git a/has/has-common/src/main/java/org/apache/kerby/has/common/spnego/Authenticator.java b/has/has-common/src/main/java/org/apache/kerby/has/common/spnego/Authenticator.java
new file mode 100644
index 0000000..a643218
--- /dev/null
+++ b/has/has-common/src/main/java/org/apache/kerby/has/common/spnego/Authenticator.java
@@ -0,0 +1,52 @@
+/**
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License. See accompanying LICENSE file.
+ */
+package org.apache.kerby.has.common.spnego;
+
+import org.apache.kerby.has.common.util.ConnectionConfigurator;
+
+import java.io.IOException;
+import java.net.URL;
+
+/**
+ * Borrow the class from Apache Hadoop
+ */
+
+/**
+ * Interface for client authentication mechanisms.
+ * <p>
+ * Implementations are use-once instances, they don't need to be thread safe.
+ */
+public interface Authenticator {
+
+ /**
+ * Sets a {@link ConnectionConfigurator} instance to use for
+ * configuring connections.
+ *
+ * @param configurator the {@link ConnectionConfigurator} instance.
+ */
+ void setConnectionConfigurator(ConnectionConfigurator configurator);
+
+ /**
+ * Authenticates against a URL and returns a {@link AuthenticatedURL.Token} to be
+ * used by subsequent requests.
+ *
+ * @param url the URl to authenticate against.
+ * @param token the authentication token being used for the user.
+ *
+ * @throws IOException if an IO error occurred.
+ * @throws AuthenticationException if an authentication error occurred.
+ */
+ void authenticate(URL url, AuthenticatedURL.Token token) throws IOException, AuthenticationException;
+
+}
http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/a8b1c28f/has/has-common/src/main/java/org/apache/kerby/has/common/spnego/KerberosAuthenticator.java
----------------------------------------------------------------------
diff --git a/has/has-common/src/main/java/org/apache/kerby/has/common/spnego/KerberosAuthenticator.java b/has/has-common/src/main/java/org/apache/kerby/has/common/spnego/KerberosAuthenticator.java
new file mode 100644
index 0000000..6c43832
--- /dev/null
+++ b/has/has-common/src/main/java/org/apache/kerby/has/common/spnego/KerberosAuthenticator.java
@@ -0,0 +1,359 @@
+/**
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License. See accompanying LICENSE file.
+ */
+package org.apache.kerby.has.common.spnego;
+
+import org.apache.commons.codec.binary.Base64;
+import org.apache.kerby.has.common.util.ConnectionConfigurator;
+import org.ietf.jgss.GSSContext;
+import org.ietf.jgss.GSSManager;
+import org.ietf.jgss.GSSName;
+import org.ietf.jgss.Oid;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.security.auth.Subject;
+import javax.security.auth.kerberos.KerberosKey;
+import javax.security.auth.kerberos.KerberosTicket;
+import javax.security.auth.login.AppConfigurationEntry;
+import javax.security.auth.login.Configuration;
+import javax.security.auth.login.LoginContext;
+import javax.security.auth.login.LoginException;
+import java.io.IOException;
+import java.net.HttpURLConnection;
+import java.net.URL;
+import java.security.AccessControlContext;
+import java.security.AccessController;
+import java.security.PrivilegedActionException;
+import java.security.PrivilegedExceptionAction;
+import java.util.HashMap;
+import java.util.Map;
+
+import static org.apache.kerby.has.common.util.PlatformName.IBM_JAVA;
+
+/**
+ * Borrow the class from Apache Hadoop
+ */
+
+/**
+ * The {@link KerberosAuthenticator} implements the Kerberos SPNEGO authentication sequence.
+ * <p>
+ * It uses the default principal for the Kerberos cache (normally set via kinit).
+ * <p>
+ */
+public class KerberosAuthenticator implements Authenticator {
+
+ private static final Logger LOG = LoggerFactory.getLogger(KerberosAuthenticator.class);
+
+ /**
+ * HTTP header used by the SPNEGO server endpoint during an authentication sequence.
+ */
+ public static final String WWW_AUTHENTICATE = "WWW-Authenticate";
+
+ /**
+ * HTTP header used by the SPNEGO client endpoint during an authentication sequence.
+ */
+ public static final String AUTHORIZATION = "Authorization";
+
+ /**
+ * HTTP header prefix used by the SPNEGO client/server endpoints during an authentication sequence.
+ */
+ public static final String NEGOTIATE = "Negotiate";
+
+ private static final String AUTH_HTTP_METHOD = "OPTIONS";
+
+ private static String keytabPrincipal = null;
+ private static String keytabFile = null;
+
+ /*
+ * Defines the Kerberos configuration that will be used to obtain the Kerberos principal from the
+ * Kerberos cache.
+ */
+ private static class KerberosConfiguration extends Configuration {
+
+ private static final String OS_LOGIN_MODULE_NAME;
+ private static final boolean WINDOWS = System.getProperty("os.name").startsWith("Windows");
+ private static final boolean IS_64_BIT = System.getProperty("os.arch").contains("64");
+ private static final boolean AIX = System.getProperty("os.name").equals("AIX");
+
+ /* Return the OS login module class name */
+ private static String getOSLoginModuleName() {
+ if (IBM_JAVA) {
+ if (WINDOWS) {
+ return IS_64_BIT ? "com.ibm.security.auth.module.Win64LoginModule"
+ : "com.ibm.security.auth.module.NTLoginModule";
+ } else if (AIX) {
+ return IS_64_BIT ? "com.ibm.security.auth.module.AIX64LoginModule"
+ : "com.ibm.security.auth.module.AIXLoginModule";
+ } else {
+ return "com.ibm.security.auth.module.LinuxLoginModule";
+ }
+ } else {
+ return WINDOWS ? "com.sun.security.auth.module.NTLoginModule"
+ : "com.sun.security.auth.module.UnixLoginModule";
+ }
+ }
+
+ static {
+ OS_LOGIN_MODULE_NAME = getOSLoginModuleName();
+ }
+
+ private static final AppConfigurationEntry OS_SPECIFIC_LOGIN =
+ new AppConfigurationEntry(OS_LOGIN_MODULE_NAME,
+ AppConfigurationEntry.LoginModuleControlFlag.REQUIRED,
+ new HashMap<String, String>());
+
+ private static final Map<String, String> KEYTAB_KERBEROS_OPTIONS
+ = new HashMap<String, String>();
+ static {
+ if (IBM_JAVA) {
+ KEYTAB_KERBEROS_OPTIONS.put("credsType", "both");
+ KEYTAB_KERBEROS_OPTIONS.put("useKeytab",
+ prependFileAuthority(keytabFile));
+ } else {
+ KEYTAB_KERBEROS_OPTIONS.put("doNotPrompt", "true");
+ KEYTAB_KERBEROS_OPTIONS.put("useKeyTab", "true");
+ KEYTAB_KERBEROS_OPTIONS.put("storeKey", "true");
+ KEYTAB_KERBEROS_OPTIONS.put("keyTab", keytabFile);
+ }
+ KEYTAB_KERBEROS_OPTIONS.put("principal", keytabPrincipal);
+ KEYTAB_KERBEROS_OPTIONS.put("refreshKrb5Config", "true");
+ KEYTAB_KERBEROS_OPTIONS.put("debug", "false");
+ }
+
+ private static final AppConfigurationEntry USER_KERBEROS_LOGIN =
+ new AppConfigurationEntry(KerberosUtil.getKrb5LoginModuleName(),
+ AppConfigurationEntry.LoginModuleControlFlag.OPTIONAL,
+ KEYTAB_KERBEROS_OPTIONS);
+
+ private static final AppConfigurationEntry[] USER_KERBEROS_CONF =
+ new AppConfigurationEntry[]{OS_SPECIFIC_LOGIN, USER_KERBEROS_LOGIN};
+
+ @Override
+ public AppConfigurationEntry[] getAppConfigurationEntry(String appName) {
+ return USER_KERBEROS_CONF;
+ }
+
+ private static String prependFileAuthority(String keytabPath) {
+ return keytabPath.startsWith("file://") ? keytabPath
+ : "file://" + keytabPath;
+ }
+ }
+
+ private URL url;
+ private HttpURLConnection conn;
+ private Base64 base64;
+ private ConnectionConfigurator connConfigurator;
+
+ /**
+ * Sets a {@link ConnectionConfigurator} instance to use for
+ * configuring connections.
+ *
+ * @param configurator the {@link ConnectionConfigurator} instance.
+ */
+ @Override
+ public void setConnectionConfigurator(ConnectionConfigurator configurator) {
+ connConfigurator = configurator;
+ }
+
+ /**
+ * Performs SPNEGO authentication against the specified URL.
+ * <p>
+ * If a token is given it does a NOP and returns the given token.
+ * <p>
+ * If no token is given, it will perform the SPNEGO authentication sequence using an
+ * HTTP <code>OPTIONS</code> request.
+ *
+ * @param url the URl to authenticate against.
+ * @param token the authentication token being used for the user.
+ *
+ * @throws IOException if an IO error occurred.
+ * @throws AuthenticationException if an authentication error occurred.
+ */
+ @Override
+ public void authenticate(URL url, AuthenticatedURL.Token token)
+ throws IOException, AuthenticationException {
+
+ if (!token.isSet()) {
+ this.url = url;
+ base64 = new Base64(0);
+ conn = (HttpURLConnection) url.openConnection();
+ if (connConfigurator != null) {
+ conn = connConfigurator.configure(conn);
+ }
+ conn.setRequestMethod(AUTH_HTTP_METHOD);
+ conn.connect();
+
+ boolean needFallback = false;
+ if (conn.getResponseCode() == HttpURLConnection.HTTP_OK) {
+ LOG.debug("JDK performed authentication on our behalf.");
+ // If the JDK already did the SPNEGO back-and-forth for
+ // us, just pull out the token.
+ AuthenticatedURL.extractToken(conn, token);
+ if (isTokenKerberos(token)) {
+ return;
+ }
+ needFallback = true;
+ }
+ if (!needFallback && isNegotiate()) {
+ LOG.debug("Performing our own SPNEGO sequence.");
+ doSpnegoSequence(token);
+ } else {
+ throw new IOException("Should perform our own SPNEGO sequence");
+ }
+ }
+ }
+
+ public void setKeyTab(String keytabFile, String keytabPrincipal) {
+ this.keytabFile = keytabFile;
+ this.keytabPrincipal = keytabPrincipal;
+ }
+
+ /*
+ * Check if the passed token is of type "kerberos" or "kerberos-dt"
+ */
+ private boolean isTokenKerberos(AuthenticatedURL.Token token)
+ throws AuthenticationException {
+ if (token.isSet()) {
+ AuthToken aToken = AuthToken.parse(token.toString());
+ if (aToken.getType().equals("kerberos")
+ || aToken.getType().equals("kerberos-dt")) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /*
+ * Indicates if the response is starting a SPNEGO negotiation.
+ */
+ private boolean isNegotiate() throws IOException {
+ boolean negotiate = false;
+ if (conn.getResponseCode() == HttpURLConnection.HTTP_UNAUTHORIZED) {
+ String authHeader = conn.getHeaderField(WWW_AUTHENTICATE);
+ negotiate = authHeader != null && authHeader.trim().startsWith(NEGOTIATE);
+ }
+ return negotiate;
+ }
+
+ /**
+ * Implements the SPNEGO authentication sequence interaction using the current default principal
+ * in the Kerberos cache (normally set via kinit).
+ *
+ * @param token the authentication token being used for the user.
+ *
+ * @throws IOException if an IO error occurred.
+ * @throws AuthenticationException if an authentication error occurred.
+ */
+ private void doSpnegoSequence(AuthenticatedURL.Token token) throws IOException, AuthenticationException {
+ try {
+ AccessControlContext context = AccessController.getContext();
+ Subject subject = Subject.getSubject(context);
+ if (subject == null
+ || (subject.getPrivateCredentials(KerberosKey.class).isEmpty()
+ && subject.getPrivateCredentials(KerberosTicket.class).isEmpty())) {
+ LOG.debug("No subject in context, logging in");
+ subject = new Subject();
+ LoginContext login = new LoginContext("", subject,
+ null, new KerberosConfiguration());
+ login.login();
+ }
+
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("Using subject: " + subject);
+ }
+ Subject.doAs(subject, new PrivilegedExceptionAction<Void>() {
+
+ @Override
+ public Void run() throws Exception {
+ GSSContext gssContext = null;
+ try {
+ GSSManager gssManager = GSSManager.getInstance();
+ String servicePrincipal = KerberosUtil.getServicePrincipal("HTTP",
+ KerberosAuthenticator.this.url.getHost());
+ LOG.info("service principal is:" + servicePrincipal);
+ Oid oid = KerberosUtil.getOidInstance("NT_GSS_KRB5_PRINCIPAL");
+ GSSName serviceName = gssManager.createName(servicePrincipal,
+ oid);
+ oid = KerberosUtil.getOidInstance("GSS_KRB5_MECH_OID");
+ gssContext = gssManager.createContext(serviceName, oid, null,
+ GSSContext.DEFAULT_LIFETIME);
+ gssContext.requestCredDeleg(true);
+ gssContext.requestMutualAuth(true);
+
+ byte[] inToken = new byte[0];
+ byte[] outToken;
+ boolean established = false;
+
+ // Loop while the context is still not established
+ while (!established) {
+ outToken = gssContext.initSecContext(inToken, 0, inToken.length);
+ if (outToken != null) {
+ sendToken(outToken);
+ }
+
+ if (!gssContext.isEstablished()) {
+ inToken = readToken();
+ } else {
+ established = true;
+ }
+ }
+ } finally {
+ if (gssContext != null) {
+ gssContext.dispose();
+ gssContext = null;
+ }
+ }
+ return null;
+ }
+ });
+ } catch (PrivilegedActionException ex) {
+ throw new AuthenticationException(ex.getException());
+ } catch (LoginException ex) {
+ throw new AuthenticationException(ex);
+ }
+ AuthenticatedURL.extractToken(conn, token);
+ }
+
+ /*
+ * Sends the Kerberos token to the server.
+ */
+ private void sendToken(byte[] outToken) throws IOException {
+ String token = base64.encodeToString(outToken);
+ conn = (HttpURLConnection) url.openConnection();
+ if (connConfigurator != null) {
+ conn = connConfigurator.configure(conn);
+ }
+ conn.setRequestMethod(AUTH_HTTP_METHOD);
+ conn.setRequestProperty(AUTHORIZATION, NEGOTIATE + " " + token);
+ conn.connect();
+ }
+
+ /*
+ * Retrieves the Kerberos token returned by the server.
+ */
+ private byte[] readToken() throws IOException, AuthenticationException {
+ int status = conn.getResponseCode();
+ if (status == HttpURLConnection.HTTP_OK || status == HttpURLConnection.HTTP_UNAUTHORIZED) {
+ String authHeader = conn.getHeaderField(WWW_AUTHENTICATE);
+ if (authHeader == null || !authHeader.trim().startsWith(NEGOTIATE)) {
+ throw new AuthenticationException("Invalid SPNEGO sequence, '" + WWW_AUTHENTICATE
+ + "' header incorrect: " + authHeader);
+ }
+ String negotiation = authHeader.trim().substring((NEGOTIATE + " ").length()).trim();
+ return base64.decode(negotiation);
+ }
+ throw new AuthenticationException("Invalid SPNEGO sequence, status code: " + status);
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/a8b1c28f/has/has-common/src/main/java/org/apache/kerby/has/common/spnego/KerberosHasAuthenticator.java
----------------------------------------------------------------------
diff --git a/has/has-common/src/main/java/org/apache/kerby/has/common/spnego/KerberosHasAuthenticator.java b/has/has-common/src/main/java/org/apache/kerby/has/common/spnego/KerberosHasAuthenticator.java
new file mode 100644
index 0000000..da598a3
--- /dev/null
+++ b/has/has-common/src/main/java/org/apache/kerby/has/common/spnego/KerberosHasAuthenticator.java
@@ -0,0 +1,25 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.kerby.has.common.spnego;
+
+public class KerberosHasAuthenticator extends KerberosAuthenticator {
+
+ public KerberosHasAuthenticator(String keytabFile, String keytabPrincipal) {
+ setKeyTab(keytabFile, keytabPrincipal);
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/a8b1c28f/has/has-common/src/main/java/org/apache/kerby/has/common/spnego/KerberosUtil.java
----------------------------------------------------------------------
diff --git a/has/has-common/src/main/java/org/apache/kerby/has/common/spnego/KerberosUtil.java b/has/has-common/src/main/java/org/apache/kerby/has/common/spnego/KerberosUtil.java
new file mode 100644
index 0000000..062b6a1
--- /dev/null
+++ b/has/has-common/src/main/java/org/apache/kerby/has/common/spnego/KerberosUtil.java
@@ -0,0 +1,262 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.kerby.has.common.spnego;
+
+import java.io.File;
+import java.io.IOException;
+import java.lang.reflect.Field;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Locale;
+import java.util.Set;
+import java.util.regex.Pattern;
+
+import org.apache.kerby.kerberos.kerb.keytab.Keytab;
+import org.apache.kerby.kerberos.kerb.type.base.PrincipalName;
+import org.ietf.jgss.GSSException;
+import org.ietf.jgss.Oid;
+
+import javax.security.auth.Subject;
+import javax.security.auth.kerberos.KerberosTicket;
+import javax.security.auth.kerberos.KeyTab;
+
+import static org.apache.kerby.has.common.util.PlatformName.IBM_JAVA;
+
+/**
+ * Borrow the class from Apache Hadoop
+ */
+
+public class KerberosUtil {
+
+ /* Return the Kerberos login module name */
+ public static String getKrb5LoginModuleName() {
+ return (IBM_JAVA)
+ ? "com.ibm.security.auth.module.Krb5LoginModule"
+ : "com.sun.security.auth.module.Krb5LoginModule";
+ }
+
+ public static Oid getOidInstance(String oidName)
+ throws ClassNotFoundException, GSSException, NoSuchFieldException,
+ IllegalAccessException {
+ Class<?> oidClass;
+ if (IBM_JAVA) {
+ if ("NT_GSS_KRB5_PRINCIPAL".equals(oidName)) {
+ // IBM JDK GSSUtil class does not have field for krb5 principal oid
+ return new Oid("1.2.840.113554.1.2.2.1");
+ }
+ oidClass = Class.forName("com.ibm.security.jgss.GSSUtil");
+ } else {
+ oidClass = Class.forName("sun.security.jgss.GSSUtil");
+ }
+ Field oidField = oidClass.getDeclaredField(oidName);
+ return (Oid) oidField.get(oidClass);
+ }
+
+ public static String getDefaultRealm()
+ throws ClassNotFoundException, NoSuchMethodException,
+ IllegalArgumentException, IllegalAccessException,
+ InvocationTargetException {
+ Object kerbConf;
+ Class<?> classRef;
+ Method getInstanceMethod;
+ Method getDefaultRealmMethod;
+ if (IBM_JAVA) {
+ classRef = Class.forName("com.ibm.security.krb5.internal.Config");
+ } else {
+ classRef = Class.forName("sun.security.krb5.Config");
+ }
+ getInstanceMethod = classRef.getMethod("getInstance", new Class[0]);
+ kerbConf = getInstanceMethod.invoke(classRef, new Object[0]);
+ getDefaultRealmMethod = classRef.getDeclaredMethod("getDefaultRealm",
+ new Class[0]);
+ return (String) getDefaultRealmMethod.invoke(kerbConf, new Object[0]);
+ }
+
+ public static String getDefaultRealmProtected() {
+ String realmString = null;
+ try {
+ realmString = getDefaultRealm();
+ } catch (RuntimeException rte) {
+ //silently catch everything
+ } catch (Exception e) {
+ //silently return null
+ }
+ return realmString;
+ }
+
+ /*
+ * For a Service Host Principal specification, map the host's domain
+ * to kerberos realm, as specified by krb5.conf [domain_realm] mappings.
+ * Unfortunately the mapping routines are private to the security.krb5
+ * package, so have to construct a PrincipalName instance to derive the realm.
+ *
+ * Many things can go wrong with Kerberos configuration, and this is not
+ * the place to be throwing exceptions to help debug them. Nor do we choose
+ * to make potentially voluminous logs on every call to a communications API.
+ * So we simply swallow all exceptions from the underlying libraries and
+ * return null if we can't get a good value for the realmString.
+ *
+ * @param shortprinc A service principal name with host fqdn as instance, e.g.
+ * "HTTP/myhost.mydomain"
+ * @return String value of Kerberos realm, mapped from host fqdn
+ * May be default realm, or may be null.
+ */
+ public static String getDomainRealm(String shortprinc) {
+ Class<?> classRef;
+ Object principalName; //of type sun.security.krb5.PrincipalName or IBM equiv
+ String realmString = null;
+ try {
+ if (IBM_JAVA) {
+ classRef = Class.forName("com.ibm.security.krb5.PrincipalName");
+ } else {
+ classRef = Class.forName("sun.security.krb5.PrincipalName");
+ }
+ int tKrbNtSrvHst = classRef.getField("KRB_NT_SRV_HST").getInt(null);
+ principalName = classRef.getConstructor(String.class, int.class).
+ newInstance(shortprinc, tKrbNtSrvHst);
+ realmString = (String) classRef.getMethod("getRealmString", new Class[0]).
+ invoke(principalName, new Object[0]);
+ } catch (RuntimeException rte) {
+ //silently catch everything
+ } catch (Exception e) {
+ //silently return default realm (which may itself be null)
+ }
+ if (null == realmString || realmString.equals("")) {
+ return getDefaultRealmProtected();
+ } else {
+ return realmString;
+ }
+ }
+
+ /* Return fqdn of the current host */
+ static String getLocalHostName() throws UnknownHostException {
+ return InetAddress.getLocalHost().getCanonicalHostName();
+ }
+
+ /**
+ * Create Kerberos principal for a given service and hostname,
+ * inferring realm from the fqdn of the hostname. It converts
+ * hostname to lower case. If hostname is null or "0.0.0.0", it uses
+ * dynamically looked-up fqdn of the current host instead.
+ * If domain_realm mappings are inadequately specified, it will
+ * use default_realm, per usual Kerberos behavior.
+ * If default_realm also gives a null value, then a principal
+ * without realm will be returned, which by Kerberos definitions is
+ * just another way to specify default realm.
+ *
+ * @param service
+ * Service for which you want to generate the principal.
+ * @param hostname
+ * Fully-qualified domain name.
+ * @return Converted Kerberos principal name.
+ * @throws UnknownHostException
+ * If no IP address for the local host could be found.
+ */
+ public static final String getServicePrincipal(String service,
+ String hostname)
+ throws UnknownHostException {
+ String fqdn = hostname;
+ String shortprinc = null;
+ String realmString = null;
+ if (null == fqdn || fqdn.equals("") || fqdn.equals("0.0.0.0")) {
+ fqdn = getLocalHostName();
+ }
+ // convert hostname to lowercase as kerberos does not work with hostnames
+ // with uppercase characters.
+ fqdn = fqdn.toLowerCase(Locale.US);
+ shortprinc = service + "/" + fqdn;
+ // Obtain the realm name inferred from the domain of the host
+ realmString = getDomainRealm(shortprinc);
+ if (null == realmString || realmString.equals("")) {
+ return shortprinc;
+ } else {
+ return shortprinc + "@" + realmString;
+ }
+ }
+
+ /**
+ * Get all the unique principals present in the keytabfile.
+ *
+ * @param keytabFileName
+ * Name of the keytab file to be read.
+ * @return list of unique principals in the keytab.
+ * @throws IOException
+ * If keytab entries cannot be read from the file.
+ */
+ static final String[] getPrincipalNames(String keytabFileName) throws IOException {
+ Keytab keytab = Keytab.loadKeytab(new File(keytabFileName));
+ Set<String> principals = new HashSet<String>();
+ List<PrincipalName> entries = keytab.getPrincipals();
+ for (PrincipalName entry : entries) {
+ principals.add(entry.getName().replace("\\", "/"));
+ }
+ return principals.toArray(new String[0]);
+ }
+
+ /**
+ * Get all the unique principals from keytabfile which matches a pattern.
+ *
+ * @param keytab Name of the keytab file to be read.
+ * @param pattern pattern to be matched.
+ * @return list of unique principals which matches the pattern.
+ * @throws IOException if cannot get the principal name
+ */
+ public static final String[] getPrincipalNames(String keytab,
+ Pattern pattern) throws IOException {
+ String[] principals = getPrincipalNames(keytab);
+ if (principals.length != 0) {
+ List<String> matchingPrincipals = new ArrayList<String>();
+ for (String principal : principals) {
+ if (pattern.matcher(principal).matches()) {
+ matchingPrincipals.add(principal);
+ }
+ }
+ principals = matchingPrincipals.toArray(new String[0]);
+ }
+ return principals;
+ }
+
+ /**
+ * Check if the subject contains Kerberos keytab related objects.
+ * The Kerberos keytab object attached in subject has been changed
+ * from KerberosKey (JDK 7) to KeyTab (JDK 8)
+ *
+ *
+ * @param subject subject to be checked
+ * @return true if the subject contains Kerberos keytab
+ */
+ public static boolean hasKerberosKeyTab(Subject subject) {
+ return !subject.getPrivateCredentials(KeyTab.class).isEmpty();
+ }
+
+ /**
+ * Check if the subject contains Kerberos ticket.
+ *
+ *
+ * @param subject subject to be checked
+ * @return true if the subject contains Kerberos ticket
+ */
+ public static boolean hasKerberosTicket(Subject subject) {
+ return !subject.getPrivateCredentials(KerberosTicket.class).isEmpty();
+ }
+}