Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions artemis-features/src/main/resources/features.xml
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,8 @@
<!--bundle dependency="true">mvn:io.micrometer/micrometer-core/${version.micrometer}</bundle-->
<bundle dependency="true">mvn:com.nimbusds/nimbus-jose-jwt/${nimbus.jwt.version}</bundle>

<bundle dependency="true">mvn:org.snakeyaml/snakeyaml-engine/${snakeyaml-engine.version}</bundle>

<bundle>mvn:org.apache.activemq/activemq-artemis-native/${activemq-artemis-native-version}</bundle>
<bundle>mvn:org.apache.artemis/artemis-lockmanager-api/${pom.version}</bundle>
<bundle>mvn:org.apache.artemis/artemis-server-osgi/${pom.version}</bundle>
Expand Down
7 changes: 7 additions & 0 deletions artemis-pom/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -936,6 +936,13 @@
<version>${apache.httpclient.version}</version>
</dependency>

<dependency>
<groupId>org.snakeyaml</groupId>
<artifactId>snakeyaml-engine</artifactId>
<version>${snakeyaml-engine.version}</version>
<!-- Apache 2.0 License -->
</dependency>

<dependency>
<groupId>com.fasterxml.jackson</groupId>
<artifactId>jackson-bom</artifactId>
Expand Down
4 changes: 4 additions & 0 deletions artemis-server/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,10 @@
<groupId>commons-beanutils</groupId>
<artifactId>commons-beanutils</artifactId>
</dependency>
<dependency>
<groupId>org.snakeyaml</groupId>
<artifactId>snakeyaml-engine</artifactId>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,9 @@
import org.apache.activemq.artemis.json.JsonObjectBuilder;
import org.apache.activemq.artemis.json.JsonString;
import org.apache.activemq.artemis.json.JsonValue;
import org.snakeyaml.engine.v2.api.Load;
import org.snakeyaml.engine.v2.api.LoadSettings;

import org.apache.activemq.artemis.utils.ByteUtil;
import org.apache.activemq.artemis.utils.ClassloadingUtil;
import org.apache.activemq.artemis.utils.Env;
Expand Down Expand Up @@ -497,7 +500,7 @@ public class ConfigurationImpl extends javax.security.auth.login.Configuration i
private File artemisInstance;
private transient JsonObject jsonStatus = JsonLoader.createObjectBuilder().build();
private final Set<String> keysToRedact = new HashSet<>();
private static final Pattern defaultPropertiesFileNamePattern = Pattern.compile(".*\\.(json|properties)");
private static final Pattern defaultPropertiesFileNamePattern = Pattern.compile(".*\\.(json|yaml|properties)");

private JsonObject getJsonStatus() {
if (jsonStatus == null) {
Expand Down Expand Up @@ -625,8 +628,11 @@ public void parseFileProperties(File file) throws Exception {
InsertionOrderedProperties brokerProperties = new InsertionOrderedProperties();
try (CheckedInputStream checkedInputStream = new CheckedInputStream(new FileInputStream(file), new Adler32())) {
try {
if (file.getName().endsWith(".json")) {
String fileName = file.getName();
if (fileName.endsWith(".json")) {
brokerProperties.loadJson(configuration, checkedInputStream);
} else if (fileName.endsWith(".yaml")) {
brokerProperties.loadYaml(configuration, checkedInputStream);
} else {
brokerProperties.load(checkedInputStream);
}
Expand Down Expand Up @@ -3882,6 +3888,49 @@ public synchronized boolean loadJson(ConfigurationImpl configuration, Reader rea
return true;
}

public synchronized boolean loadYaml(ConfigurationImpl configuration, InputStream inputStream) {
LoadSettings settings = LoadSettings.builder()
.setMaxAliasesForCollections(50)
.setCodePointLimit(3 * 1024 * 1024)
.build();
Load yamlLoad = new Load(settings);
@SuppressWarnings("unchecked")
Map<String, Object> yamlMap = (Map<String, Object>) yamlLoad.loadFromInputStream(inputStream);
if (yamlMap == null) {
return false;
}
final String surroundString = determineSurroundString(configuration, yamlMap);
Comment thread
gtully marked this conversation as resolved.
loadYamlMap(surroundString, "", yamlMap);
return true;
}

@SuppressWarnings("unchecked")
private void loadYamlMap(String keySurroundString, String parentKey, Map<String, Object> map) {
for (Map.Entry<String, Object> entry : map.entrySet()) {
String key = entry.getKey();
key = autoSurroundIfNecessary(key, keySurroundString);
String propertyKey = parentKey + key;
Object value = entry.getValue();
if (value instanceof Map) {
loadYamlMap(keySurroundString, propertyKey + ".", (Map<String, Object>) value);
} else if (value != null) {
put(propertyKey, String.valueOf(value));
}
}
}

private String determineSurroundString(ConfigurationImpl configuration, Map<String, Object> yamlMap) {
Object surroundValue = yamlMap.get(ActiveMQDefaultConfiguration.BROKER_PROPERTIES_KEY_SURROUND_PROPERTY);
if (surroundValue != null) {
return String.valueOf(surroundValue);
}
Object brokerSurroundValue = yamlMap.get("brokerPropertiesKeySurround");
if (brokerSurroundValue != null) {
return String.valueOf(brokerSurroundValue);
}
return configuration.getBrokerPropertiesKeySurround();
}

private void loadJsonObject(String keySurroundString, String parentKey, JsonObject jsonObject) {
jsonObject.entrySet().stream().forEach(jsonEntry -> {
JsonValue jsonValue = jsonEntry.getValue();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2589,6 +2589,147 @@ public void testInvalidJsonPropertiesReaderFromFile() throws Exception {
assertEquals("$$", configuration.getBrokerPropertiesKeySurround());
}

@Test
public void testYamlSecurityRolesWithAnchors() throws Exception {

File tmpFile = File.createTempFile("yaml-security-roles-test", ".yaml", temporaryFolder);
try (FileOutputStream fileOutputStream = new FileOutputStream(tmpFile);
PrintWriter printWriter = new PrintWriter(fileOutputStream)) {
printWriter.write("""
securityRoles:
"TEMP.*":
role1: &base_perms
createAddress: true
send: true
consume: true
createNonDurableQueue: true
role2: *base_perms
role3: *base_perms
""");
}

ConfigurationImpl configuration = new ConfigurationImpl();
configuration.parseProperties(tmpFile.getAbsolutePath());

assertTrue(configuration.getStatus().contains("\"errors\":[]"), configuration.getStatus());

Set<Role> roles = configuration.getSecurityRoles().get("TEMP.*");
assertNotNull(roles, "Expected security roles for TEMP.*");
assertEquals(3, roles.size(), "Expected 3 roles under TEMP.*");

for (String roleName : new String[]{"role1", "role2", "role3"}) {
Role role = roles.stream()
.filter(r -> r.getName().equals(roleName))
.findFirst()
.orElse(null);
assertNotNull(role, "Missing role: " + roleName);
assertTrue(role.isCreateAddress(), roleName + " should have createAddress");
assertTrue(role.isSend(), roleName + " should have send");
assertTrue(role.isConsume(), roleName + " should have consume");
assertTrue(role.isCreateNonDurableQueue(), roleName + " should have createNonDurableQueue");
}
}

@Test
public void testYamlPropertiesReaderFromFile() throws Exception {

File tmpFile = File.createTempFile("yaml-props-test", ".yaml", temporaryFolder);
try (FileOutputStream fileOutputStream = new FileOutputStream(tmpFile);
PrintWriter printWriter = new PrintWriter(fileOutputStream)) {
printWriter.write("""
globalMaxSize: "25K"
gracefulShutdownEnabled: true
securityEnabled: false
""");
}

ConfigurationImpl configuration = new ConfigurationImpl();
configuration.parseProperties(tmpFile.getAbsolutePath());

assertTrue(configuration.getStatus().contains("\"errors\":[]"), configuration.getStatus());
assertEquals(25 * 1024, configuration.getGlobalMaxSize());
assertTrue(configuration.isGracefulShutdownEnabled());
assertFalse(configuration.isSecurityEnabled());
}

@Test
public void testInvalidYamlPropertiesReaderFromFile() throws Exception {

File tmpFile = File.createTempFile("yaml-props-test", ".yaml", temporaryFolder);
try (FileOutputStream fileOutputStream = new FileOutputStream(tmpFile);
PrintWriter printWriter = new PrintWriter(fileOutputStream)) {
printWriter.write("{ invalid yaml: [}");
}

ConfigurationImpl configuration = new ConfigurationImpl();
configuration.parseProperties(tmpFile.getAbsolutePath());

assertFalse(configuration.getStatus().contains(".yaml\":{\"errors\":[]"), configuration.getStatus());
}

@Test
public void testYamlBillionLaughsRejected() throws Exception {

File tmpFile = File.createTempFile("yaml-bomb-test", ".yaml", temporaryFolder);
try (FileOutputStream fileOutputStream = new FileOutputStream(tmpFile);
PrintWriter printWriter = new PrintWriter(fileOutputStream)) {
StringBuilder sb = new StringBuilder();
sb.append("a: &a [\"lol\"]\n");
for (int i = 1; i <= 60; i++) {
char prev = (char) ('a' + i - 1);
char curr = (char) ('a' + i);
sb.append(curr).append(": &").append(curr)
.append(" [*").append(prev).append(", *").append(prev)
.append(", *").append(prev).append("]\n");
}
printWriter.write(sb.toString());
}

ConfigurationImpl configuration = new ConfigurationImpl();
configuration.parseProperties(tmpFile.getAbsolutePath());

assertTrue(configuration.getStatus().contains("loadError"), configuration.getStatus());
}

@Test
public void testYamlPropertiesKeySurround() throws Exception {

File tmpFile = File.createTempFile("yaml-surround-props-test", ".yaml", temporaryFolder);
try (FileOutputStream fileOutputStream = new FileOutputStream(tmpFile);
PrintWriter printWriter = new PrintWriter(fileOutputStream)) {
printWriter.write("""
key.surround: "$$"
addressSettings:
$$a."with_quote".b$$:
maxDeliveryAttempts: 0
""");
}

ConfigurationImpl configuration = new ConfigurationImpl();
configuration.parseProperties(tmpFile.getAbsolutePath());

assertEquals(0, configuration.getAddressSettings().get("a.\"with_quote\".b").getMaxDeliveryAttempts());
}

@Test
public void testYamlPropertiesAutoSurround() throws Exception {

File tmpFile = File.createTempFile("yaml-auto-surround-props-test", ".yaml", temporaryFolder);
try (FileOutputStream fileOutputStream = new FileOutputStream(tmpFile);
PrintWriter printWriter = new PrintWriter(fileOutputStream)) {
printWriter.write("""
addressSettings:
a.b.c:
maxDeliveryAttempts: 2
""");
}

ConfigurationImpl configuration = new ConfigurationImpl();
configuration.parseProperties(tmpFile.getAbsolutePath());

assertEquals(2, configuration.getAddressSettings().get("a.b.c").getMaxDeliveryAttempts());
}

private JsonObject buildSimpleConfigJsonObject() {
JsonObjectBuilder configObjectBuilder = JsonLoader.createObjectBuilder();
{
Expand Down
1 change: 1 addition & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,7 @@
<arquillian-weld-embedded.version>2.1.0.Final</arquillian-weld-embedded.version>
<owb.version>2.0.28</owb.version>
<arquillian.version>1.10.2.Final</arquillian.version>
<snakeyaml-engine.version>2.10</snakeyaml-engine.version>
<servicemix.json-1.1.spec.version>2.9.0</servicemix.json-1.1.spec.version>
<version.org.jacoco>0.8.14</version.org.jacoco>
<version.org.jacoco.plugin>0.8.14</version.org.jacoco.plugin>
Expand Down