|
@@ -42,7 +42,7 @@ public class KerberosUtil {
|
|
|
|
|
|
/* Return the Kerberos login module name */
|
|
|
public static String getKrb5LoginModuleName() {
|
|
|
- return System.getProperty("java.vendor").contains("IBM")
|
|
|
+ return (IBM_JAVA)
|
|
|
? "com.ibm.security.auth.module.Krb5LoginModule"
|
|
|
: "com.sun.security.auth.module.Krb5LoginModule";
|
|
|
}
|
|
@@ -72,7 +72,7 @@ public class KerberosUtil {
|
|
|
Class<?> classRef;
|
|
|
Method getInstanceMethod;
|
|
|
Method getDefaultRealmMethod;
|
|
|
- if (System.getProperty("java.vendor").contains("IBM")) {
|
|
|
+ if (IBM_JAVA) {
|
|
|
classRef = Class.forName("com.ibm.security.krb5.internal.Config");
|
|
|
} else {
|
|
|
classRef = Class.forName("sun.security.krb5.Config");
|
|
@@ -83,17 +83,79 @@ public class KerberosUtil {
|
|
|
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. It converts
|
|
|
+ * 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
|
|
@@ -102,15 +164,26 @@ public class KerberosUtil {
|
|
|
* @throws UnknownHostException
|
|
|
* If no IP address for the local host could be found.
|
|
|
*/
|
|
|
- public static final String getServicePrincipal(String service, String hostname)
|
|
|
+ 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.
|
|
|
- return service + "/" + fqdn.toLowerCase(Locale.US);
|
|
|
+ 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;
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
/**
|