diff --git a/esignet-core/src/main/java/io/mosip/esignet/core/config/ActuatorSanitizationConfig.java b/esignet-core/src/main/java/io/mosip/esignet/core/config/ActuatorSanitizationConfig.java new file mode 100644 index 000000000..6272e127b --- /dev/null +++ b/esignet-core/src/main/java/io/mosip/esignet/core/config/ActuatorSanitizationConfig.java @@ -0,0 +1,36 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ +package io.mosip.esignet.core.config; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.actuate.endpoint.SanitizableData; +import org.springframework.boot.actuate.endpoint.SanitizingFunction; +import org.springframework.context.annotation.Configuration; + +import java.util.List; +import java.util.Locale; + +/** + * Custom sanitization rules for Spring Boot Actuator endpoints (e.g. /actuator/env). + * Any property whose key matches the configured patterns will have its value masked. + */ +@Configuration +public class ActuatorSanitizationConfig implements SanitizingFunction { + + @Value("#{${mosip.esignet.actuator.sanitize.key.endsWith:{'password','secret','key','token','vcap_services','sun.java.command'}}}") + private List keysToBeSanitizedEndsWith; + + @Value("#{${mosip.esignet.actuator.sanitize.key.contains:{'credentials'}}}") + private List keysToBeSanitizedContains; + + @Override + public SanitizableData apply(SanitizableData data) { + String key = data.getKey().toLowerCase(Locale.ROOT); + if (keysToBeSanitizedEndsWith.stream().anyMatch(key::endsWith) + || keysToBeSanitizedContains.stream().anyMatch(key::contains)) return data.withSanitizedValue(); + return data; + } +} diff --git a/esignet-core/src/test/java/io/mosip/esignet/core/config/ActuatorSanitizationConfigTest.java b/esignet-core/src/test/java/io/mosip/esignet/core/config/ActuatorSanitizationConfigTest.java new file mode 100644 index 000000000..ac9d43fde --- /dev/null +++ b/esignet-core/src/test/java/io/mosip/esignet/core/config/ActuatorSanitizationConfigTest.java @@ -0,0 +1,71 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ +package io.mosip.esignet.core.config; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.springframework.boot.actuate.endpoint.SanitizableData; +import org.springframework.test.util.ReflectionTestUtils; + +import java.util.List; + +import static org.junit.jupiter.api.Assertions.assertSame; +import static org.mockito.Mockito.*; + +class ActuatorSanitizationConfigTest { + + private ActuatorSanitizationConfig sanitizingFunction; + + @BeforeEach + void setUp() { + sanitizingFunction = new ActuatorSanitizationConfig(); + ReflectionTestUtils.setField(sanitizingFunction, "keysToBeSanitizedEndsWith", List.of("password", "secret")); + ReflectionTestUtils.setField(sanitizingFunction, "keysToBeSanitizedContains", List.of("credentials")); + } + + @Test + void test_sanitizingFunction_endMatch_thenSanitized() { + SanitizableData data = mock(SanitizableData.class); + SanitizableData sanitizedData = mock(SanitizableData.class); + + when(data.getKey()).thenReturn("db.password"); + when(data.withSanitizedValue()).thenReturn(sanitizedData); + + SanitizableData result = sanitizingFunction.apply(data); + + assertSame(sanitizedData, result); + verify(data).withSanitizedValue(); + verify(data, atLeastOnce()).getKey(); + } + + @Test + void test_sanitizingFunction_containsMatch_thenSanitized() { + SanitizableData data = mock(SanitizableData.class); + SanitizableData sanitizedData = mock(SanitizableData.class); + + when(data.getKey()).thenReturn("API_CREDENTIALS_ID"); + when(data.withSanitizedValue()).thenReturn(sanitizedData); + + SanitizableData result = sanitizingFunction.apply(data); + + assertSame(sanitizedData, result); + verify(data).withSanitizedValue(); + verify(data, atLeastOnce()).getKey(); + } + + @Test + void test_sanitizingFunction_noMatch_thenOriginalData() { + SanitizableData data = mock(SanitizableData.class); + + when(data.getKey()).thenReturn("application.name"); + + SanitizableData result = sanitizingFunction.apply(data); + + assertSame(data, result); + verify(data, never()).withSanitizedValue(); + verify(data, atLeastOnce()).getKey(); + } +} diff --git a/esignet-service/src/main/resources/bootstrap.properties b/esignet-service/src/main/resources/bootstrap.properties index a2c1b92c6..48ce1160f 100644 --- a/esignet-service/src/main/resources/bootstrap.properties +++ b/esignet-service/src/main/resources/bootstrap.properties @@ -41,6 +41,7 @@ management.endpoint.metrics.access=read-only management.endpoints.web.exposure.include=* management.endpoint.prometheus.access=read-only management.prometheus.metrics.export.enabled=true +management.endpoint.env.show-values=ALWAYS # disable mapping unknown endpoints to static resources instead throw exception spring.web.resources.add-mappings=false \ No newline at end of file