diff --git a/docs/FEATURES.md b/docs/FEATURES.md index 1c5a7bb4e..ede3aa835 100644 --- a/docs/FEATURES.md +++ b/docs/FEATURES.md @@ -55,6 +55,7 @@ | Remove clientScopeMappings | 2.5.0 | Remove existing clientScopeMappings while creating or updating realms | | Synchronize user federation | 3.5.0 | Synchronize the user federation defined on the realm configuration | | Synchronize user profile | 5.4.0 | Synchronize the user profile configuration defined on the realm configuration | +| Normalize realm exports | 5.5.0 | Normalize a full realm export to be more minimal | # Specificities diff --git a/docs/NORMALIZE.md b/docs/NORMALIZE.md new file mode 100644 index 000000000..b34aa925e --- /dev/null +++ b/docs/NORMALIZE.md @@ -0,0 +1,6 @@ +# Realm normalization + + + +To run the normalization, run keycloak-config-cli with the CLI option `--run.operation=NORMALIZE`. +The default value for this option is `IMPORT`, which will run the regular keycloak-config-cli import. diff --git a/src/main/java/de/adorsys/keycloak/config/service/export/RealmNormalizationService.java b/src/main/java/de/adorsys/keycloak/config/service/export/RealmNormalizationService.java index 18d11d188..b6086030a 100644 --- a/src/main/java/de/adorsys/keycloak/config/service/export/RealmNormalizationService.java +++ b/src/main/java/de/adorsys/keycloak/config/service/export/RealmNormalizationService.java @@ -86,6 +86,7 @@ public class RealmNormalizationService { realmIgnoredProperties.add("applications"); realmIgnoredProperties.add("oauthClients"); realmIgnoredProperties.add("clientTemplates"); + realmIgnoredProperties.add("attributes"); JAVERS = JaversBuilder.javers() .registerEntity(new EntityDefinition(RealmRepresentation.class, "realm", realmIgnoredProperties)) @@ -175,6 +176,17 @@ public void normalize(RealmRepresentation exportedRealm) throws Exception { minimizedRealm.setClientScopeMappings(clientScopeMappings); } + var attributes = getMinimizedAttributes(exportedRealm, baselineRealm); + if (!attributes.isEmpty()) { + minimizedRealm.setAttributes(attributes); + } + + var protocolMappers = getMinimizedProtocolMappers(exportedRealm.getProtocolMappers(), + baselineRealm.getProtocolMappers()); + if (!protocolMappers.isEmpty()) { + minimizedRealm.setProtocolMappers(protocolMappers); + } + var outputFile = outputLocation.resolve(String.format("%s.yaml", exportedRealmRealm)); try (var os = new FileOutputStream(outputFile.toFile())) { @@ -182,6 +194,33 @@ public void normalize(RealmRepresentation exportedRealm) throws Exception { } } + private Map getMinimizedAttributes(RealmRepresentation exportedRealm, RealmRepresentation baselineRealm) { + var exportedAttributes = exportedRealm.getAttributesOrEmpty(); + var baselineAttributes = baselineRealm.getAttributesOrEmpty(); + var minimizedAttributes = new HashMap(); + + for (var entry : baselineAttributes.entrySet()) { + var key = entry.getKey(); + var exportedValue = exportedAttributes.get(key); + if (!Objects.equals(exportedValue, entry.getValue())) { + minimizedAttributes.put(key, exportedValue); + } + } + + for (var entry : exportedAttributes.entrySet()) { + var key = entry.getKey(); + if (!baselineAttributes.containsKey(key)) { + minimizedAttributes.put(key, entry.getValue()); + } + } + return minimizedAttributes; + } + + private List getMinimizedProtocolMappers(List exportedMappers, + List baselineMappers) { + return List.of(); + } + private List getMinimizedClients(RealmRepresentation exportedRealm, RealmRepresentation baselineRealm) throws IOException, NoSuchFieldException, IllegalAccessException { // Get a client map for better lookups