/* * Copyright (C) 2026 Ignite Realtime Foundation. All rights reserved. * * Licensed 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 org.jivesoftware.util; import org.jivesoftware.Fixtures; import org.junit.jupiter.api.*; import java.io.ByteArrayInputStream; import java.lang.reflect.Field; import java.nio.charset.StandardCharsets; import static org.junit.jupiter.api.Assertions.*; /** * These tests intentionally exercise {@link JiveGlobals#migrateProperty(String)} with encryption markers coming from * security configuration. */ public class XMLPropertiesMigrationEncryptionTest { @BeforeAll public static void setUpClass() throws Exception { Fixtures.reconfigureOpenfireHome(); Fixtures.disableDatabasePersistence(); } @BeforeEach @AfterEach public void resetProperties() throws Exception { Fixtures.clearExistingProperties(); setPrivateStaticField(JiveGlobals.class, "securityProperties", null); setPrivateStaticField(JiveGlobals.class, "propertyEncryptor", null); setPrivateStaticField(JiveGlobals.class, "propertyEncryptorNew", null); setPrivateStaticField(JiveGlobals.class, "currentKey", null); } /** * Asserts that when migrating an XML property, not yet stored in the database, is encrypted, its encryption state * is persisted. * * @see OF-3296: Encrypted XML properties can lose encryption during database migration */ @Test public void migrateEncryptedXmlOnlyPropertyPreservesEncryption() throws Exception { // Setup test fixture. final String propertyName = "of3175.password"; final String propertyValue = "s3cr3t"; configureEncryptedSecurityProperties(propertyName); JiveGlobals.setXMLProperty(propertyName, propertyValue); assertTrue(JiveGlobals.isXMLPropertyEncrypted(propertyName), "Unable to prepare test fixture: encrypted XML property must be set."); assertNull(JiveGlobals.getProperty(propertyName), "Unable to prepare test fixture: encrypted XML property must not be set in DB."); // Execute system under test. JiveGlobals.migrateProperty(propertyName); // Verify results. assertEquals(propertyValue, JiveGlobals.getProperty(propertyName), "Expected the migrated property to have the same value as the original (but it did not)."); assertTrue(JiveGlobals.isPropertyEncrypted(propertyName), "Regression for OF-3296: migrated encrypted XML property must end up being encrypted in DB."); } /** * Asserts that when migrating an XML property, already stored in the database, is encrypted, its encryption state * (as defined by the XML property) is persisted. * * @see OF-3296: Encrypted XML properties can lose encryption during database migration */ @Test public void migrateEncryptedDuplicatePropertyPreservesEncryption() throws Exception { // Setup test fixture. final String propertyName = "of3175.duplicate.password"; final String propertyValue = "same-value"; configureEncryptedSecurityProperties(propertyName); JiveGlobals.setXMLProperty(propertyName, propertyValue); // duplicate XML value JiveGlobals.setProperty(propertyName, propertyValue); // existing DB value assertTrue(JiveGlobals.isXMLPropertyEncrypted(propertyName), "Unable to prepare test fixture: encrypted XML property must be set."); assertFalse(JiveGlobals.isPropertyEncrypted(propertyName), "Unable to prepare test fixture: property must not (yet) be defined as 'encrypted' in DB."); // Execute system under test. JiveGlobals.migrateProperty(propertyName); // Verify results. assertEquals(propertyValue, JiveGlobals.getProperty(propertyName), "Expected the migrated property to have the same value as the original (but it did not)."); assertTrue(JiveGlobals.isPropertyEncrypted(propertyName), "Regression for OF-3296: migrated encrypted XML property must end up being encrypted in DB."); } private static void configureEncryptedSecurityProperties(String... encryptedPropertyNames) throws Exception { final StringBuilder xml = new StringBuilder(""); for (final String propertyName : encryptedPropertyNames) { xml.append("").append(propertyName).append(""); } xml.append(""); final XMLProperties security = XMLProperties.getNonPersistedInstance( new ByteArrayInputStream(xml.toString().getBytes(StandardCharsets.UTF_8)) ); setPrivateStaticField(JiveGlobals.class, "securityProperties", security); } private static void setPrivateStaticField(Class clazz, String fieldName, Object value) throws Exception { final Field field = clazz.getDeclaredField(fieldName); field.setAccessible(true); field.set(null, value); } }