From 55fb559f87e02e42cc34eb64b99fdd7e2a80b50d Mon Sep 17 00:00:00 2001 From: Daan Hoogland Date: Thu, 23 Jul 2026 10:20:05 +0200 Subject: [PATCH] add rabbitmq jasypt property encryption facility --- ...ryptablePropertyPlaceholderConfigurer.java | 59 +++++++++++++++ ...ablePropertyPlaceholderConfigurerTest.java | 73 +++++++++++++++++++ 2 files changed, 132 insertions(+) create mode 100644 utils/src/main/java/com/cloud/utils/crypt/EncryptablePropertyPlaceholderConfigurer.java create mode 100644 utils/src/test/java/com/cloud/utils/crypt/EncryptablePropertyPlaceholderConfigurerTest.java diff --git a/utils/src/main/java/com/cloud/utils/crypt/EncryptablePropertyPlaceholderConfigurer.java b/utils/src/main/java/com/cloud/utils/crypt/EncryptablePropertyPlaceholderConfigurer.java new file mode 100644 index 000000000000..6317019ba033 --- /dev/null +++ b/utils/src/main/java/com/cloud/utils/crypt/EncryptablePropertyPlaceholderConfigurer.java @@ -0,0 +1,59 @@ +// +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +// + +package com.cloud.utils.crypt; + +import org.jasypt.encryption.StringEncryptor; +import org.springframework.beans.factory.config.PropertyPlaceholderConfigurer; + +/** + * Spring bean that resolves property placeholders, decrypting any value wrapped as + * {@code ENC(...)} with the given jasypt {@link StringEncryptor}. Values that are not wrapped + * are passed through unchanged. + * + * This replaces {@code org.jasypt.spring3.properties.EncryptablePropertyPlaceholderConfigurer} + * (from the jasypt-spring3 artifact), which is not on the classpath and is incompatible with + * Spring 5, so beans referencing it fail with a ClassNotFoundException. + */ +public class EncryptablePropertyPlaceholderConfigurer extends PropertyPlaceholderConfigurer { + + private static final String ENC_PREFIX = "ENC("; + private static final String ENC_SUFFIX = ")"; + + private final StringEncryptor encryptor; + + public EncryptablePropertyPlaceholderConfigurer(StringEncryptor encryptor) { + this.encryptor = encryptor; + } + + @Override + protected String convertPropertyValue(String originalValue) { + if (originalValue == null) { + return null; + } + + String trimmedValue = originalValue.trim(); + if (trimmedValue.startsWith(ENC_PREFIX) && trimmedValue.endsWith(ENC_SUFFIX)) { + String encryptedValue = trimmedValue.substring(ENC_PREFIX.length(), trimmedValue.length() - ENC_SUFFIX.length()); + return encryptor.decrypt(encryptedValue); + } + + return originalValue; + } +} diff --git a/utils/src/test/java/com/cloud/utils/crypt/EncryptablePropertyPlaceholderConfigurerTest.java b/utils/src/test/java/com/cloud/utils/crypt/EncryptablePropertyPlaceholderConfigurerTest.java new file mode 100644 index 000000000000..1ab2cb2b74a1 --- /dev/null +++ b/utils/src/test/java/com/cloud/utils/crypt/EncryptablePropertyPlaceholderConfigurerTest.java @@ -0,0 +1,73 @@ +// +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +// + +package com.cloud.utils.crypt; + +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verifyNoInteractions; +import static org.mockito.Mockito.when; + +import org.jasypt.encryption.StringEncryptor; +import org.junit.Assert; +import org.junit.Test; + +public class EncryptablePropertyPlaceholderConfigurerTest { + + @Test + public void convertPropertyValueDecryptsWrappedValue() { + StringEncryptor encryptor = mock(StringEncryptor.class); + when(encryptor.decrypt("bmb2VaFdQb")).thenReturn("secret"); + EncryptablePropertyPlaceholderConfigurer configurer = new EncryptablePropertyPlaceholderConfigurer(encryptor); + + String result = configurer.convertPropertyValue("ENC(bmb2VaFdQb)"); + + Assert.assertEquals("secret", result); + } + + @Test + public void convertPropertyValueTrimsSurroundingWhitespaceBeforeDecrypting() { + StringEncryptor encryptor = mock(StringEncryptor.class); + when(encryptor.decrypt("bmb2VaFdQb")).thenReturn("secret"); + EncryptablePropertyPlaceholderConfigurer configurer = new EncryptablePropertyPlaceholderConfigurer(encryptor); + + String result = configurer.convertPropertyValue(" ENC(bmb2VaFdQb) "); + + Assert.assertEquals("secret", result); + } + + @Test + public void convertPropertyValuePassesThroughPlainValues() { + StringEncryptor encryptor = mock(StringEncryptor.class); + EncryptablePropertyPlaceholderConfigurer configurer = new EncryptablePropertyPlaceholderConfigurer(encryptor); + + String result = configurer.convertPropertyValue("guest"); + + Assert.assertEquals("guest", result); + verifyNoInteractions(encryptor); + } + + @Test + public void convertPropertyValueHandlesNull() { + StringEncryptor encryptor = mock(StringEncryptor.class); + EncryptablePropertyPlaceholderConfigurer configurer = new EncryptablePropertyPlaceholderConfigurer(encryptor); + + Assert.assertNull(configurer.convertPropertyValue(null)); + verifyNoInteractions(encryptor); + } +}