keycloak-aplcache

Changes

Details

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 1acf907..f06ca93 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
@@ -40,7 +40,7 @@ public class KerberosUsernamePasswordAuthenticator {
 
     private static final Logger logger = Logger.getLogger(KerberosUsernamePasswordAuthenticator.class);
 
-    private final CommonKerberosConfig config;
+    protected final CommonKerberosConfig config;
     private LoginContext loginContext;
 
     public KerberosUsernamePasswordAuthenticator(CommonKerberosConfig config) {
diff --git a/misc/Testsuite.md b/misc/Testsuite.md
index df7bfc6..1d7565c 100644
--- a/misc/Testsuite.md
+++ b/misc/Testsuite.md
@@ -111,7 +111,14 @@ To start a ApacheDS based Kerberos server for testing Kerberos + LDAP sending ru
     mvn exec:java -Pkerberos
     
 There are additional system properties you can use to configure (See LDAPEmbeddedServer and KerberosEmbeddedServer class for details) but for testing purposes default values should be good.
-By default ApacheDS LDAP server will be running on localhost:10389 and Kerberos KDC on localhost:6088 . 
+By default ApacheDS LDAP server will be running on localhost:10389 and Kerberos KDC on localhost:6088 .
+
+The alternative is to start Kerberos with the alternative realm KC2.COM instead of default KEYCLOAK.ORG. 
+The ApacheDS server will be then started with all ports shifted by 1000 (EG. LDAP on 11389, Kerberos KDC on 7088).
+This allows to start 2 kerberos servers in parallel to test things like Kerberos cross-realm trust:
+
+    mvn exec:java -Pkerberos -Dkeycloak.kerberos.realm=KC2.COM
+ 
 
 Once kerberos is running, you can create LDAP Federation provider in Keycloak admin console with same settings like mentioned in previous LDAP section. 
 But additionally you can enable Kerberos authentication in LDAP provider with the settings like:
diff --git a/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/java/org/keycloak/testsuite/rest/resource/TestLDAPResource.java b/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/java/org/keycloak/testsuite/rest/resource/TestLDAPResource.java
index bae7cbe..f4c7f68 100644
--- a/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/java/org/keycloak/testsuite/rest/resource/TestLDAPResource.java
+++ b/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/java/org/keycloak/testsuite/rest/resource/TestLDAPResource.java
@@ -20,6 +20,7 @@ package org.keycloak.testsuite.rest.resource;
 import java.util.Map;
 
 import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
 import javax.ws.rs.POST;
 import javax.ws.rs.Path;
 import javax.ws.rs.Produces;
@@ -161,4 +162,20 @@ public class TestLDAPResource {
         LDAPObject james = LDAPTestUtils.addLDAPUser(ldapFedProvider, realm, "jameskeycloak", "James", "Brown", "james@email.org", null, "8910");
         LDAPTestUtils.updateLDAPPassword(ldapFedProvider, james, "Password1");
     }
+
+
+    /**
+     * Remove specified user directly just from the LDAP server
+     */
+    @DELETE
+    @Path("/remove-ldap-user")
+    @Consumes(MediaType.APPLICATION_JSON)
+    public void removeLDAPUser(@QueryParam("username") String ldapUsername) {
+        ComponentModel ldapCompModel = LDAPTestUtils.getLdapProviderModel(session, realm);
+        UserStorageProviderModel ldapModel = new UserStorageProviderModel(ldapCompModel);
+        LDAPStorageProvider ldapProvider = LDAPTestUtils.getLdapProvider(session, ldapModel);
+
+        LDAPTestUtils.removeLDAPUserByUsername(ldapProvider, realm,
+                ldapProvider.getLdapIdentityStore().getConfig(), ldapUsername);
+    }
 }
diff --git a/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/java/org/keycloak/testsuite/util/LDAPTestUtils.java b/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/java/org/keycloak/testsuite/util/LDAPTestUtils.java
index bbec673..4be3fa9 100644
--- a/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/java/org/keycloak/testsuite/util/LDAPTestUtils.java
+++ b/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/java/org/keycloak/testsuite/util/LDAPTestUtils.java
@@ -29,6 +29,7 @@ import org.keycloak.representations.idm.CredentialRepresentation;
 import org.keycloak.storage.UserStorageProvider;
 import org.keycloak.storage.ldap.LDAPStorageProvider;
 import org.keycloak.storage.ldap.LDAPConfig;
+import org.keycloak.storage.ldap.LDAPStorageProviderFactory;
 import org.keycloak.storage.ldap.LDAPUtils;
 import org.keycloak.storage.ldap.idm.model.LDAPObject;
 import org.keycloak.storage.ldap.idm.query.internal.LDAPQuery;
@@ -120,7 +121,7 @@ public class LDAPTestUtils {
     public static ComponentModel getLdapProviderModel(KeycloakSession session, RealmModel realm) {
         List<ComponentModel> components = realm.getComponents(realm.getId(), UserStorageProvider.class.getName());
         for (ComponentModel component : components) {
-            if ("test-ldap".equals(component.getName())) {
+            if (LDAPStorageProviderFactory.PROVIDER_NAME.equals(component.getProviderId())) {
                 return component;
             }
         }
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/client/resources/TestingLDAPResource.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/client/resources/TestingLDAPResource.java
index 4eb45a1..99c2a06 100644
--- a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/client/resources/TestingLDAPResource.java
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/client/resources/TestingLDAPResource.java
@@ -20,6 +20,7 @@ package org.keycloak.testsuite.client.resources;
 import java.util.Map;
 
 import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
 import javax.ws.rs.POST;
 import javax.ws.rs.Path;
 import javax.ws.rs.Produces;
@@ -53,4 +54,13 @@ public interface TestingLDAPResource {
     @Produces(MediaType.APPLICATION_JSON)
     @Consumes(MediaType.APPLICATION_JSON)
     void prepareGroupsLDAPTest();
+
+
+    /**
+     * Remove specified user directly just from the LDAP server
+     */
+    @DELETE
+    @Path("/remove-ldap-user")
+    @Consumes(MediaType.APPLICATION_JSON)
+    void removeLDAPUser(@QueryParam("username") String ldapUsername);
 }
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/util/KerberosRule.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/util/KerberosRule.java
index 223a387..ed6702c 100644
--- a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/util/KerberosRule.java
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/util/KerberosRule.java
@@ -34,9 +34,11 @@ public class KerberosRule extends LDAPRule {
     private static final Logger log = Logger.getLogger(KerberosRule.class);
 
     private final String configLocation;
+    private final String kerberosRealm;
 
-    public KerberosRule(String configLocation) {
+    public KerberosRule(String configLocation, String kerberosRealm) {
         this.configLocation = configLocation;
+        this.kerberosRealm = kerberosRealm;
 
         // Global kerberos configuration
         String krb5ConfPath = getKrb5ConfPath();
@@ -61,11 +63,25 @@ public class KerberosRule extends LDAPRule {
         return configLocation;
     }
 
+
+    public String getKerberosRealm() {
+        return kerberosRealm;
+    }
+
+
     @Override
     protected LDAPEmbeddedServer createServer() {
         Properties defaultProperties = new Properties();
         defaultProperties.setProperty(LDAPEmbeddedServer.PROPERTY_DSF, LDAPEmbeddedServer.DSF_INMEMORY);
-        defaultProperties.setProperty(LDAPEmbeddedServer.PROPERTY_LDIF_FILE, "classpath:kerberos/users-kerberos.ldif");
+
+        KerberosEmbeddedServer.configureDefaultPropertiesForRealm(this.kerberosRealm, defaultProperties);
+
+        // Improve if more flexibility is needed
+        if ("KEYCLOAK.ORG".equals(kerberosRealm)) {
+            defaultProperties.setProperty(LDAPEmbeddedServer.PROPERTY_LDIF_FILE, "classpath:kerberos/users-kerberos.ldif");
+        } else if ("KC2.COM".equals(kerberosRealm)) {
+            defaultProperties.setProperty(LDAPEmbeddedServer.PROPERTY_LDIF_FILE, "classpath:kerberos/users-kerberos-kc2.ldif");
+        }
 
         return new KerberosEmbeddedServer(defaultProperties);
     }
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/federation/kerberos/AbstractKerberosSingleRealmTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/federation/kerberos/AbstractKerberosSingleRealmTest.java
new file mode 100644
index 0000000..0adce7c
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/federation/kerberos/AbstractKerberosSingleRealmTest.java
@@ -0,0 +1,173 @@
+/*
+ * Copyright 2017 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.testsuite.federation.kerberos;
+
+import java.util.List;
+
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.Response;
+
+import org.ietf.jgss.GSSCredential;
+import org.junit.Assume;
+import org.junit.Test;
+import org.keycloak.admin.client.resource.ClientResource;
+import org.keycloak.common.constants.KerberosConstants;
+import org.keycloak.common.util.KerberosSerializationUtils;
+import org.keycloak.events.Details;
+import org.keycloak.models.AuthenticationExecutionModel;
+import org.keycloak.models.ProtocolMapperModel;
+import org.keycloak.models.utils.ModelToRepresentation;
+import org.keycloak.protocol.oidc.mappers.UserSessionNoteMapper;
+import org.keycloak.representations.AccessToken;
+import org.keycloak.representations.idm.ProtocolMapperRepresentation;
+import org.keycloak.representations.idm.UserRepresentation;
+import org.keycloak.storage.UserStorageProvider;
+import org.keycloak.testsuite.Assert;
+import org.keycloak.testsuite.admin.ApiUtil;
+
+import static org.keycloak.testsuite.admin.ApiUtil.findClientByClientId;
+
+/**
+ * Contains just test methods
+ *
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+public abstract class AbstractKerberosSingleRealmTest extends AbstractKerberosTest {
+
+    @Test
+    public void spnegoNotAvailableTest() throws Exception {
+        initHttpClient(false);
+
+        String kcLoginPageLocation = oauth.getLoginFormUrl();
+
+        Response response = client.target(kcLoginPageLocation).request().get();
+        Assert.assertEquals(401, response.getStatus());
+        Assert.assertEquals(KerberosConstants.NEGOTIATE, response.getHeaderString(HttpHeaders.WWW_AUTHENTICATE));
+        String responseText = response.readEntity(String.class);
+        response.close();
+    }
+
+    // KEYCLOAK-7823
+    @Test
+    public void spnegoLoginWithRequiredKerberosAuthExecutionTest() {
+        AuthenticationExecutionModel.Requirement oldRequirement = updateKerberosAuthExecutionRequirement(
+                AuthenticationExecutionModel.Requirement.REQUIRED);
+        Response response = spnegoLogin("hnelson", "secret");
+        updateKerberosAuthExecutionRequirement(oldRequirement);
+
+        Assert.assertEquals(Response.Status.OK.getStatusCode(), response.getStatus());
+    }
+
+
+    // KEYCLOAK-2102
+    @Test
+    public void spnegoCaseInsensitiveTest() throws Exception {
+        assertSuccessfulSpnegoLogin(getKerberosRule().isCaseSensitiveLogin() ? "MyDuke" : "myduke", "myduke", "theduke");
+    }
+
+
+    @Test
+    public void usernamePasswordLoginTest() throws Exception {
+        // Change editMode to READ_ONLY
+        updateProviderEditMode(UserStorageProvider.EditMode.READ_ONLY);
+
+        // Login with username/password from kerberos
+        changePasswordPage.open();
+        loginPage.assertCurrent();
+        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"));
+
+        // Change editMode to UNSYNCED
+        updateProviderEditMode(UserStorageProvider.EditMode.UNSYNCED);
+
+        // Successfully change password now
+        changePasswordPage.changePassword("theduke", "newPass", "newPass");
+        Assert.assertTrue(driver.getPageSource().contains("Your password has been updated."));
+        changePasswordPage.logout();
+
+        // Login with old password doesn't work, but with new password works
+        loginPage.login("jduke", "theduke");
+        loginPage.assertCurrent();
+        loginPage.login("jduke", "newPass");
+        changePasswordPage.assertCurrent();
+        changePasswordPage.logout();
+
+        // Assert SPNEGO login still with the old password as mode is unsynced
+        events.clear();
+        Response spnegoResponse = spnegoLogin("jduke", "theduke");
+        Assert.assertEquals(302, spnegoResponse.getStatus());
+        List<UserRepresentation> users = testRealmResource().users().search("jduke", 0, 1);
+        String userId = users.get(0).getId();
+        events.expectLogin()
+                .client("kerberos-app")
+                .user(userId)
+                .detail(Details.USERNAME, "jduke")
+                .assertEvent();
+
+        String codeUrl = spnegoResponse.getLocation().toString();
+
+        assertAuthenticationSuccess(codeUrl);
+    }
+
+
+    @Test
+    public void credentialDelegationTest() throws Exception {
+        Assume.assumeTrue("Ignoring test as the embedded server is not started", getKerberosRule().isStartEmbeddedLdapServer());
+        // Add kerberos delegation credential mapper
+        ProtocolMapperModel protocolMapper = UserSessionNoteMapper.createClaimMapper(KerberosConstants.GSS_DELEGATION_CREDENTIAL_DISPLAY_NAME,
+                KerberosConstants.GSS_DELEGATION_CREDENTIAL,
+                KerberosConstants.GSS_DELEGATION_CREDENTIAL, "String",
+                true, false);
+        ProtocolMapperRepresentation protocolMapperRep = ModelToRepresentation.toRepresentation(protocolMapper);
+        ClientResource clientResource = findClientByClientId(testRealmResource(), "kerberos-app");
+        Response response = clientResource.getProtocolMappers().createMapper(protocolMapperRep);
+        String protocolMapperId = ApiUtil.getCreatedId(response);
+        response.close();
+
+        // SPNEGO login
+        AccessToken token = assertSuccessfulSpnegoLogin("hnelson", "hnelson", "secret");
+
+        // Assert kerberos ticket in the accessToken can be re-used to authenticate against other 3rd party kerberos service (ApacheDS Server in this case)
+        String serializedGssCredential = (String) token.getOtherClaims().get(KerberosConstants.GSS_DELEGATION_CREDENTIAL);
+        Assert.assertNotNull(serializedGssCredential);
+        GSSCredential gssCredential = KerberosSerializationUtils.deserializeCredential(serializedGssCredential);
+        String ldapResponse = invokeLdap(gssCredential, token.getPreferredUsername());
+        Assert.assertEquals("Horatio Nelson", ldapResponse);
+
+        // Logout
+        oauth.openLogout();
+
+        // Remove protocolMapper
+        clientResource.getProtocolMappers().delete(protocolMapperId);
+
+        // Login and assert delegated credential not anymore
+        token = assertSuccessfulSpnegoLogin("hnelson", "hnelson", "secret");
+        Assert.assertFalse(token.getOtherClaims().containsKey(KerberosConstants.GSS_DELEGATION_CREDENTIAL));
+
+        events.clear();
+    }
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/federation/kerberos/AbstractKerberosTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/federation/kerberos/AbstractKerberosTest.java
index aceaf8a..58094b5 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/federation/kerberos/AbstractKerberosTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/federation/kerberos/AbstractKerberosTest.java
@@ -18,7 +18,6 @@
 package org.keycloak.testsuite.federation.kerberos;
 
 import static org.keycloak.testsuite.admin.AbstractAdminTest.loadJson;
-import static org.keycloak.testsuite.admin.ApiUtil.findClientByClientId;
 
 import java.net.URI;
 import java.nio.charset.Charset;
@@ -34,7 +33,6 @@ import javax.naming.directory.Attributes;
 import javax.naming.directory.DirContext;
 import javax.naming.directory.InitialDirContext;
 import javax.security.sasl.Sasl;
-import javax.ws.rs.core.HttpHeaders;
 import javax.ws.rs.core.Response;
 
 import org.apache.http.NameValuePair;
@@ -49,34 +47,27 @@ import org.jboss.resteasy.client.jaxrs.ResteasyClient;
 import org.jboss.resteasy.client.jaxrs.ResteasyClientBuilder;
 import org.jboss.resteasy.client.jaxrs.engines.ApacheHttpClient4Engine;
 import org.junit.After;
-import org.junit.Assume;
 import org.junit.Before;
 import org.junit.Rule;
-import org.junit.Test;
 import org.keycloak.OAuth2Constants;
 import org.keycloak.adapters.HttpClientBuilder;
-import org.keycloak.admin.client.resource.ClientResource;
 import org.keycloak.admin.client.resource.RealmResource;
 import org.keycloak.authentication.authenticators.browser.SpnegoAuthenticatorFactory;
-import org.keycloak.common.constants.KerberosConstants;
-import org.keycloak.common.util.KerberosSerializationUtils;
 import org.keycloak.common.util.MultivaluedHashMap;
 import org.keycloak.events.Details;
 import org.keycloak.federation.kerberos.CommonKerberosConfig;
 import org.keycloak.models.AuthenticationExecutionModel;
 import org.keycloak.models.LDAPConstants;
-import org.keycloak.models.ProtocolMapperModel;
 import org.keycloak.models.UserModel;
 import org.keycloak.models.utils.DefaultAuthenticationFlows;
 import org.keycloak.models.utils.ModelToRepresentation;
-import org.keycloak.protocol.oidc.mappers.UserSessionNoteMapper;
 import org.keycloak.representations.AccessToken;
 import org.keycloak.representations.idm.AuthenticationExecutionInfoRepresentation;
 import org.keycloak.representations.idm.ComponentRepresentation;
-import org.keycloak.representations.idm.ProtocolMapperRepresentation;
 import org.keycloak.representations.idm.RealmRepresentation;
 import org.keycloak.representations.idm.UserRepresentation;
 import org.keycloak.storage.UserStorageProvider;
+import org.keycloak.storage.UserStorageProviderModel;
 import org.keycloak.testsuite.AbstractAuthTest;
 import org.keycloak.testsuite.Assert;
 import org.keycloak.testsuite.AssertEvents;
@@ -84,9 +75,12 @@ import org.keycloak.testsuite.admin.ApiUtil;
 import org.keycloak.testsuite.auth.page.AuthRealm;
 import org.keycloak.testsuite.pages.AccountPasswordPage;
 import org.keycloak.testsuite.pages.LoginPage;
+import org.keycloak.testsuite.util.KerberosRule;
 import org.keycloak.testsuite.util.OAuthClient;
 
 /**
+ * Contains just helper methods. No test methods.
+ *
  * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
  */
 public abstract class AbstractKerberosTest extends AbstractAuthTest {
@@ -104,13 +98,30 @@ public abstract class AbstractKerberosTest extends AbstractAuthTest {
     @Page
     protected AccountPasswordPage changePasswordPage;
 
+    protected abstract KerberosRule getKerberosRule();
+
     protected abstract CommonKerberosConfig getKerberosConfig();
 
     protected abstract ComponentRepresentation getUserStorageConfiguration();
 
-    protected abstract void setKrb5ConfPath();
 
-    protected abstract boolean isStartEmbeddedLdapServer();
+    protected ComponentRepresentation getUserStorageConfiguration(String providerName, String providerId) {
+        Map<String,String> kerberosConfig = getKerberosRule().getConfig();
+        MultivaluedHashMap<String, String> config = toComponentConfig(kerberosConfig);
+
+        UserStorageProviderModel model = new UserStorageProviderModel();
+        model.setLastSync(0);
+        model.setChangedSyncPeriod(-1);
+        model.setFullSyncPeriod(-1);
+        model.setName(providerName);
+        model.setPriority(0);
+        model.setProviderId(providerId);
+        model.setConfig(config);
+
+        ComponentRepresentation rep = ModelToRepresentation.toRepresentationWithoutConfig(model);
+        return rep;
+    }
+
 
     @Override
     public void addTestRealms(List<RealmRepresentation> testRealms) {
@@ -118,6 +129,11 @@ public abstract class AbstractKerberosTest extends AbstractAuthTest {
         testRealms.add(realmRep);
     }
 
+    @Override
+    public RealmResource testRealmResource() {
+        return adminClient.realm("test");
+    }
+
 
     @Before
     @Override
@@ -127,7 +143,7 @@ public abstract class AbstractKerberosTest extends AbstractAuthTest {
         testRealmPage.setAuthRealm(AuthRealm.TEST);
         changePasswordPage.realm(AuthRealm.TEST);
 
-        setKrb5ConfPath();
+        getKerberosRule().setKrb5ConfPath(testingClient.testing());
 
         spnegoSchemeFactory = new KeycloakSPNegoSchemeFactory(getKerberosConfig());
         initHttpClient(true);
@@ -161,164 +177,31 @@ public abstract class AbstractKerberosTest extends AbstractAuthTest {
 //    }
 
 
-    @Test
-    public void spnegoNotAvailableTest() throws Exception {
-        initHttpClient(false);
-
-        String kcLoginPageLocation = oauth.getLoginFormUrl();
-
-        Response response = client.target(kcLoginPageLocation).request().get();
-        Assert.assertEquals(401, response.getStatus());
-        Assert.assertEquals(KerberosConstants.NEGOTIATE, response.getHeaderString(HttpHeaders.WWW_AUTHENTICATE));
-        String responseText = response.readEntity(String.class);
-        response.close();
-    }
-
-    // KEYCLOAK-7823
-    @Test
-    public void spnegoLoginWithRequiredKerberosAuthExecutionTest() {
-        AuthenticationExecutionModel.Requirement oldRequirement = updateKerberosAuthExecutionRequirement(
-                AuthenticationExecutionModel.Requirement.REQUIRED);
-        Response response = spnegoLogin("hnelson", "secret");
-        updateKerberosAuthExecutionRequirement(oldRequirement);
-
-        Assert.assertEquals(Response.Status.OK.getStatusCode(), response.getStatus());
-    }
-
-    protected OAuthClient.AccessTokenResponse spnegoLoginTestImpl() throws Exception {
-        Response spnegoResponse = spnegoLogin("hnelson", "secret");
+    protected AccessToken assertSuccessfulSpnegoLogin(String loginUsername, String expectedUsername, String password) throws Exception {
+        Response spnegoResponse = spnegoLogin(loginUsername, password);
         Assert.assertEquals(302, spnegoResponse.getStatus());
 
-        List<UserRepresentation> users = testRealmResource().users().search("hnelson", 0, 1);
-        String userId = users.get(0).getId();
-        events.expectLogin()
-                .client("kerberos-app")
-                .user(userId)
-                .detail(Details.USERNAME, "hnelson")
-                .assertEvent();
-
-        String codeUrl = spnegoResponse.getLocation().toString();
-
-        return assertAuthenticationSuccess(codeUrl);
-    }
-
-
-    protected abstract boolean isCaseSensitiveLogin();
-
-    // KEYCLOAK-2102
-    @Test
-    public void spnegoCaseInsensitiveTest() throws Exception {
-        Response spnegoResponse = spnegoLogin(isCaseSensitiveLogin() ? "MyDuke" : "myduke", "theduke");
-        Assert.assertEquals(302, spnegoResponse.getStatus());
-        List<UserRepresentation> users = testRealmResource().users().search("myduke", 0, 1);
+        List<UserRepresentation> users = testRealmResource().users().search(expectedUsername, 0, 1);
         String userId = users.get(0).getId();
         events.expectLogin()
                 .client("kerberos-app")
                 .user(userId)
-                .detail(Details.USERNAME, "myduke")
+                .detail(Details.USERNAME, expectedUsername)
                 .assertEvent();
 
         String codeUrl = spnegoResponse.getLocation().toString();
 
-        assertAuthenticationSuccess(codeUrl);
-    }
-
-    @Test
-    public void usernamePasswordLoginTest() throws Exception {
-        // Change editMode to READ_ONLY
-        updateProviderEditMode(UserStorageProvider.EditMode.READ_ONLY);
-
-        // Login with username/password from kerberos
-        changePasswordPage.open();
-        loginPage.assertCurrent();
-        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"));
-
-        // Change editMode to UNSYNCED
-        updateProviderEditMode(UserStorageProvider.EditMode.UNSYNCED);
-
-        // Successfully change password now
-        changePasswordPage.changePassword("theduke", "newPass", "newPass");
-        Assert.assertTrue(driver.getPageSource().contains("Your password has been updated."));
-        changePasswordPage.logout();
-
-        // Login with old password doesn't work, but with new password works
-        loginPage.login("jduke", "theduke");
-        loginPage.assertCurrent();
-        loginPage.login("jduke", "newPass");
-        changePasswordPage.assertCurrent();
-        changePasswordPage.logout();
-
-        // Assert SPNEGO login still with the old password as mode is unsynced
-        events.clear();
-        Response spnegoResponse = spnegoLogin("jduke", "theduke");
-        Assert.assertEquals(302, spnegoResponse.getStatus());
-        List<UserRepresentation> users = testRealmResource().users().search("jduke", 0, 1);
-        String userId = users.get(0).getId();
-        events.expectLogin()
-                .client("kerberos-app")
-                .user(userId)
-                .detail(Details.USERNAME, "jduke")
-                .assertEvent();
+        OAuthClient.AccessTokenResponse tokenResponse = assertAuthenticationSuccess(codeUrl);
 
-        String codeUrl = spnegoResponse.getLocation().toString();
+        AccessToken token = oauth.verifyToken(tokenResponse.getAccessToken());
+        Assert.assertEquals(userId, token.getSubject());
+        Assert.assertEquals(expectedUsername, token.getPreferredUsername());
 
-        assertAuthenticationSuccess(codeUrl);
+        return token;
     }
 
 
-    @Test
-    public void credentialDelegationTest() throws Exception {
-    	Assume.assumeTrue("Ignoring test as the embedded server is not started", isStartEmbeddedLdapServer());
-    	// Add kerberos delegation credential mapper
-        ProtocolMapperModel protocolMapper = UserSessionNoteMapper.createClaimMapper(KerberosConstants.GSS_DELEGATION_CREDENTIAL_DISPLAY_NAME,
-                KerberosConstants.GSS_DELEGATION_CREDENTIAL,
-                KerberosConstants.GSS_DELEGATION_CREDENTIAL, "String",
-                true, false);
-        ProtocolMapperRepresentation protocolMapperRep = ModelToRepresentation.toRepresentation(protocolMapper);
-        ClientResource clientResource = findClientByClientId(testRealmResource(), "kerberos-app");
-        Response response = clientResource.getProtocolMappers().createMapper(protocolMapperRep);
-        String protocolMapperId = ApiUtil.getCreatedId(response);
-        response.close();
-
-        // SPNEGO login
-        OAuthClient.AccessTokenResponse tokenResponse = spnegoLoginTestImpl();
-
-        // Assert kerberos ticket in the accessToken can be re-used to authenticate against other 3rd party kerberos service (ApacheDS Server in this case)
-        String accessToken = tokenResponse.getAccessToken();
-        AccessToken token = oauth.verifyToken(accessToken);
-
-        String serializedGssCredential = (String) token.getOtherClaims().get(KerberosConstants.GSS_DELEGATION_CREDENTIAL);
-        Assert.assertNotNull(serializedGssCredential);
-        GSSCredential gssCredential = KerberosSerializationUtils.deserializeCredential(serializedGssCredential);
-        String ldapResponse = invokeLdap(gssCredential, token.getPreferredUsername());
-        Assert.assertEquals("Horatio Nelson", ldapResponse);
-
-        // Logout
-        oauth.openLogout();
-
-        // Remove protocolMapper
-        clientResource.getProtocolMappers().delete(protocolMapperId);
-
-        // Login and assert delegated credential not anymore
-        tokenResponse = spnegoLoginTestImpl();
-        accessToken = tokenResponse.getAccessToken();
-        token = oauth.verifyToken(accessToken);
-        Assert.assertFalse(token.getOtherClaims().containsKey(KerberosConstants.GSS_DELEGATION_CREDENTIAL));
-
-        events.clear();
-    }
-
-    private String invokeLdap(GSSCredential gssCredential, String username) throws NamingException {
+    protected String invokeLdap(GSSCredential gssCredential, String username) throws NamingException {
         Hashtable env = new Hashtable(11);
         env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
         env.put(Context.PROVIDER_URL, "ldap://localhost:10389");
@@ -462,7 +345,8 @@ public abstract class AbstractKerberosTest extends AbstractAuthTest {
         testRealmResource().components().component(kerberosProvider.getId()).update(kerberosProvider);
     }
 
-    private AuthenticationExecutionModel.Requirement updateKerberosAuthExecutionRequirement(AuthenticationExecutionModel.Requirement requirement) {
+
+    protected AuthenticationExecutionModel.Requirement updateKerberosAuthExecutionRequirement(AuthenticationExecutionModel.Requirement requirement) {
         Optional<AuthenticationExecutionInfoRepresentation> kerberosAuthExecutionOpt = testRealmResource()
                 .flows()
                 .getExecutions(DefaultAuthenticationFlows.BROWSER_FLOW)
@@ -483,15 +367,9 @@ public abstract class AbstractKerberosTest extends AbstractAuthTest {
 
         return oldRequirement;
     }
-    
-    @Override
-    public RealmResource testRealmResource() {
-        return adminClient.realm("test");
-    }
 
 
-    // TODO: Use LDAPTestUtils.toComponentConfig once it's migrated to new testsuite
-    public static MultivaluedHashMap<String, String> toComponentConfig(Map<String, String> ldapConfig) {
+    private static MultivaluedHashMap<String, String> toComponentConfig(Map<String, String> ldapConfig) {
         MultivaluedHashMap<String, String> config = new MultivaluedHashMap<>();
         for (Map.Entry<String, String> entry : ldapConfig.entrySet()) {
             config.add(entry.getKey(), entry.getValue());
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/federation/kerberos/KerberosLdapCrossRealmTrustTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/federation/kerberos/KerberosLdapCrossRealmTrustTest.java
new file mode 100644
index 0000000..8251885
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/federation/kerberos/KerberosLdapCrossRealmTrustTest.java
@@ -0,0 +1,117 @@
+/*
+ * Copyright 2017 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.testsuite.federation.kerberos;
+
+import javax.ws.rs.core.Response;
+
+import org.jboss.arquillian.container.test.api.Deployment;
+import org.jboss.arquillian.container.test.api.TargetsContainer;
+import org.jboss.shrinkwrap.api.spec.WebArchive;
+import org.junit.ClassRule;
+import org.junit.FixMethodOrder;
+import org.junit.Test;
+import org.junit.runners.MethodSorters;
+import org.keycloak.admin.client.resource.UserResource;
+import org.keycloak.federation.kerberos.CommonKerberosConfig;
+import org.keycloak.models.RealmModel;
+import org.keycloak.representations.AccessToken;
+import org.keycloak.representations.idm.ComponentRepresentation;
+import org.keycloak.storage.ldap.LDAPStorageProviderFactory;
+import org.keycloak.storage.ldap.kerberos.LDAPProviderKerberosConfig;
+import org.keycloak.testsuite.Assert;
+import org.keycloak.testsuite.federation.ldap.LDAPTestContext;
+import org.keycloak.testsuite.runonserver.RunOnServerDeployment;
+import org.keycloak.testsuite.util.KerberosRule;
+import org.keycloak.testsuite.util.LDAPTestUtils;
+import org.keycloak.util.ldap.KerberosEmbeddedServer;
+import org.keycloak.util.ldap.LDAPEmbeddedServer;
+
+import static org.keycloak.testsuite.arquillian.DeploymentTargetModifier.AUTH_SERVER_CURRENT;
+
+/**
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+public class KerberosLdapCrossRealmTrustTest extends AbstractKerberosTest {
+
+    @Deployment
+    @TargetsContainer(AUTH_SERVER_CURRENT)
+    public static WebArchive deploy() {
+        return RunOnServerDeployment.create(UserResource.class, LDAPEmbeddedServer.class, KerberosEmbeddedServer.class)
+                .addPackages(true,
+                        "org.keycloak.testsuite",
+                        "org.keycloak.testsuite.federation.ldap",
+                        "org.keycloak.testsuite.federation.kerberos");
+    }
+
+
+    private static final String PROVIDER_CONFIG_LOCATION = "classpath:kerberos/kerberos-ldap-crt-connection.properties";
+
+    @ClassRule
+    public static KerberosRule kerberosRule = new KerberosRule(PROVIDER_CONFIG_LOCATION, KerberosEmbeddedServer.DEFAULT_KERBEROS_REALM);
+
+    @ClassRule
+    public static KerberosRule kerberosRule2 = new KerberosRule(PROVIDER_CONFIG_LOCATION, KerberosEmbeddedServer.DEFAULT_KERBEROS_REALM_2);
+
+
+    @Override
+    protected KerberosRule getKerberosRule() {
+        return kerberosRule;
+    }
+
+
+    @Override
+    protected CommonKerberosConfig getKerberosConfig() {
+        return new LDAPProviderKerberosConfig(getUserStorageConfiguration());
+    }
+
+    @Override
+    protected ComponentRepresentation getUserStorageConfiguration() {
+        return getUserStorageConfiguration("kerberos-ldap", LDAPStorageProviderFactory.PROVIDER_NAME);
+    }
+
+
+    @Test
+    public void test01SpnegoLoginCRTSuccess() throws Exception {
+        // Login as user from realm KC2.COM . Realm KEYCLOAK.ORG will trust us
+        AccessToken token = assertSuccessfulSpnegoLogin("hnelson2@KC2.COM", "hnelson2", "secret");
+
+        Assert.assertEquals(token.getEmail(), "hnelson2@kc2.com");
+        assertUser("hnelson2", "hnelson2@kc2.com", "Horatio", "Nelson", false);
+    }
+
+
+    @Test
+    public void test02DisableTrust() throws Exception {
+        // Remove the LDAP entry corresponding to the Kerberos principal krbtgt/KEYCLOAK.ORG@KC2.COM
+        // This will effectively disable kerberos cross-realm trust
+        testingClient.testing().ldap("test").removeLDAPUser("krbtgt2");
+
+
+        // There is no trust among kerberos realms anymore. SPNEGO shouldn't work. There would be failure even on Apache HTTP client side
+        // as it's not possible to start GSS context ( initSecContext ) due the missing trust among realms.
+        try {
+            Response spnegoResponse = spnegoLogin("hnelson2@KC2.COM", "secret");
+            Assert.fail("Not expected to successfully login");
+        } catch (Exception e) {
+            // Expected
+        }
+    }
+
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/federation/kerberos/KerberosLdapTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/federation/kerberos/KerberosLdapTest.java
index 3cdddc6..1488a4c 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/federation/kerberos/KerberosLdapTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/federation/kerberos/KerberosLdapTest.java
@@ -17,85 +17,57 @@
 
 package org.keycloak.testsuite.federation.kerberos;
 
-import java.io.File;
 import java.util.List;
-import java.util.Map;
 
 import javax.ws.rs.core.Response;
 
-import org.apache.commons.io.FileUtils;
-import org.apache.directory.server.core.api.authn.ppolicy.PasswordPolicyConfiguration;
 import org.junit.Assert;
 import org.junit.ClassRule;
 import org.junit.Test;
-import org.keycloak.common.util.MultivaluedHashMap;
 import org.keycloak.events.Details;
 import org.keycloak.federation.kerberos.CommonKerberosConfig;
-import org.keycloak.models.PasswordPolicy;
-import org.keycloak.models.utils.ModelToRepresentation;
 import org.keycloak.representations.idm.ComponentRepresentation;
-import org.keycloak.representations.idm.RealmRepresentation;
 import org.keycloak.representations.idm.UserRepresentation;
 import org.keycloak.storage.UserStorageProvider;
-import org.keycloak.storage.UserStorageProviderModel;
 import org.keycloak.storage.ldap.LDAPStorageProviderFactory;
 import org.keycloak.storage.ldap.kerberos.LDAPProviderKerberosConfig;
 import org.keycloak.testsuite.util.KerberosRule;
+import org.keycloak.util.ldap.KerberosEmbeddedServer;
 
 /**
+ * Test for the LDAPStorageProvider with kerberos enabled (kerberos with LDAP integration)
+ *
  * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
  */
-public class KerberosLdapTest extends AbstractKerberosTest {
+public class KerberosLdapTest extends AbstractKerberosSingleRealmTest {
 
     private static final String PROVIDER_CONFIG_LOCATION = "classpath:kerberos/kerberos-ldap-connection.properties";
 
     @ClassRule
-    public static KerberosRule kerberosRule = new KerberosRule(PROVIDER_CONFIG_LOCATION);
+    public static KerberosRule kerberosRule = new KerberosRule(PROVIDER_CONFIG_LOCATION, KerberosEmbeddedServer.DEFAULT_KERBEROS_REALM);
 
-    @Override
-    protected CommonKerberosConfig getKerberosConfig() {
-        return new LDAPProviderKerberosConfig(getUserStorageConfiguration());
-    }
 
     @Override
-    protected ComponentRepresentation getUserStorageConfiguration() {
-        Map<String,String> kerberosConfig = kerberosRule.getConfig();
-        MultivaluedHashMap<String, String> config = toComponentConfig(kerberosConfig);
-
-        UserStorageProviderModel model = new UserStorageProviderModel();
-        model.setLastSync(0);
-        model.setChangedSyncPeriod(-1);
-        model.setFullSyncPeriod(-1);
-        model.setName("kerberos-ldap");
-        model.setPriority(0);
-        model.setProviderId(LDAPStorageProviderFactory.PROVIDER_NAME);
-        model.setConfig(config);
-
-        ComponentRepresentation rep = ModelToRepresentation.toRepresentationWithoutConfig(model);
-        return rep;
+    protected KerberosRule getKerberosRule() {
+        return kerberosRule;
     }
 
 
     @Override
-    protected boolean isCaseSensitiveLogin() {
-        return kerberosRule.isCaseSensitiveLogin();
+    protected CommonKerberosConfig getKerberosConfig() {
+        return new LDAPProviderKerberosConfig(getUserStorageConfiguration());
     }
 
     @Override
-    protected boolean isStartEmbeddedLdapServer() {
-        return kerberosRule.isStartEmbeddedLdapServer();
+    protected ComponentRepresentation getUserStorageConfiguration() {
+        return getUserStorageConfiguration("kerberos-ldap", LDAPStorageProviderFactory.PROVIDER_NAME);
     }
 
 
-    @Override
-    protected void setKrb5ConfPath() {
-        kerberosRule.setKrb5ConfPath(testingClient.testing());
-    }
-
 
     @Test
     public void spnegoLoginTest() throws Exception {
-        spnegoLoginTestImpl();
+        assertSuccessfulSpnegoLogin("hnelson", "hnelson", "secret");
 
         // Assert user was imported and hasn't any required action on him. Profile info is synced from LDAP
         assertUser("hnelson", "hnelson@keycloak.org", "Horatio", "Nelson", false);
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/federation/kerberos/KerberosStandaloneCrossRealmTrustTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/federation/kerberos/KerberosStandaloneCrossRealmTrustTest.java
new file mode 100644
index 0000000..20ce414
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/federation/kerberos/KerberosStandaloneCrossRealmTrustTest.java
@@ -0,0 +1,100 @@
+/*
+ * Copyright 2017 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.testsuite.federation.kerberos;
+
+import org.jboss.arquillian.container.test.api.Deployment;
+import org.jboss.arquillian.container.test.api.TargetsContainer;
+import org.jboss.shrinkwrap.api.spec.WebArchive;
+import org.junit.ClassRule;
+import org.junit.FixMethodOrder;
+import org.junit.Test;
+import org.junit.runners.MethodSorters;
+import org.keycloak.admin.client.resource.UserResource;
+import org.keycloak.federation.kerberos.CommonKerberosConfig;
+import org.keycloak.federation.kerberos.KerberosConfig;
+import org.keycloak.federation.kerberos.KerberosFederationProviderFactory;
+import org.keycloak.representations.idm.ComponentRepresentation;
+import org.keycloak.testsuite.federation.ldap.AbstractLDAPTest;
+import org.keycloak.testsuite.runonserver.RunOnServerDeployment;
+import org.keycloak.testsuite.util.KerberosRule;
+import org.keycloak.util.ldap.KerberosEmbeddedServer;
+
+import static org.keycloak.testsuite.arquillian.DeploymentTargetModifier.AUTH_SERVER_CURRENT;
+
+/**
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+public class KerberosStandaloneCrossRealmTrustTest extends AbstractKerberosTest {
+
+    @Deployment
+    @TargetsContainer(AUTH_SERVER_CURRENT)
+    public static WebArchive deploy() {
+        return RunOnServerDeployment.create(UserResource.class, AbstractLDAPTest.class, AbstractKerberosTest.class)
+                .addPackages(true,
+                        "org.keycloak.testsuite",
+                        "org.keycloak.testsuite.federation.ldap",
+                        "org.keycloak.testsuite.federation.kerberos");
+    }
+
+
+    private static final String PROVIDER_CONFIG_LOCATION = "classpath:kerberos/kerberos-standalone-connection.properties";
+
+
+    @ClassRule
+    public static KerberosRule kerberosRule = new KerberosRule(PROVIDER_CONFIG_LOCATION, KerberosEmbeddedServer.DEFAULT_KERBEROS_REALM);
+
+
+    @ClassRule
+    public static KerberosRule kerberosRule2 = new KerberosRule(PROVIDER_CONFIG_LOCATION, KerberosEmbeddedServer.DEFAULT_KERBEROS_REALM_2);
+
+
+    @Override
+    protected KerberosRule getKerberosRule() {
+        return kerberosRule;
+    }
+
+
+    @Override
+    protected CommonKerberosConfig getKerberosConfig() {
+        return new KerberosConfig(getUserStorageConfiguration());
+    }
+
+    @Override
+    protected ComponentRepresentation getUserStorageConfiguration() {
+        return getUserStorageConfiguration("kerberos-standalone", KerberosFederationProviderFactory.PROVIDER_NAME);
+    }
+
+
+    @Test
+    public void test01spnegoLoginSameRealmTest() throws Exception {
+        assertSuccessfulSpnegoLogin("hnelson", "hnelson", "secret");
+        assertUser("hnelson", "hnelson@keycloak.org", null, null, false);
+    }
+
+
+    @Test
+    public void test02spnegoLoginDifferentRealmTest() throws Exception {
+        // Cross-realm trust login. Realm KEYCLOAK.ORG trusts realm KC2.COM.
+        // TODO: email hnelson2@keycloak.org is not very good. Will be better to have more flexibility for mapping of kerberos principals to Keycloak UserModel in KerberosFederationProvider (if needed)
+        assertSuccessfulSpnegoLogin("hnelson2@KC2.COM", "hnelson2", "secret");
+        assertUser("hnelson2", "hnelson2@keycloak.org", null, null, false);
+    }
+
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/federation/kerberos/KerberosStandaloneTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/federation/kerberos/KerberosStandaloneTest.java
index 148d7e1..43f440a 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/federation/kerberos/KerberosStandaloneTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/federation/kerberos/KerberosStandaloneTest.java
@@ -18,11 +18,7 @@
 package org.keycloak.testsuite.federation.kerberos;
 
 import java.net.URI;
-import java.net.URL;
 import java.util.List;
-import java.util.Map;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
 
 
 import javax.ws.rs.client.Entity;
@@ -33,74 +29,51 @@ import org.junit.Assert;
 import org.junit.ClassRule;
 import org.junit.Test;
 import org.keycloak.common.constants.KerberosConstants;
-import org.keycloak.common.util.KeycloakUriBuilder;
-import org.keycloak.common.util.MultivaluedHashMap;
 import org.keycloak.federation.kerberos.CommonKerberosConfig;
 import org.keycloak.federation.kerberos.KerberosConfig;
 import org.keycloak.federation.kerberos.KerberosFederationProviderFactory;
-import org.keycloak.models.utils.ModelToRepresentation;
 import org.keycloak.representations.idm.ComponentRepresentation;
 import org.keycloak.representations.idm.UserRepresentation;
 import org.keycloak.storage.UserStorageProvider;
-import org.keycloak.storage.UserStorageProviderModel;
 import org.keycloak.testsuite.ActionURIUtils;
 import org.keycloak.testsuite.util.KerberosRule;
+import org.keycloak.util.ldap.KerberosEmbeddedServer;
 
 /**
+ * Test for the KerberosFederationProvider (kerberos without LDAP integration)
+ *
  * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
  */
-public class KerberosStandaloneTest extends AbstractKerberosTest {
+public class KerberosStandaloneTest extends AbstractKerberosSingleRealmTest {
 
     private static final String PROVIDER_CONFIG_LOCATION = "classpath:kerberos/kerberos-standalone-connection.properties";
 
     @ClassRule
-    public static KerberosRule kerberosRule = new KerberosRule(PROVIDER_CONFIG_LOCATION);
+    public static KerberosRule kerberosRule = new KerberosRule(PROVIDER_CONFIG_LOCATION, KerberosEmbeddedServer.DEFAULT_KERBEROS_REALM);
 
-    @Override
-    protected CommonKerberosConfig getKerberosConfig() {
-        return new KerberosConfig(getUserStorageConfiguration());
-    }
 
     @Override
-    protected ComponentRepresentation getUserStorageConfiguration() {
-        Map<String,String> kerberosConfig = kerberosRule.getConfig();
-        MultivaluedHashMap<String, String> config = toComponentConfig(kerberosConfig);
-
-        UserStorageProviderModel model = new UserStorageProviderModel();
-        model.setLastSync(0);
-        model.setChangedSyncPeriod(-1);
-        model.setFullSyncPeriod(-1);
-        model.setName("kerberos-standalone");
-        model.setPriority(0);
-        model.setProviderId(KerberosFederationProviderFactory.PROVIDER_NAME);
-        model.setConfig(config);
-
-        ComponentRepresentation rep = ModelToRepresentation.toRepresentationWithoutConfig(model);
-        return rep;
+    protected KerberosRule getKerberosRule() {
+        return kerberosRule;
     }
 
 
     @Override
-    protected boolean isCaseSensitiveLogin() {
-        return kerberosRule.isCaseSensitiveLogin();
-    }
-    
-    @Override
-    protected boolean isStartEmbeddedLdapServer() {
-        return kerberosRule.isStartEmbeddedLdapServer();
+    protected CommonKerberosConfig getKerberosConfig() {
+        return new KerberosConfig(getUserStorageConfiguration());
     }
 
-
     @Override
-    protected void setKrb5ConfPath() {
-        kerberosRule.setKrb5ConfPath(testingClient.testing());
+    protected ComponentRepresentation getUserStorageConfiguration() {
+        return getUserStorageConfiguration("kerberos-standalone", KerberosFederationProviderFactory.PROVIDER_NAME);
     }
 
+
     @Test
     public void spnegoLoginTest() throws Exception {
-        spnegoLoginTestImpl();
+        assertSuccessfulSpnegoLogin("hnelson", "hnelson", "secret");
 
-        // Assert user was imported and hasn't any required action on him. Profile info is synced from LDAP
+        // Assert user was imported and hasn't any required action on him. Profile info is NOT synced from LDAP. Just username is filled and email is "guessed"
         assertUser("hnelson", "hnelson@" + kerberosRule.getConfig().get(KerberosConstants.KERBEROS_REALM).toLowerCase(), null, null, false);
     }
 
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/federation/kerberos/KeycloakSPNegoSchemeFactory.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/federation/kerberos/KeycloakSPNegoSchemeFactory.java
index c4e0243..5133127 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/federation/kerberos/KeycloakSPNegoSchemeFactory.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/federation/kerberos/KeycloakSPNegoSchemeFactory.java
@@ -31,6 +31,8 @@ import org.keycloak.federation.kerberos.CommonKerberosConfig;
 import org.keycloak.federation.kerberos.impl.KerberosUsernamePasswordAuthenticator;
 
 import javax.security.auth.Subject;
+import javax.security.auth.login.LoginException;
+
 import java.security.PrivilegedExceptionAction;
 
 /**
@@ -74,7 +76,19 @@ public class KeycloakSPNegoSchemeFactory extends SPNegoSchemeFactory {
 
         @Override
         protected byte[] generateGSSToken(byte[] input, Oid oid, String authServer, Credentials credentials) throws GSSException {
-            KerberosUsernamePasswordAuthenticator authenticator = new KerberosUsernamePasswordAuthenticator(kerberosConfig);
+            KerberosUsernamePasswordAuthenticator authenticator = new KerberosUsernamePasswordAuthenticator(kerberosConfig) {
+
+                // Disable strict check for the configured kerberos realm, which is on super-method
+                @Override
+                protected String getKerberosPrincipal(String username) throws LoginException {
+                    if (username.contains("@")) {
+                        return username;
+                    } else {
+                        return username + "@" + config.getKerberosRealm();
+                    }
+                }
+            };
+
             try {
                 Subject clientSubject = authenticator.authenticateSubject(username, password);
 
@@ -109,7 +123,8 @@ public class KeycloakSPNegoSchemeFactory extends SPNegoSchemeFactory {
                     token = new byte[0];
                 }
                 GSSManager manager = getManager();
-                GSSName serverName = manager.createName("HTTP/" + authServer + "@" + kerberosConfig.getKerberosRealm(), null);
+                String httPrincipal = kerberosConfig.getServerPrincipal().replaceFirst("/.*@", "/" + authServer + "@");
+                GSSName serverName = manager.createName(httPrincipal, null);
                 GSSContext gssContext = manager.createContext(
                         serverName.canonicalize(oid), oid, null, GSSContext.DEFAULT_LIFETIME);
                 gssContext.requestMutualAuth(true);
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/federation/ldap/LDAPGroupMapper2WaySyncTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/federation/ldap/LDAPGroupMapper2WaySyncTest.java
index ff13657..1bd1a4d 100755
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/federation/ldap/LDAPGroupMapper2WaySyncTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/federation/ldap/LDAPGroupMapper2WaySyncTest.java
@@ -24,20 +24,12 @@ import org.junit.Assert;
 import org.junit.Before;
 import org.junit.ClassRule;
 import org.junit.FixMethodOrder;
-import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runners.MethodSorters;
 import org.keycloak.admin.client.resource.UserResource;
-import org.keycloak.common.util.MultivaluedHashMap;
 import org.keycloak.component.ComponentModel;
-import org.keycloak.storage.UserStorageProvider;
-import org.keycloak.storage.UserStorageProviderModel;
 import org.keycloak.storage.ldap.LDAPStorageProvider;
-import org.keycloak.storage.ldap.LDAPStorageProviderFactory;
-import org.keycloak.storage.ldap.LDAPUtils;
-import org.keycloak.storage.ldap.idm.model.LDAPObject;
 import org.keycloak.storage.ldap.mappers.membership.LDAPGroupMapperMode;
-import org.keycloak.storage.ldap.mappers.membership.MembershipType;
 import org.keycloak.storage.ldap.mappers.membership.group.GroupLDAPStorageMapperFactory;
 import org.keycloak.storage.ldap.mappers.membership.group.GroupMapperConfig;
 import org.keycloak.models.GroupModel;
diff --git a/testsuite/integration-arquillian/tests/base/src/test/resources/kerberos/kerberos-ldap-crt-connection.properties b/testsuite/integration-arquillian/tests/base/src/test/resources/kerberos/kerberos-ldap-crt-connection.properties
new file mode 100644
index 0000000..7277587
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/resources/kerberos/kerberos-ldap-crt-connection.properties
@@ -0,0 +1,36 @@
+#
+# Copyright 2017 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.
+#
+
+# Using LDAP from "kc2" domain, but HTTP principal is configured to use KEYCLOAK.ORG domain.
+# Realm KC2.COM has the purpose just for the client side login (KerberosUsernamePasswordAuthenticator used by Apache HTTP client in the test)
+idm.test.ldap.connection.url=ldap\://localhost\:11389
+idm.test.ldap.base.dn=dc\=kc2,dc\=com
+idm.test.ldap.roles.dn.suffix=ou\=Roles,dc\=kc2,dc\=com
+idm.test.ldap.group.dn.suffix=ou\=Groups,dc\=kc2,dc\=com
+idm.test.ldap.user.dn.suffix=ou\=People,dc\=kc2,dc\=com
+idm.test.ldap.start.embedded.ldap.server=true
+idm.test.ldap.bind.dn=uid\=admin,ou\=system
+idm.test.ldap.bind.credential=secret
+idm.test.ldap.connection.pooling=true
+idm.test.ldap.pagination=true
+idm.test.ldap.batch.size.for.sync=3
+
+idm.test.kerberos.allow.kerberos.authentication=true
+idm.test.kerberos.realm=KC2.COM
+idm.test.kerberos.server.principal=HTTP/localhost@KEYCLOAK.ORG
+idm.test.kerberos.debug=true
+idm.test.kerberos.use.kerberos.for.password.authentication=true
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/tests/base/src/test/resources/kerberos/test-krb5.conf b/testsuite/integration-arquillian/tests/base/src/test/resources/kerberos/test-krb5.conf
index 6989b7f..6ca62ce 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/resources/kerberos/test-krb5.conf
+++ b/testsuite/integration-arquillian/tests/base/src/test/resources/kerberos/test-krb5.conf
@@ -14,6 +14,9 @@
     KEYCLOAK.ORG = {
         kdc = localhost:6088
     }
+    KC2.COM = {
+        kdc = localhost:7088
+    }
 
 [domain_realm]
     localhost = KEYCLOAK.ORG
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/tests/base/src/test/resources/kerberos/users-kerberos.ldif b/testsuite/integration-arquillian/tests/base/src/test/resources/kerberos/users-kerberos.ldif
index 9d55092..554f625 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/resources/kerberos/users-kerberos.ldif
+++ b/testsuite/integration-arquillian/tests/base/src/test/resources/kerberos/users-kerberos.ldif
@@ -22,6 +22,20 @@ userPassword: secret
 krb5PrincipalName: krbtgt/KEYCLOAK.ORG@KEYCLOAK.ORG
 krb5KeyVersionNumber: 0
 
+# Cross-realm trust support! Realm KEYCLOAK.ORG will trust the realm KC2.COM
+dn: uid=krbtgt2,ou=People,dc=keycloak,dc=org
+objectClass: top
+objectClass: person
+objectClass: inetOrgPerson
+objectClass: krb5principal
+objectClass: krb5kdcentry
+cn: KDC Service
+sn: Service
+uid: krbtgt2
+userPassword: secret
+krb5PrincipalName: krbtgt/KEYCLOAK.ORG@KC2.COM
+krb5KeyVersionNumber: 0
+
 dn: uid=ldap,ou=People,dc=keycloak,dc=org
 objectClass: top
 objectClass: person
diff --git a/testsuite/integration-arquillian/tests/base/src/test/resources/kerberos/users-kerberos-kc2.ldif b/testsuite/integration-arquillian/tests/base/src/test/resources/kerberos/users-kerberos-kc2.ldif
new file mode 100644
index 0000000..8758643
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/resources/kerberos/users-kerberos-kc2.ldif
@@ -0,0 +1,104 @@
+dn: dc=kc2,dc=com
+objectclass: dcObject
+objectclass: organization
+o: Kc2
+dc: Kc2
+
+dn: ou=People,dc=kc2,dc=com
+objectClass: organizationalUnit
+objectClass: top
+ou: People
+
+dn: uid=krbtgt,ou=People,dc=kc2,dc=com
+objectClass: top
+objectClass: person
+objectClass: inetOrgPerson
+objectClass: krb5principal
+objectClass: krb5kdcentry
+cn: KDC Service
+sn: Service
+uid: krbtgt
+userPassword: secret
+krb5PrincipalName: krbtgt/KC2.COM@KC2.COM
+krb5KeyVersionNumber: 0
+
+# Cross-realm trust support! Realm KEYCLOAK.ORG will trust the realm KC2.COM
+dn: uid=krbtgt2,ou=People,dc=kc2,dc=com
+objectClass: top
+objectClass: person
+objectClass: inetOrgPerson
+objectClass: krb5principal
+objectClass: krb5kdcentry
+cn: KDC Service
+sn: Service
+uid: krbtgt2
+userPassword: secret
+krb5PrincipalName: krbtgt/KEYCLOAK.ORG@KC2.COM
+krb5KeyVersionNumber: 0
+
+dn: uid=ldap,ou=People,dc=kc2,dc=com
+objectClass: top
+objectClass: person
+objectClass: inetOrgPerson
+objectClass: krb5principal
+objectClass: krb5kdcentry
+cn: LDAP
+sn: Service
+uid: ldap
+userPassword: randall
+krb5PrincipalName: ${ldapSaslPrincipal}
+krb5KeyVersionNumber: 0
+
+dn: uid=HTTP,ou=People,dc=kc2,dc=com
+objectClass: top
+objectClass: person
+objectClass: inetOrgPerson
+objectClass: krb5principal
+objectClass: krb5kdcentry
+cn: HTTP
+sn: Service
+uid: HTTP
+userPassword: httppwd
+krb5PrincipalName: HTTP/${hostname}@KC2.COM
+krb5KeyVersionNumber: 0
+
+dn: uid=hnelson2,ou=People,dc=kc2,dc=com
+objectClass: top
+objectClass: person
+objectClass: inetOrgPerson
+objectClass: krb5principal
+objectClass: krb5kdcentry
+cn: Horatio
+sn: Nelson
+mail: hnelson2@kc2.com
+uid: hnelson2
+userPassword: secret
+krb5PrincipalName: hnelson2@KC2.COM
+krb5KeyVersionNumber: 0
+
+dn: uid=jduke2,ou=People,dc=kc2,dc=com
+objectClass: top
+objectClass: person
+objectClass: inetOrgPerson
+objectClass: krb5principal
+objectClass: krb5kdcentry
+cn: Java
+sn: Duke
+mail: jduke2@keycloak.org
+uid: jduke2
+userPassword: theduke
+krb5PrincipalName: jduke2@KC2.COM
+krb5KeyVersionNumber: 0
+
+dn: uid=gsstestserver,ou=People,dc=kc2,dc=com
+objectClass: top
+objectClass: person
+objectClass: inetOrgPerson
+objectClass: krb5principal
+objectClass: krb5kdcentry
+cn: gsstestserver
+sn: Service
+uid: gsstestserver
+userPassword: gsstestpwd
+krb5PrincipalName: gsstestserver/xxx@KC2.COM
+krb5KeyVersionNumber: 0
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/tests/base/src/test/resources/run-on-server-jboss-deployment-structure.xml b/testsuite/integration-arquillian/tests/base/src/test/resources/run-on-server-jboss-deployment-structure.xml
index 034e0b6..ec7403c 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/resources/run-on-server-jboss-deployment-structure.xml
+++ b/testsuite/integration-arquillian/tests/base/src/test/resources/run-on-server-jboss-deployment-structure.xml
@@ -10,6 +10,7 @@
             <module name="org.keycloak.keycloak-services"/>
             <module name="org.keycloak.keycloak-model-infinispan"/>
             <module name="org.keycloak.keycloak-model-jpa"/>
+            <module name="org.keycloak.keycloak-kerberos-federation"/>
             <module name="org.keycloak.keycloak-ldap-federation"/>
         </dependencies>
     </deployment>
diff --git a/util/embedded-ldap/pom.xml b/util/embedded-ldap/pom.xml
index 0610d1c..0af7ae7 100644
--- a/util/embedded-ldap/pom.xml
+++ b/util/embedded-ldap/pom.xml
@@ -43,6 +43,7 @@
         <dependency>
             <groupId>log4j</groupId>
             <artifactId>log4j</artifactId>
+            <scope>compile</scope>
         </dependency>
         <dependency>
             <groupId>org.slf4j</groupId>
diff --git a/util/embedded-ldap/src/main/java/org/keycloak/util/ldap/InMemoryDirectoryServiceFactory.java b/util/embedded-ldap/src/main/java/org/keycloak/util/ldap/InMemoryDirectoryServiceFactory.java
index 35fb1b8..649030a 100644
--- a/util/embedded-ldap/src/main/java/org/keycloak/util/ldap/InMemoryDirectoryServiceFactory.java
+++ b/util/embedded-ldap/src/main/java/org/keycloak/util/ldap/InMemoryDirectoryServiceFactory.java
@@ -106,7 +106,8 @@ class InMemoryDirectoryServiceFactory implements DirectoryServiceFactory {
 
         // EhCache in disabled-like-mode
         Configuration ehCacheConfig = new Configuration();
-        CacheConfiguration defaultCache = new CacheConfiguration("default", 1).eternal(false).timeToIdleSeconds(30)
+        ehCacheConfig.setName(name);
+        CacheConfiguration defaultCache = new CacheConfiguration(name + "-default", 1).eternal(false).timeToIdleSeconds(30)
                 .timeToLiveSeconds(30).overflowToDisk(false);
         ehCacheConfig.addDefaultCache(defaultCache);
         CacheService cacheService = new CacheService(new CacheManager(ehCacheConfig));
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 6845bc4..f3343a7 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
@@ -60,7 +60,9 @@ public class KerberosEmbeddedServer extends LDAPEmbeddedServer {
 
     private static final String DEFAULT_KERBEROS_LDIF_FILE = "classpath:kerberos/default-users.ldif";
 
-    private static final String DEFAULT_KERBEROS_REALM = "KEYCLOAK.ORG";
+    public static final String DEFAULT_KERBEROS_REALM = "KEYCLOAK.ORG";
+    public static final String DEFAULT_KERBEROS_REALM_2 = "KC2.COM";
+
     private static final String DEFAULT_KDC_PORT = "6088";
     private static final String DEFAULT_KDC_ENCRYPTION_TYPES = "aes128-cts-hmac-sha1-96, des-cbc-md5, des3-cbc-sha1-kd";
 
@@ -75,9 +77,31 @@ public class KerberosEmbeddedServer extends LDAPEmbeddedServer {
         Properties defaultProperties = new Properties();
         defaultProperties.put(PROPERTY_DSF, DSF_FILE);
 
+        String kerberosRealm = System.getProperty("keycloak.kerberos.realm", DEFAULT_KERBEROS_REALM);
+        configureDefaultPropertiesForRealm(kerberosRealm, defaultProperties);
+
         execute(args, defaultProperties);
     }
 
+
+    public static void configureDefaultPropertiesForRealm(String kerberosRealm, Properties properties) {
+        log.infof("Using kerberos realm: %s", kerberosRealm);
+        if (DEFAULT_KERBEROS_REALM.equals(kerberosRealm)) {
+            // No more configs
+        } else if (DEFAULT_KERBEROS_REALM_2.equals(kerberosRealm)) {
+            properties.put(PROPERTY_BASE_DN, "dc=kc2,dc=com");
+            properties.put(PROPERTY_BIND_PORT, "11389");
+            properties.put(PROPERTY_BIND_LDAPS_PORT, "11636");
+            properties.put(PROPERTY_LDIF_FILE, "classpath:kerberos/default-users-kc2.ldif");
+            properties.put(PROPERTY_KERBEROS_REALM, DEFAULT_KERBEROS_REALM_2);
+            properties.put(PROPERTY_KDC_PORT, "7088");
+        } else {
+            throw new IllegalArgumentException("Valid values for kerberos realm are [ " + DEFAULT_KERBEROS_REALM + " , "
+                    + DEFAULT_KERBEROS_REALM_2 + " ]");
+        }
+    }
+
+
     public static void execute(String[] args, Properties defaultProperties) throws Exception {
         final KerberosEmbeddedServer kerberosEmbeddedServer = new KerberosEmbeddedServer(defaultProperties);
         kerberosEmbeddedServer.init();
diff --git a/util/embedded-ldap/src/main/resources/kerberos/default-users.ldif b/util/embedded-ldap/src/main/resources/kerberos/default-users.ldif
index fd9936c..4141193 100644
--- a/util/embedded-ldap/src/main/resources/kerberos/default-users.ldif
+++ b/util/embedded-ldap/src/main/resources/kerberos/default-users.ldif
@@ -22,6 +22,20 @@ userPassword: secret
 krb5PrincipalName: krbtgt/KEYCLOAK.ORG@KEYCLOAK.ORG
 krb5KeyVersionNumber: 0
 
+# Cross-realm trust support! Realm KEYCLOAK.ORG will trust the realm KC2.COM
+dn: uid=krbtgt2,ou=People,dc=keycloak,dc=org
+objectClass: top
+objectClass: person
+objectClass: inetOrgPerson
+objectClass: krb5principal
+objectClass: krb5kdcentry
+cn: KDC Service
+sn: Service
+uid: krbtgt2
+userPassword: secret
+krb5PrincipalName: krbtgt/KEYCLOAK.ORG@KC2.COM
+krb5KeyVersionNumber: 0
+
 dn: uid=ldap,ou=People,dc=keycloak,dc=org
 objectClass: top
 objectClass: person
diff --git a/util/embedded-ldap/src/main/resources/kerberos/default-users-kc2.ldif b/util/embedded-ldap/src/main/resources/kerberos/default-users-kc2.ldif
new file mode 100644
index 0000000..8758643
--- /dev/null
+++ b/util/embedded-ldap/src/main/resources/kerberos/default-users-kc2.ldif
@@ -0,0 +1,104 @@
+dn: dc=kc2,dc=com
+objectclass: dcObject
+objectclass: organization
+o: Kc2
+dc: Kc2
+
+dn: ou=People,dc=kc2,dc=com
+objectClass: organizationalUnit
+objectClass: top
+ou: People
+
+dn: uid=krbtgt,ou=People,dc=kc2,dc=com
+objectClass: top
+objectClass: person
+objectClass: inetOrgPerson
+objectClass: krb5principal
+objectClass: krb5kdcentry
+cn: KDC Service
+sn: Service
+uid: krbtgt
+userPassword: secret
+krb5PrincipalName: krbtgt/KC2.COM@KC2.COM
+krb5KeyVersionNumber: 0
+
+# Cross-realm trust support! Realm KEYCLOAK.ORG will trust the realm KC2.COM
+dn: uid=krbtgt2,ou=People,dc=kc2,dc=com
+objectClass: top
+objectClass: person
+objectClass: inetOrgPerson
+objectClass: krb5principal
+objectClass: krb5kdcentry
+cn: KDC Service
+sn: Service
+uid: krbtgt2
+userPassword: secret
+krb5PrincipalName: krbtgt/KEYCLOAK.ORG@KC2.COM
+krb5KeyVersionNumber: 0
+
+dn: uid=ldap,ou=People,dc=kc2,dc=com
+objectClass: top
+objectClass: person
+objectClass: inetOrgPerson
+objectClass: krb5principal
+objectClass: krb5kdcentry
+cn: LDAP
+sn: Service
+uid: ldap
+userPassword: randall
+krb5PrincipalName: ${ldapSaslPrincipal}
+krb5KeyVersionNumber: 0
+
+dn: uid=HTTP,ou=People,dc=kc2,dc=com
+objectClass: top
+objectClass: person
+objectClass: inetOrgPerson
+objectClass: krb5principal
+objectClass: krb5kdcentry
+cn: HTTP
+sn: Service
+uid: HTTP
+userPassword: httppwd
+krb5PrincipalName: HTTP/${hostname}@KC2.COM
+krb5KeyVersionNumber: 0
+
+dn: uid=hnelson2,ou=People,dc=kc2,dc=com
+objectClass: top
+objectClass: person
+objectClass: inetOrgPerson
+objectClass: krb5principal
+objectClass: krb5kdcentry
+cn: Horatio
+sn: Nelson
+mail: hnelson2@kc2.com
+uid: hnelson2
+userPassword: secret
+krb5PrincipalName: hnelson2@KC2.COM
+krb5KeyVersionNumber: 0
+
+dn: uid=jduke2,ou=People,dc=kc2,dc=com
+objectClass: top
+objectClass: person
+objectClass: inetOrgPerson
+objectClass: krb5principal
+objectClass: krb5kdcentry
+cn: Java
+sn: Duke
+mail: jduke2@keycloak.org
+uid: jduke2
+userPassword: theduke
+krb5PrincipalName: jduke2@KC2.COM
+krb5KeyVersionNumber: 0
+
+dn: uid=gsstestserver,ou=People,dc=kc2,dc=com
+objectClass: top
+objectClass: person
+objectClass: inetOrgPerson
+objectClass: krb5principal
+objectClass: krb5kdcentry
+cn: gsstestserver
+sn: Service
+uid: gsstestserver
+userPassword: gsstestpwd
+krb5PrincipalName: gsstestserver/xxx@KC2.COM
+krb5KeyVersionNumber: 0
\ No newline at end of file
diff --git a/util/embedded-ldap/src/main/resources/log4j.properties b/util/embedded-ldap/src/main/resources/log4j.properties
index 0dac21b..81f5973 100644
--- a/util/embedded-ldap/src/main/resources/log4j.properties
+++ b/util/embedded-ldap/src/main/resources/log4j.properties
@@ -23,4 +23,7 @@ log4j.appender.stdout.layout.ConversionPattern=%d{HH:mm:ss,SSS} %-5p [%c] %m%n
 
 log4j.logger.org.keycloak=info
 log4j.logger.org.apache.directory.api=warn
-log4j.logger.org.apache.directory.server.core=warn
\ No newline at end of file
+log4j.logger.org.apache.directory.server.core=warn
+
+# Enable to view detailed AS REQ and TGS REQ requests to embedded Kerberos server
+#log4j.logger.org.apache.directory.server.kerberos=debug
\ No newline at end of file