Skip to content

Commit 2a1131e

Browse files
committed
Merge branch 'main' into broker-mbean-transport-filter
2 parents d1f4548 + 85fa7bb commit 2a1131e

7 files changed

Lines changed: 809 additions & 19 deletions

File tree

activemq-spring/src/main/java/org/apache/activemq/spring/Utils.java

Lines changed: 56 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,9 @@
1919
import java.io.File;
2020
import java.io.FileNotFoundException;
2121
import java.net.MalformedURLException;
22+
import java.net.URI;
23+
import java.net.URISyntaxException;
24+
import java.util.Set;
2225
import org.springframework.core.io.ClassPathResource;
2326
import org.springframework.core.io.FileSystemResource;
2427
import org.springframework.core.io.Resource;
@@ -27,22 +30,69 @@
2730

2831
public class Utils {
2932

33+
public static final String FILE_PROTOCOL = "file";
34+
public static final String CLASSPATH_PROTOCOL = "classpath";
35+
3036
public static Resource resourceFromString(String uri) throws MalformedURLException {
31-
Resource resource;
32-
File file = new File(uri);
33-
if (file.exists()) {
37+
// default allows all
38+
return resourceFromString(uri, null);
39+
}
40+
41+
public static Resource resourceFromString(String uri, Set<String> allowedProtocols) throws MalformedURLException {
42+
// Empty set means nothing is allowed
43+
if (allowedProtocols != null && allowedProtocols.isEmpty()) {
44+
throw new IllegalArgumentException("No protocols are allowed for loading resources.");
45+
}
46+
47+
final Resource resource;
48+
49+
// First, just try and load a local file (if it exists) and if "file"
50+
// as part of the allow list. This preserves previous behavior of
51+
// always optimistically trying a local file first.
52+
if (isAllowFile(allowedProtocols) && new File(uri).exists()) {
3453
resource = new FileSystemResource(uri);
54+
// If file isn't allowed, or if the file can't be found then check
55+
// if the string is a valid URL. If it's valid, then we need
56+
// to validate if it's allowed before loading the URL.
57+
// isUrl() uses URI internally so it won't actually load anything
3558
} else if (ResourceUtils.isUrl(uri)) {
3659
try {
60+
validateUrlAllowed(uri, allowedProtocols);
3761
resource = new UrlResource(ResourceUtils.getURL(uri));
38-
} catch (FileNotFoundException e) {
62+
} catch (FileNotFoundException | URISyntaxException e) {
3963
MalformedURLException malformedURLException = new MalformedURLException(uri);
4064
malformedURLException.initCause(e);
41-
throw malformedURLException;
65+
throw malformedURLException;
4266
}
43-
} else {
67+
// Fallback to trying on the classpath if not a valid Url, and we allow it which
68+
// also preserves the previous behavior (if classpath is allowed)
69+
} else if (isAllowClasspath(allowedProtocols)){
4470
resource = new ClassPathResource(uri);
71+
// Catch all fail-safe if nothing else matches. This could happen if file is allowed
72+
// but not classpath but the file doesn't exist
73+
} else {
74+
throw new IllegalArgumentException("URL [" + uri + "] can't be found or is not allowed"
75+
+ " for loading resources");
4576
}
4677
return resource;
4778
}
79+
80+
static boolean isAllowFile(Set<String> allowedProtocols) {
81+
return allowedProtocols == null || allowedProtocols.contains(FILE_PROTOCOL);
82+
}
83+
84+
static boolean isAllowClasspath(Set<String> allowedProtocols) {
85+
return allowedProtocols == null || allowedProtocols.contains(CLASSPATH_PROTOCOL);
86+
}
87+
88+
private static void validateUrlAllowed(String uriString, Set<String> allowedProtocols)
89+
throws URISyntaxException {
90+
// Use new URI() to get the scheme
91+
// This is important because ResourceUtils.getURL() actually searches
92+
// the classpath which we don't want to do if not allowed
93+
if (allowedProtocols != null && !allowedProtocols.contains(new URI(uriString).getScheme())) {
94+
throw new IllegalArgumentException("URL [" + uriString +
95+
"] does not use an allowed protocol for loading URL resources");
96+
}
97+
}
4898
}

activemq-spring/src/main/java/org/apache/activemq/xbean/XBeanBrokerFactory.java

Lines changed: 35 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,9 @@
2020
import java.net.MalformedURLException;
2121
import java.net.URI;
2222

23-
import org.apache.activemq.broker.BrokerContextAware;
23+
import java.util.Arrays;
24+
import java.util.Set;
25+
import java.util.stream.Collectors;
2426
import org.apache.activemq.broker.BrokerFactoryHandler;
2527
import org.apache.activemq.broker.BrokerService;
2628
import org.apache.activemq.spring.SpringBrokerContext;
@@ -35,20 +37,38 @@
3537
import org.springframework.beans.FatalBeanException;
3638
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
3739
import org.springframework.context.ApplicationContext;
38-
import org.springframework.context.ApplicationContextAware;
3940
import org.springframework.core.io.Resource;
4041

4142
/**
4243
*
4344
*/
4445
public class XBeanBrokerFactory implements BrokerFactoryHandler {
45-
private static final transient Logger LOG = LoggerFactory.getLogger(XBeanBrokerFactory.class);
46+
private static final Logger LOG = LoggerFactory.getLogger(XBeanBrokerFactory.class);
47+
48+
public static final String XBEAN_BROKER_FACTORY_PROTOCOLS_PROP =
49+
"org.apache.activemq.xbean.XBEAN_BROKER_FACTORY_PROTOCOLS";
50+
public static final String DEFAULT_ALLOWED_PROTOCOLS = Utils.FILE_PROTOCOL + "," + Utils.CLASSPATH_PROTOCOL;
51+
52+
private final Set<String> allowedProtocols;
4653

4754
static {
4855
PropertyEditorManager.registerEditor(URI.class, URIEditor.class);
4956
}
5057

58+
public XBeanBrokerFactory() {
59+
final String allowedProtocols = System.getProperty(XBEAN_BROKER_FACTORY_PROTOCOLS_PROP,
60+
DEFAULT_ALLOWED_PROTOCOLS);
61+
62+
// Asterisk will map to null which will allow all and skip checking
63+
// Empty string will map to an empty set and will deny all
64+
this.allowedProtocols = !allowedProtocols.equals("*") ?
65+
Arrays.stream(allowedProtocols.split("\\s*,\\s*"))
66+
.filter(s -> !s.isBlank())
67+
.collect(Collectors.toUnmodifiableSet()) : null;
68+
}
69+
5170
private boolean validate = true;
71+
5272
public boolean isValidate() {
5373
return validate;
5474
}
@@ -75,12 +95,10 @@ public BrokerService createBroker(URI config) throws Exception {
7595
if (broker == null) {
7696
// lets try find by type
7797
String[] names = context.getBeanNamesForType(BrokerService.class);
78-
for (int i = 0; i < names.length; i++) {
79-
String name = names[i];
80-
broker = (BrokerService)context.getBean(name);
81-
if (broker != null) {
82-
break;
83-
}
98+
for (String name : names) {
99+
// No need to check for null, this will throw an exception if not found
100+
broker = (BrokerService) context.getBean(name);
101+
break;
84102
}
85103
}
86104
if (broker == null) {
@@ -98,8 +116,8 @@ public BrokerService createBroker(URI config) throws Exception {
98116
}
99117

100118
protected ApplicationContext createApplicationContext(String uri) throws MalformedURLException {
101-
Resource resource = Utils.resourceFromString(uri);
102-
LOG.debug("Using " + resource + " from " + uri);
119+
Resource resource = Utils.resourceFromString(uri, allowedProtocols);
120+
LOG.debug("Using {} from {}", resource, uri);
103121
try {
104122
return new ResourceXmlApplicationContext(resource) {
105123
@Override
@@ -108,9 +126,14 @@ protected void initBeanDefinitionReader(XmlBeanDefinitionReader reader) {
108126
}
109127
};
110128
} catch (FatalBeanException errorToLog) {
111-
LOG.error("Failed to load: " + resource + ", reason: " + errorToLog.getLocalizedMessage(), errorToLog);
129+
LOG.error("Failed to load: {}, reason: {}", resource, errorToLog.getLocalizedMessage(),
130+
errorToLog);
112131
throw errorToLog;
113132
}
114133
}
115134

135+
// Package scope for testing
136+
Set<String> getAllowedProtocols() {
137+
return allowedProtocols;
138+
}
116139
}

0 commit comments

Comments
 (0)