keycloak-aplcache

Kerberos automated test

2/19/2015 5:45:45 PM

Changes

Details

diff --git a/dependencies/server-all/pom.xml b/dependencies/server-all/pom.xml
index f697926..339afad 100755
--- a/dependencies/server-all/pom.xml
+++ b/dependencies/server-all/pom.xml
@@ -95,11 +95,6 @@
         </dependency>
         <dependency>
             <groupId>org.keycloak</groupId>
-            <artifactId>keycloak-kerberos-federation</artifactId>
-            <version>${project.version}</version>
-        </dependency>
-        <dependency>
-            <groupId>org.keycloak</groupId>
             <artifactId>keycloak-social-github</artifactId>
             <version>${project.version}</version>
         </dependency>
@@ -130,6 +125,11 @@
             <version>${project.version}</version>
         </dependency>
         <dependency>
+            <groupId>org.keycloak</groupId>
+            <artifactId>keycloak-kerberos-federation</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+        <dependency>
             <groupId>org.picketlink</groupId>
             <artifactId>picketlink-common</artifactId>
         </dependency>
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 6fe528c..04b498e 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
@@ -3,7 +3,7 @@ package org.keycloak.federation.kerberos;
 import java.util.Map;
 
 import org.keycloak.models.UserFederationProviderModel;
-import org.keycloak.models.utils.KerberosConstants;
+import org.keycloak.models.KerberosConstants;
 
 /**
  * Common configuration useful for all providers
@@ -24,19 +24,19 @@ public abstract class CommonKerberosConfig {
     }
 
     public String getKerberosRealm() {
-        return getConfig().get("kerberosRealm");
+        return getConfig().get(KerberosConstants.KERBEROS_REALM);
     }
 
     public String getServerPrincipal() {
-        return getConfig().get("serverPrincipal");
+        return getConfig().get(KerberosConstants.SERVER_PRINCIPAL);
     }
 
     public String getKeyTab() {
-        return getConfig().get("keyTab");
+        return getConfig().get(KerberosConstants.KEYTAB);
     }
 
     public boolean getDebug() {
-        return Boolean.valueOf(getConfig().get("debug"));
+        return Boolean.valueOf(getConfig().get(KerberosConstants.DEBUG));
     }
 
     protected Map<String, String> getConfig() {
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 6515950..c8e6fa0 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
@@ -4,6 +4,7 @@ import java.io.IOException;
 import java.util.HashMap;
 import java.util.Map;
 
+import javax.security.auth.Subject;
 import javax.security.auth.callback.Callback;
 import javax.security.auth.callback.CallbackHandler;
 import javax.security.auth.callback.NameCallback;
@@ -25,11 +26,13 @@ public class KerberosUsernamePasswordAuthenticator {
     private static final Logger logger = Logger.getLogger(KerberosUsernamePasswordAuthenticator.class);
 
     private final CommonKerberosConfig config;
+    private LoginContext loginContext;
 
     public KerberosUsernamePasswordAuthenticator(CommonKerberosConfig config) {
         this.config = config;
     }
 
+
     /**
      * Returns true if user with given username exists in kerberos database
      *
@@ -41,7 +44,7 @@ public class KerberosUsernamePasswordAuthenticator {
 
         logger.debug("Checking existence of principal: " + principal);
         try {
-            LoginContext loginContext = new LoginContext("does-not-matter", null,
+            loginContext = new LoginContext("does-not-matter", null,
                     createJaasCallbackHandler(principal, "fake-password-which-nobody-has"),
                     createJaasConfiguration());
 
@@ -58,6 +61,7 @@ public class KerberosUsernamePasswordAuthenticator {
         }
     }
 
+
     /**
      * Returns true if user was successfully authenticated against Kerberos
      *
@@ -66,18 +70,9 @@ public class KerberosUsernamePasswordAuthenticator {
      * @return  true if user was successfully authenticated
      */
     public boolean validUser(String username, String password) {
-        String principal = getKerberosPrincipal(username);
-
-        logger.debug("Validating password of principal: " + principal);
         try {
-            LoginContext loginContext = new LoginContext("does-not-matter", null,
-                    createJaasCallbackHandler(principal, password),
-                    createJaasConfiguration());
-
-            loginContext.login();
-            logger.debug("Principal " + principal + " authenticated succesfully");
-
-            loginContext.logout();
+            authenticateSubject(username, password);
+            logoutSubject();
             return true;
         } catch (LoginException le) {
             logger.debug("Failed to authenticate user " + username, le);
@@ -86,6 +81,38 @@ public class KerberosUsernamePasswordAuthenticator {
     }
 
 
+    /**
+     * Returns true if user was successfully authenticated against Kerberos
+     *
+     * @param username username without Kerberos realm attached
+     * @param password kerberos password
+     * @return  true if user was successfully authenticated
+     */
+    public Subject authenticateSubject(String username, String password) throws LoginException {
+        String principal = getKerberosPrincipal(username);
+
+        logger.debug("Validating password of principal: " + principal);
+        loginContext = new LoginContext("does-not-matter", null,
+                createJaasCallbackHandler(principal, password),
+                createJaasConfiguration());
+
+        loginContext.login();
+        logger.debug("Principal " + principal + " authenticated succesfully");
+        return loginContext.getSubject();
+    }
+
+    public void logoutSubject() {
+        if (loginContext != null) {
+            try {
+                loginContext.logout();
+            } catch (LoginException le) {
+                logger.error("Failed to logout kerberos server subject: " + config.getServerPrincipal(), le);
+            }
+        }
+    }
+
+
+
     protected String getKerberosPrincipal(String username) {
         return username + "@" + config.getKerberosRealm();
     }
diff --git a/federation/kerberos/src/main/java/org/keycloak/federation/kerberos/KerberosConfig.java b/federation/kerberos/src/main/java/org/keycloak/federation/kerberos/KerberosConfig.java
index 950f9cd..c1f59b7 100644
--- a/federation/kerberos/src/main/java/org/keycloak/federation/kerberos/KerberosConfig.java
+++ b/federation/kerberos/src/main/java/org/keycloak/federation/kerberos/KerberosConfig.java
@@ -1,5 +1,7 @@
 package org.keycloak.federation.kerberos;
 
+import org.keycloak.models.KerberosConstants;
+import org.keycloak.models.LDAPConstants;
 import org.keycloak.models.UserFederationProvider;
 import org.keycloak.models.UserFederationProviderModel;
 
@@ -15,7 +17,7 @@ public class KerberosConfig extends CommonKerberosConfig {
     }
 
     public UserFederationProvider.EditMode getEditMode() {
-        String editModeString = getConfig().get("editMode");
+        String editModeString = getConfig().get(LDAPConstants.EDIT_MODE);
         if (editModeString == null) {
             return UserFederationProvider.EditMode.UNSYNCED;
         } else {
@@ -24,11 +26,11 @@ public class KerberosConfig extends CommonKerberosConfig {
     }
 
     public boolean isAllowPasswordAuthentication() {
-        return Boolean.valueOf(getConfig().get("allowPasswordAuthentication"));
+        return Boolean.valueOf(getConfig().get(KerberosConstants.ALLOW_PASSWORD_AUTHENTICATION));
     }
 
     public boolean isUpdateProfileFirstLogin() {
-        return Boolean.valueOf(getConfig().get("updateProfileFirstLogin"));
+        return Boolean.valueOf(getConfig().get(KerberosConstants.UPDATE_PROFILE_FIRST_LOGIN));
     }
 
 }
diff --git a/federation/kerberos/src/main/java/org/keycloak/federation/kerberos/KerberosFederationProvider.java b/federation/kerberos/src/main/java/org/keycloak/federation/kerberos/KerberosFederationProvider.java
index 35f5885..b0d23dc 100644
--- a/federation/kerberos/src/main/java/org/keycloak/federation/kerberos/KerberosFederationProvider.java
+++ b/federation/kerberos/src/main/java/org/keycloak/federation/kerberos/KerberosFederationProvider.java
@@ -20,7 +20,7 @@ import org.keycloak.models.UserCredentialValueModel;
 import org.keycloak.models.UserFederationProvider;
 import org.keycloak.models.UserFederationProviderModel;
 import org.keycloak.models.UserModel;
-import org.keycloak.models.utils.KerberosConstants;
+import org.keycloak.models.KerberosConstants;
 
 /**
  * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
diff --git a/federation/ldap/src/main/java/org/keycloak/federation/ldap/kerberos/LDAPProviderKerberosConfig.java b/federation/ldap/src/main/java/org/keycloak/federation/ldap/kerberos/LDAPProviderKerberosConfig.java
index b98c5ca..4363ce9 100644
--- a/federation/ldap/src/main/java/org/keycloak/federation/ldap/kerberos/LDAPProviderKerberosConfig.java
+++ b/federation/ldap/src/main/java/org/keycloak/federation/ldap/kerberos/LDAPProviderKerberosConfig.java
@@ -1,6 +1,7 @@
 package org.keycloak.federation.ldap.kerberos;
 
 import org.keycloak.federation.kerberos.CommonKerberosConfig;
+import org.keycloak.models.KerberosConstants;
 import org.keycloak.models.UserFederationProviderModel;
 
 /**
@@ -15,6 +16,6 @@ public class LDAPProviderKerberosConfig extends CommonKerberosConfig {
     }
 
     public boolean isUseKerberosForPasswordAuthentication() {
-        return Boolean.valueOf(getConfig().get("useKerberosForPasswordAuthentication"));
+        return Boolean.valueOf(getConfig().get(KerberosConstants.USE_KERBEROS_FOR_PASSWORD_AUTHENTICATION));
     }
 }
diff --git a/federation/ldap/src/main/java/org/keycloak/federation/ldap/LDAPFederationProvider.java b/federation/ldap/src/main/java/org/keycloak/federation/ldap/LDAPFederationProvider.java
index 9a92604..3e2237d 100755
--- a/federation/ldap/src/main/java/org/keycloak/federation/ldap/LDAPFederationProvider.java
+++ b/federation/ldap/src/main/java/org/keycloak/federation/ldap/LDAPFederationProvider.java
@@ -6,6 +6,7 @@ import org.keycloak.federation.kerberos.impl.SPNEGOAuthenticator;
 import org.keycloak.federation.ldap.kerberos.LDAPProviderKerberosConfig;
 import org.keycloak.models.CredentialValidationOutput;
 import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.LDAPConstants;
 import org.keycloak.models.ModelException;
 import org.keycloak.models.RealmModel;
 import org.keycloak.models.RoleModel;
@@ -14,7 +15,7 @@ import org.keycloak.models.UserCredentialValueModel;
 import org.keycloak.models.UserFederationProvider;
 import org.keycloak.models.UserFederationProviderModel;
 import org.keycloak.models.UserModel;
-import org.keycloak.models.utils.KerberosConstants;
+import org.keycloak.models.KerberosConstants;
 import org.picketlink.idm.IdentityManagementException;
 import org.picketlink.idm.IdentityManager;
 import org.picketlink.idm.PartitionManager;
@@ -39,7 +40,6 @@ public class LDAPFederationProvider implements UserFederationProvider {
     private static final Logger logger = Logger.getLogger(LDAPFederationProvider.class);
     public static final String LDAP_ID = "LDAP_ID";
     public static final String SYNC_REGISTRATIONS = "syncRegistrations";
-    public static final String EDIT_MODE = "editMode";
 
     protected LDAPFederationProviderFactory factory;
     protected KeycloakSession session;
@@ -56,7 +56,7 @@ public class LDAPFederationProvider implements UserFederationProvider {
         this.model = model;
         this.partitionManager = partitionManager;
         this.kerberosConfig = new LDAPProviderKerberosConfig(model);
-        String editModeString = model.getConfig().get(EDIT_MODE);
+        String editModeString = model.getConfig().get(LDAPConstants.EDIT_MODE);
         if (editModeString == null) {
             editMode = EditMode.READ_ONLY;
         } else {
diff --git a/model/api/src/main/java/org/keycloak/models/LDAPConstants.java b/model/api/src/main/java/org/keycloak/models/LDAPConstants.java
index 97651fc..bf76be7 100644
--- a/model/api/src/main/java/org/keycloak/models/LDAPConstants.java
+++ b/model/api/src/main/java/org/keycloak/models/LDAPConstants.java
@@ -23,6 +23,8 @@ public class LDAPConstants {
     public static final String CONNECTION_POOLING = "connectionPooling";
     public static final String PAGINATION = "pagination";
 
+    public static final String EDIT_MODE = "editMode";
+
     // Count of users processed per single transaction during sync process
     public static final String BATCH_SIZE_FOR_SYNC = "batchSizeForSync";
     public static final int DEFAULT_BATCH_SIZE_FOR_SYNC = 1000;
diff --git a/services/src/main/java/org/keycloak/services/managers/HttpAuthenticationManager.java b/services/src/main/java/org/keycloak/services/managers/HttpAuthenticationManager.java
index ca0488e..34ed900 100644
--- a/services/src/main/java/org/keycloak/services/managers/HttpAuthenticationManager.java
+++ b/services/src/main/java/org/keycloak/services/managers/HttpAuthenticationManager.java
@@ -7,6 +7,7 @@ import javax.ws.rs.core.UriInfo;
 import org.jboss.logging.Logger;
 import org.jboss.resteasy.spi.HttpRequest;
 import org.keycloak.ClientConnection;
+import org.keycloak.events.Details;
 import org.keycloak.events.Errors;
 import org.keycloak.events.EventBuilder;
 import org.keycloak.login.LoginFormsProvider;
@@ -18,7 +19,7 @@ import org.keycloak.models.RequiredCredentialModel;
 import org.keycloak.models.UserCredentialModel;
 import org.keycloak.models.UserModel;
 import org.keycloak.models.UserSessionModel;
-import org.keycloak.models.utils.KerberosConstants;
+import org.keycloak.models.KerberosConstants;
 import org.keycloak.protocol.oidc.TokenManager;
 import org.keycloak.representations.idm.CredentialRepresentation;
 import org.keycloak.services.messages.Messages;
@@ -59,11 +60,15 @@ public class HttpAuthenticationManager {
         boolean kerberosSupported = false;
         for (RequiredCredentialModel c : realm.getRequiredCredentials()) {
             if (c.getType().equals(CredentialRepresentation.KERBEROS)) {
-                logger.debug("Kerberos authentication is supported");
                 kerberosSupported = true;
             }
         }
 
+        if (logger.isTraceEnabled()) {
+            String log = kerberosSupported ? "SPNEGO authentication is supported" : "SPNEGO authentication is not supported";
+            logger.trace(log);
+        }
+
         if (!kerberosSupported) {
             return new HttpAuthOutput(null, null);
         }
@@ -100,6 +105,10 @@ public class HttpAuthenticationManager {
 
     // Send response after successful authentication
     private HttpAuthOutput sendResponse(UserModel user, String authMethod) {
+        if (logger.isTraceEnabled()) {
+            logger.trace("User " + user.getUsername() + " authenticated with " + authMethod);
+        }
+
         Response response;
         if (!user.isEnabled()) {
             event.error(Errors.USER_DISABLED);
@@ -107,7 +116,10 @@ public class HttpAuthenticationManager {
         } else {
             UserSessionModel userSession = session.sessions().createUserSession(realm, user, user.getUsername(), clientConnection.getRemoteAddr(), authMethod, false);
             TokenManager.attachClientSession(userSession, clientSession);
-            event.session(userSession);
+            event.user(user)
+                    .session(userSession)
+                    .detail(Details.AUTH_METHOD, authMethod)
+                    .detail(Details.USERNAME, user.getUsername());
             response = AuthenticationManager.nextActionAfterAuthentication(session, userSession, clientSession, clientConnection, request, uriInfo, event);
         }
 
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/UserFederationResource.java b/services/src/main/java/org/keycloak/services/resources/admin/UserFederationResource.java
index 730252c..04e3c7f 100755
--- a/services/src/main/java/org/keycloak/services/resources/admin/UserFederationResource.java
+++ b/services/src/main/java/org/keycloak/services/resources/admin/UserFederationResource.java
@@ -10,7 +10,7 @@ import org.keycloak.models.UserCredentialModel;
 import org.keycloak.models.UserFederationProvider;
 import org.keycloak.models.UserFederationProviderFactory;
 import org.keycloak.models.UserFederationProviderModel;
-import org.keycloak.models.utils.KerberosConstants;
+import org.keycloak.models.KerberosConstants;
 import org.keycloak.models.utils.ModelToRepresentation;
 import org.keycloak.provider.ProviderFactory;
 import org.keycloak.representations.idm.UserFederationProviderFactoryRepresentation;
diff --git a/testsuite/integration/pom.xml b/testsuite/integration/pom.xml
index 98697e5..d584650 100755
--- a/testsuite/integration/pom.xml
+++ b/testsuite/integration/pom.xml
@@ -125,6 +125,11 @@
         </dependency>
         <dependency>
             <groupId>org.keycloak</groupId>
+            <artifactId>keycloak-kerberos-federation</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.keycloak</groupId>
             <artifactId>keycloak-undertow-adapter</artifactId>
             <version>${project.version}</version>
         </dependency>
diff --git a/testsuite/integration/src/main/java/org/keycloak/testutils/ldap/LDAPConfiguration.java b/testsuite/integration/src/main/java/org/keycloak/testutils/ldap/LDAPConfiguration.java
index 1312143..63445b2 100644
--- a/testsuite/integration/src/main/java/org/keycloak/testutils/ldap/LDAPConfiguration.java
+++ b/testsuite/integration/src/main/java/org/keycloak/testutils/ldap/LDAPConfiguration.java
@@ -1,55 +1,88 @@
 package org.keycloak.testutils.ldap;
 
+import java.io.File;
 import java.io.InputStream;
+import java.net.URL;
 import java.util.HashMap;
 import java.util.Map;
 import java.util.Properties;
 
+import org.jboss.logging.Logger;
+import org.keycloak.models.KerberosConstants;
 import org.keycloak.models.LDAPConstants;
+import org.keycloak.models.UserFederationProvider;
 
 /**
  * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
  */
 public class LDAPConfiguration {
 
-    public static final String CONNECTION_PROPERTIES = "ldap/ldap-connection.properties";
-
-    protected String connectionUrl = "ldap://localhost:10389";
-    protected String baseDn =  "dc=keycloak,dc=org";
-    protected String userDnSuffix = "ou=People,dc=keycloak,dc=org";
-    protected String rolesDnSuffix = "ou=Roles,dc=keycloak,dc=org";
-    protected String groupDnSuffix = "ou=Groups,dc=keycloak,dc=org";
-    protected String agentDnSuffix = "ou=Agent,dc=keycloak,dc=org";
-    protected boolean startEmbeddedLdapLerver = true;
-    protected String bindDn = "uid=admin,ou=system";
-    protected String bindCredential = "secret";
-    protected String vendor = LDAPConstants.VENDOR_OTHER;
-    protected boolean connectionPooling = true;
-    protected boolean pagination = true;
-    protected int batchSizeForSync = LDAPConstants.DEFAULT_BATCH_SIZE_FOR_SYNC;
-    protected String usernameLDAPAttribute;
-    protected String userObjectClasses;
-    protected boolean userAccountControlsAfterPasswordUpdate;
-
-    public static String IDM_TEST_LDAP_CONNECTION_URL = "idm.test.ldap.connection.url";
-    public static String IDM_TEST_LDAP_BASE_DN = "idm.test.ldap.base.dn";
-    public static String IDM_TEST_LDAP_ROLES_DN_SUFFIX = "idm.test.ldap.roles.dn.suffix";
-    public static String IDM_TEST_LDAP_GROUP_DN_SUFFIX = "idm.test.ldap.group.dn.suffix";
-    public static String IDM_TEST_LDAP_USER_DN_SUFFIX = "idm.test.ldap.user.dn.suffix";
-    public static String IDM_TEST_LDAP_AGENT_DN_SUFFIX = "idm.test.ldap.agent.dn.suffix";
-    public static String IDM_TEST_LDAP_START_EMBEDDED_LDAP_SERVER = "idm.test.ldap.start.embedded.ldap.server";
-    public static String IDM_TEST_LDAP_BIND_DN = "idm.test.ldap.bind.dn";
-    public static String IDM_TEST_LDAP_BIND_CREDENTIAL = "idm.test.ldap.bind.credential";
-    public static String IDM_TEST_LDAP_VENDOR = "idm.test.ldap.vendor";
-    public static String IDM_TEST_LDAP_CONNECTION_POOLING = "idm.test.ldap.connection.pooling";
-    public static String IDM_TEST_LDAP_PAGINATION = "idm.test.ldap.pagination";
-    public static String IDM_TEST_LDAP_BATCH_SIZE_FOR_SYNC = "idm.test.ldap.batch.size.for.sync";
-    public static String IDM_TEST_LDAP_USERNAME_LDAP_ATTRIBUTE = "idm.test.ldap.username.ldap.attribute";
-    public static String IDM_TEST_LDAP_USER_OBJECT_CLASSES = "idm.test.ldap.user.object.classes";
-    public static String IDM_TEST_LDAP_USER_ACCOUNT_CONTROLS_AFTER_PASSWORD_UPDATE = "idm.test.ldap.user.account.controls.after.password.update";
-
-    public static LDAPConfiguration readConfiguration() {
+    private static final Logger log = Logger.getLogger(LDAPConfiguration.class);
+
+    private String connectionPropertiesLocation;
+    private boolean startEmbeddedLdapLerver = true;
+    private Map<String, String> config;
+
+    protected static final Map<String, String> PROP_MAPPINGS = new HashMap<String, String>();
+    protected static final Map<String, String> DEFAULT_VALUES = new HashMap<String, String>();
+
+    static {
+        PROP_MAPPINGS.put(LDAPConstants.CONNECTION_URL, "idm.test.ldap.connection.url");
+        PROP_MAPPINGS.put(LDAPConstants.BASE_DN, "idm.test.ldap.base.dn");
+        PROP_MAPPINGS.put("rolesDnSuffix", "idm.test.ldap.roles.dn.suffix");
+        PROP_MAPPINGS.put("groupDnSuffix", "idm.test.ldap.group.dn.suffix");
+        PROP_MAPPINGS.put(LDAPConstants.USER_DN_SUFFIX, "idm.test.ldap.user.dn.suffix");
+        PROP_MAPPINGS.put(LDAPConstants.BIND_DN, "idm.test.ldap.bind.dn");
+        PROP_MAPPINGS.put(LDAPConstants.BIND_CREDENTIAL, "idm.test.ldap.bind.credential");
+        PROP_MAPPINGS.put(LDAPConstants.VENDOR, "idm.test.ldap.vendor");
+        PROP_MAPPINGS.put(LDAPConstants.CONNECTION_POOLING, "idm.test.ldap.connection.pooling");
+        PROP_MAPPINGS.put(LDAPConstants.PAGINATION, "idm.test.ldap.pagination");
+        PROP_MAPPINGS.put(LDAPConstants.BATCH_SIZE_FOR_SYNC, "idm.test.ldap.batch.size.for.sync");
+        PROP_MAPPINGS.put(LDAPConstants.USERNAME_LDAP_ATTRIBUTE, "idm.test.ldap.username.ldap.attribute");
+        PROP_MAPPINGS.put(LDAPConstants.USER_OBJECT_CLASSES, "idm.test.ldap.user.object.classes");
+        PROP_MAPPINGS.put(LDAPConstants.USER_ACCOUNT_CONTROLS_AFTER_PASSWORD_UPDATE, "idm.test.ldap.user.account.controls.after.password.update");
+        PROP_MAPPINGS.put(LDAPConstants.EDIT_MODE, "idm.test.ldap.edit.mode");
+
+        PROP_MAPPINGS.put(KerberosConstants.ALLOW_KERBEROS_AUTHENTICATION, "idm.test.kerberos.allow.kerberos.authentication");
+        PROP_MAPPINGS.put(KerberosConstants.KERBEROS_REALM, "idm.test.kerberos.realm");
+        PROP_MAPPINGS.put(KerberosConstants.SERVER_PRINCIPAL, "idm.test.kerberos.server.principal");
+        PROP_MAPPINGS.put(KerberosConstants.KEYTAB, "idm.test.kerberos.keytab");
+        PROP_MAPPINGS.put(KerberosConstants.DEBUG, "idm.test.kerberos.debug");
+        PROP_MAPPINGS.put(KerberosConstants.ALLOW_PASSWORD_AUTHENTICATION, "idm.test.kerberos.allow.password.authentication");
+        PROP_MAPPINGS.put(KerberosConstants.UPDATE_PROFILE_FIRST_LOGIN, "idm.test.kerberos.update.profile.first.login");
+        PROP_MAPPINGS.put(KerberosConstants.USE_KERBEROS_FOR_PASSWORD_AUTHENTICATION, "idm.test.kerberos.use.kerberos.for.password.authentication");
+
+        DEFAULT_VALUES.put(LDAPConstants.CONNECTION_URL, "ldap://localhost:10389");
+        DEFAULT_VALUES.put(LDAPConstants.BASE_DN, "dc=keycloak,dc=org");
+        DEFAULT_VALUES.put("rolesDnSuffix", "ou=Roles,dc=keycloak,dc=org");
+        DEFAULT_VALUES.put("groupDnSuffix", "ou=Groups,dc=keycloak,dc=org");
+        DEFAULT_VALUES.put(LDAPConstants.USER_DN_SUFFIX, "ou=People,dc=keycloak,dc=org");
+        DEFAULT_VALUES.put(LDAPConstants.BIND_DN, "uid=admin,ou=system");
+        DEFAULT_VALUES.put(LDAPConstants.BIND_CREDENTIAL, "secret");
+        DEFAULT_VALUES.put(LDAPConstants.VENDOR, LDAPConstants.VENDOR_OTHER);
+        DEFAULT_VALUES.put(LDAPConstants.CONNECTION_POOLING, "true");
+        DEFAULT_VALUES.put(LDAPConstants.PAGINATION, "true");
+        DEFAULT_VALUES.put(LDAPConstants.BATCH_SIZE_FOR_SYNC, String.valueOf(LDAPConstants.DEFAULT_BATCH_SIZE_FOR_SYNC));
+        DEFAULT_VALUES.put(LDAPConstants.USERNAME_LDAP_ATTRIBUTE, null);
+        DEFAULT_VALUES.put(LDAPConstants.USER_OBJECT_CLASSES, null);
+        DEFAULT_VALUES.put(LDAPConstants.USER_ACCOUNT_CONTROLS_AFTER_PASSWORD_UPDATE, "false");
+        DEFAULT_VALUES.put(LDAPConstants.EDIT_MODE, UserFederationProvider.EditMode.READ_ONLY.toString());
+
+        DEFAULT_VALUES.put(KerberosConstants.ALLOW_KERBEROS_AUTHENTICATION, "false");
+        DEFAULT_VALUES.put(KerberosConstants.KERBEROS_REALM, "KEYCLOAK.ORG");
+        DEFAULT_VALUES.put(KerberosConstants.SERVER_PRINCIPAL, "HTTP/localhost@KEYCLOAK.ORG");
+        URL keytabUrl = LDAPConfiguration.class.getResource("/kerberos/http.keytab");
+        String keyTabPath = new File(keytabUrl.getFile()).getAbsolutePath();
+        DEFAULT_VALUES.put(KerberosConstants.KEYTAB, keyTabPath);
+        DEFAULT_VALUES.put(KerberosConstants.DEBUG, "true");
+        DEFAULT_VALUES.put(KerberosConstants.ALLOW_PASSWORD_AUTHENTICATION, "true");
+        DEFAULT_VALUES.put(KerberosConstants.UPDATE_PROFILE_FIRST_LOGIN, "true");
+        DEFAULT_VALUES.put(KerberosConstants.USE_KERBEROS_FOR_PASSWORD_AUTHENTICATION, "false");
+    }
+
+    public static LDAPConfiguration readConfiguration(String connectionPropertiesLocation) {
         LDAPConfiguration ldapConfiguration = new LDAPConfiguration();
+        ldapConfiguration.setConnectionPropertiesLocation(connectionPropertiesLocation);
         ldapConfiguration.loadConnectionProperties();
         return ldapConfiguration;
     }
@@ -57,109 +90,42 @@ public class LDAPConfiguration {
     protected void loadConnectionProperties() {
         Properties p = new Properties();
         try {
-            InputStream is = Thread.currentThread().getContextClassLoader().getResourceAsStream(CONNECTION_PROPERTIES);
+            log.info("Reading LDAP configuration from: " + connectionPropertiesLocation);
+            InputStream is = Thread.currentThread().getContextClassLoader().getResourceAsStream(connectionPropertiesLocation);
             p.load(is);
         }
         catch (Exception e) {
             throw new RuntimeException(e);
         }
 
-        connectionUrl = p.getProperty(IDM_TEST_LDAP_CONNECTION_URL, connectionUrl);
-        baseDn = p.getProperty(IDM_TEST_LDAP_BASE_DN, baseDn);
-        userDnSuffix = p.getProperty(IDM_TEST_LDAP_USER_DN_SUFFIX, userDnSuffix);
-        rolesDnSuffix = p.getProperty(IDM_TEST_LDAP_ROLES_DN_SUFFIX, rolesDnSuffix);
-        groupDnSuffix = p.getProperty(IDM_TEST_LDAP_GROUP_DN_SUFFIX, groupDnSuffix);
-        agentDnSuffix = p.getProperty(IDM_TEST_LDAP_AGENT_DN_SUFFIX, agentDnSuffix);
-        startEmbeddedLdapLerver = Boolean.parseBoolean(p.getProperty(IDM_TEST_LDAP_START_EMBEDDED_LDAP_SERVER, "true"));
-        bindDn = p.getProperty(IDM_TEST_LDAP_BIND_DN, bindDn);
-        bindCredential = p.getProperty(IDM_TEST_LDAP_BIND_CREDENTIAL, bindCredential);
-        vendor = p.getProperty(IDM_TEST_LDAP_VENDOR);
-        connectionPooling = Boolean.parseBoolean(p.getProperty(IDM_TEST_LDAP_CONNECTION_POOLING, "true"));
-        pagination = Boolean.parseBoolean(p.getProperty(IDM_TEST_LDAP_PAGINATION, "true"));
-        batchSizeForSync = Integer.parseInt(p.getProperty(IDM_TEST_LDAP_BATCH_SIZE_FOR_SYNC, String.valueOf(batchSizeForSync)));
-        usernameLDAPAttribute = p.getProperty(IDM_TEST_LDAP_USERNAME_LDAP_ATTRIBUTE);
-        userObjectClasses = p.getProperty(IDM_TEST_LDAP_USER_OBJECT_CLASSES);
-        userAccountControlsAfterPasswordUpdate = Boolean.parseBoolean(p.getProperty(IDM_TEST_LDAP_USER_ACCOUNT_CONTROLS_AFTER_PASSWORD_UPDATE));
-    }
-
-    public Map<String,String> getLDAPConfig() {
-        Map<String,String> ldapConfig = new HashMap<String,String>();
-        ldapConfig.put(LDAPConstants.CONNECTION_URL, getConnectionUrl());
-        ldapConfig.put(LDAPConstants.BASE_DN, getBaseDn());
-        ldapConfig.put(LDAPConstants.BIND_DN, getBindDn());
-        ldapConfig.put(LDAPConstants.BIND_CREDENTIAL, getBindCredential());
-        ldapConfig.put(LDAPConstants.USER_DN_SUFFIX, getUserDnSuffix());
-        ldapConfig.put(LDAPConstants.VENDOR, getVendor());
-        ldapConfig.put(LDAPConstants.CONNECTION_POOLING, String.valueOf(isConnectionPooling()));
-        ldapConfig.put(LDAPConstants.PAGINATION, String.valueOf(isPagination()));
-        ldapConfig.put(LDAPConstants.BATCH_SIZE_FOR_SYNC, String.valueOf(getBatchSizeForSync()));
-        ldapConfig.put(LDAPConstants.USERNAME_LDAP_ATTRIBUTE, getUsernameLDAPAttribute());
-        ldapConfig.put(LDAPConstants.USER_OBJECT_CLASSES, getUserObjectClasses());
-        ldapConfig.put(LDAPConstants.USER_ACCOUNT_CONTROLS_AFTER_PASSWORD_UPDATE, String.valueOf(isUserAccountControlsAfterPasswordUpdate()));
-        return ldapConfig;
-    }
+        config = new HashMap<String, String>();
+        for (Map.Entry<String, String> property : PROP_MAPPINGS.entrySet()) {
+            String propertyName = property.getKey();
+            String configName = property.getValue();
 
-    public String getConnectionUrl() {
-        return connectionUrl;
-    }
-
-    public String getBaseDn() {
-        return baseDn;
-    }
+            String value = (String) p.get(configName);
+            if (value == null) {
+                value = DEFAULT_VALUES.get(propertyName);
+            }
 
-    public String getUserDnSuffix() {
-        return userDnSuffix;
-    }
+            config.put(propertyName, value);
+        }
 
-    public String getRolesDnSuffix() {
-        return rolesDnSuffix;
+        startEmbeddedLdapLerver = Boolean.parseBoolean(p.getProperty("idm.test.ldap.start.embedded.ldap.server", "true"));
+        log.info("Start embedded server: " + startEmbeddedLdapLerver);
+        log.info("Read config: " + config);
     }
 
-    public String getGroupDnSuffix() {
-        return groupDnSuffix;
+    public Map<String,String> getLDAPConfig() {
+        return config;
     }
 
-    public String getAgentDnSuffix() {
-        return agentDnSuffix;
+    public void setConnectionPropertiesLocation(String connectionPropertiesLocation) {
+        this.connectionPropertiesLocation = connectionPropertiesLocation;
     }
 
     public boolean isStartEmbeddedLdapLerver() {
         return startEmbeddedLdapLerver;
     }
 
-    public String getBindDn() {
-        return bindDn;
-    }
-
-    public String getBindCredential() {
-        return bindCredential;
-    }
-
-    public String getVendor() {
-        return vendor;
-    }
-
-    public boolean isConnectionPooling() {
-        return connectionPooling;
-    }
-
-    public boolean isPagination() {
-        return pagination;
-    }
-
-    public int getBatchSizeForSync() {
-        return batchSizeForSync;
-    }
-
-    public String getUsernameLDAPAttribute() {
-        return usernameLDAPAttribute;
-    }
-
-    public String getUserObjectClasses() {
-        return userObjectClasses;
-    }
-
-    public boolean isUserAccountControlsAfterPasswordUpdate() {
-        return userAccountControlsAfterPasswordUpdate;
-    }
 }
diff --git a/testsuite/integration/src/main/resources/kerberos/kerberos-ldap-connection.properties b/testsuite/integration/src/main/resources/kerberos/kerberos-ldap-connection.properties
new file mode 100644
index 0000000..4b7a741
--- /dev/null
+++ b/testsuite/integration/src/main/resources/kerberos/kerberos-ldap-connection.properties
@@ -0,0 +1,17 @@
+idm.test.ldap.connection.url=ldap\://localhost\:10389
+idm.test.ldap.base.dn=dc\=keycloak,dc\=org
+idm.test.ldap.roles.dn.suffix=ou\=Roles,dc\=keycloak,dc\=org
+idm.test.ldap.group.dn.suffix=ou\=Groups,dc\=keycloak,dc\=org
+idm.test.ldap.user.dn.suffix=ou\=People,dc\=keycloak,dc\=org
+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=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
diff --git a/testsuite/integration/src/main/resources/kerberos/kerberos-standalone-connection.properties b/testsuite/integration/src/main/resources/kerberos/kerberos-standalone-connection.properties
new file mode 100644
index 0000000..78bffb0
--- /dev/null
+++ b/testsuite/integration/src/main/resources/kerberos/kerberos-standalone-connection.properties
@@ -0,0 +1,6 @@
+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.allow.password.authentication=true
+idm.test.kerberos.update.profile.first.login=false
\ No newline at end of file
diff --git a/testsuite/integration/src/main/resources/kerberos/test-krb5.conf b/testsuite/integration/src/main/resources/kerberos/test-krb5.conf
new file mode 100644
index 0000000..2ba050d
--- /dev/null
+++ b/testsuite/integration/src/main/resources/kerberos/test-krb5.conf
@@ -0,0 +1,17 @@
+[libdefaults]
+    default_realm = KEYCLOAK.ORG
+    default_tgs_enctypes = des3-cbc-sha1-kd rc4-hmac
+    default_tkt_enctypes = des3-cbc-sha1-kd rc4-hmac
+    kdc_timeout = 30000
+    dns_lookup_realm = false
+    dns_lookup_kdc = false
+    dns_canonicalize_hostname = false
+    ignore_acceptor_hostname = true
+
+[realms]
+    KEYCLOAK.ORG = {
+        kdc = localhost:6088
+    }
+
+[domain_realm]
+    localhost = KEYCLOAK.ORG
\ No newline at end of file
diff --git a/testsuite/integration/src/main/resources/kerberos/users-kerberos.ldif b/testsuite/integration/src/main/resources/kerberos/users-kerberos.ldif
index fcde10e..acdd570 100644
--- a/testsuite/integration/src/main/resources/kerberos/users-kerberos.ldif
+++ b/testsuite/integration/src/main/resources/kerberos/users-kerberos.ldif
@@ -54,8 +54,9 @@ objectClass: person
 objectClass: inetOrgPerson
 objectClass: krb5principal
 objectClass: krb5kdcentry
-cn: Horatio Nelson
+cn: Horatio
 sn: Nelson
+mail: hnelson@keycloak.org
 uid: hnelson
 userPassword: secret
 krb5PrincipalName: hnelson@KEYCLOAK.ORG
@@ -67,8 +68,9 @@ objectClass: person
 objectClass: inetOrgPerson
 objectClass: krb5principal
 objectClass: krb5kdcentry
-cn: Java Duke
-sn: duke
+cn: Java
+sn: Duke
+mail: jduke@keycloak.org
 uid: jduke
 userPassword: theduke
 krb5PrincipalName: jduke@KEYCLOAK.ORG
diff --git a/testsuite/integration/src/main/resources/ldap/ldap-connection.properties b/testsuite/integration/src/main/resources/ldap/ldap-connection.properties
index c275c2f..c759f4a 100644
--- a/testsuite/integration/src/main/resources/ldap/ldap-connection.properties
+++ b/testsuite/integration/src/main/resources/ldap/ldap-connection.properties
@@ -3,7 +3,6 @@ idm.test.ldap.base.dn=dc\=keycloak,dc\=org
 idm.test.ldap.roles.dn.suffix=ou\=Roles,dc\=keycloak,dc\=org
 idm.test.ldap.group.dn.suffix=ou\=Groups,dc\=keycloak,dc\=org
 idm.test.ldap.user.dn.suffix=ou\=People,dc\=keycloak,dc\=org
-idm.test.ldap.agent.dn.suffix=ou\=Agent,dc\=keycloak,dc\=org
 idm.test.ldap.start.embedded.ldap.server=true
 idm.test.ldap.bind.dn=uid\=admin,ou\=system
 idm.test.ldap.bind.credential=secret
diff --git a/testsuite/integration/src/main/resources/log4j.properties b/testsuite/integration/src/main/resources/log4j.properties
index 5e78b31..cfd1259 100755
--- a/testsuite/integration/src/main/resources/log4j.properties
+++ b/testsuite/integration/src/main/resources/log4j.properties
@@ -20,7 +20,7 @@ log4j.logger.org.keycloak=info
 # log4j.logger.org.keycloak.broker.kerberos=trace
 
 # Enable to view detailed AS REQ and TGS REQ requests to embedded Kerberos server
-log4j.logger.org.apache.directory.server.kerberos=debug
+# log4j.logger.org.apache.directory.server.kerberos=debug
 
 log4j.logger.org.xnio=off
 log4j.logger.org.hibernate=off
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
new file mode 100644
index 0000000..2f8cb01
--- /dev/null
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/federation/AbstractKerberosTest.java
@@ -0,0 +1,262 @@
+package org.keycloak.testsuite.federation;
+
+import java.security.Principal;
+import java.util.List;
+
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.Response;
+
+import org.apache.http.auth.AuthScope;
+import org.apache.http.auth.Credentials;
+import org.apache.http.client.params.AuthPolicy;
+import org.apache.http.impl.client.DefaultHttpClient;
+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.Assert;
+import org.junit.Before;
+import org.junit.FixMethodOrder;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runners.MethodSorters;
+import org.keycloak.OAuth2Constants;
+import org.keycloak.adapters.HttpClientBuilder;
+import org.keycloak.events.Details;
+import org.keycloak.federation.kerberos.CommonKerberosConfig;
+import org.keycloak.federation.kerberos.KerberosConfig;
+import org.keycloak.models.KerberosConstants;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.LDAPConstants;
+import org.keycloak.models.RealmModel;
+import org.keycloak.models.UserFederationProvider;
+import org.keycloak.models.UserFederationProviderModel;
+import org.keycloak.models.UserModel;
+import org.keycloak.services.managers.RealmManager;
+import org.keycloak.testsuite.AssertEvents;
+import org.keycloak.testsuite.OAuthClient;
+import org.keycloak.testsuite.pages.AccountPasswordPage;
+import org.keycloak.testsuite.pages.AppPage;
+import org.keycloak.testsuite.pages.LoginPage;
+import org.keycloak.testsuite.rule.KeycloakRule;
+import org.keycloak.testsuite.rule.WebResource;
+import org.keycloak.testsuite.rule.WebRule;
+import org.openqa.selenium.WebDriver;
+
+/**
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+public abstract class AbstractKerberosTest {
+
+    protected KeycloakSPNegoSchemeFactory spnegoSchemeFactory;
+    protected ResteasyClient client;
+
+    @WebResource
+    protected OAuthClient oauth;
+
+    @WebResource
+    protected WebDriver driver;
+
+    @WebResource
+    protected LoginPage loginPage;
+
+    @WebResource
+    protected AccountPasswordPage changePasswordPage;
+
+    @WebResource
+    protected AppPage appPage;
+
+    protected abstract CommonKerberosConfig getKerberosConfig();
+    protected abstract KeycloakRule getKeycloakRule();
+    protected abstract AssertEvents getAssertEvents();
+
+    @Before
+    public void before() {
+        CommonKerberosConfig kerberosConfig = getKerberosConfig();
+        spnegoSchemeFactory = new KeycloakSPNegoSchemeFactory(kerberosConfig);
+        initHttpClient(true);
+        removeAllUsers();
+    }
+
+    @After
+    public void after() {
+        client.close();
+        client = null;
+    }
+
+
+    @Test
+    public void spnegoNotAvailableTest() throws Exception {
+        initHttpClient(false);
+        Response response = client.target(oauth.getLoginFormUrl()).request().get();
+        Assert.assertEquals(401, response.getStatus());
+        Assert.assertEquals(KerberosConstants.NEGOTIATE, response.getHeaderString(HttpHeaders.WWW_AUTHENTICATE));
+        String responseText = response.readEntity(String.class);
+        responseText.contains("Log in to test");
+    }
+
+
+    protected void spnegoLoginTestImpl() throws Exception {
+        KeycloakRule keycloakRule = getKeycloakRule();
+        AssertEvents events = getAssertEvents();
+
+        Response spnegoResponse = spnegoLogin("hnelson", "secret");
+        Assert.assertEquals(302, spnegoResponse.getStatus());
+
+        events.expectLogin()
+                .user(keycloakRule.getUser("test", "hnelson").getId())
+                .detail(Details.AUTH_METHOD, "spnego")
+                .detail(Details.USERNAME, "hnelson")
+                .assertEvent();
+
+        String location = spnegoResponse.getLocation().toString();
+        driver.navigate().to(location);
+        Assert.assertEquals(AppPage.RequestType.AUTH_RESPONSE, appPage.getRequestType());
+        Assert.assertNotNull(oauth.getCurrentQuery().get(OAuth2Constants.CODE));
+    }
+
+
+    @Test
+    public void usernamePasswordLoginTest() throws Exception {
+        KeycloakRule keycloakRule = getKeycloakRule();
+        AssertEvents events = getAssertEvents();
+
+        // Change editMode to READ_ONLY
+        updateProviderEditMode(UserFederationProvider.EditMode.READ_ONLY);
+
+        // Login with username/password from kerberos
+        changePasswordPage.open();
+        loginPage.assertCurrent();
+        loginPage.login("jduke", "theduke");
+        changePasswordPage.assertCurrent();
+
+        // 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(UserFederationProvider.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());
+        events.expectLogin()
+                .user(keycloakRule.getUser("test", "jduke").getId())
+                .detail(Details.AUTH_METHOD, "spnego")
+                .detail(Details.USERNAME, "jduke")
+                .assertEvent();
+    }
+
+
+
+    protected Response spnegoLogin(String username, String password) {
+        spnegoSchemeFactory.setCredentials(username, password);
+        return client.target(oauth.getLoginFormUrl()).request().get();
+    }
+
+
+    protected void initHttpClient(boolean useSpnego) {
+        if (client != null) {
+            after();
+        }
+
+        DefaultHttpClient httpClient = (DefaultHttpClient) new HttpClientBuilder().build();
+        httpClient.getAuthSchemes().register(AuthPolicy.SPNEGO, spnegoSchemeFactory);
+
+        if (useSpnego) {
+            Credentials fake = new Credentials() {
+
+                public String getPassword() {
+                    return null;
+                }
+
+                public Principal getUserPrincipal() {
+                    return null;
+                }
+
+            };
+
+            httpClient.getCredentialsProvider().setCredentials(
+                    new AuthScope(null, -1, null),
+                    fake);
+        }
+
+        ApacheHttpClient4Engine engine = new ApacheHttpClient4Engine(httpClient);
+        client = new ResteasyClientBuilder().httpEngine(engine).build();
+    }
+
+
+    protected void removeAllUsers() {
+        KeycloakRule keycloakRule = getKeycloakRule();
+
+        KeycloakSession session = keycloakRule.startSession();
+        try {
+            RealmManager manager = new RealmManager(session);
+
+            RealmModel appRealm = manager.getRealm("test");
+            List<UserModel> users = session.userStorage().getUsers(appRealm);
+            for (UserModel user : users) {
+                if (!user.getUsername().equals(AssertEvents.DEFAULT_USERNAME)) {
+                    session.userStorage().removeUser(appRealm, user);
+                }
+            }
+
+            Assert.assertEquals(1, session.userStorage().getUsers(appRealm).size());
+        } finally {
+            keycloakRule.stopSession(session, true);
+        }
+    }
+
+
+    protected void assertUser(String expectedUsername, String expectedEmail, String expectedFirstname, String expectedLastname, boolean updateProfileActionExpected) {
+        KeycloakRule keycloakRule = getKeycloakRule();
+
+        KeycloakSession session = keycloakRule.startSession();
+        try {
+            RealmManager manager = new RealmManager(session);
+            RealmModel appRealm = manager.getRealm("test");
+
+            UserModel user = session.users().getUserByUsername(expectedUsername, appRealm);
+            Assert.assertNotNull(user);
+            Assert.assertEquals(user.getEmail(), expectedEmail);
+            Assert.assertEquals(user.getFirstName(), expectedFirstname);
+            Assert.assertEquals(user.getLastName(), expectedLastname);
+
+            if (updateProfileActionExpected) {
+                Assert.assertEquals(UserModel.RequiredAction.UPDATE_PROFILE.toString(), user.getRequiredActions().iterator().next().name());
+            } else {
+                Assert.assertTrue(user.getRequiredActions().isEmpty());
+            }
+        } finally {
+            keycloakRule.stopSession(session, true);
+        }
+    }
+
+
+    protected void updateProviderEditMode(UserFederationProvider.EditMode editMode) {
+        KeycloakRule keycloakRule = getKeycloakRule();
+
+        KeycloakSession session = keycloakRule.startSession();
+        try {
+            RealmModel realm = session.realms().getRealm("test");
+            UserFederationProviderModel kerberosProviderModel = realm.getUserFederationProviders().get(0);
+            kerberosProviderModel.getConfig().put(LDAPConstants.EDIT_MODE, editMode.toString());
+            realm.updateUserFederationProvider(kerberosProviderModel);
+        } finally {
+            keycloakRule.stopSession(session, true);
+        }
+    }
+}
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/federation/KerberosLdapTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/federation/KerberosLdapTest.java
new file mode 100644
index 0000000..49efabc
--- /dev/null
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/federation/KerberosLdapTest.java
@@ -0,0 +1,147 @@
+package org.keycloak.testsuite.federation;
+
+import java.util.Map;
+
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.Response;
+
+import org.junit.Assert;
+import org.junit.ClassRule;
+import org.junit.FixMethodOrder;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.RuleChain;
+import org.junit.rules.TestRule;
+import org.junit.runners.MethodSorters;
+import org.keycloak.OAuth2Constants;
+import org.keycloak.events.Details;
+import org.keycloak.federation.kerberos.CommonKerberosConfig;
+import org.keycloak.federation.kerberos.KerberosConfig;
+import org.keycloak.federation.kerberos.KerberosFederationProviderFactory;
+import org.keycloak.federation.ldap.LDAPFederationProviderFactory;
+import org.keycloak.federation.ldap.kerberos.LDAPProviderKerberosConfig;
+import org.keycloak.models.KerberosConstants;
+import org.keycloak.models.RealmModel;
+import org.keycloak.models.UserCredentialModel;
+import org.keycloak.models.UserFederationProvider;
+import org.keycloak.models.UserFederationProviderModel;
+import org.keycloak.services.managers.RealmManager;
+import org.keycloak.testsuite.AssertEvents;
+import org.keycloak.testsuite.OAuthClient;
+import org.keycloak.testsuite.pages.AccountPasswordPage;
+import org.keycloak.testsuite.pages.AccountUpdateProfilePage;
+import org.keycloak.testsuite.pages.AppPage;
+import org.keycloak.testsuite.pages.LoginPage;
+import org.keycloak.testsuite.pages.RegisterPage;
+import org.keycloak.testsuite.rule.KerberosRule;
+import org.keycloak.testsuite.rule.KeycloakRule;
+import org.keycloak.testsuite.rule.WebResource;
+import org.keycloak.testsuite.rule.WebRule;
+import org.openqa.selenium.WebDriver;
+
+/**
+ * Test of LDAPFederationProvider (Kerberos backed by LDAP)
+ *
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+public class KerberosLdapTest extends AbstractKerberosTest {
+
+    public static final String CONFIG_LOCATION = "kerberos/kerberos-ldap-connection.properties";
+
+    private static UserFederationProviderModel ldapModel = null;
+
+    private static KerberosRule kerberosRule = new KerberosRule(CONFIG_LOCATION);
+
+    private static KeycloakRule keycloakRule = new KeycloakRule(new KeycloakRule.KeycloakSetup() {
+
+        @Override
+        public void config(RealmManager manager, RealmModel adminstrationRealm, RealmModel appRealm) {
+            Map<String,String> ldapConfig = kerberosRule.getConfig();
+            ldapModel = appRealm.addUserFederationProvider(LDAPFederationProviderFactory.PROVIDER_NAME, ldapConfig, 0, "kerberos-ldap", -1, -1, 0);
+            appRealm.addRequiredCredential(UserCredentialModel.KERBEROS);
+        }
+    });
+
+    @ClassRule
+    public static TestRule chain = RuleChain
+            .outerRule(kerberosRule)
+            .around(keycloakRule);
+
+    @Rule
+    public WebRule webRule = new WebRule(this);
+
+    @Rule
+    public AssertEvents events = new AssertEvents(keycloakRule);
+
+    @Override
+    protected CommonKerberosConfig getKerberosConfig() {
+        return new LDAPProviderKerberosConfig(ldapModel);
+    }
+
+    @Override
+    protected KeycloakRule getKeycloakRule() {
+        return keycloakRule;
+    }
+
+    @Override
+    protected AssertEvents getAssertEvents() {
+        return events;
+    }
+
+
+    @Test
+    public void spnegoLoginTest() throws Exception {
+        spnegoLoginTestImpl();
+
+        // 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);
+    }
+
+
+    @Test
+    public void writableEditModeTest() throws Exception {
+        KeycloakRule keycloakRule = getKeycloakRule();
+        AssertEvents events = getAssertEvents();
+
+        // Change editMode to READ_ONLY
+        updateProviderEditMode(UserFederationProvider.EditMode.WRITABLE);
+
+        // Login with username/password from kerberos
+        changePasswordPage.open();
+        loginPage.assertCurrent();
+        loginPage.login("jduke", "theduke");
+        changePasswordPage.assertCurrent();
+
+        // 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 with the new password as mode is writable
+        events.clear();
+        Response spnegoResponse = spnegoLogin("jduke", "newPass");
+        Assert.assertEquals(302, spnegoResponse.getStatus());
+        events.expectLogin()
+                .user(keycloakRule.getUser("test", "jduke").getId())
+                .detail(Details.AUTH_METHOD, "spnego")
+                .detail(Details.USERNAME, "jduke")
+                .assertEvent();
+
+        // Change password back
+        loginPage.login("jduke", "newPass");
+        changePasswordPage.assertCurrent();
+        changePasswordPage.changePassword("newPass", "theduke", "theduke");
+        Assert.assertTrue(driver.getPageSource().contains("Your password has been updated"));
+        changePasswordPage.logout();
+
+        events.clear();
+    }
+
+}
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/federation/KerberosStandaloneTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/federation/KerberosStandaloneTest.java
new file mode 100644
index 0000000..0decc0b
--- /dev/null
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/federation/KerberosStandaloneTest.java
@@ -0,0 +1,124 @@
+package org.keycloak.testsuite.federation;
+
+import java.util.Map;
+
+import javax.ws.rs.core.Response;
+
+import org.junit.Assert;
+import org.junit.ClassRule;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.RuleChain;
+import org.junit.rules.TestRule;
+import org.keycloak.federation.kerberos.CommonKerberosConfig;
+import org.keycloak.federation.kerberos.KerberosConfig;
+import org.keycloak.federation.kerberos.KerberosFederationProviderFactory;
+import org.keycloak.models.KerberosConstants;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.RealmModel;
+import org.keycloak.models.UserCredentialModel;
+import org.keycloak.models.UserFederationProviderModel;
+import org.keycloak.services.managers.RealmManager;
+import org.keycloak.testsuite.AssertEvents;
+import org.keycloak.testsuite.rule.KerberosRule;
+import org.keycloak.testsuite.rule.KeycloakRule;
+import org.keycloak.testsuite.rule.WebRule;
+
+/**
+ * Test of KerberosFederationProvider (Kerberos not backed by LDAP)
+ *
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+public class KerberosStandaloneTest extends AbstractKerberosTest {
+
+    public static final String CONFIG_LOCATION = "kerberos/kerberos-standalone-connection.properties";
+
+    private static UserFederationProviderModel kerberosModel;
+
+    private static KerberosRule kerberosRule = new KerberosRule(CONFIG_LOCATION);
+
+    private static KeycloakRule keycloakRule = new KeycloakRule(new KeycloakRule.KeycloakSetup() {
+
+        @Override
+        public void config(RealmManager manager, RealmModel adminstrationRealm, RealmModel appRealm) {
+            Map<String,String> kerberosConfig = kerberosRule.getConfig();
+
+            kerberosModel = appRealm.addUserFederationProvider(KerberosFederationProviderFactory.PROVIDER_NAME, kerberosConfig, 0, "kerberos-standalone", -1, -1, 0);
+            appRealm.addRequiredCredential(UserCredentialModel.KERBEROS);
+        }
+    });
+
+
+
+    @ClassRule
+    public static TestRule chain = RuleChain
+            .outerRule(kerberosRule)
+            .around(keycloakRule);
+
+    @Rule
+    public WebRule webRule = new WebRule(this);
+
+    @Rule
+    public AssertEvents events = new AssertEvents(keycloakRule);
+
+
+    @Override
+    protected CommonKerberosConfig getKerberosConfig() {
+        return new KerberosConfig(kerberosModel);
+    }
+
+    @Override
+    protected KeycloakRule getKeycloakRule() {
+        return keycloakRule;
+    }
+
+    @Override
+    protected AssertEvents getAssertEvents() {
+        return events;
+    }
+
+
+    @Test
+    public void spnegoLoginTest() throws Exception {
+        spnegoLoginTestImpl();
+
+        // Assert user was imported and hasn't any required action on him
+        assertUser("hnelson", "hnelson@keycloak.org", null, null, false);
+    }
+
+
+    @Test
+    public void updateProfileEnabledTest() throws Exception {
+        // Switch updateProfileOnFirstLogin to on
+        KeycloakSession session = keycloakRule.startSession();
+        try {
+            RealmModel realm = session.realms().getRealm("test");
+            UserFederationProviderModel kerberosProviderModel = realm.getUserFederationProviders().get(0);
+            kerberosProviderModel.getConfig().put(KerberosConstants.UPDATE_PROFILE_FIRST_LOGIN, "true");
+            realm.updateUserFederationProvider(kerberosProviderModel);
+        } finally {
+            keycloakRule.stopSession(session, true);
+        }
+
+        // Assert update profile page is displayed
+        Response spnegoResponse = spnegoLogin("hnelson", "secret");
+        Assert.assertEquals(200, spnegoResponse.getStatus());
+        String responseText = spnegoResponse.readEntity(String.class);
+        Assert.assertTrue(responseText.contains("You need to update your user profile to activate your account."));
+        Assert.assertTrue(responseText.contains("hnelson@keycloak.org"));
+
+        // Assert user was imported and has required action on him
+        assertUser("hnelson", "hnelson@keycloak.org", null, null, true);
+
+        // Switch updateProfileOnFirstLogin to off
+        session = keycloakRule.startSession();
+        try {
+            RealmModel realm = session.realms().getRealm("test");
+            UserFederationProviderModel kerberosProviderModel = realm.getUserFederationProviders().get(0);
+            kerberosProviderModel.getConfig().put(KerberosConstants.UPDATE_PROFILE_FIRST_LOGIN, "false");
+            realm.updateUserFederationProvider(kerberosProviderModel);
+        } finally {
+            keycloakRule.stopSession(session, true);
+        }
+    }
+}
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/federation/KeycloakSPNegoSchemeFactory.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/federation/KeycloakSPNegoSchemeFactory.java
new file mode 100644
index 0000000..3403263
--- /dev/null
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/federation/KeycloakSPNegoSchemeFactory.java
@@ -0,0 +1,100 @@
+package org.keycloak.testsuite.federation;
+
+import java.security.PrivilegedExceptionAction;
+
+import javax.security.auth.Subject;
+
+import org.apache.http.auth.AuthScheme;
+import org.apache.http.impl.auth.SPNegoScheme;
+import org.apache.http.impl.auth.SPNegoSchemeFactory;
+import org.apache.http.params.HttpParams;
+import org.ietf.jgss.GSSException;
+import org.ietf.jgss.Oid;
+import org.keycloak.federation.kerberos.CommonKerberosConfig;
+import org.keycloak.federation.kerberos.impl.KerberosUsernamePasswordAuthenticator;
+
+/**
+ * Usable for testing only. Username and password are shared for the whole factory
+ *
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+public class KeycloakSPNegoSchemeFactory extends SPNegoSchemeFactory {
+
+    private final CommonKerberosConfig kerberosConfig;
+
+    private String username;
+    private String password;
+
+
+    public KeycloakSPNegoSchemeFactory(CommonKerberosConfig kerberosConfig) {
+        super(true);
+        this.kerberosConfig = kerberosConfig;
+    }
+
+
+    public void setCredentials(String username, String password) {
+        this.username = username;
+        this.password = password;
+    }
+
+
+    @Override
+    public AuthScheme newInstance(HttpParams params) {
+        return new KeycloakSPNegoScheme(isStripPort());
+    }
+
+
+    public class KeycloakSPNegoScheme extends SPNegoScheme {
+
+        public KeycloakSPNegoScheme(boolean stripPort) {
+            super(stripPort);
+        }
+
+
+        @Override
+        protected byte[] generateGSSToken(byte[] input, Oid oid, String authServer) throws GSSException {
+            KerberosUsernamePasswordAuthenticator authenticator = new KerberosUsernamePasswordAuthenticator(kerberosConfig);
+            try {
+                Subject clientSubject = authenticator.authenticateSubject(username, password);
+
+                ByteArrayHolder holder = Subject.doAs(clientSubject, new ClientAcceptSecContext(input, oid, authServer));
+
+                return holder.bytes;
+            } catch (Exception le) {
+                throw new RuntimeException(le);
+            } finally {
+                authenticator.logoutSubject();
+            }
+        }
+
+
+        private class ClientAcceptSecContext implements PrivilegedExceptionAction<ByteArrayHolder> {
+
+            private final byte[] input;
+            private final Oid oid;
+            private final String authServer;
+
+            public ClientAcceptSecContext(byte[] input, Oid oid, String authServer) {
+                this.input = input;
+                this.oid = oid;
+                this.authServer = authServer;
+            }
+
+
+            @Override
+            public ByteArrayHolder run() throws Exception {
+                byte[] outputToken = KeycloakSPNegoScheme.super.generateGSSToken(input, oid, authServer);
+
+                ByteArrayHolder result = new ByteArrayHolder();
+                result.bytes = outputToken;
+                return result;
+            }
+
+        }
+
+
+        private class ByteArrayHolder {
+            private byte[] bytes;
+        }
+    }
+}
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/rule/KerberosRule.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/rule/KerberosRule.java
new file mode 100644
index 0000000..61d7f32
--- /dev/null
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/rule/KerberosRule.java
@@ -0,0 +1,39 @@
+package org.keycloak.testsuite.rule;
+
+import java.io.File;
+import java.net.URL;
+
+import org.jboss.logging.Logger;
+import org.keycloak.testutils.ldap.EmbeddedServersFactory;
+import org.keycloak.testutils.ldap.LDAPConfiguration;
+import org.keycloak.testutils.ldap.LDAPEmbeddedServer;
+
+/**
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+public class KerberosRule extends LDAPRule {
+
+    private static final Logger log = Logger.getLogger(KerberosRule.class);
+
+    private final String configLocation;
+
+    public KerberosRule(String configLocation) {
+        this.configLocation = configLocation;
+
+        // Global kerberos configuration
+        URL krb5ConfURL = LDAPConfiguration.class.getResource("/kerberos/test-krb5.conf");
+        String krb5ConfPath = new File(krb5ConfURL.getFile()).getAbsolutePath();
+        log.info("Krb5.conf file location is: " + krb5ConfPath);
+        System.setProperty("java.security.krb5.conf", krb5ConfPath);
+    }
+
+    @Override
+    protected String getConnectionPropertiesLocation() {
+        return configLocation;
+    }
+
+    @Override
+    protected LDAPEmbeddedServer createServer(EmbeddedServersFactory factory) {
+        return factory.createKerberosServer();
+    }
+}
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/rule/LDAPRule.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/rule/LDAPRule.java
index 5b12037..2fa5f01 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/rule/LDAPRule.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/rule/LDAPRule.java
@@ -12,16 +12,19 @@ import org.keycloak.testutils.ldap.LDAPEmbeddedServer;
  */
 public class LDAPRule extends ExternalResource {
 
-    private LDAPConfiguration ldapConfiguration;
-    private LDAPEmbeddedServer ldapEmbeddedServer;
+    public static final String LDAP_CONNECTION_PROPERTIES_LOCATION = "ldap/ldap-connection.properties";
+
+    protected LDAPConfiguration ldapConfiguration;
+    protected LDAPEmbeddedServer ldapEmbeddedServer;
 
     @Override
     protected void before() throws Throwable {
-        ldapConfiguration = LDAPConfiguration.readConfiguration();
+        String connectionPropsLocation = getConnectionPropertiesLocation();
+        ldapConfiguration = LDAPConfiguration.readConfiguration(connectionPropsLocation);
 
         if (ldapConfiguration.isStartEmbeddedLdapLerver()) {
             EmbeddedServersFactory factory = EmbeddedServersFactory.readConfiguration();
-            ldapEmbeddedServer = factory.createLdapServer();
+            ldapEmbeddedServer = createServer(factory);
             ldapEmbeddedServer.init();
             ldapEmbeddedServer.start();
         }
@@ -40,7 +43,15 @@ public class LDAPRule extends ExternalResource {
         }
     }
 
-    public Map<String, String> getLdapConfig() {
+    protected String getConnectionPropertiesLocation() {
+        return LDAP_CONNECTION_PROPERTIES_LOCATION;
+    }
+
+    protected LDAPEmbeddedServer createServer(EmbeddedServersFactory factory) {
+        return factory.createLdapServer();
+    }
+
+    public Map<String, String> getConfig() {
         return ldapConfiguration.getLDAPConfig();
     }
 }
diff --git a/testsuite/jetty/jetty81/pom.xml b/testsuite/jetty/jetty81/pom.xml
index a8936a8..c6c57ce 100755
--- a/testsuite/jetty/jetty81/pom.xml
+++ b/testsuite/jetty/jetty81/pom.xml
@@ -115,6 +115,11 @@
         </dependency>
        <dependency>
            <groupId>org.keycloak</groupId>
+           <artifactId>keycloak-kerberos-federation</artifactId>
+           <version>${project.version}</version>
+       </dependency>
+       <dependency>
+           <groupId>org.keycloak</groupId>
            <artifactId>keycloak-undertow-adapter</artifactId>
            <version>${project.version}</version>
        </dependency>
diff --git a/testsuite/jetty/jetty91/pom.xml b/testsuite/jetty/jetty91/pom.xml
index 5ef51a1..be3e483 100755
--- a/testsuite/jetty/jetty91/pom.xml
+++ b/testsuite/jetty/jetty91/pom.xml
@@ -115,6 +115,11 @@
         </dependency>
        <dependency>
            <groupId>org.keycloak</groupId>
+           <artifactId>keycloak-kerberos-federation</artifactId>
+           <version>${project.version}</version>
+       </dependency>
+       <dependency>
+           <groupId>org.keycloak</groupId>
            <artifactId>keycloak-undertow-adapter</artifactId>
            <version>${project.version}</version>
        </dependency>
diff --git a/testsuite/jetty/jetty92/pom.xml b/testsuite/jetty/jetty92/pom.xml
index c7d91c7..3ddef42 100755
--- a/testsuite/jetty/jetty92/pom.xml
+++ b/testsuite/jetty/jetty92/pom.xml
@@ -115,6 +115,11 @@
         </dependency>
        <dependency>
            <groupId>org.keycloak</groupId>
+           <artifactId>keycloak-kerberos-federation</artifactId>
+           <version>${project.version}</version>
+       </dependency>
+       <dependency>
+           <groupId>org.keycloak</groupId>
            <artifactId>keycloak-undertow-adapter</artifactId>
            <version>${project.version}</version>
        </dependency>
diff --git a/testsuite/proxy/pom.xml b/testsuite/proxy/pom.xml
index 721e4c3..809feff 100755
--- a/testsuite/proxy/pom.xml
+++ b/testsuite/proxy/pom.xml
@@ -120,6 +120,11 @@
         </dependency>
        <dependency>
            <groupId>org.keycloak</groupId>
+           <artifactId>keycloak-kerberos-federation</artifactId>
+           <version>${project.version}</version>
+       </dependency>
+       <dependency>
+           <groupId>org.keycloak</groupId>
            <artifactId>keycloak-undertow-adapter</artifactId>
            <version>${project.version}</version>
        </dependency>
diff --git a/testsuite/tomcat6/pom.xml b/testsuite/tomcat6/pom.xml
index b8cbf76..42621a5 100755
--- a/testsuite/tomcat6/pom.xml
+++ b/testsuite/tomcat6/pom.xml
@@ -114,6 +114,11 @@
         </dependency>
        <dependency>
            <groupId>org.keycloak</groupId>
+           <artifactId>keycloak-kerberos-federation</artifactId>
+           <version>${project.version}</version>
+       </dependency>
+       <dependency>
+           <groupId>org.keycloak</groupId>
            <artifactId>keycloak-undertow-adapter</artifactId>
            <version>${project.version}</version>
        </dependency>
diff --git a/testsuite/tomcat7/pom.xml b/testsuite/tomcat7/pom.xml
index 8e17fd3..088ec71 100755
--- a/testsuite/tomcat7/pom.xml
+++ b/testsuite/tomcat7/pom.xml
@@ -115,6 +115,11 @@
         </dependency>
        <dependency>
            <groupId>org.keycloak</groupId>
+           <artifactId>keycloak-kerberos-federation</artifactId>
+           <version>${project.version}</version>
+       </dependency>
+       <dependency>
+           <groupId>org.keycloak</groupId>
            <artifactId>keycloak-undertow-adapter</artifactId>
            <version>${project.version}</version>
        </dependency>
diff --git a/testsuite/tomcat8/pom.xml b/testsuite/tomcat8/pom.xml
index b9c7af9..6941dd5 100755
--- a/testsuite/tomcat8/pom.xml
+++ b/testsuite/tomcat8/pom.xml
@@ -114,6 +114,11 @@
         </dependency>
        <dependency>
            <groupId>org.keycloak</groupId>
+           <artifactId>keycloak-kerberos-federation</artifactId>
+           <version>${project.version}</version>
+       </dependency>
+       <dependency>
+           <groupId>org.keycloak</groupId>
            <artifactId>keycloak-undertow-adapter</artifactId>
            <version>${project.version}</version>
        </dependency>