Check the authentication config exists before returning its reference

Closes #34888


(cherry picked from commit 8d559d542c)

Signed-off-by: rmartinc <rmartinc@redhat.com>
This commit is contained in:
Ricardo Martin
2024-11-22 12:11:42 +01:00
committed by GitHub
parent 4c2ebfbde6
commit 154e14122f
3 changed files with 53 additions and 4 deletions

View File

@@ -929,7 +929,9 @@ public class ModelToRepresentation {
AuthenticationExecutionExportRepresentation rep = new AuthenticationExecutionExportRepresentation();
if (model.getAuthenticatorConfig() != null) {
AuthenticatorConfigModel config = new DeployedConfigurationsManager(session).getAuthenticatorConfig(realm, model.getAuthenticatorConfig());
rep.setAuthenticatorConfig(config.getAlias());
if (config != null) {
rep.setAuthenticatorConfig(config.getAlias());
}
}
rep.setAuthenticator(model.getAuthenticator());
rep.setAuthenticatorFlow(model.isAuthenticatorFlow());

View File

@@ -655,6 +655,19 @@ public class AuthenticationManagementResource {
return result;
}
private String getAuthenticationConfig(String flowAlias, AuthenticationExecutionModel model) {
if (model.getAuthenticatorConfig() == null) {
return null;
}
AuthenticatorConfigModel config = new DeployedConfigurationsManager(session).getAuthenticatorConfig(realm, model.getAuthenticatorConfig());
if (config == null) {
logger.warnf("Authenticator configuration '%s' is missing for execution '%s' (%s) in flow '%s'",
model.getAuthenticatorConfig(), model.getId(), model.getAuthenticator(), flowAlias);
return null;
}
return config.getId();
}
public void recurseExecutions(AuthenticationFlowModel flow, List<AuthenticationExecutionInfoRepresentation> result, int level) {
AtomicInteger index = new AtomicInteger(0);
realm.getAuthenticationExecutionsStream(flow.getId()).forEachOrdered(execution -> {
@@ -674,7 +687,7 @@ public class AuthenticationManagementResource {
rep.getRequirementChoices().add(AuthenticationExecutionModel.Requirement.REQUIRED.name());
rep.getRequirementChoices().add(AuthenticationExecutionModel.Requirement.DISABLED.name());
rep.setProviderId(execution.getAuthenticator());
rep.setAuthenticationConfig(execution.getAuthenticatorConfig());
rep.setAuthenticationConfig(getAuthenticationConfig(flow.getAlias(), execution));
} else if (AuthenticationFlow.CLIENT_FLOW.equals(flowRef.getProviderId())) {
rep.getRequirementChoices().add(AuthenticationExecutionModel.Requirement.ALTERNATIVE.name());
rep.getRequirementChoices().add(AuthenticationExecutionModel.Requirement.REQUIRED.name());
@@ -724,7 +737,7 @@ public class AuthenticationManagementResource {
}
rep.setProviderId(providerId);
rep.setAuthenticationConfig(execution.getAuthenticatorConfig());
rep.setAuthenticationConfig(getAuthenticationConfig(flow.getAlias(), execution));
result.add(rep);
}
});

View File

@@ -22,6 +22,9 @@ import org.junit.Test;
import org.keycloak.authentication.authenticators.broker.IdpCreateUserIfUniqueAuthenticatorFactory;
import org.keycloak.events.admin.OperationType;
import org.keycloak.events.admin.ResourceType;
import org.keycloak.models.AuthenticatorConfigModel;
import org.keycloak.models.RealmModel;
import org.keycloak.representations.idm.AuthenticationExecutionExportRepresentation;
import org.keycloak.representations.idm.AuthenticationExecutionInfoRepresentation;
import org.keycloak.representations.idm.AuthenticationFlowRepresentation;
import org.keycloak.representations.idm.AuthenticatorConfigInfoRepresentation;
@@ -42,12 +45,13 @@ import jakarta.ws.rs.BadRequestException;
*/
public class AuthenticatorConfigTest extends AbstractAuthenticationTest {
private String flowId;
private String executionId;
@Before
public void beforeConfigTest() {
AuthenticationFlowRepresentation flowRep = newFlow("firstBrokerLogin2", "firstBrokerLogin2", "basic-flow", true, false);
createFlow(flowRep);
flowId = createFlow(flowRep);
HashMap<String, Object> params = new HashMap<>();
params.put("provider", IdpCreateUserIfUniqueAuthenticatorFactory.PROVIDER_ID);
@@ -178,6 +182,36 @@ public class AuthenticatorConfigTest extends AbstractAuthenticationTest {
Assert.assertTrue(description.getProperties().isEmpty());
}
@Test
public void testMissingConfig() {
AuthenticatorConfigRepresentation cfg = newConfig("foo", IdpCreateUserIfUniqueAuthenticatorFactory.REQUIRE_PASSWORD_UPDATE_AFTER_REGISTRATION, "true");
final String cfgId = createConfig(executionId, cfg);
final String realmId = testRealmId;
AuthenticatorConfigRepresentation cfgRep = authMgmtResource.getAuthenticatorConfig(cfgId);
Assert.assertNotNull(cfgRep);
testingClient.server().run(session -> {
// emulating a broken config id, remove the config but do not remove the link in the authenticator
RealmModel realm = session.realms().getRealm(realmId);
AuthenticatorConfigModel config = realm.getAuthenticatorConfigById(cfgId);
realm.removeAuthenticatorConfig(config);
});
// check the flow can be read and execution has no config
AuthenticationFlowRepresentation flow = authMgmtResource.getFlow(flowId);
AuthenticationExecutionExportRepresentation execExport = flow.getAuthenticationExecutions().stream()
.filter(ae -> IdpCreateUserIfUniqueAuthenticatorFactory.PROVIDER_ID.equals(ae.getAuthenticator()))
.findAny()
.orElse(null);
Assert.assertNotNull(execExport);
Assert.assertNull(execExport.getAuthenticatorConfig());
// check the execution can be read with no configuration assigned
AuthenticationExecutionInfoRepresentation execInfo = findExecutionByProvider(
IdpCreateUserIfUniqueAuthenticatorFactory.PROVIDER_ID, authMgmtResource.getExecutions("firstBrokerLogin2"));
Assert.assertNull(execInfo.getAuthenticationConfig());
}
private String createConfig(String executionId, AuthenticatorConfigRepresentation cfg) {
Response resp = authMgmtResource.newExecutionConfig(executionId, cfg);
Assert.assertEquals(201, resp.getStatus());