From 7a7bcd07da2901f82d4bc8c596c93a8729439828 Mon Sep 17 00:00:00 2001 From: Chris Bono Date: Tue, 23 Apr 2024 18:15:42 -0500 Subject: [PATCH] Encode JSON string in Pulsar auth params The values in the `spring.pulsar.client.authentication.param` config props map are not currently JSON encoded. For simple values this is fine. However, some custom auth modules may require more complex parameter values that may contain special characters that results in invalid JSON. This commmit encodes the parameter values using a very simple hand-rolled escape function. See gh-40493 --- .../pulsar/PulsarPropertiesMapper.java | 13 ++++++++++++- .../pulsar/PulsarPropertiesMapperTests.java | 12 ++++++++---- 2 files changed, 20 insertions(+), 5 deletions(-) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/pulsar/PulsarPropertiesMapper.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/pulsar/PulsarPropertiesMapper.java index 83f66f0a705..99b1b8cd21a 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/pulsar/PulsarPropertiesMapper.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/pulsar/PulsarPropertiesMapper.java @@ -89,7 +89,7 @@ final class PulsarPropertiesMapper { try { return sortedParams.entrySet() .stream() - .map((entry) -> "\"%s\":\"%s\"".formatted(entry.getKey(), entry.getValue())) + .map((entry) -> "\"%s\":\"%s\"".formatted(entry.getKey(), escapeJson(entry.getValue()))) .collect(Collectors.joining(",", "{", "}")); } catch (Exception ex) { @@ -97,6 +97,17 @@ final class PulsarPropertiesMapper { } } + private String escapeJson(String raw) { + return raw.replace("\\", "\\\\") + .replace("\"", "\\\"") + .replace("/", "\\/") + .replace("\b", "\\b") + .replace("\t", "\\t") + .replace("\n", "\\n") + .replace("\f", "\\f") + .replace("\r", "\\r"); + } + void customizeProducerBuilder(ProducerBuilder producerBuilder) { PulsarProperties.Producer properties = this.properties.getProducer(); PropertyMapper map = PropertyMapper.get().alwaysApplyingWhenNonNull(); diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/pulsar/PulsarPropertiesMapperTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/pulsar/PulsarPropertiesMapperTests.java index 458b3abf480..6b13de91c24 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/pulsar/PulsarPropertiesMapperTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/pulsar/PulsarPropertiesMapperTests.java @@ -72,8 +72,10 @@ class PulsarPropertiesMapperTests { @Test void customizeClientBuilderWhenHasAuthentication() throws UnsupportedAuthenticationException { PulsarProperties properties = new PulsarProperties(); - Map params = Map.of("param", "name"); - String authParamString = "{\"param\":\"name\"}"; + Map params = Map.of("simpleParam", "foo", "complexParam", + "{\n\t\"k1\" : \"v1\",\n\t\"k2\":\"v2\"\n}"); + String authParamString = "{\"complexParam\":\"{\\n\\t\\\"k1\\\" : \\\"v1\\\",\\n\\t\\\"k2\\\":\\\"v2\\\"\\n}\"" + + ",\"simpleParam\":\"foo\"}"; properties.getClient().getAuthentication().setPluginClassName("myclass"); properties.getClient().getAuthentication().setParam(params); ClientBuilder builder = mock(ClientBuilder.class); @@ -112,8 +114,10 @@ class PulsarPropertiesMapperTests { @Test void customizeAdminBuilderWhenHasAuthentication() throws UnsupportedAuthenticationException { PulsarProperties properties = new PulsarProperties(); - Map params = Map.of("param", "name"); - String authParamString = "{\"param\":\"name\"}"; + Map params = Map.of("simpleParam", "foo", "complexParam", + "{\n\t\"k1\" : \"v1\",\n\t\"k2\":\"v2\"\n}"); + String authParamString = "{\"complexParam\":\"{\\n\\t\\\"k1\\\" : \\\"v1\\\",\\n\\t\\\"k2\\\":\\\"v2\\\"\\n}\"" + + ",\"simpleParam\":\"foo\"}"; properties.getAdmin().getAuthentication().setPluginClassName("myclass"); properties.getAdmin().getAuthentication().setParam(params); PulsarAdminBuilder builder = mock(PulsarAdminBuilder.class);