mirror of
https://github.com/keycloak/keycloak.git
synced 2026-01-09 23:12:06 -03:30
KEYCLOAK-12424 SPNEGO / Kerberos sends multiple 401 responses with WWW-Authenticate: Negotiate header when kerberos token is invalid
This commit is contained in:
parent
0f8d988d58
commit
fea7b4e031
@ -208,9 +208,14 @@ public class KerberosFederationProvider implements UserStorageProvider,
|
||||
|
||||
return new CredentialValidationOutput(user, CredentialValidationOutput.Status.AUTHENTICATED, state);
|
||||
}
|
||||
} else {
|
||||
} else if (spnegoAuthenticator.getResponseToken() != null) {
|
||||
// Case when SPNEGO handshake requires multiple steps
|
||||
logger.tracef("SPNEGO Handshake will continue");
|
||||
state.put(KerberosConstants.RESPONSE_TOKEN, spnegoAuthenticator.getResponseToken());
|
||||
return new CredentialValidationOutput(null, CredentialValidationOutput.Status.CONTINUE, state);
|
||||
} else {
|
||||
logger.tracef("SPNEGO Handshake not successful");
|
||||
return CredentialValidationOutput.failed();
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
@ -712,9 +712,14 @@ public class LDAPStorageProvider implements UserStorageProvider,
|
||||
|
||||
return new CredentialValidationOutput(user, CredentialValidationOutput.Status.AUTHENTICATED, state);
|
||||
}
|
||||
} else {
|
||||
} else if (spnegoAuthenticator.getResponseToken() != null) {
|
||||
// Case when SPNEGO handshake requires multiple steps
|
||||
logger.tracef("SPNEGO Handshake will continue");
|
||||
state.put(KerberosConstants.RESPONSE_TOKEN, spnegoAuthenticator.getResponseToken());
|
||||
return new CredentialValidationOutput(null, CredentialValidationOutput.Status.CONTINUE, state);
|
||||
} else {
|
||||
logger.tracef("SPNEGO Handshake not successful");
|
||||
return CredentialValidationOutput.failed();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -17,9 +17,13 @@
|
||||
|
||||
package org.keycloak.testsuite.federation.kerberos;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
import javax.ws.rs.client.Entity;
|
||||
import javax.ws.rs.core.HttpHeaders;
|
||||
import javax.ws.rs.core.MultivaluedMap;
|
||||
import javax.ws.rs.core.Response;
|
||||
|
||||
import org.ietf.jgss.GSSCredential;
|
||||
@ -37,6 +41,7 @@ import org.keycloak.representations.AccessToken;
|
||||
import org.keycloak.representations.idm.ProtocolMapperRepresentation;
|
||||
import org.keycloak.representations.idm.UserRepresentation;
|
||||
import org.keycloak.storage.UserStorageProvider;
|
||||
import org.keycloak.testsuite.ActionURIUtils;
|
||||
import org.keycloak.testsuite.Assert;
|
||||
import org.keycloak.testsuite.admin.ApiUtil;
|
||||
|
||||
@ -62,6 +67,43 @@ public abstract class AbstractKerberosSingleRealmTest extends AbstractKerberosTe
|
||||
response.close();
|
||||
}
|
||||
|
||||
|
||||
// KEYCLOAK-12424
|
||||
@Test
|
||||
public void spnegoWithInvalidTokenTest() throws Exception {
|
||||
initHttpClient(true);
|
||||
|
||||
// Update kerberos configuration with some invalid location of keytab file
|
||||
AtomicReference<String> origKeytab = new AtomicReference<>();
|
||||
updateUserStorageProvider(kerberosProviderRep -> {
|
||||
String keytab = kerberosProviderRep.getConfig().getFirst(KerberosConstants.KEYTAB);
|
||||
origKeytab.set(keytab);
|
||||
|
||||
kerberosProviderRep.getConfig().putSingle(KerberosConstants.KEYTAB, keytab + "-invalid");
|
||||
});
|
||||
|
||||
try {
|
||||
/*
|
||||
To do this we do a valid kerberos login on client side. The authenticator will obtain a valid token, but user
|
||||
storage provider is incorrectly configured, so SPNEGO login will fail on server side. However the server should continue to
|
||||
the login page (username/password) and return status 200. It should not return 401 with "Kerberos unsupported" page as that
|
||||
would display some strange dialogs in the web browser on windows - see KEYCLOAK-12424
|
||||
*/
|
||||
Response spnegoResponse = spnegoLogin("hnelson", "secret");
|
||||
|
||||
Assert.assertEquals(200, spnegoResponse.getStatus());
|
||||
String context = spnegoResponse.readEntity(String.class);
|
||||
spnegoResponse.close();
|
||||
|
||||
org.junit.Assert.assertTrue(context.contains("Log in to test"));
|
||||
|
||||
events.clear();
|
||||
} finally {
|
||||
// Revert keytab configuration
|
||||
updateUserStorageProvider(kerberosProviderRep -> kerberosProviderRep.getConfig().putSingle(KerberosConstants.KEYTAB, origKeytab.get()));
|
||||
}
|
||||
}
|
||||
|
||||
// KEYCLOAK-7823
|
||||
@Test
|
||||
public void spnegoLoginWithRequiredKerberosAuthExecutionTest() {
|
||||
|
||||
@ -25,6 +25,7 @@ import java.util.Hashtable;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import javax.naming.Context;
|
||||
import javax.naming.NamingException;
|
||||
@ -337,18 +338,25 @@ public abstract class AbstractKerberosTest extends AbstractAuthTest {
|
||||
|
||||
|
||||
protected void updateProviderEditMode(UserStorageProvider.EditMode editMode) {
|
||||
List<ComponentRepresentation> reps = testRealmResource().components().query("test", UserStorageProvider.class.getName());
|
||||
Assert.assertEquals(1, reps.size());
|
||||
ComponentRepresentation kerberosProvider = reps.get(0);
|
||||
kerberosProvider.getConfig().putSingle(LDAPConstants.EDIT_MODE, editMode.toString());
|
||||
testRealmResource().components().component(kerberosProvider.getId()).update(kerberosProvider);
|
||||
updateUserStorageProvider(kerberosProvider -> kerberosProvider.getConfig().putSingle(LDAPConstants.EDIT_MODE, editMode.toString()));
|
||||
}
|
||||
|
||||
protected void updateProviderValidatePasswordPolicy(Boolean validatePasswordPolicy) {
|
||||
updateUserStorageProvider(kerberosProvider -> kerberosProvider.getConfig().putSingle(LDAPConstants.VALIDATE_PASSWORD_POLICY, validatePasswordPolicy.toString()));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Update UserStorage provider (Kerberos provider or LDAP provider with Kerberos enabled) with specified updater and save it
|
||||
*
|
||||
*/
|
||||
protected void updateUserStorageProvider(Consumer<ComponentRepresentation> updater) {
|
||||
List<ComponentRepresentation> reps = testRealmResource().components().query("test", UserStorageProvider.class.getName());
|
||||
Assert.assertEquals(1, reps.size());
|
||||
ComponentRepresentation kerberosProvider = reps.get(0);
|
||||
kerberosProvider.getConfig().putSingle(LDAPConstants.VALIDATE_PASSWORD_POLICY, validatePasswordPolicy.toString());
|
||||
|
||||
updater.accept(kerberosProvider);
|
||||
|
||||
testRealmResource().components().component(kerberosProvider.getId()).update(kerberosProvider);
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user