keycloak-memoizeit
Changes
distribution/adapters/as7-eap6-adapter/as7-modules/src/main/resources/modules/org/keycloak/keycloak-common/main/module.xml 1(+0 -1)
distribution/adapters/as7-eap6-adapter/as7-modules/src/main/resources/modules/org/keycloak/keycloak-core/main/module.xml 1(+0 -1)
distribution/adapters/wf8-adapter/wf8-modules/src/main/resources/modules/org/keycloak/keycloak-common/main/module.xml 1(+0 -1)
distribution/adapters/wf8-adapter/wf8-modules/src/main/resources/modules/org/keycloak/keycloak-core/main/module.xml 1(+0 -1)
distribution/adapters/wildfly-adapter/wildfly-modules/src/main/resources/modules/org/keycloak/keycloak-common/main/module.xml 1(+0 -1)
distribution/adapters/wildfly-adapter/wildfly-modules/src/main/resources/modules/org/keycloak/keycloak-core/main/module.xml 1(+0 -1)
distribution/feature-packs/adapter-feature-pack/src/main/resources/modules/system/add-ons/keycloak/org/keycloak/keycloak-common/main/module.xml 1(+0 -1)
distribution/feature-packs/adapter-feature-pack/src/main/resources/modules/system/add-ons/keycloak/org/keycloak/keycloak-core/main/module.xml 1(+0 -1)
distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/keycloak/org/keycloak/keycloak-common/main/module.xml 1(+0 -1)
distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/keycloak/org/keycloak/keycloak-core/main/module.xml 1(+0 -1)
distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/keycloak/sun/jdk/jgss/main/module.xml 35(+0 -35)
distribution/saml-adapters/as7-eap6-adapter/as7-modules/src/main/resources/modules/org/keycloak/keycloak-common/main/module.xml 1(+0 -1)
distribution/saml-adapters/wildfly-adapter/wildfly-modules/src/main/resources/modules/org/keycloak/keycloak-common/main/module.xml 1(+0 -1)
federation/kerberos/src/main/java/org/keycloak/federation/kerberos/CommonKerberosConfig.java 2(+1 -1)
federation/kerberos/src/main/java/org/keycloak/federation/kerberos/impl/KerberosServerSubjectAuthenticator.java 41(+20 -21)
federation/kerberos/src/main/java/org/keycloak/federation/kerberos/impl/KerberosUsernamePasswordAuthenticator.java 21(+7 -14)
federation/kerberos/src/main/java/org/keycloak/federation/kerberos/impl/SPNEGOAuthenticator.java 22(+20 -2)
pom.xml 7(+5 -2)
Details
diff --git a/common/src/main/java/org/keycloak/common/constants/KerberosConstants.java b/common/src/main/java/org/keycloak/common/constants/KerberosConstants.java
index 4089a0e..b644f16 100644
--- a/common/src/main/java/org/keycloak/common/constants/KerberosConstants.java
+++ b/common/src/main/java/org/keycloak/common/constants/KerberosConstants.java
@@ -17,6 +17,9 @@
package org.keycloak.common.constants;
+import org.ietf.jgss.GSSException;
+import org.ietf.jgss.Oid;
+
/**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/
@@ -31,19 +34,33 @@ public class KerberosConstants {
/**
* OID of SPNEGO mechanism. See http://www.oid-info.com/get/1.3.6.1.5.5.2
*/
- public static final String SPNEGO_OID = "1.3.6.1.5.5.2";
+ private static final String SPNEGO_OID_STR = "1.3.6.1.5.5.2";
+ public static final Oid SPNEGO_OID;
/**
* OID of Kerberos v5 mechanism. See http://www.oid-info.com/get/1.2.840.113554.1.2.2
*/
- public static final String KRB5_OID = "1.2.840.113554.1.2.2";
+ private static final String KRB5_OID_STR = "1.2.840.113554.1.2.2";
+ public static final Oid KRB5_OID;
/**
* OID of Kerberos v5 name. See http://www.oid-info.com/get/1.2.840.113554.1.2.2.1
*/
- public static final String KRB5_NAME_OID = "1.2.840.113554.1.2.2.1";
+ private static final String KRB5_NAME_OID_STR = "1.2.840.113554.1.2.2.1";
+ public static final Oid KRB5_NAME_OID;
+
+
+ static {
+ try {
+ KRB5_OID = new Oid(KerberosConstants.KRB5_OID_STR);
+ KRB5_NAME_OID = new Oid(KerberosConstants.KRB5_NAME_OID_STR);
+ SPNEGO_OID = new Oid(KerberosConstants.SPNEGO_OID_STR);
+ } catch (GSSException e) {
+ throw new RuntimeException(e);
+ }
+ }
/**
diff --git a/common/src/main/java/org/keycloak/common/util/KerberosJdkProvider.java b/common/src/main/java/org/keycloak/common/util/KerberosJdkProvider.java
new file mode 100644
index 0000000..00a5f12
--- /dev/null
+++ b/common/src/main/java/org/keycloak/common/util/KerberosJdkProvider.java
@@ -0,0 +1,227 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * 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.
+ */
+
+package org.keycloak.common.util;
+
+import java.io.File;
+import java.lang.reflect.Method;
+import java.net.MalformedURLException;
+import java.security.PrivilegedExceptionAction;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+
+import javax.security.auth.Subject;
+import javax.security.auth.kerberos.KerberosPrincipal;
+import javax.security.auth.kerberos.KerberosTicket;
+import javax.security.auth.login.AppConfigurationEntry;
+import javax.security.auth.login.Configuration;
+
+import org.ietf.jgss.GSSCredential;
+import org.ietf.jgss.GSSManager;
+import org.ietf.jgss.GSSName;
+import org.keycloak.common.constants.KerberosConstants;
+
+/**
+ * Provides abstraction to handle differences between various JDK vendors (Sun, IBM)
+ *
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+public abstract class KerberosJdkProvider {
+
+ public abstract Configuration createJaasConfigurationForServer(String keytab, String serverPrincipal, boolean debug);
+ public abstract Configuration createJaasConfigurationForUsernamePasswordLogin(boolean debug);
+
+ public abstract KerberosTicket gssCredentialToKerberosTicket(KerberosTicket kerberosTicket, GSSCredential gssCredential);
+
+
+
+ public GSSCredential kerberosTicketToGSSCredential(KerberosTicket kerberosTicket) {
+ return kerberosTicketToGSSCredential(kerberosTicket, GSSCredential.DEFAULT_LIFETIME, GSSCredential.INITIATE_ONLY);
+ }
+
+ // Actually same on both JDKs
+ public GSSCredential kerberosTicketToGSSCredential(KerberosTicket kerberosTicket, final int lifetime, final int usage) {
+ try {
+ final GSSManager gssManager = GSSManager.getInstance();
+
+ KerberosPrincipal kerberosPrincipal = kerberosTicket.getClient();
+ String krbPrincipalName = kerberosTicket.getClient().getName();
+ final GSSName gssName = gssManager.createName(krbPrincipalName, KerberosConstants.KRB5_NAME_OID);
+
+ Set<KerberosPrincipal> principals = Collections.singleton(kerberosPrincipal);
+ Set<GSSName> publicCreds = Collections.singleton(gssName);
+ Set<KerberosTicket> privateCreds = Collections.singleton(kerberosTicket);
+ Subject subject = new Subject(false, principals, publicCreds, privateCreds);
+
+ return Subject.doAs(subject, new PrivilegedExceptionAction<GSSCredential>() {
+
+ @Override
+ public GSSCredential run() throws Exception {
+ return gssManager.createCredential(gssName, lifetime, KerberosConstants.KRB5_OID, usage);
+ }
+
+ });
+ } catch (Exception e) {
+ throw new KerberosSerializationUtils.KerberosSerializationException("Unexpected exception during convert KerberosTicket to GSSCredential", e);
+ }
+ }
+
+
+ public static KerberosJdkProvider getProvider() {
+ if (KerberosSerializationUtils.JAVA_INFO.contains("IBM")) {
+ return new IBMJDKProvider();
+ } else {
+ return new SunJDKProvider();
+ }
+ }
+
+
+ // IMPL Subclasses
+
+
+ // Works for Oracle and OpenJDK
+ private static class SunJDKProvider extends KerberosJdkProvider {
+
+
+ @Override
+ public Configuration createJaasConfigurationForServer(final String keytab, final String serverPrincipal, final boolean debug) {
+ return new Configuration() {
+
+ @Override
+ public AppConfigurationEntry[] getAppConfigurationEntry(String name) {
+ Map<String, Object> options = new HashMap<>();
+ options.put("storeKey", "true");
+ options.put("doNotPrompt", "true");
+ options.put("isInitiator", "false");
+ options.put("useKeyTab", "true");
+
+ options.put("keyTab", keytab);
+ options.put("principal", serverPrincipal);
+ options.put("debug", String.valueOf(debug));
+ AppConfigurationEntry kerberosLMConfiguration = new AppConfigurationEntry("com.sun.security.auth.module.Krb5LoginModule", AppConfigurationEntry.LoginModuleControlFlag.REQUIRED, options);
+ return new AppConfigurationEntry[] { kerberosLMConfiguration };
+ }
+ };
+ }
+
+
+ @Override
+ public Configuration createJaasConfigurationForUsernamePasswordLogin(final boolean debug) {
+ return new Configuration() {
+
+ @Override
+ public AppConfigurationEntry[] getAppConfigurationEntry(String name) {
+ Map<String, Object> options = new HashMap<>();
+ options.put("storeKey", "true");
+ options.put("debug", String.valueOf(debug));
+ AppConfigurationEntry kerberosLMConfiguration = new AppConfigurationEntry("com.sun.security.auth.module.Krb5LoginModule", AppConfigurationEntry.LoginModuleControlFlag.REQUIRED, options);
+ return new AppConfigurationEntry[] { kerberosLMConfiguration };
+ }
+ };
+ }
+
+
+ // Note: input kerberosTicket is null for Sun based JDKs
+ @Override
+ public KerberosTicket gssCredentialToKerberosTicket(KerberosTicket kerberosTicket, GSSCredential gssCredential) {
+ try {
+ Class<?> gssUtil = Class.forName("com.sun.security.jgss.GSSUtil");
+ Method createSubject = gssUtil.getMethod("createSubject", GSSName.class, GSSCredential.class);
+ Subject subject = (Subject) createSubject.invoke(null, null, gssCredential);
+ Set<KerberosTicket> kerberosTickets = subject.getPrivateCredentials(KerberosTicket.class);
+ Iterator<KerberosTicket> iterator = kerberosTickets.iterator();
+ if (iterator.hasNext()) {
+ return iterator.next();
+ } else {
+ throw new KerberosSerializationUtils.KerberosSerializationException("Not available kerberosTicket in subject credentials. Subject was: " + subject.toString());
+ }
+ } catch (KerberosSerializationUtils.KerberosSerializationException ke) {
+ throw ke;
+ } catch (Exception e) {
+ throw new KerberosSerializationUtils.KerberosSerializationException("Unexpected error during convert GSSCredential to KerberosTicket", e);
+ }
+ }
+
+ }
+
+
+ // Works for IBM JDK
+ private static class IBMJDKProvider extends KerberosJdkProvider {
+
+ @Override
+ public Configuration createJaasConfigurationForServer(String keytab, final String serverPrincipal, final boolean debug) {
+ final String keytabUrl = getKeytabURL(keytab);
+
+ return new Configuration() {
+
+ @Override
+ public AppConfigurationEntry[] getAppConfigurationEntry(String name) {
+ Map<String, Object> options = new HashMap<>();
+ options.put("noAddress", "true");
+ options.put("credsType","acceptor");
+ options.put("useKeytab", keytabUrl);
+ options.put("principal", serverPrincipal);
+ options.put("debug", String.valueOf(debug));
+
+ AppConfigurationEntry kerberosLMConfiguration = new AppConfigurationEntry("com.ibm.security.auth.module.Krb5LoginModule", AppConfigurationEntry.LoginModuleControlFlag.REQUIRED, options);
+ return new AppConfigurationEntry[] { kerberosLMConfiguration };
+ }
+ };
+ }
+
+ private String getKeytabURL(String keytab) {
+ try {
+ return new File(keytab).toURI().toURL().toString();
+ } catch (MalformedURLException mfe) {
+ System.err.println("Invalid keytab location specified in configuration: " + keytab);
+ mfe.printStackTrace();
+ return keytab;
+ }
+ }
+
+
+ @Override
+ public Configuration createJaasConfigurationForUsernamePasswordLogin(final boolean debug) {
+ return new Configuration() {
+
+ @Override
+ public AppConfigurationEntry[] getAppConfigurationEntry(String name) {
+ Map<String, Object> options = new HashMap<>();
+ options.put("credsType","initiator");
+ options.put("noAddress", "true");
+ options.put("debug", String.valueOf(debug));
+ AppConfigurationEntry kerberosLMConfiguration = new AppConfigurationEntry("com.ibm.security.auth.module.Krb5LoginModule", AppConfigurationEntry.LoginModuleControlFlag.REQUIRED, options);
+ return new AppConfigurationEntry[] { kerberosLMConfiguration };
+ }
+ };
+ }
+
+
+ // For IBM, kerberosTicket was set on JAAS Subject, so we can just return it
+ @Override
+ public KerberosTicket gssCredentialToKerberosTicket(KerberosTicket kerberosTicket, GSSCredential gssCredential) {
+ if (kerberosTicket == null) {
+ throw new KerberosSerializationUtils.KerberosSerializationException("Not available kerberosTicket in subject credentials in IBM JDK");
+ } else {
+ return kerberosTicket;
+ }
+ }
+ }
+}
diff --git a/common/src/main/java/org/keycloak/common/util/KerberosSerializationUtils.java b/common/src/main/java/org/keycloak/common/util/KerberosSerializationUtils.java
index bc9d174..17a11e4 100644
--- a/common/src/main/java/org/keycloak/common/util/KerberosSerializationUtils.java
+++ b/common/src/main/java/org/keycloak/common/util/KerberosSerializationUtils.java
@@ -25,22 +25,13 @@ import java.io.ObjectInputStream;
import java.io.ObjectOutput;
import java.io.ObjectOutputStream;
import java.io.Serializable;
-import java.lang.reflect.Method;
+import java.util.Iterator;
+import java.util.Set;
+import javax.security.auth.Subject;
import javax.security.auth.kerberos.KerberosTicket;
import org.ietf.jgss.GSSCredential;
-import org.ietf.jgss.GSSException;
-import org.ietf.jgss.GSSManager;
-import org.ietf.jgss.Oid;
-import org.keycloak.common.constants.KerberosConstants;
-import org.keycloak.common.util.reflections.Reflections;
-import sun.security.jgss.GSSCredentialImpl;
-import sun.security.jgss.GSSManagerImpl;
-import sun.security.jgss.krb5.Krb5InitCredential;
-import sun.security.jgss.krb5.Krb5NameElement;
-import sun.security.jgss.spi.GSSCredentialSpi;
-import sun.security.krb5.Credentials;
/**
* Provides serialization/deserialization of kerberos {@link org.ietf.jgss.GSSCredential}, so it can be transmitted from auth-server to the application
@@ -50,18 +41,9 @@ import sun.security.krb5.Credentials;
*/
public class KerberosSerializationUtils {
- public static final Oid KRB5_OID;
- public static final Oid KRB5_NAME_OID;
public static final String JAVA_INFO;
static {
- try {
- KRB5_OID = new Oid(KerberosConstants.KRB5_OID);
- KRB5_NAME_OID = new Oid(KerberosConstants.KRB5_NAME_OID);
- } catch (GSSException e) {
- throw new RuntimeException(e);
- }
-
String javaVersion = System.getProperty("java.version");
String javaRuntimeVersion = System.getProperty("java.runtime.version");
String javaVendor = System.getProperty("java.vendor");
@@ -72,50 +54,17 @@ public class KerberosSerializationUtils {
private KerberosSerializationUtils() {
}
- public static String serializeCredential(GSSCredential gssCredential) throws KerberosSerializationException {
+ public static String serializeCredential(KerberosTicket kerberosTicket, GSSCredential gssCredential) throws KerberosSerializationException {
try {
if (gssCredential == null) {
throw new KerberosSerializationException("Null credential given as input");
}
- if (!(gssCredential instanceof GSSCredentialImpl)) {
- throw new KerberosSerializationException("Unknown credential type: " + gssCredential.getClass());
- }
-
- GSSCredentialImpl gssCredImpl = (GSSCredentialImpl) gssCredential;
- Oid[] mechs = gssCredImpl.getMechs();
-
- for (Oid oid : mechs) {
- if (oid.equals(KRB5_OID)) {
- int usage = gssCredImpl.getUsage(oid);
- boolean initiate = (usage == GSSCredential.INITIATE_ONLY || usage == GSSCredential.INITIATE_AND_ACCEPT);
-
- GSSCredentialSpi credentialSpi = gssCredImpl.getElement(oid, initiate);
- if (credentialSpi instanceof Krb5InitCredential) {
- Krb5InitCredential credential = (Krb5InitCredential) credentialSpi;
- KerberosTicket kerberosTicket = new KerberosTicket(credential.getEncoded(),
- credential.getClient(),
- credential.getServer(),
- credential.getSessionKey().getEncoded(),
- credential.getSessionKeyType(),
- credential.getFlags(),
- credential.getAuthTime(),
- credential.getStartTime(),
- credential.getEndTime(),
- credential.getRenewTill(),
- credential.getClientAddresses());
- return serialize(kerberosTicket);
- } else {
- throw new KerberosSerializationException("Unsupported type of credentialSpi: " + credentialSpi.getClass());
- }
- }
- }
+ kerberosTicket = KerberosJdkProvider.getProvider().gssCredentialToKerberosTicket(kerberosTicket, gssCredential);
- throw new KerberosSerializationException("Kerberos credential not found. Available mechanisms: " + mechs);
+ return serialize(kerberosTicket);
} catch (IOException e) {
- throw new KerberosSerializationException("Exception occured", e);
- } catch (GSSException e) {
- throw new KerberosSerializationException("Exception occured", e);
+ throw new KerberosSerializationException("Unexpected exception when serialize GSSCredential", e);
}
}
@@ -132,32 +81,12 @@ public class KerberosSerializationUtils {
}
KerberosTicket ticket = (KerberosTicket) deserializedCred;
- String fullName = ticket.getClient().getName();
-
- Method getInstance = Reflections.findDeclaredMethod(Krb5NameElement.class, "getInstance", String.class, Oid.class);
- Krb5NameElement krb5Name = Reflections.invokeMethod(true, getInstance, Krb5NameElement.class, null, fullName, KRB5_NAME_OID);
-
- Credentials krb5CredsInternal = new Credentials(
- ticket.getEncoded(),
- ticket.getClient().getName(),
- ticket.getServer().getName(),
- ticket.getSessionKey().getEncoded(),
- ticket.getSessionKeyType(),
- ticket.getFlags(),
- ticket.getAuthTime(),
- ticket.getStartTime(),
- ticket.getEndTime(),
- ticket.getRenewTill(),
- ticket.getClientAddresses()
- );
-
- Method getInstance2 = Reflections.findDeclaredMethod(Krb5InitCredential.class, "getInstance", Krb5NameElement.class, Credentials.class);
- Krb5InitCredential initCredential = Reflections.invokeMethod(true, getInstance2, Krb5InitCredential.class, null, krb5Name, krb5CredsInternal);
-
- GSSManagerImpl manager = (GSSManagerImpl) GSSManager.getInstance();
- return new GSSCredentialImpl(manager, initCredential);
+
+ return KerberosJdkProvider.getProvider().kerberosTicketToGSSCredential(ticket);
+ } catch (KerberosSerializationException ke) {
+ throw ke;
} catch (Exception ioe) {
- throw new KerberosSerializationException("Exception occured", ioe);
+ throw new KerberosSerializationException("Unexpected exception when deserialize GSSCredential", ioe);
}
}
diff --git a/distribution/adapters/as7-eap6-adapter/as7-modules/src/main/resources/modules/org/keycloak/keycloak-common/main/module.xml b/distribution/adapters/as7-eap6-adapter/as7-modules/src/main/resources/modules/org/keycloak/keycloak-common/main/module.xml
index 0d05dc2..4afb80d 100755
--- a/distribution/adapters/as7-eap6-adapter/as7-modules/src/main/resources/modules/org/keycloak/keycloak-common/main/module.xml
+++ b/distribution/adapters/as7-eap6-adapter/as7-modules/src/main/resources/modules/org/keycloak/keycloak-common/main/module.xml
@@ -28,7 +28,6 @@
<module name="javax.api"/>
<module name="javax.activation.api"/>
<module name="sun.jdk" optional="true" />
- <module name="sun.jdk.jgss" optional="true" />
</dependencies>
</module>
diff --git a/distribution/adapters/as7-eap6-adapter/as7-modules/src/main/resources/modules/org/keycloak/keycloak-core/main/module.xml b/distribution/adapters/as7-eap6-adapter/as7-modules/src/main/resources/modules/org/keycloak/keycloak-core/main/module.xml
index 7821396..1d1be60 100755
--- a/distribution/adapters/as7-eap6-adapter/as7-modules/src/main/resources/modules/org/keycloak/keycloak-core/main/module.xml
+++ b/distribution/adapters/as7-eap6-adapter/as7-modules/src/main/resources/modules/org/keycloak/keycloak-core/main/module.xml
@@ -33,7 +33,6 @@
<module name="javax.api"/>
<module name="javax.activation.api"/>
<module name="sun.jdk" optional="true" />
- <module name="sun.jdk.jgss" optional="true" />
</dependencies>
</module>
diff --git a/distribution/adapters/wf8-adapter/wf8-modules/src/main/resources/modules/org/keycloak/keycloak-common/main/module.xml b/distribution/adapters/wf8-adapter/wf8-modules/src/main/resources/modules/org/keycloak/keycloak-common/main/module.xml
index 0d05dc2..4afb80d 100755
--- a/distribution/adapters/wf8-adapter/wf8-modules/src/main/resources/modules/org/keycloak/keycloak-common/main/module.xml
+++ b/distribution/adapters/wf8-adapter/wf8-modules/src/main/resources/modules/org/keycloak/keycloak-common/main/module.xml
@@ -28,7 +28,6 @@
<module name="javax.api"/>
<module name="javax.activation.api"/>
<module name="sun.jdk" optional="true" />
- <module name="sun.jdk.jgss" optional="true" />
</dependencies>
</module>
diff --git a/distribution/adapters/wf8-adapter/wf8-modules/src/main/resources/modules/org/keycloak/keycloak-core/main/module.xml b/distribution/adapters/wf8-adapter/wf8-modules/src/main/resources/modules/org/keycloak/keycloak-core/main/module.xml
index ab0b69a..f40e1e3 100755
--- a/distribution/adapters/wf8-adapter/wf8-modules/src/main/resources/modules/org/keycloak/keycloak-core/main/module.xml
+++ b/distribution/adapters/wf8-adapter/wf8-modules/src/main/resources/modules/org/keycloak/keycloak-core/main/module.xml
@@ -33,7 +33,6 @@
<module name="javax.api"/>
<module name="javax.activation.api"/>
<module name="sun.jdk" optional="true" />
- <module name="sun.jdk.jgss" optional="true" />
</dependencies>
</module>
diff --git a/distribution/adapters/wildfly-adapter/wildfly-modules/src/main/resources/modules/org/keycloak/keycloak-common/main/module.xml b/distribution/adapters/wildfly-adapter/wildfly-modules/src/main/resources/modules/org/keycloak/keycloak-common/main/module.xml
index 0d05dc2..4afb80d 100755
--- a/distribution/adapters/wildfly-adapter/wildfly-modules/src/main/resources/modules/org/keycloak/keycloak-common/main/module.xml
+++ b/distribution/adapters/wildfly-adapter/wildfly-modules/src/main/resources/modules/org/keycloak/keycloak-common/main/module.xml
@@ -28,7 +28,6 @@
<module name="javax.api"/>
<module name="javax.activation.api"/>
<module name="sun.jdk" optional="true" />
- <module name="sun.jdk.jgss" optional="true" />
</dependencies>
</module>
diff --git a/distribution/adapters/wildfly-adapter/wildfly-modules/src/main/resources/modules/org/keycloak/keycloak-core/main/module.xml b/distribution/adapters/wildfly-adapter/wildfly-modules/src/main/resources/modules/org/keycloak/keycloak-core/main/module.xml
index ab0b69a..f40e1e3 100755
--- a/distribution/adapters/wildfly-adapter/wildfly-modules/src/main/resources/modules/org/keycloak/keycloak-core/main/module.xml
+++ b/distribution/adapters/wildfly-adapter/wildfly-modules/src/main/resources/modules/org/keycloak/keycloak-core/main/module.xml
@@ -33,7 +33,6 @@
<module name="javax.api"/>
<module name="javax.activation.api"/>
<module name="sun.jdk" optional="true" />
- <module name="sun.jdk.jgss" optional="true" />
</dependencies>
</module>
diff --git a/distribution/feature-packs/adapter-feature-pack/src/main/resources/modules/system/add-ons/keycloak/org/keycloak/keycloak-common/main/module.xml b/distribution/feature-packs/adapter-feature-pack/src/main/resources/modules/system/add-ons/keycloak/org/keycloak/keycloak-common/main/module.xml
index 04f1e61..81578ae 100755
--- a/distribution/feature-packs/adapter-feature-pack/src/main/resources/modules/system/add-ons/keycloak/org/keycloak/keycloak-common/main/module.xml
+++ b/distribution/feature-packs/adapter-feature-pack/src/main/resources/modules/system/add-ons/keycloak/org/keycloak/keycloak-common/main/module.xml
@@ -28,7 +28,6 @@
<module name="javax.api"/>
<module name="javax.activation.api"/>
<module name="sun.jdk" optional="true" />
- <module name="sun.jdk.jgss" optional="true" />
</dependencies>
</module>
diff --git a/distribution/feature-packs/adapter-feature-pack/src/main/resources/modules/system/add-ons/keycloak/org/keycloak/keycloak-core/main/module.xml b/distribution/feature-packs/adapter-feature-pack/src/main/resources/modules/system/add-ons/keycloak/org/keycloak/keycloak-core/main/module.xml
index 0ca522d..885b944 100755
--- a/distribution/feature-packs/adapter-feature-pack/src/main/resources/modules/system/add-ons/keycloak/org/keycloak/keycloak-core/main/module.xml
+++ b/distribution/feature-packs/adapter-feature-pack/src/main/resources/modules/system/add-ons/keycloak/org/keycloak/keycloak-core/main/module.xml
@@ -33,7 +33,6 @@
<module name="javax.api"/>
<module name="javax.activation.api"/>
<module name="sun.jdk" optional="true" />
- <module name="sun.jdk.jgss" optional="true" />
</dependencies>
</module>
diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/keycloak/org/keycloak/keycloak-common/main/module.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/keycloak/org/keycloak/keycloak-common/main/module.xml
index 04f1e61..81578ae 100755
--- a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/keycloak/org/keycloak/keycloak-common/main/module.xml
+++ b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/keycloak/org/keycloak/keycloak-common/main/module.xml
@@ -28,7 +28,6 @@
<module name="javax.api"/>
<module name="javax.activation.api"/>
<module name="sun.jdk" optional="true" />
- <module name="sun.jdk.jgss" optional="true" />
</dependencies>
</module>
diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/keycloak/org/keycloak/keycloak-core/main/module.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/keycloak/org/keycloak/keycloak-core/main/module.xml
index ca35e20..40b0e69 100755
--- a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/keycloak/org/keycloak/keycloak-core/main/module.xml
+++ b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/keycloak/org/keycloak/keycloak-core/main/module.xml
@@ -33,7 +33,6 @@
<module name="javax.api"/>
<module name="javax.activation.api"/>
<module name="sun.jdk" optional="true" />
- <module name="sun.jdk.jgss" optional="true" />
</dependencies>
</module>
diff --git a/distribution/saml-adapters/as7-eap6-adapter/as7-modules/src/main/resources/modules/org/keycloak/keycloak-common/main/module.xml b/distribution/saml-adapters/as7-eap6-adapter/as7-modules/src/main/resources/modules/org/keycloak/keycloak-common/main/module.xml
index 0d05dc2..4afb80d 100755
--- a/distribution/saml-adapters/as7-eap6-adapter/as7-modules/src/main/resources/modules/org/keycloak/keycloak-common/main/module.xml
+++ b/distribution/saml-adapters/as7-eap6-adapter/as7-modules/src/main/resources/modules/org/keycloak/keycloak-common/main/module.xml
@@ -28,7 +28,6 @@
<module name="javax.api"/>
<module name="javax.activation.api"/>
<module name="sun.jdk" optional="true" />
- <module name="sun.jdk.jgss" optional="true" />
</dependencies>
</module>
diff --git a/distribution/saml-adapters/wildfly-adapter/wildfly-modules/src/main/resources/modules/org/keycloak/keycloak-common/main/module.xml b/distribution/saml-adapters/wildfly-adapter/wildfly-modules/src/main/resources/modules/org/keycloak/keycloak-common/main/module.xml
index 0d05dc2..4afb80d 100755
--- a/distribution/saml-adapters/wildfly-adapter/wildfly-modules/src/main/resources/modules/org/keycloak/keycloak-common/main/module.xml
+++ b/distribution/saml-adapters/wildfly-adapter/wildfly-modules/src/main/resources/modules/org/keycloak/keycloak-common/main/module.xml
@@ -28,7 +28,6 @@
<module name="javax.api"/>
<module name="javax.activation.api"/>
<module name="sun.jdk" optional="true" />
- <module name="sun.jdk.jgss" optional="true" />
</dependencies>
</module>
diff --git a/docbook/auth-server-docs/reference/en/en-US/modules/client-registration.xml b/docbook/auth-server-docs/reference/en/en-US/modules/client-registration.xml
index d60c1cd..d1d5838 100755
--- a/docbook/auth-server-docs/reference/en/en-US/modules/client-registration.xml
+++ b/docbook/auth-server-docs/reference/en/en-US/modules/client-registration.xml
@@ -155,7 +155,7 @@ Authorization: basic BASE64(client-id + ':' + client-secret)
</para>
<para>
To retrieve the Adapter Configuration then do a HTTP GET to:
- <literal><KEYCLOAK URL>//realms/<realm>/clients-registrations/installation/<client id></literal>
+ <literal><KEYCLOAK URL>//realms/<realm>/clients-registrations/install/<client id></literal>
</para>
<para>
No authentication is required for public clients. This means that for the JavaScript adapter you can
diff --git a/federation/kerberos/src/main/java/org/keycloak/federation/kerberos/CommonKerberosConfig.java b/federation/kerberos/src/main/java/org/keycloak/federation/kerberos/CommonKerberosConfig.java
index c2eccde..4d3bf62 100644
--- a/federation/kerberos/src/main/java/org/keycloak/federation/kerberos/CommonKerberosConfig.java
+++ b/federation/kerberos/src/main/java/org/keycloak/federation/kerberos/CommonKerberosConfig.java
@@ -52,7 +52,7 @@ public abstract class CommonKerberosConfig {
return getConfig().get(KerberosConstants.KEYTAB);
}
- public boolean getDebug() {
+ public boolean isDebug() {
return Boolean.valueOf(getConfig().get(KerberosConstants.DEBUG));
}
diff --git a/federation/kerberos/src/main/java/org/keycloak/federation/kerberos/impl/KerberosServerSubjectAuthenticator.java b/federation/kerberos/src/main/java/org/keycloak/federation/kerberos/impl/KerberosServerSubjectAuthenticator.java
index 2a155ed..aeaa074 100644
--- a/federation/kerberos/src/main/java/org/keycloak/federation/kerberos/impl/KerberosServerSubjectAuthenticator.java
+++ b/federation/kerberos/src/main/java/org/keycloak/federation/kerberos/impl/KerberosServerSubjectAuthenticator.java
@@ -17,16 +17,18 @@
package org.keycloak.federation.kerberos.impl;
-import java.util.HashMap;
-import java.util.Map;
+import java.io.IOException;
import javax.security.auth.Subject;
-import javax.security.auth.login.AppConfigurationEntry;
+import javax.security.auth.callback.Callback;
+import javax.security.auth.callback.CallbackHandler;
+import javax.security.auth.callback.UnsupportedCallbackException;
import javax.security.auth.login.Configuration;
import javax.security.auth.login.LoginContext;
import javax.security.auth.login.LoginException;
import org.jboss.logging.Logger;
+import org.keycloak.common.util.KerberosJdkProvider;
import org.keycloak.federation.kerberos.CommonKerberosConfig;
/**
@@ -36,20 +38,32 @@ public class KerberosServerSubjectAuthenticator {
private static final Logger logger = Logger.getLogger(KerberosServerSubjectAuthenticator.class);
+ private static final CallbackHandler NO_CALLBACK_HANDLER = new CallbackHandler() {
+
+ @Override
+ public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {
+ throw new UnsupportedCallbackException(callbacks[0]);
+ }
+ };
+
+
private final CommonKerberosConfig config;
private LoginContext loginContext;
+
public KerberosServerSubjectAuthenticator(CommonKerberosConfig config) {
this.config = config;
}
+
public Subject authenticateServerSubject() throws LoginException {
Configuration config = createJaasConfiguration();
- loginContext = new LoginContext("does-not-matter", null, null, config);
+ loginContext = new LoginContext("does-not-matter", null, NO_CALLBACK_HANDLER, config);
loginContext.login();
return loginContext.getSubject();
}
+
public void logoutServerSubject() {
if (loginContext != null) {
try {
@@ -60,24 +74,9 @@ public class KerberosServerSubjectAuthenticator {
}
}
+
protected Configuration createJaasConfiguration() {
- return new Configuration() {
-
- @Override
- public AppConfigurationEntry[] getAppConfigurationEntry(String name) {
- Map<String, Object> options = new HashMap<String, Object>();
- options.put("storeKey", "true");
- options.put("doNotPrompt", "true");
- options.put("isInitiator", "false");
- options.put("useKeyTab", "true");
-
- options.put("keyTab", config.getKeyTab());
- options.put("principal", config.getServerPrincipal());
- options.put("debug", String.valueOf(config.getDebug()));
- AppConfigurationEntry kerberosLMConfiguration = new AppConfigurationEntry("com.sun.security.auth.module.Krb5LoginModule", AppConfigurationEntry.LoginModuleControlFlag.REQUIRED, options);
- return new AppConfigurationEntry[] { kerberosLMConfiguration };
- }
- };
+ return KerberosJdkProvider.getProvider().createJaasConfigurationForServer(config.getKeyTab(), config.getServerPrincipal(), config.isDebug());
}
}
diff --git a/federation/kerberos/src/main/java/org/keycloak/federation/kerberos/impl/KerberosUsernamePasswordAuthenticator.java b/federation/kerberos/src/main/java/org/keycloak/federation/kerberos/impl/KerberosUsernamePasswordAuthenticator.java
index f18cf2c..2254a6e 100644
--- a/federation/kerberos/src/main/java/org/keycloak/federation/kerberos/impl/KerberosUsernamePasswordAuthenticator.java
+++ b/federation/kerberos/src/main/java/org/keycloak/federation/kerberos/impl/KerberosUsernamePasswordAuthenticator.java
@@ -33,6 +33,7 @@ import javax.security.auth.login.LoginContext;
import javax.security.auth.login.LoginException;
import org.jboss.logging.Logger;
+import org.keycloak.common.util.KerberosJdkProvider;
import org.keycloak.federation.kerberos.CommonKerberosConfig;
import org.keycloak.models.ModelException;
@@ -58,7 +59,7 @@ public class KerberosUsernamePasswordAuthenticator {
* @return true if user available
*/
public boolean isUserAvailable(String username) {
- logger.debug("Checking existence of user: " + username);
+ logger.debugf("Checking existence of user: %s", username);
try {
String principal = getKerberosPrincipal(username);
loginContext = new LoginContext("does-not-matter", null,
@@ -70,7 +71,7 @@ public class KerberosUsernamePasswordAuthenticator {
throw new IllegalStateException("Didn't expect to end here");
} catch (LoginException le) {
String message = le.getMessage();
- logger.debug("Message from kerberos: " + message);
+ logger.debugf("Message from kerberos: %s", message);
checkKerberosServerAvailable(le);
@@ -128,6 +129,7 @@ public class KerberosUsernamePasswordAuthenticator {
return loginContext.getSubject();
}
+
public void logoutSubject() {
if (loginContext != null) {
try {
@@ -139,7 +141,6 @@ public class KerberosUsernamePasswordAuthenticator {
}
-
protected String getKerberosPrincipal(String username) throws LoginException {
if (username.contains("@")) {
String[] tokens = username.split("@");
@@ -156,6 +157,7 @@ public class KerberosUsernamePasswordAuthenticator {
return username + "@" + config.getKerberosRealm();
}
+
protected CallbackHandler createJaasCallbackHandler(final String principal, final String password) {
return new CallbackHandler() {
@@ -176,17 +178,8 @@ public class KerberosUsernamePasswordAuthenticator {
};
}
- protected Configuration createJaasConfiguration() {
- return new Configuration() {
- @Override
- public AppConfigurationEntry[] getAppConfigurationEntry(String name) {
- Map<String, Object> options = new HashMap<String, Object>();
- options.put("storeKey", "true");
- options.put("debug", String.valueOf(config.getDebug()));
- AppConfigurationEntry kerberosLMConfiguration = new AppConfigurationEntry("com.sun.security.auth.module.Krb5LoginModule", AppConfigurationEntry.LoginModuleControlFlag.REQUIRED, options);
- return new AppConfigurationEntry[] { kerberosLMConfiguration };
- }
- };
+ protected Configuration createJaasConfiguration() {
+ return KerberosJdkProvider.getProvider().createJaasConfigurationForUsernamePasswordLogin(config.isDebug());
}
}
diff --git a/federation/kerberos/src/main/java/org/keycloak/federation/kerberos/impl/SPNEGOAuthenticator.java b/federation/kerberos/src/main/java/org/keycloak/federation/kerberos/impl/SPNEGOAuthenticator.java
index f09ea6e..c2b928e 100644
--- a/federation/kerberos/src/main/java/org/keycloak/federation/kerberos/impl/SPNEGOAuthenticator.java
+++ b/federation/kerberos/src/main/java/org/keycloak/federation/kerberos/impl/SPNEGOAuthenticator.java
@@ -19,15 +19,21 @@ package org.keycloak.federation.kerberos.impl;
import java.io.IOException;
import java.security.PrivilegedExceptionAction;
+import java.util.Iterator;
+import java.util.Set;
import javax.security.auth.Subject;
+import javax.security.auth.kerberos.KerberosTicket;
+import org.ietf.jgss.Oid;
+import org.keycloak.common.constants.KerberosConstants;
import org.keycloak.common.util.Base64;
import org.ietf.jgss.GSSContext;
import org.ietf.jgss.GSSCredential;
import org.ietf.jgss.GSSException;
import org.ietf.jgss.GSSManager;
import org.jboss.logging.Logger;
+import org.keycloak.common.util.KerberosJdkProvider;
import org.keycloak.federation.kerberos.CommonKerberosConfig;
import org.keycloak.common.util.KerberosSerializationUtils;
@@ -45,6 +51,7 @@ public class SPNEGOAuthenticator {
private boolean authenticated = false;
private String authenticatedKerberosPrincipal = null;
private GSSCredential delegationCredential;
+ private KerberosTicket kerberosTicket;
private String responseToken = null;
public SPNEGOAuthenticator(CommonKerberosConfig kerberosConfig, KerberosServerSubjectAuthenticator kerberosSubjectAuthenticator, String spnegoToken) {
@@ -61,6 +68,14 @@ public class SPNEGOAuthenticator {
try {
Subject serverSubject = kerberosSubjectAuthenticator.authenticateServerSubject();
authenticated = Subject.doAs(serverSubject, new AcceptSecContext());
+
+ // kerberosTicketis available in IBM JDK in case that GSSContext supports delegated credentials
+ Set<KerberosTicket> kerberosTickets = serverSubject.getPrivateCredentials(KerberosTicket.class);
+ Iterator<KerberosTicket> iterator = kerberosTickets.iterator();
+ if (iterator.hasNext()) {
+ kerberosTicket = iterator.next();
+ }
+
} catch (Exception e) {
log.warn("SPNEGO login failed", e);
} finally {
@@ -89,7 +104,7 @@ public class SPNEGOAuthenticator {
if (log.isTraceEnabled()) {
log.trace("Serializing credential " + delegationCredential);
}
- return KerberosSerializationUtils.serializeCredential(delegationCredential);
+ return KerberosSerializationUtils.serializeCredential(kerberosTicket, delegationCredential);
} catch (KerberosSerializationUtils.KerberosSerializationException kse) {
log.warn("Couldn't serialize credential: " + delegationCredential, kse);
return null;
@@ -150,7 +165,10 @@ public class SPNEGOAuthenticator {
protected GSSContext establishContext() throws GSSException, IOException {
GSSManager manager = GSSManager.getInstance();
- GSSContext gssContext = manager.createContext((GSSCredential) null);
+
+ Oid[] supportedMechs = new Oid[] { KerberosConstants.KRB5_OID, KerberosConstants.SPNEGO_OID };
+ GSSCredential gssCredential = manager.createCredential(null, GSSCredential.INDEFINITE_LIFETIME, supportedMechs, GSSCredential.ACCEPT_ONLY);
+ GSSContext gssContext = manager.createContext(gssCredential);
byte[] inputToken = Base64.decode(spnegoToken);
byte[] respToken = gssContext.acceptSecContext(inputToken, 0, inputToken.length);
pom.xml 7(+5 -2)
diff --git a/pom.xml b/pom.xml
index 8486817..a736a45 100644
--- a/pom.xml
+++ b/pom.xml
@@ -72,8 +72,7 @@
<undertow.version>1.3.15.Final</undertow.version>
<wildfly.core.version>2.0.10.Final</wildfly.core.version>
<wildfly.build-tools.version>1.1.0.Final</wildfly.build-tools.version>
- <!--<xmlsec.version>2.0.5</xmlsec.version>--> <!-- WILDFLY VERSION -->
- <xmlsec.version>1.5.1</xmlsec.version>
+ <xmlsec.version>2.0.5</xmlsec.version>
<!-- Others -->
<apacheds.version>2.0.0-M17</apacheds.version>
@@ -377,6 +376,10 @@
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
</exclusion>
+ <exclusion>
+ <groupId>org.codehaus.woodstox</groupId>
+ <artifactId>woodstox-core-asl</artifactId>
+ </exclusion>
</exclusions>
</dependency>
<dependency>
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/federation/AbstractKerberosTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/federation/AbstractKerberosTest.java
index 16e302e..12f0f5e 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/federation/AbstractKerberosTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/federation/AbstractKerberosTest.java
@@ -192,6 +192,10 @@ public abstract class AbstractKerberosTest {
loginPage.login("jduke", "theduke");
changePasswordPage.assertCurrent();
+ // Bad existing password
+ changePasswordPage.changePassword("theduke-invalid", "newPass", "newPass");
+ Assert.assertTrue(driver.getPageSource().contains("Invalid existing password."));
+
// Change password is not possible as editMode is READ_ONLY
changePasswordPage.changePassword("theduke", "newPass", "newPass");
Assert.assertTrue(driver.getPageSource().contains("You can't update your password as your account is read only"));
diff --git a/testsuite/integration/src/test/resources/kerberos/kerberos-ldap-connection.properties b/testsuite/integration/src/test/resources/kerberos/kerberos-ldap-connection.properties
index a0ea537..3170d6c 100644
--- a/testsuite/integration/src/test/resources/kerberos/kerberos-ldap-connection.properties
+++ b/testsuite/integration/src/test/resources/kerberos/kerberos-ldap-connection.properties
@@ -31,4 +31,4 @@ idm.test.kerberos.allow.kerberos.authentication=true
idm.test.kerberos.realm=KEYCLOAK.ORG
idm.test.kerberos.server.principal=HTTP/localhost@KEYCLOAK.ORG
idm.test.kerberos.debug=false
-idm.test.kerberos.use.kerberos.for.password.authentication=false
\ No newline at end of file
+idm.test.kerberos.use.kerberos.for.password.authentication=true
\ No newline at end of file
diff --git a/testsuite/integration/src/test/resources/kerberos/test-krb5.conf b/testsuite/integration/src/test/resources/kerberos/test-krb5.conf
index a775b47..6989b7f 100644
--- a/testsuite/integration/src/test/resources/kerberos/test-krb5.conf
+++ b/testsuite/integration/src/test/resources/kerberos/test-krb5.conf
@@ -1,8 +1,8 @@
[libdefaults]
default_realm = KEYCLOAK.ORG
- default_tgs_enctypes = des3-cbc-sha1-kd aes256-cts-hmac-sha1-96 rc4-hmac
- default_tkt_enctypes = des3-cbc-sha1-kd aes256-cts-hmac-sha1-96 rc4-hmac
- permitted_enctypes = des3-cbc-sha1-kd aes256-cts-hmac-sha1-96 rc4-hmac
+ default_tgs_enctypes = des3-cbc-sha1-kd aes256-cts-hmac-sha1-96 rc4-hmac aes128-cts-hmac-sha1-96
+ default_tkt_enctypes = des3-cbc-sha1-kd aes256-cts-hmac-sha1-96 rc4-hmac aes128-cts-hmac-sha1-96
+ permitted_enctypes = des3-cbc-sha1-kd aes256-cts-hmac-sha1-96 rc4-hmac aes128-cts-hmac-sha1-96
kdc_timeout = 30000
dns_lookup_realm = false
dns_lookup_kdc = false
diff --git a/util/embedded-ldap/src/main/java/org/keycloak/util/ldap/KerberosEmbeddedServer.java b/util/embedded-ldap/src/main/java/org/keycloak/util/ldap/KerberosEmbeddedServer.java
index 1f8fe07..d7f868f 100644
--- a/util/embedded-ldap/src/main/java/org/keycloak/util/ldap/KerberosEmbeddedServer.java
+++ b/util/embedded-ldap/src/main/java/org/keycloak/util/ldap/KerberosEmbeddedServer.java
@@ -19,8 +19,11 @@ package org.keycloak.util.ldap;
import java.io.IOException;
import java.lang.reflect.Field;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.HashSet;
+import java.util.Locale;
import java.util.Properties;
import java.util.Set;
@@ -43,13 +46,7 @@ import org.apache.directory.server.protocol.shared.transport.UdpTransport;
import org.apache.directory.shared.kerberos.KerberosTime;
import org.apache.directory.shared.kerberos.KerberosUtils;
import org.apache.directory.shared.kerberos.codec.types.EncryptionType;
-import org.ietf.jgss.GSSException;
-import org.ietf.jgss.GSSManager;
-import org.ietf.jgss.GSSName;
import org.jboss.logging.Logger;
-import org.keycloak.common.util.KerberosSerializationUtils;
-import sun.security.jgss.GSSNameImpl;
-import sun.security.jgss.krb5.Krb5NameElement;
/**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
@@ -113,15 +110,8 @@ public class KerberosEmbeddedServer extends LDAPEmbeddedServer {
this.kdcEncryptionTypes = readProperty(PROPERTY_KDC_ENCTYPES, DEFAULT_KDC_ENCRYPTION_TYPES);
if (ldapSaslPrincipal == null || ldapSaslPrincipal.isEmpty()) {
- try {
- // Same algorithm like sun.security.krb5.PrincipalName constructor
- GSSName gssName = GSSManager.getInstance().createName("ldap@" + bindHost, GSSName.NT_HOSTBASED_SERVICE);
- GSSNameImpl gssName1 = (GSSNameImpl) gssName;
- Krb5NameElement krb5NameElement = (Krb5NameElement) gssName1.getElement(KerberosSerializationUtils.KRB5_OID);
- this.ldapSaslPrincipal = krb5NameElement.getKrb5PrincipalName().toString();
- } catch (GSSException uhe) {
- throw new RuntimeException(uhe);
- }
+ String hostname = getHostnameForSASLPrincipal(bindHost);
+ this.ldapSaslPrincipal = "ldap/" + hostname + "@" + this.kerberosRealm;
}
}
@@ -219,6 +209,31 @@ public class KerberosEmbeddedServer extends LDAPEmbeddedServer {
}
+ // Forked from sun.security.krb5.PrincipalName constructor
+ private String getHostnameForSASLPrincipal(String hostName) {
+ try {
+ // RFC4120 does not recommend canonicalizing a hostname.
+ // However, for compatibility reason, we will try
+ // canonicalize it and see if the output looks better.
+
+ String canonicalized = (InetAddress.getByName(hostName)).
+ getCanonicalHostName();
+
+ // Looks if canonicalized is a longer format of hostName,
+ // we accept cases like
+ // bunny -> bunny.rabbit.hole
+ if (canonicalized.toLowerCase(Locale.ENGLISH).startsWith(
+ hostName.toLowerCase(Locale.ENGLISH)+".")) {
+ hostName = canonicalized;
+ }
+ } catch (UnknownHostException | SecurityException e) {
+ // not canonicalized or no permission to do so, use old
+ }
+ return hostName.toLowerCase(Locale.ENGLISH);
+ }
+
+
+
/**
* Replacement of apacheDS KdcServer class with disabled ticket replay cache.
*