Skip to content

Commit

Permalink
httpd: Fix a couple of bugs
Browse files Browse the repository at this point in the history
Target: trunk
Require-notes: no
Require-book: no
Request: 2.9
Request: 2.8
Request: 2.7
Request: 2.6
Acked-by: Paul Millar <paul.millar@desy.de>
Patch: http://rb.dcache.org/r/7002/
(cherry picked from commit ed1975e)

Conflicts:
	modules/dcache/src/main/java/org/dcache/cells/UniversalSpringCell.java
  • Loading branch information
gbehrmann committed May 13, 2014
1 parent 78e5831 commit 633ec78
Showing 1 changed file with 139 additions and 44 deletions.
183 changes: 139 additions & 44 deletions modules/dcache/src/main/java/org/dcache/cells/UniversalSpringCell.java
Expand Up @@ -16,13 +16,16 @@
import org.springframework.beans.BeanWrapperImpl;
import org.springframework.beans.BeansException;
import org.springframework.beans.InvalidPropertyException;
import org.springframework.beans.NotReadablePropertyException;
import org.springframework.beans.PropertyAccessException;
import org.springframework.beans.PropertyAccessorUtils;
import org.springframework.beans.factory.BeanCreationException;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.core.env.ConfigurableEnvironment;
Expand Down Expand Up @@ -109,6 +112,15 @@ public class UniversalSpringCell

private static final long WAIT_FOR_FILE_SLEEP = 30000;

private static final Set<Class<?>> PRIMITIVE_TYPES =
Sets.<Class<?>>newHashSet(Byte.class, Byte.TYPE, Short.class, Short.TYPE,
Integer.class, Integer.TYPE, Long.class, Long.TYPE,
Float.class, Float.TYPE, Double.class, Double.TYPE,
Character.class, Character.TYPE, Boolean.class,
Boolean.TYPE, String.class);
private static final Class<?>[] TERMINAL_TYPES = new Class<?>[] { Class.class, ApplicationContext.class };
private static final Class<?>[] HIDDEN_TYPES = new Class<?>[] { ApplicationContext.class, AutoCloseable.class };

/**
* Environment map this cell was instantiated in.
*/
Expand Down Expand Up @@ -294,7 +306,7 @@ private void setupCellExecutors(String callbackExecutor, String messageExecutor)
if (messageExecutor != null) {
Object executor = getBean(messageExecutor);
checkState(executor instanceof ThreadPoolExecutor,
"No such bean: " + messageExecutor);
"No such bean: " + messageExecutor);
getNucleus().setMessageExecutor((ThreadPoolExecutor) executor);
}
}
Expand Down Expand Up @@ -606,16 +618,11 @@ public String ac_bean_ls(Args args)
ConfigurableListableBeanFactory factory = _context.getBeanFactory();
s.format(format, "Bean", "Description");
s.format(format, "----", "-----------");
for (String name : getBeanNames()) {
for (String name : factory.getBeanDefinitionNames()) {
if (!name.startsWith("org.springframework.")) {
try {
BeanDefinition definition = factory.getBeanDefinition(name);
String description = definition.getDescription();
s.format(format, name,
(description != null ? description : "-"));
} catch (NoSuchBeanDefinitionException e) {
debug("Failed to query bean definition for " + name);
}
BeanDefinition definition = factory.getBeanDefinition(name);
String description = definition.getDescription();
s.format(format, name, (description != null ? description : "-"));
}
}

Expand Down Expand Up @@ -651,7 +658,7 @@ private Object getBeanProperty(String s)
String[] a = s.split("\\.", 2);
Object o = getBean(a[0]);
if (o != null && a.length == 2) {
BeanWrapper bean = new BeanWrapperImpl(o);
BeanWrapper bean = new RestrictedBeanWrapper(o);
o = bean.isReadableProperty(a[1])
? bean.getPropertyValue(a[1])
: null;
Expand Down Expand Up @@ -697,18 +704,16 @@ private CharSequence valueToString(Object value)
Object o = getBeanProperty(name);
if (o != null) {
StringBuilder s = new StringBuilder();
BeanWrapper bean = new BeanWrapperImpl(o);
BeanWrapper bean = new RestrictedBeanWrapper(o);
for (PropertyDescriptor p : bean.getPropertyDescriptors()) {
if (!p.isHidden()) {
String property = p.getName();
if (bean.isReadableProperty(property)) {
Object value = bean.getPropertyValue(property);
s.append(property).append('=').append(valueToString(value));
if (!bean.isWritableProperty(property)) {
s.append(" [read-only]");
}
s.append('\n');
String property = p.getName();
if (bean.isReadableProperty(property)) {
Object value = bean.getPropertyValue(property);
s.append(property).append('=').append(valueToString(value));
if (!bean.isWritableProperty(property)) {
s.append(" [read-only]");
}
s.append('\n');
}
}
return s.toString();
Expand Down Expand Up @@ -793,8 +798,11 @@ public BeanQueryMessage messageArrived(BeanQueryAllPropertiesMessage message)
throws CacheException
{
Map<String,Object> beans = Maps.newHashMap();
for (String name : getBeanNames()) {
beans.put(name, getBean(name));
ConfigurableListableBeanFactory factory = _context.getBeanFactory();
for (String name : factory.getBeanDefinitionNames()) {
if (!name.startsWith("org.springframework.")) {
beans.put(name, getBean(name));
}
}
message.setResult(serialize(beans));
return message;
Expand All @@ -803,28 +811,45 @@ public BeanQueryMessage messageArrived(BeanQueryAllPropertiesMessage message)
public BeanQueryMessage messageArrived(BeanQuerySinglePropertyMessage message)
throws CacheException
{
Object o = getBeanProperty(message.getPropertyName());
String[] a = message.getPropertyName().split("\\.", 2);
String name = a[0];
Object o = null;
if (_context != null && _context.isSingleton(name) && _context.containsBeanDefinition(name)) {
o = _context.getBean(name);
if (a.length == 2) {
String propertyName = a[1];
BeanWrapper bean = new RestrictedBeanWrapper(o);
o = bean.isReadableProperty(propertyName)
? bean.getPropertyValue(propertyName)
: null;
}
}
if (o == null) {
throw new CacheException("No such property");
}
message.setResult(serialize(o));
return message;
}

private final static Set<Class<?>> PRIMITIVES =
Sets.<Class<?>>newHashSet(Byte.class, Byte.TYPE, Short.class, Short.TYPE,
Integer.class, Integer.TYPE, Long.class, Long.TYPE,
Float.class, Float.TYPE, Double.class, Double.TYPE,
Character.class, Character.TYPE, Boolean.class,
Boolean.TYPE, String.class);
private final static Set<Class<?>> TERMINALS =
Sets.<Class<?>>newHashSet(Class.class);
/**
* Returns true if {@code clazz} is assignable to any of the classes in {@code classes}, false
* otherwise.
*/
private boolean isAssignableTo(Class<?> clazz, Class<?>... classes)
{
for (Class<?> aClass : classes) {
if (aClass.isAssignableFrom(clazz)) {
return true;
}
}
return false;
}

private Object serialize(Set<Object> prune, Queue<Map.Entry<String,Object>> queue, Object o)
{
if (o == null || PRIMITIVES.contains(o.getClass())) {
if (o == null || PRIMITIVE_TYPES.contains(o.getClass())) {
return o;
} else if (TERMINALS.contains(o.getClass())) {
} else if (isAssignableTo(o.getClass(), TERMINAL_TYPES)) {
return o.toString();
} else if (o.getClass().isEnum()) {
return o;
Expand Down Expand Up @@ -870,17 +895,15 @@ private Object serialize(Set<Object> prune, Queue<Map.Entry<String,Object>> queu
prune.add(o);

Map<String,Object> values = Maps.newHashMap();
BeanWrapper bean = new BeanWrapperImpl(o);
BeanWrapper bean = new RestrictedBeanWrapper(o);
for (PropertyDescriptor p: bean.getPropertyDescriptors()) {
if (!p.isHidden()) {
String property = p.getName();
if (bean.isReadableProperty(property)) {
try {
values.put(property, bean.getPropertyValue(property));
} catch (InvalidPropertyException | PropertyAccessException e) {
LOGGER.debug("Failed to read {} of object of class {}: {}",
property, o.getClass(), e.getMessage());
}
String property = p.getName();
if (bean.isReadableProperty(property)) {
try {
values.put(property, bean.getPropertyValue(property));
} catch (InvalidPropertyException | PropertyAccessException e) {
LOGGER.debug("Failed to read {} of object of class {}: {}",
property, o.getClass(), e.getMessage());
}
}
}
Expand Down Expand Up @@ -1098,4 +1121,76 @@ public synchronized ConfigurableEnvironment getEnvironment() {
return environment;
}
}

/**
* BeanWrapper that restricts access to certain private properties that should not be exposed.
*/
private class RestrictedBeanWrapper extends BeanWrapperImpl
{
private RestrictedBeanWrapper(Object object)
{
super(object);
}

private RestrictedBeanWrapper(Object object, String nestedPath, Object rootObject)
{
super(object, nestedPath, rootObject);
}

@Override
protected BeanWrapperImpl getBeanWrapperForPropertyPath(String propertyPath)
{
int pos = PropertyAccessorUtils.getFirstNestedPropertySeparatorIndex(propertyPath);
if (pos > -1) {
String nestedProperty = propertyPath.substring(0, pos);
if (!isReadableProperty(nestedProperty)) {
throw new NotReadablePropertyException(getRootClass(), nestedProperty);
}
}
return super.getBeanWrapperForPropertyPath(propertyPath);
}

@Override
public boolean isReadableProperty(String propertyName)
{
if (isAllowedName(propertyName)) {
PropertyDescriptor pd = getPropertyDescriptorInternal(propertyName);
if (pd == null || pd.getReadMethod() != null && !pd.isHidden() && isAllowedType(pd.getPropertyType())) {
try {
Object value = super.getPropertyValue(propertyName);
if (value == null || isAllowedType(value.getClass())) {
return true;
}
} catch (InvalidPropertyException ignored) {
}
}
}
return false;
}

private boolean isAllowedType(Class<?> clazz)
{
return !isAssignableTo(clazz, HIDDEN_TYPES);
}

private boolean isAllowedName(String propertyName)
{
String s = propertyName.toLowerCase();
return !s.contains("password") && !s.contains("username");
}

@Override
public Object getPropertyValue(String propertyName) throws BeansException
{
if (!isReadableProperty(propertyName)) {
throw new NotReadablePropertyException(getRootClass(), propertyName);
}
return super.getPropertyValue(propertyName);
}

@Override
protected BeanWrapperImpl newNestedBeanWrapper(Object object, String nestedPath) {
return new RestrictedBeanWrapper(object, nestedPath, this);
}
}
}

0 comments on commit 633ec78

Please sign in to comment.