Skip to content

Commit

Permalink
Use temp auth flow instead remove overrides (remove the gap in import…
Browse files Browse the repository at this point in the history
… config when client without overrides).
  • Loading branch information
ma1uta committed Nov 13, 2024
1 parent 55996a3 commit b818383
Show file tree
Hide file tree
Showing 2 changed files with 52 additions and 6 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
import de.adorsys.keycloak.config.repository.ClientRepository;
import de.adorsys.keycloak.config.repository.IdentityProviderRepository;
import de.adorsys.keycloak.config.repository.RealmRepository;
import de.adorsys.keycloak.config.util.CloneUtil;
import org.apache.logging.log4j.util.Strings;
import org.keycloak.representations.idm.AuthenticationFlowRepresentation;
import org.keycloak.representations.idm.ClientRepresentation;
Expand Down Expand Up @@ -70,6 +71,7 @@ public UsedAuthenticationFlowWorkaround buildFor(RealmImport realmImport) {
*/
public class UsedAuthenticationFlowWorkaround {
private static final String TEMPORARY_CREATED_AUTH_FLOW = "TEMPORARY_CREATED_AUTH_FLOW";
private static final String TEMPORARY_CREATED_CLIENT_AUTH_FLOW = "TEMPORARY_CREATED_CLIENT_AUTH_FLOW";
private final Logger logger = LoggerFactory.getLogger(UsedAuthenticationFlowWorkaround.class);
private final RealmImport realmImport;
private final Map<String, String> resetFirstBrokerLoginFlow = new HashMap<>();
Expand Down Expand Up @@ -101,10 +103,12 @@ public void disableTopLevelFlowIfNeeded(String topLevelFlowAlias) {
/**
* Find and remove flow overrides with specified ID in all realm clients.
*
* @param flowId flow ID to remove overrides
* @param patchedAuthenticationFlow flow to remove overrides
* @return Map "client" -> "auth name" -> "flow id" which were removed. Used to restore overrides.
*/
public Map<String, Map<String, String>> removeFlowOverridesInClients(String flowId) {
public Map<String, Map<String, String>> removeFlowOverridesInClients(AuthenticationFlowRepresentation patchedAuthenticationFlow) {
final String flowId = patchedAuthenticationFlow.getId();

final Map<String, Map<String, String>> clientsWithFlow = new HashMap<>();
// For all clients
for (ClientRepresentation client : clientRepository.getAll(realmImport.getRealm())) {
Expand All @@ -116,8 +120,11 @@ public Map<String, Map<String, String>> removeFlowOverridesInClients(String flow
final Map<String, String> clientBinding = clientsWithFlow.computeIfAbsent(client.getClientId(), k -> new HashMap<>());
// Save override and ...
clientBinding.put(flowBinding.getKey(), flowBinding.getValue());
// Set null to the value to remove this override on update
authenticationFlowBindingOverrides.put(flowBinding.getKey(), null);

// Search or create temporary auth flow
final String temporaryClientFlow = createTemporaryClientFlow(patchedAuthenticationFlow);

authenticationFlowBindingOverrides.put(flowBinding.getKey(), temporaryClientFlow);
updateClient = true;
}
}
Expand All @@ -136,8 +143,11 @@ public Map<String, Map<String, String>> removeFlowOverridesInClients(String flow
* @param clientsWithFlow map "client" -> "auth name" -> "flow id" to restore flow overrides.
*/
public void restoreClientOverrides(Map<String, Map<String, String>> clientsWithFlow) {
boolean removeTemporaryFlow = false;

// restore overrides with the new patched flow
for (Map.Entry<String, Map<String, String>> clientWithFlow : clientsWithFlow.entrySet()) {
removeTemporaryFlow = true;
final String clientId = clientWithFlow.getKey();
final Map<String, String> overrides = clientWithFlow.getValue();

Expand All @@ -146,6 +156,12 @@ public void restoreClientOverrides(Map<String, Map<String, String>> clientsWithF
client.getAuthenticationFlowBindingOverrides().putAll(overrides);
clientRepository.update(realmImport.getRealm(), client);
}

if (removeTemporaryFlow) {
searchForTemporaryCreatedClientFlow().ifPresent(flow -> {
authenticationFlowRepository.delete(realmImport.getRealm(), flow.getId());
});
}
}

private void disableBrowserFlowIfNeeded(String topLevelFlowAlias, RealmRepresentation existingRealm) {
Expand Down Expand Up @@ -339,11 +355,20 @@ private String searchTemporaryCreatedTopLevelFlowForReplacement() {
}

private Optional<AuthenticationFlowRepresentation> searchForTemporaryCreatedFlow() {
List<AuthenticationFlowRepresentation> existingTopLevelFlows = authenticationFlowRepository
.getTopLevelFlows(realmImport.getRealm());

return existingTopLevelFlows.stream()
.filter(f -> Objects.equals(f.getAlias(), TEMPORARY_CREATED_AUTH_FLOW))
.findFirst();
}

private Optional<AuthenticationFlowRepresentation> searchForTemporaryCreatedClientFlow() {
List<AuthenticationFlowRepresentation> existingTopLevelFlows = authenticationFlowRepository
.getTopLevelFlows(realmImport.getRealm());

return existingTopLevelFlows.stream()
.filter(f -> Objects.equals(f.getAlias(), TEMPORARY_CREATED_AUTH_FLOW))
.filter(f -> Objects.equals(f.getAlias(), TEMPORARY_CREATED_CLIENT_AUTH_FLOW))
.findFirst();
}

Expand Down Expand Up @@ -508,5 +533,26 @@ private AuthenticationFlowRepresentation setupTemporaryCreatedFlow() {

return tempFlow;
}

private AuthenticationFlowRepresentation setupTemporaryClientFlow(AuthenticationFlowRepresentation patchedAuthenticationFlow) {
AuthenticationFlowRepresentation tempFlow = CloneUtil.deepClone(patchedAuthenticationFlow, "id", "alias");

tempFlow.setAlias(TEMPORARY_CREATED_CLIENT_AUTH_FLOW);
tempFlow.setProviderId(TEMPORARY_CREATED_CLIENT_AUTH_FLOW);

return tempFlow;
}

private String createTemporaryClientFlow(AuthenticationFlowRepresentation patchedAuthenticationFlow) {
Optional<AuthenticationFlowRepresentation> authenticationFlowRepresentation = searchForTemporaryCreatedClientFlow();
if (authenticationFlowRepresentation.isPresent()) {
return authenticationFlowRepresentation.get().getId();
}

authenticationFlowRepository.createTopLevel(realmImport.getRealm(), setupTemporaryClientFlow(patchedAuthenticationFlow));

return searchForTemporaryCreatedClientFlow().orElseThrow(() -> new RuntimeException("Unable to create temporary client authorization flow"))
.getId();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -314,7 +314,7 @@ private void recreateTopLevelFlow(
UsedAuthenticationFlowWorkaroundFactory.UsedAuthenticationFlowWorkaround workaround = workaroundFactory.buildFor(realmImport);
workaround.disableTopLevelFlowIfNeeded(topLevelFlowToImport.getAlias());

final Map<String, Map<String, String>> overrides = workaround.removeFlowOverridesInClients(patchedAuthenticationFlow.getId());
final Map<String, Map<String, String>> overrides = workaround.removeFlowOverridesInClients(patchedAuthenticationFlow);

authenticatorConfigImportService.deleteAuthenticationConfigs(realmImport, patchedAuthenticationFlow);
authenticationFlowRepository.delete(realmImport.getRealm(), patchedAuthenticationFlow.getId());
Expand Down

0 comments on commit b818383

Please sign in to comment.