Skip to content

Commit 68f57aa

Browse files
committed
SPR-6308 - Spring Expression Language creates systemProperties bean calling System.getProperties() which in enterprise shared containers is locked down
1 parent 7844a63 commit 68f57aa

File tree

3 files changed

+165
-11
lines changed

3 files changed

+165
-11
lines changed

org.springframework.context/src/main/java/org/springframework/context/support/AbstractApplicationContext.java

Lines changed: 26 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,11 @@
2020
import java.lang.annotation.Annotation;
2121
import java.security.AccessControlException;
2222
import java.util.ArrayList;
23-
import java.util.Collections;
2423
import java.util.Date;
2524
import java.util.LinkedHashMap;
2625
import java.util.List;
2726
import java.util.Locale;
2827
import java.util.Map;
29-
import java.util.Properties;
3028

3129
import org.apache.commons.logging.Log;
3230
import org.apache.commons.logging.LogFactory;
@@ -498,15 +496,24 @@ protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
498496

499497
// Register default environment beans.
500498
if (!beanFactory.containsBean(SYSTEM_PROPERTIES_BEAN_NAME)) {
501-
Properties systemProperties;
499+
Map systemProperties;
502500
try {
503501
systemProperties = System.getProperties();
504502
}
505503
catch (AccessControlException ex) {
506-
if (logger.isInfoEnabled()) {
507-
logger.info("Not allowed to obtain system properties: " + ex.getMessage());
508-
}
509-
systemProperties = new Properties();
504+
systemProperties = new ReadOnlySystemAttributesMap() {
505+
506+
@Override
507+
protected String getSystemAttribute(String propertyName) {
508+
try {
509+
return System.getProperty(propertyName);
510+
} catch (AccessControlException ex) {
511+
logger.info("Not allowed to obtain system property [" + propertyName + "]: "
512+
+ ex.getMessage());
513+
return null;
514+
}
515+
}
516+
};
510517
}
511518
beanFactory.registerSingleton(SYSTEM_PROPERTIES_BEAN_NAME, systemProperties);
512519
}
@@ -516,10 +523,18 @@ protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
516523
systemEnvironment = System.getenv();
517524
}
518525
catch (AccessControlException ex) {
519-
if (logger.isInfoEnabled()) {
520-
logger.info("Not allowed to obtain system environment: " + ex.getMessage());
521-
}
522-
systemEnvironment = Collections.emptyMap();
526+
systemEnvironment = new ReadOnlySystemAttributesMap() {
527+
@Override
528+
protected String getSystemAttribute(String variableName) {
529+
try {
530+
return System.getenv(variableName);
531+
} catch (AccessControlException ex) {
532+
logger.info("Not allowed to obtain system environment variable [" + variableName + "]: " +
533+
ex.getMessage());
534+
return null;
535+
}
536+
}
537+
};
523538
}
524539
beanFactory.registerSingleton(SYSTEM_ENVIRONMENT_BEAN_NAME, systemEnvironment);
525540
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
/*
2+
* Copyright 2002-2009 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.context.support;
18+
19+
import java.util.Collection;
20+
import java.util.Map;
21+
import java.util.Set;
22+
23+
/**
24+
* Read-only {@code Map<String, String>} implementation that is backed by system properties or environment
25+
* variables.
26+
*
27+
* <p>Used by {@link AbstractApplicationContext} when a {@link SecurityManager} prohibits access to {@link
28+
* System#getProperties()} or {@link System#getenv()}.
29+
*
30+
* @author Arjen Poutsma
31+
* @since 3.0
32+
*/
33+
abstract class ReadOnlySystemAttributesMap implements Map<String, String> {
34+
35+
public boolean containsKey(Object key) {
36+
return get(key) != null;
37+
}
38+
39+
public String get(Object key) {
40+
if (key instanceof String) {
41+
String attributeName = (String) key;
42+
return getSystemAttribute(attributeName);
43+
}
44+
else {
45+
return null;
46+
}
47+
}
48+
49+
public boolean isEmpty() {
50+
return false;
51+
}
52+
53+
/**
54+
* Template method that returns the underlying system attribute.
55+
*
56+
* <p>Implementations typically call {@link System#getProperty(String)} or {@link System#getenv(String)} here.
57+
*/
58+
protected abstract String getSystemAttribute(String attributeName);
59+
60+
// Unsupported
61+
62+
public int size() {
63+
throw new UnsupportedOperationException();
64+
}
65+
66+
public String put(String key, String value) {
67+
throw new UnsupportedOperationException();
68+
}
69+
70+
public boolean containsValue(Object value) {
71+
throw new UnsupportedOperationException();
72+
}
73+
74+
public String remove(Object key) {
75+
throw new UnsupportedOperationException();
76+
}
77+
78+
public void clear() {
79+
throw new UnsupportedOperationException();
80+
}
81+
82+
public Set<String> keySet() {
83+
throw new UnsupportedOperationException();
84+
}
85+
86+
public void putAll(Map<? extends String, ? extends String> m) {
87+
throw new UnsupportedOperationException();
88+
}
89+
90+
public Collection<String> values() {
91+
throw new UnsupportedOperationException();
92+
}
93+
94+
public Set<Entry<String, String>> entrySet() {
95+
throw new UnsupportedOperationException();
96+
}
97+
98+
}

org.springframework.context/src/test/java/org/springframework/context/expression/ApplicationContextExpressionTests.java

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@
1717
package org.springframework.context.expression;
1818

1919
import java.io.Serializable;
20+
import java.security.AccessControlException;
21+
import java.security.Permission;
2022
import java.util.Properties;
2123

2224
import org.apache.commons.logging.Log;
@@ -236,6 +238,45 @@ public void prototypeCreationIsFastEnough() {
236238
assertTrue("Prototype creation took too long: " + sw.getTotalTimeMillis(), sw.getTotalTimeMillis() < 6000);
237239
}
238240

241+
@Test
242+
public void systemPropertiesSecurityManager() {
243+
GenericApplicationContext ac = new GenericApplicationContext();
244+
AnnotationConfigUtils.registerAnnotationConfigProcessors(ac);
245+
246+
247+
GenericBeanDefinition bd = new GenericBeanDefinition();
248+
bd.setBeanClass(TestBean.class);
249+
bd.getPropertyValues().addPropertyValue("country", "#{systemProperties.country}");
250+
ac.registerBeanDefinition("tb", bd);
251+
252+
SecurityManager oldSecurityManager = System.getSecurityManager();
253+
try {
254+
System.setProperty("country", "NL");
255+
256+
SecurityManager securityManager = new SecurityManager() {
257+
@Override
258+
public void checkPropertiesAccess() {
259+
throw new AccessControlException("Not Allowed");
260+
}
261+
262+
@Override
263+
public void checkPermission(Permission perm) {
264+
// allow everything else
265+
}
266+
267+
};
268+
System.setSecurityManager(securityManager);
269+
ac.refresh();
270+
271+
TestBean tb = ac.getBean("tb", TestBean.class);
272+
assertEquals("NL", tb.getCountry());
273+
274+
}
275+
finally {
276+
System.setSecurityManager(oldSecurityManager);
277+
System.getProperties().remove("country");
278+
}
279+
}
239280

240281
public static class ValueTestBean implements Serializable {
241282

0 commit comments

Comments
 (0)