From 1747960c66aed88cabc797eeda6358f8faff7bf7 Mon Sep 17 00:00:00 2001 From: iacsha <122627209+iacsha@users.noreply.github.com> Date: Fri, 6 Nov 2026 19:47:06 +0000 Subject: [PATCH] Validate the configuration map before persisting it (fixes #520) setConfigurationProperties saved the map before building the in-memory copy, so an invalid PUT body was written to the database and then threw, corrupting the configuration map on restart. Validate the map first, build the in-memory maps, and persist last. Signed-off-by: iacsha <122627209+iacsha@users.noreply.github.com> --- .../DefaultConfigurationController.java | 36 ++++++++++++-- .../DefaultConfigurationControllerTest.java | 49 +++++++++++++++++++ 2 files changed, 82 insertions(+), 3 deletions(-) diff --git a/server/src/main/java/com/mirth/connect/server/controllers/DefaultConfigurationController.java b/server/src/main/java/com/mirth/connect/server/controllers/DefaultConfigurationController.java index bfee2eddbf..811f8d3b9d 100644 --- a/server/src/main/java/com/mirth/connect/server/controllers/DefaultConfigurationController.java +++ b/server/src/main/java/com/mirth/connect/server/controllers/DefaultConfigurationController.java @@ -922,9 +922,7 @@ public synchronized Map getConfigurationPropertie @Override public synchronized void setConfigurationProperties(Map map, boolean persist) throws ControllerException { - if (persist) { - saveConfigurationProperties(map); - } + validateConfigurationMap(map); Map valueMap = new HashMap(); Map commentMap = new HashMap(); @@ -934,10 +932,42 @@ public synchronized void setConfigurationProperties(Map map) throws ControllerException { + if (map == null) { + throw new ControllerException("Configuration map must not be null."); + } + + for (Entry entry : map.entrySet()) { + if (!(entry.getKey() instanceof String)) { + throw new ControllerException("Configuration map contains a non-string key: " + entry.getKey() + "."); + } + if (!(entry.getValue() instanceof ConfigurationProperty)) { + throw new ControllerException("Configuration map contains an invalid value for key '" + entry.getKey() + "'."); + } + } + } + @Override public void setStatus(int status) { this.status = status; diff --git a/server/src/test/java/com/mirth/connect/server/controllers/DefaultConfigurationControllerTest.java b/server/src/test/java/com/mirth/connect/server/controllers/DefaultConfigurationControllerTest.java index 759a0bb618..2edea89f10 100644 --- a/server/src/test/java/com/mirth/connect/server/controllers/DefaultConfigurationControllerTest.java +++ b/server/src/test/java/com/mirth/connect/server/controllers/DefaultConfigurationControllerTest.java @@ -45,6 +45,9 @@ import com.mirth.connect.client.core.ControllerException; import com.mirth.connect.donkey.testing.StaticOverride; import com.mirth.connect.model.DriverInfo; +import java.util.HashMap; +import java.util.Map; +import com.mirth.connect.util.ConfigurationProperty; public class DefaultConfigurationControllerTest { @@ -412,4 +415,50 @@ private String normalizeXml(String xml) throws Exception { " \n" + ""; // @formatter:on + + @Test + public void setConfigurationProperties_nullMap_throwsControllerException() throws Exception { + DefaultConfigurationController configurationController = spy(new DefaultConfigurationController()); + try { + configurationController.setConfigurationProperties(null, false); + fail("Expected ControllerException for a null configuration map"); + } catch (ControllerException expected) { + } + } + + @Test + public void validateConfigurationMap_nullValue_throwsControllerException() throws Exception { + Map map = new HashMap(); + map.put("good", new ConfigurationProperty("value", "comment")); + map.put("bad", null); + try { + DefaultConfigurationController.validateConfigurationMap(map); + fail("Expected ControllerException for a null configuration property value"); + } catch (ControllerException expected) { + } + } + + @SuppressWarnings({ "unchecked", "rawtypes" }) + @Test + public void validateConfigurationMap_nonStringKey_throwsControllerException() throws Exception { + Map map = new HashMap(); + map.put(Integer.valueOf(1), new ConfigurationProperty("value", "comment")); + try { + DefaultConfigurationController.validateConfigurationMap(map); + fail("Expected ControllerException for a non-string key"); + } catch (ControllerException expected) { + } + } + + @Test + public void setConfigurationProperties_validMap_isApplied() throws Exception { + DefaultConfigurationController configurationController = spy(new DefaultConfigurationController()); + doNothing().when(configurationController).loadDatabaseConfigPropsIfNecessary(); + + Map map = new HashMap(); + map.put("alpha", new ConfigurationProperty("1", "first")); + configurationController.setConfigurationProperties(map, false); + + assertEquals("1", configurationController.getConfigurationMap().get("alpha")); + } }