Kerberos fixes for jboss-modules refactoring. Fix environment specific test failures
This commit is contained in:
parent
8d4d497063
commit
0c893b6175
12 changed files with 86 additions and 24 deletions
|
@ -228,6 +228,10 @@
|
|||
<maven-resource group="org.keycloak" artifact="keycloak-social-facebook"/>
|
||||
</module-def>
|
||||
|
||||
<module-def name="org.keycloak.keycloak-kerberos-federation">
|
||||
<maven-resource group="org.keycloak" artifact="keycloak-kerberos-federation"/>
|
||||
</module-def>
|
||||
|
||||
<module-def name="org.keycloak.keycloak-ldap-federation">
|
||||
<maven-resource group="org.keycloak" artifact="keycloak-ldap-federation"/>
|
||||
</module-def>
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
|
||||
|
||||
<module xmlns="urn:jboss:module:1.1" name="org.keycloak.keycloak-kerberos-federation">
|
||||
<resources>
|
||||
<!-- Insert resources here -->
|
||||
</resources>
|
||||
<dependencies>
|
||||
<module name="org.keycloak.keycloak-core"/>
|
||||
<module name="org.keycloak.keycloak-model-api"/>
|
||||
<module name="net.iharder.base64"/>
|
||||
<module name="javax.ws.rs.api"/>
|
||||
<module name="org.jboss.resteasy.resteasy-jaxrs"/>
|
||||
<module name="org.jboss.logging"/>
|
||||
<module name="javax.api"/>
|
||||
</dependencies>
|
||||
|
||||
</module>
|
|
@ -9,6 +9,7 @@
|
|||
<dependencies>
|
||||
<module name="org.keycloak.keycloak-core"/>
|
||||
<module name="org.keycloak.keycloak-model-api"/>
|
||||
<module name="org.keycloak.keycloak-kerberos-federation"/>
|
||||
<module name="org.keycloak.keycloak-picketlink-api"/>
|
||||
<module name="javax.ws.rs.api"/>
|
||||
<module name="org.jboss.resteasy.resteasy-jaxrs"/>
|
||||
|
|
|
@ -35,6 +35,7 @@
|
|||
<module name="org.keycloak.keycloak-invalidation-cache-model" services="import"/>
|
||||
<module name="org.keycloak.keycloak-jboss-adapter-core" services="import"/>
|
||||
<module name="org.keycloak.keycloak-js-adapter" services="import"/>
|
||||
<module name="org.keycloak.keycloak-kerberos-federation" services="import"/>
|
||||
<module name="org.keycloak.keycloak-ldap-federation" services="import"/>
|
||||
<module name="org.keycloak.keycloak-login-api" services="import"/>
|
||||
<module name="org.keycloak.keycloak-login-freemarker" services="import"/>
|
||||
|
|
|
@ -35,6 +35,7 @@
|
|||
<module name="org.keycloak.keycloak-invalidation-cache-model" services="import"/>
|
||||
<module name="org.keycloak.keycloak-jboss-adapter-core" services="import"/>
|
||||
<module name="org.keycloak.keycloak-js-adapter" services="import"/>
|
||||
<module name="org.keycloak.keycloak-kerberos-federation" services="import"/>
|
||||
<module name="org.keycloak.keycloak-ldap-federation" services="import"/>
|
||||
<module name="org.keycloak.keycloak-login-api" services="import"/>
|
||||
<module name="org.keycloak.keycloak-login-freemarker" services="import"/>
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
<module name="org.keycloak.keycloak-invalidation-cache-model" services="import"/>
|
||||
<module name="org.keycloak.keycloak-jboss-adapter-core" services="import"/>
|
||||
<module name="org.keycloak.keycloak-js-adapter" services="import"/>
|
||||
<module name="org.keycloak.keycloak-kerberos-federation" services="import"/>
|
||||
<module name="org.keycloak.keycloak-ldap-federation" services="import"/>
|
||||
<module name="org.keycloak.keycloak-login-api" services="import"/>
|
||||
<module name="org.keycloak.keycloak-login-freemarker" services="import"/>
|
||||
|
|
|
@ -69,12 +69,13 @@ public class KerberosFederationProvider implements UserFederationProvider {
|
|||
|
||||
@Override
|
||||
public UserModel getUserByUsername(RealmModel realm, String username) {
|
||||
KerberosUsernamePasswordAuthenticator authenticator = factory.createKerberosUsernamePasswordAuthenticator(kerberosConfig);
|
||||
if (authenticator.isUserAvailable(username)) {
|
||||
// Case when method was called with username including kerberos realm like john@REALM.ORG . Authenticator already checked that kerberos realm was correct
|
||||
if (username.contains("@")) {
|
||||
username = username.split("@")[0];
|
||||
}
|
||||
|
||||
KerberosUsernamePasswordAuthenticator authenticator = factory.createKerberosUsernamePasswordAuthenticator(kerberosConfig);
|
||||
if (authenticator.isUserAvailable(username)) {
|
||||
return findOrCreateAuthenticatedUser(realm, username);
|
||||
} else {
|
||||
return null;
|
||||
|
@ -106,7 +107,7 @@ public class KerberosFederationProvider implements UserFederationProvider {
|
|||
// KerberosUsernamePasswordAuthenticator.isUserAvailable is an overhead, so avoid it for now
|
||||
|
||||
String kerberosPrincipal = local.getUsername() + "@" + kerberosConfig.getKerberosRealm();
|
||||
return model.getId().equals(local.getFederationLink()) && kerberosPrincipal.equals(local.getAttribute(KERBEROS_PRINCIPAL));
|
||||
return kerberosPrincipal.equals(local.getAttribute(KERBEROS_PRINCIPAL));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -181,8 +182,11 @@ public class KerberosFederationProvider implements UserFederationProvider {
|
|||
|
||||
String username = spnegoAuthenticator.getAuthenticatedUsername();
|
||||
UserModel user = findOrCreateAuthenticatedUser(realm, username);
|
||||
|
||||
if (user == null) {
|
||||
return CredentialValidationOutput.failed();
|
||||
} else {
|
||||
return new CredentialValidationOutput(user, CredentialValidationOutput.Status.AUTHENTICATED, state);
|
||||
}
|
||||
} else {
|
||||
Map<String, Object> state = new HashMap<String, Object>();
|
||||
state.put(KerberosConstants.RESPONSE_TOKEN, spnegoAuthenticator.getResponseToken());
|
||||
|
@ -202,19 +206,24 @@ public class KerberosFederationProvider implements UserFederationProvider {
|
|||
/**
|
||||
* Called after successful authentication
|
||||
*
|
||||
* @param realm
|
||||
* @param realm realm
|
||||
* @param username username without realm prefix
|
||||
* @return
|
||||
* @return user if found or successfully created. Null if user with same username already exists, but is not linked to this provider
|
||||
*/
|
||||
protected UserModel findOrCreateAuthenticatedUser(RealmModel realm, String username) {
|
||||
UserModel user = session.userStorage().getUserByUsername(username, realm);
|
||||
if (user != null) {
|
||||
logger.debug("Kerberos authenticated user " + username + " found in Keycloak storage");
|
||||
if (isValid(user)) {
|
||||
|
||||
if (!model.getId().equals(user.getFederationLink())) {
|
||||
logger.warn("User with username " + username + " already exists, but is not linked to provider [" + model.getDisplayName() + "]");
|
||||
return null;
|
||||
} else if (isValid(user)) {
|
||||
return proxy(user);
|
||||
} else {
|
||||
logger.warn("User with username " + username + " already exists, but is not linked to provider [" + model.getDisplayName() +
|
||||
"] or kerberos principal is not correct. Kerberos principal on user is: " + user.getAttribute(KERBEROS_PRINCIPAL));
|
||||
logger.warn("User with username " + username + " already exists and is linked to provider [" + model.getDisplayName() +
|
||||
"] but kerberos principal is not correct. Kerberos principal on user is: " + user.getAttribute(KERBEROS_PRINCIPAL));
|
||||
logger.warn("Will re-create user");
|
||||
session.userStorage().removeUser(realm, user);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -36,14 +36,13 @@ public class KerberosUsernamePasswordAuthenticator {
|
|||
/**
|
||||
* Returns true if user with given username exists in kerberos database
|
||||
*
|
||||
* @param username username without Kerberos realm attached
|
||||
* @param username username without Kerberos realm attached or with correct realm attached
|
||||
* @return true if user available
|
||||
*/
|
||||
public boolean isUserAvailable(String username) {
|
||||
String principal = getKerberosPrincipal(username);
|
||||
|
||||
logger.debug("Checking existence of principal: " + principal);
|
||||
logger.debug("Checking existence of user: " + username);
|
||||
try {
|
||||
String principal = getKerberosPrincipal(username);
|
||||
loginContext = new LoginContext("does-not-matter", null,
|
||||
createJaasCallbackHandler(principal, "fake-password-which-nobody-has"),
|
||||
createJaasConfiguration());
|
||||
|
@ -65,7 +64,7 @@ public class KerberosUsernamePasswordAuthenticator {
|
|||
/**
|
||||
* Returns true if user was successfully authenticated against Kerberos
|
||||
*
|
||||
* @param username username without Kerberos realm attached
|
||||
* @param username username without Kerberos realm attached or with correct realm attached
|
||||
* @param password kerberos password
|
||||
* @return true if user was successfully authenticated
|
||||
*/
|
||||
|
@ -113,7 +112,17 @@ public class KerberosUsernamePasswordAuthenticator {
|
|||
|
||||
|
||||
|
||||
protected String getKerberosPrincipal(String username) {
|
||||
protected String getKerberosPrincipal(String username) throws LoginException {
|
||||
if (username.contains("@")) {
|
||||
String[] tokens = username.split("@");
|
||||
username = tokens[0];
|
||||
String kerberosRealm = tokens[1];
|
||||
if (kerberosRealm.toUpperCase().equals(config.getKerberosRealm())) {
|
||||
logger.warn("Invalid kerberos realm. Expected realm: " + config.getKerberosRealm() + ", username: " + username);
|
||||
throw new LoginException("Invalid kerberos realm");
|
||||
}
|
||||
}
|
||||
|
||||
return username + "@" + config.getKerberosRealm();
|
||||
}
|
||||
|
||||
|
|
|
@ -47,7 +47,7 @@ public class SPNEGOAuthenticator {
|
|||
Subject serverSubject = kerberosSubjectAuthenticator.authenticateServerSubject();
|
||||
authenticated = Subject.doAs(serverSubject, new AcceptSecContext());
|
||||
} catch (Exception e) {
|
||||
log.warn("SPNEGO login failed: " + e.getMessage(), e);
|
||||
log.warn("SPNEGO login failed", e);
|
||||
} finally {
|
||||
kerberosSubjectAuthenticator.logoutServerSubject();
|
||||
}
|
||||
|
|
|
@ -409,11 +409,15 @@ public class LDAPFederationProvider implements UserFederationProvider {
|
|||
UserModel user = session.userStorage().getUserByUsername(username, realm);
|
||||
if (user != null) {
|
||||
logger.debug("Kerberos authenticated user " + username + " found in Keycloak storage");
|
||||
if (isValid(user)) {
|
||||
if (!model.getId().equals(user.getFederationLink())) {
|
||||
logger.warn("User with username " + username + " already exists, but is not linked to provider [" + model.getDisplayName() + "]");
|
||||
return null;
|
||||
} else if (isValid(user)) {
|
||||
return proxy(user);
|
||||
} else {
|
||||
logger.warn("User with username " + username + " already exists, but is not linked to provider [" + model.getDisplayName() +
|
||||
"] or LDAP_ID is not correct. Stale LDAP_ID on local user is: " + user.getAttribute(LDAP_ID));
|
||||
logger.warn("User with username " + username + " already exists and is linked to provider [" + model.getDisplayName() +
|
||||
"] but is not valid. Stale LDAP_ID on local user is: " + user.getAttribute(LDAP_ID));
|
||||
logger.warn("Will re-create user");
|
||||
session.userStorage().removeUser(realm, user);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -103,7 +103,7 @@ public class KerberosLdapTest extends AbstractKerberosTest {
|
|||
KeycloakRule keycloakRule = getKeycloakRule();
|
||||
AssertEvents events = getAssertEvents();
|
||||
|
||||
// Change editMode to READ_ONLY
|
||||
// Change editMode to WRITABLE
|
||||
updateProviderEditMode(UserFederationProvider.EditMode.WRITABLE);
|
||||
|
||||
// Login with username/password from kerberos
|
||||
|
|
|
@ -8,7 +8,10 @@ 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.GSSContext;
|
||||
import org.ietf.jgss.GSSException;
|
||||
import org.ietf.jgss.GSSManager;
|
||||
import org.ietf.jgss.GSSName;
|
||||
import org.ietf.jgss.Oid;
|
||||
import org.keycloak.federation.kerberos.CommonKerberosConfig;
|
||||
import org.keycloak.federation.kerberos.impl.KerberosUsernamePasswordAuthenticator;
|
||||
|
@ -83,7 +86,17 @@ public class KeycloakSPNegoSchemeFactory extends SPNegoSchemeFactory {
|
|||
|
||||
@Override
|
||||
public ByteArrayHolder run() throws Exception {
|
||||
byte[] outputToken = KeycloakSPNegoScheme.super.generateGSSToken(input, oid, authServer);
|
||||
byte[] token = input;
|
||||
if (token == null) {
|
||||
token = new byte[0];
|
||||
}
|
||||
GSSManager manager = getManager();
|
||||
GSSName serverName = manager.createName("HTTP/" + authServer + "@" + kerberosConfig.getKerberosRealm(), null);
|
||||
GSSContext gssContext = manager.createContext(
|
||||
serverName.canonicalize(oid), oid, null, GSSContext.DEFAULT_LIFETIME);
|
||||
gssContext.requestMutualAuth(true);
|
||||
gssContext.requestCredDeleg(true);
|
||||
byte[] outputToken = gssContext.initSecContext(token, 0, token.length);
|
||||
|
||||
ByteArrayHolder result = new ByteArrayHolder();
|
||||
result.bytes = outputToken;
|
||||
|
|
Loading…
Reference in a new issue