keycloak-aplcache
Changes
dependencies/server-all/pom.xml 10(+5 -5)
federation/kerberos/src/main/java/org/keycloak/federation/kerberos/CommonKerberosConfig.java 10(+5 -5)
federation/kerberos/src/main/java/org/keycloak/federation/kerberos/impl/KerberosUsernamePasswordAuthenticator.java 51(+39 -12)
federation/kerberos/src/main/java/org/keycloak/federation/kerberos/KerberosFederationProvider.java 2(+1 -1)
federation/ldap/src/main/java/org/keycloak/federation/ldap/kerberos/LDAPProviderKerberosConfig.java 3(+2 -1)
testsuite/integration/pom.xml 5(+5 -0)
testsuite/integration/src/main/java/org/keycloak/testutils/ldap/LDAPConfiguration.java 212(+89 -123)
testsuite/integration/src/main/resources/kerberos/kerberos-standalone-connection.properties 6(+6 -0)
testsuite/integration/src/test/java/org/keycloak/testsuite/federation/AbstractKerberosTest.java 262(+262 -0)
testsuite/integration/src/test/java/org/keycloak/testsuite/federation/FederationProvidersIntegrationTest.java 15(+8 -7)
testsuite/integration/src/test/java/org/keycloak/testsuite/federation/KerberosLdapTest.java 147(+147 -0)
testsuite/integration/src/test/java/org/keycloak/testsuite/federation/KerberosStandaloneTest.java 124(+124 -0)
testsuite/integration/src/test/java/org/keycloak/testsuite/federation/KeycloakSPNegoSchemeFactory.java 100(+100 -0)
testsuite/integration/src/test/java/org/keycloak/testsuite/federation/SyncProvidersTest.java 7(+4 -3)
testsuite/jetty/jetty81/pom.xml 5(+5 -0)
testsuite/jetty/jetty91/pom.xml 5(+5 -0)
testsuite/jetty/jetty92/pom.xml 5(+5 -0)
testsuite/proxy/pom.xml 5(+5 -0)
testsuite/tomcat6/pom.xml 5(+5 -0)
testsuite/tomcat7/pom.xml 5(+5 -0)
testsuite/tomcat8/pom.xml 5(+5 -0)
Details
dependencies/server-all/pom.xml 10(+5 -5)
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;
testsuite/integration/pom.xml 5(+5 -0)
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();
}
}
testsuite/jetty/jetty81/pom.xml 5(+5 -0)
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>
testsuite/jetty/jetty91/pom.xml 5(+5 -0)
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>
testsuite/jetty/jetty92/pom.xml 5(+5 -0)
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>
testsuite/proxy/pom.xml 5(+5 -0)
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>
testsuite/tomcat6/pom.xml 5(+5 -0)
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>
testsuite/tomcat7/pom.xml 5(+5 -0)
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>
testsuite/tomcat8/pom.xml 5(+5 -0)
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>