diff --git a/server-spi-private/src/main/java/org/keycloak/models/utils/ModelToRepresentation.java b/server-spi-private/src/main/java/org/keycloak/models/utils/ModelToRepresentation.java index 26ac23ba1c5e..63b3c5e77dd9 100755 --- a/server-spi-private/src/main/java/org/keycloak/models/utils/ModelToRepresentation.java +++ b/server-spi-private/src/main/java/org/keycloak/models/utils/ModelToRepresentation.java @@ -930,7 +930,9 @@ public static AuthenticationExecutionExportRepresentation toRepresentation(Keycl 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()); diff --git a/services/src/main/java/org/keycloak/services/resources/admin/AuthenticationManagementResource.java b/services/src/main/java/org/keycloak/services/resources/admin/AuthenticationManagementResource.java index 163cb6c2a882..9144a42b569b 100755 --- a/services/src/main/java/org/keycloak/services/resources/admin/AuthenticationManagementResource.java +++ b/services/src/main/java/org/keycloak/services/resources/admin/AuthenticationManagementResource.java @@ -663,6 +663,19 @@ public List getExecutions(@Parameter( 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 result, int level) { AtomicInteger index = new AtomicInteger(0); realm.getAuthenticationExecutionsStream(flow.getId()).forEachOrdered(execution -> { @@ -682,7 +695,7 @@ public void recurseExecutions(AuthenticationFlowModel flow, List { + // 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) { try (Response resp = authMgmtResource.newExecutionConfig(executionId, cfg)) { Assert.assertEquals(201, resp.getStatus());