Browse Source

+ interaction with user code uses now dedicated privileged when running under a security manager

conversation
Costin Leau 15 years ago
parent
commit
d5d3104b7b
  1. 88
      org.springframework.beans/src/main/java/org/springframework/beans/BeanWrapperImpl.java
  2. 128
      org.springframework.beans/src/main/java/org/springframework/beans/factory/support/AbstractAutowireCapableBeanFactory.java
  3. 122
      org.springframework.beans/src/main/java/org/springframework/beans/factory/support/AbstractBeanFactory.java
  4. 54
      org.springframework.beans/src/main/java/org/springframework/beans/factory/support/ConstructorResolver.java
  5. 33
      org.springframework.beans/src/main/java/org/springframework/beans/factory/support/DefaultListableBeanFactory.java
  6. 46
      org.springframework.beans/src/main/java/org/springframework/beans/factory/support/DisposableBeanAdapter.java
  7. 98
      org.springframework.beans/src/main/java/org/springframework/beans/factory/support/FactoryBeanRegistrySupport.java
  8. 33
      org.springframework.beans/src/main/java/org/springframework/beans/factory/support/SecurityContextProvider.java
  9. 22
      org.springframework.beans/src/main/java/org/springframework/beans/factory/support/SimpleInstantiationStrategy.java
  10. 57
      org.springframework.beans/src/main/java/org/springframework/beans/factory/support/SimpleSecurityContextProvider.java
  11. 223
      org.springframework.beans/src/test/java/org/springframework/beans/factory/support/security/CallbacksSecurityTest.java
  12. 48
      org.springframework.beans/src/test/java/org/springframework/beans/factory/support/security/callbacks.xml
  13. 3
      org.springframework.beans/src/test/java/org/springframework/beans/factory/support/security/policy.all
  14. 30
      org.springframework.beans/src/test/java/org/springframework/beans/factory/support/security/support/ConstructorBean.java
  15. 30
      org.springframework.beans/src/test/java/org/springframework/beans/factory/support/security/support/CustomCallbackBean.java
  16. 39
      org.springframework.beans/src/test/java/org/springframework/beans/factory/support/security/support/CustomFactoryBean.java
  17. 28
      org.springframework.beans/src/test/java/org/springframework/beans/factory/support/security/support/DestroyBean.java
  18. 36
      org.springframework.beans/src/test/java/org/springframework/beans/factory/support/security/support/FactoryBean.java
  19. 28
      org.springframework.beans/src/test/java/org/springframework/beans/factory/support/security/support/InitBean.java
  20. 30
      org.springframework.beans/src/test/java/org/springframework/beans/factory/support/security/support/PropertyBean.java
  21. 41
      org.springframework.context/src/main/java/org/springframework/context/support/ApplicationContextAwareProcessor.java

88
org.springframework.beans/src/main/java/org/springframework/beans/BeanWrapperImpl.java

@ -22,6 +22,10 @@ import java.lang.reflect.Array; @@ -22,6 +22,10 @@ import java.lang.reflect.Array;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.security.AccessControlContext;
import java.security.AccessController;
import java.security.PrivilegedActionException;
import java.security.PrivilegedExceptionAction;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
@ -31,7 +35,6 @@ import java.util.Set; @@ -31,7 +35,6 @@ import java.util.Set;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.core.GenericCollectionTypeResolver;
import org.springframework.core.MethodParameter;
import org.springframework.util.Assert;
@ -102,6 +105,9 @@ public class BeanWrapperImpl extends AbstractPropertyAccessor implements BeanWra @@ -102,6 +105,9 @@ public class BeanWrapperImpl extends AbstractPropertyAccessor implements BeanWra
*/
private Map<String, BeanWrapperImpl> nestedBeanWrappers;
/** The security context used for invoking the property methods */
private AccessControlContext acc;
/**
* Create new empty BeanWrapperImpl. Wrapped instance needs to be set afterwards.
@ -198,6 +204,16 @@ public class BeanWrapperImpl extends AbstractPropertyAccessor implements BeanWra @@ -198,6 +204,16 @@ public class BeanWrapperImpl extends AbstractPropertyAccessor implements BeanWra
setIntrospectionClass(object.getClass());
}
/**
* Set the security context used during the invocation of the wrapped instance methods.
* Can be null.
*
* @param acc
*/
public void setSecurityContext(AccessControlContext acc) {
this.acc = acc;
}
public final Object getWrappedInstance() {
return this.object;
}
@ -539,12 +555,29 @@ public class BeanWrapperImpl extends AbstractPropertyAccessor implements BeanWra @@ -539,12 +555,29 @@ public class BeanWrapperImpl extends AbstractPropertyAccessor implements BeanWra
if (pd == null || pd.getReadMethod() == null) {
throw new NotReadablePropertyException(getRootClass(), this.nestedPath + propertyName);
}
Method readMethod = pd.getReadMethod();
final Method readMethod = pd.getReadMethod();
try {
if (!Modifier.isPublic(readMethod.getDeclaringClass().getModifiers())) {
readMethod.setAccessible(true);
}
Object value = readMethod.invoke(this.object, (Object[]) null);
Object value = null;
if (System.getSecurityManager() != null) {
try {
value = AccessController.doPrivileged(new PrivilegedExceptionAction<Object>() {
public Object run() throws Exception {
return readMethod.invoke(object, (Object[]) null);
}
},acc);
} catch (PrivilegedActionException pae) {
throw pae.getException();
}
}
else {
value = readMethod.invoke(object, (Object[]) null);
}
if (tokens.keys != null) {
// apply indexes and map keys
for (int i = 0; i < tokens.keys.length; i++) {
@ -602,7 +635,8 @@ public class BeanWrapperImpl extends AbstractPropertyAccessor implements BeanWra @@ -602,7 +635,8 @@ public class BeanWrapperImpl extends AbstractPropertyAccessor implements BeanWra
throw new InvalidPropertyException(getRootClass(), this.nestedPath + propertyName,
"Getter for property '" + actualName + "' threw exception", ex);
}
catch (IllegalAccessException ex) {
catch(IllegalAccessException ex) {
throw new InvalidPropertyException(getRootClass(), this.nestedPath + propertyName,
"Illegal attempt to get property '" + actualName + "' threw exception", ex);
}
@ -614,6 +648,10 @@ public class BeanWrapperImpl extends AbstractPropertyAccessor implements BeanWra @@ -614,6 +648,10 @@ public class BeanWrapperImpl extends AbstractPropertyAccessor implements BeanWra
throw new InvalidPropertyException(getRootClass(), this.nestedPath + propertyName,
"Invalid index in property path '" + propertyName + "'", ex);
}
catch (Exception ex) {
throw new InvalidPropertyException(getRootClass(), this.nestedPath + propertyName,
"Invalid index in property path '" + propertyName + "'", ex);
}
}
@Override
@ -813,14 +851,26 @@ public class BeanWrapperImpl extends AbstractPropertyAccessor implements BeanWra @@ -813,14 +851,26 @@ public class BeanWrapperImpl extends AbstractPropertyAccessor implements BeanWra
}
else {
if (isExtractOldValueForEditor() && pd.getReadMethod() != null) {
Method readMethod = pd.getReadMethod();
final Method readMethod = pd.getReadMethod();
if (!Modifier.isPublic(readMethod.getDeclaringClass().getModifiers())) {
readMethod.setAccessible(true);
}
try {
oldValue = readMethod.invoke(this.object);
if (System.getSecurityManager() != null) {
oldValue = AccessController.doPrivileged(new PrivilegedExceptionAction<Object>() {
public Object run() throws Exception {
return readMethod.invoke(object);
}
},acc);
}
else {
oldValue = readMethod.invoke(object);
}
}
catch (Exception ex) {
if (ex instanceof PrivilegedActionException) {
ex = ((PrivilegedActionException) ex).getException();
}
if (logger.isDebugEnabled()) {
logger.debug("Could not read previous value of property '" +
this.nestedPath + propertyName + "'", ex);
@ -831,11 +881,28 @@ public class BeanWrapperImpl extends AbstractPropertyAccessor implements BeanWra @@ -831,11 +881,28 @@ public class BeanWrapperImpl extends AbstractPropertyAccessor implements BeanWra
}
pv.getOriginalPropertyValue().conversionNecessary = (valueToApply != originalValue);
}
Method writeMethod = pd.getWriteMethod();
final Method writeMethod = pd.getWriteMethod();
if (!Modifier.isPublic(writeMethod.getDeclaringClass().getModifiers())) {
writeMethod.setAccessible(true);
}
writeMethod.invoke(this.object, valueToApply);
final Object value = valueToApply;
if (System.getSecurityManager() != null) {
try {
AccessController.doPrivileged(new PrivilegedExceptionAction<Object>() {
public Object run() throws Exception {
writeMethod.invoke(object, value);
return null;
}
},acc);
} catch (PrivilegedActionException ex) {
throw ex.getException();
}
}
else {
writeMethod.invoke(object, value);
}
}
catch (InvocationTargetException ex) {
PropertyChangeEvent propertyChangeEvent =
@ -862,6 +929,11 @@ public class BeanWrapperImpl extends AbstractPropertyAccessor implements BeanWra @@ -862,6 +929,11 @@ public class BeanWrapperImpl extends AbstractPropertyAccessor implements BeanWra
new PropertyChangeEvent(this.rootObject, this.nestedPath + propertyName, oldValue, pv.getValue());
throw new MethodInvocationException(pce, ex);
}
catch (Exception ex) {
PropertyChangeEvent pce =
new PropertyChangeEvent(this.rootObject, this.nestedPath + propertyName, oldValue, pv.getValue());
throw new MethodInvocationException(pce, ex);
}
}
}

128
org.springframework.beans/src/main/java/org/springframework/beans/factory/support/AbstractAutowireCapableBeanFactory.java

@ -24,6 +24,8 @@ import java.lang.reflect.Modifier; @@ -24,6 +24,8 @@ import java.lang.reflect.Modifier;
import java.security.AccessControlContext;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.security.PrivilegedActionException;
import java.security.PrivilegedExceptionAction;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
@ -330,13 +332,27 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac @@ -330,13 +332,27 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
public Object autowire(Class beanClass, int autowireMode, boolean dependencyCheck) throws BeansException {
// Use non-singleton bean definition, to avoid registering bean as dependent bean.
RootBeanDefinition bd = new RootBeanDefinition(beanClass, autowireMode, dependencyCheck);
final RootBeanDefinition bd = new RootBeanDefinition(beanClass, autowireMode, dependencyCheck);
bd.setScope(BeanDefinition.SCOPE_PROTOTYPE);
if (bd.getResolvedAutowireMode() == AUTOWIRE_CONSTRUCTOR) {
return autowireConstructor(beanClass.getName(), bd, null, null).getWrappedInstance();
}
else {
Object bean = getInstantiationStrategy().instantiate(bd, null, this);
Object bean = null;
final BeanFactory parent = this;
if (System.getSecurityManager() != null) {
bean = AccessController.doPrivileged(new PrivilegedAction<Object>() {
public Object run() {
return getInstantiationStrategy().instantiate(bd, null, parent);
}
}, getAccessControlContext());
}
else {
bean = getInstantiationStrategy().instantiate(bd, null, parent);
}
populateBean(beanClass.getName(), bd, new BeanWrapperImpl(bean));
return bean;
}
@ -403,9 +419,6 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac @@ -403,9 +419,6 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
protected Object createBean(final String beanName, final RootBeanDefinition mbd, final Object[] args)
throws BeanCreationException {
AccessControlContext acc = AccessController.getContext();
return AccessController.doPrivileged(new PrivilegedAction<Object>() {
public Object run() {
if (logger.isDebugEnabled()) {
logger.debug("Creating instance of bean '" + beanName + "'");
}
@ -438,8 +451,6 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac @@ -438,8 +451,6 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
logger.debug("Finished creating instance of bean '" + beanName + "'");
}
return beanInstance;
}
}, acc);
}
/**
@ -904,9 +915,22 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac @@ -904,9 +915,22 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
* @param mbd the bean definition for the bean
* @return BeanWrapper for the new instance
*/
protected BeanWrapper instantiateBean(String beanName, RootBeanDefinition mbd) {
protected BeanWrapper instantiateBean(final String beanName, final RootBeanDefinition mbd) {
try {
Object beanInstance = getInstantiationStrategy().instantiate(mbd, beanName, this);
Object beanInstance = null;
final BeanFactory parent = this;
if (System.getSecurityManager() != null) {
beanInstance = AccessController.doPrivileged(new PrivilegedAction<Object>() {
public Object run() {
return getInstantiationStrategy().instantiate(mbd, beanName, parent);
}
}, getAccessControlContext());
}
else {
beanInstance = getInstantiationStrategy().instantiate(mbd, beanName, parent);
}
BeanWrapper bw = new BeanWrapperImpl(beanInstance);
initBeanWrapper(bw);
return bw;
@ -1229,6 +1253,12 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac @@ -1229,6 +1253,12 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
MutablePropertyValues mpvs = null;
List<PropertyValue> original;
if (System.getSecurityManager()!= null) {
if (bw instanceof BeanWrapperImpl) {
((BeanWrapperImpl) bw).setSecurityContext(getAccessControlContext());
}
}
if (pvs instanceof MutablePropertyValues) {
mpvs = (MutablePropertyValues) pvs;
@ -1337,19 +1367,20 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac @@ -1337,19 +1367,20 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
* @see #invokeInitMethods
* @see #applyBeanPostProcessorsAfterInitialization
*/
protected Object initializeBean(String beanName, Object bean, RootBeanDefinition mbd) {
if (bean instanceof BeanNameAware) {
((BeanNameAware) bean).setBeanName(beanName);
}
if (bean instanceof BeanClassLoaderAware) {
((BeanClassLoaderAware) bean).setBeanClassLoader(getBeanClassLoader());
protected Object initializeBean(final String beanName, final Object bean, RootBeanDefinition mbd) {
if (System.getSecurityManager() != null) {
AccessController.doPrivileged(new PrivilegedAction<Object>() {
public Object run() {
invokeAwareMethods(beanName, bean);
return null;
}
}, getAccessControlContext());
}
if (bean instanceof BeanFactoryAware) {
((BeanFactoryAware) bean).setBeanFactory(this);
else {
invokeAwareMethods(beanName, bean);
}
Object wrappedBean = bean;
if (mbd == null || !mbd.isSynthetic()) {
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
@ -1369,6 +1400,20 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac @@ -1369,6 +1400,20 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
}
return wrappedBean;
}
private void invokeAwareMethods(final String beanName, final Object bean) {
if (bean instanceof BeanNameAware) {
((BeanNameAware) bean).setBeanName(beanName);
}
if (bean instanceof BeanClassLoaderAware) {
((BeanClassLoaderAware) bean).setBeanClassLoader(getBeanClassLoader());
}
if (bean instanceof BeanFactoryAware) {
((BeanFactoryAware) bean).setBeanFactory(AbstractAutowireCapableBeanFactory.this);
}
}
/**
* Give a bean a chance to react now all its properties are set,
@ -1382,7 +1427,7 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac @@ -1382,7 +1427,7 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
* @throws Throwable if thrown by init methods or by the invocation process
* @see #invokeCustomInitMethod
*/
protected void invokeInitMethods(String beanName, Object bean, RootBeanDefinition mbd)
protected void invokeInitMethods(String beanName, final Object bean, RootBeanDefinition mbd)
throws Throwable {
boolean isInitializingBean = (bean instanceof InitializingBean);
@ -1390,7 +1435,22 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac @@ -1390,7 +1435,22 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
if (logger.isDebugEnabled()) {
logger.debug("Invoking afterPropertiesSet() on bean with name '" + beanName + "'");
}
((InitializingBean) bean).afterPropertiesSet();
if (System.getSecurityManager() != null) {
try {
AccessController.doPrivileged(new PrivilegedExceptionAction<Object>() {
public Object run() throws Exception {
((InitializingBean) bean).afterPropertiesSet();
return null;
}
},getAccessControlContext());
} catch (PrivilegedActionException pae) {
throw pae.getException();
}
}
else {
((InitializingBean) bean).afterPropertiesSet();
}
}
if (mbd != null) {
@ -1413,9 +1473,9 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac @@ -1413,9 +1473,9 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
* @param enforceInitMethod indicates whether the defined init method needs to exist
* @see #invokeInitMethods
*/
protected void invokeCustomInitMethod(String beanName, Object bean, RootBeanDefinition mbd) throws Throwable {
protected void invokeCustomInitMethod(String beanName, final Object bean, RootBeanDefinition mbd) throws Throwable {
String initMethodName = mbd.getInitMethodName();
Method initMethod = (mbd.isNonPublicAccessAllowed() ?
final Method initMethod = (mbd.isNonPublicAccessAllowed() ?
BeanUtils.findMethod(bean.getClass(), initMethodName) :
ClassUtils.getMethodIfAvailable(bean.getClass(), initMethodName));
if (initMethod == null) {
@ -1437,11 +1497,23 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac @@ -1437,11 +1497,23 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
logger.debug("Invoking init method '" + initMethodName + "' on bean with name '" + beanName + "'");
}
ReflectionUtils.makeAccessible(initMethod);
try {
initMethod.invoke(bean, (Object[]) null);
if (System.getSecurityManager() != null) {
try {
AccessController.doPrivileged(new PrivilegedExceptionAction<Object>() {
public Object run() throws Exception {
initMethod.invoke(bean, (Object[]) null);
return null;
}
}, getAccessControlContext());
}
catch (PrivilegedActionException pae) {
InvocationTargetException ex = (InvocationTargetException) pae.getException();
throw ex.getTargetException();
}
}
catch (InvocationTargetException ex) {
throw ex.getTargetException();
else {
initMethod.invoke(bean, (Object[]) null);
}
}

122
org.springframework.beans/src/main/java/org/springframework/beans/factory/support/AbstractBeanFactory.java

@ -17,6 +17,11 @@ @@ -17,6 +17,11 @@
package org.springframework.beans.factory.support;
import java.beans.PropertyEditor;
import java.security.AccessControlContext;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.security.PrivilegedActionException;
import java.security.PrivilegedExceptionAction;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
@ -151,6 +156,9 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp @@ -151,6 +156,9 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp
private final ThreadLocal<Object> prototypesCurrentlyInCreation =
new NamedThreadLocal<Object>("Prototype beans currently in creation");
/** security context used when running with a Security Manager */
private volatile SecurityContextProvider securityProvider = new SimpleSecurityContextProvider();
/**
* Create a new AbstractBeanFactory.
*/
@ -196,6 +204,16 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp @@ -196,6 +204,16 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp
return doGetBean(name, requiredType, args, false);
}
protected <T> T doGetBean(
final String name, final Class<T> requiredType, final Object[] args, final boolean typeCheckOnly)
throws BeansException {
return AccessController.doPrivileged(new PrivilegedAction<T>() {
public T run() {
return doGetBeanRaw(name, requiredType, args, typeCheckOnly);
}
});
}
/**
* Return an instance, which may be shared or independent, of the specified bean.
* @param name the name of the bean to retrieve
@ -208,7 +226,7 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp @@ -208,7 +226,7 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp
* @throws BeansException if the bean could not be created
*/
@SuppressWarnings("unchecked")
protected <T> T doGetBean(
private <T> T doGetBeanRaw(
final String name, final Class<T> requiredType, final Object[] args, boolean typeCheckOnly)
throws BeansException {
@ -409,9 +427,19 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp @@ -409,9 +427,19 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp
return false;
}
if (isFactoryBean(beanName, mbd)) {
FactoryBean factoryBean = (FactoryBean) getBean(FACTORY_BEAN_PREFIX + beanName);
return ((factoryBean instanceof SmartFactoryBean && ((SmartFactoryBean) factoryBean).isPrototype()) ||
!factoryBean.isSingleton());
final FactoryBean factoryBean = (FactoryBean) getBean(FACTORY_BEAN_PREFIX + beanName);
if (System.getSecurityManager() != null) {
return AccessController.doPrivileged(new PrivilegedAction<Boolean>() {
public Boolean run() {
return Boolean.valueOf(((factoryBean instanceof SmartFactoryBean && ((SmartFactoryBean) factoryBean).isPrototype()) ||
!factoryBean.isSingleton()));
}
}, getAccessControlContext()).booleanValue();
}
else {
return ((factoryBean instanceof SmartFactoryBean && ((SmartFactoryBean) factoryBean).isPrototype()) ||
!factoryBean.isSingleton());
}
}
else {
return false;
@ -861,7 +889,7 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp @@ -861,7 +889,7 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp
* @param mbd the merged bean definition
*/
protected void destroyBean(String beanName, Object beanInstance, RootBeanDefinition mbd) {
new DisposableBeanAdapter(beanInstance, beanName, mbd, getBeanPostProcessors()).destroy();
new DisposableBeanAdapter(beanInstance, beanName, mbd, getBeanPostProcessors(), getAccessControlContext()).destroy();
}
public void destroyScopedBean(String beanName) {
@ -1136,34 +1164,54 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp @@ -1136,34 +1164,54 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp
* @return the resolved bean class (or <code>null</code> if none)
* @throws CannotLoadBeanClassException if we failed to load the class
*/
protected Class resolveBeanClass(RootBeanDefinition mbd, String beanName, Class[] typesToMatch)
protected Class resolveBeanClass(final RootBeanDefinition mbd, String beanName, final Class[] typesToMatch)
throws CannotLoadBeanClassException {
try {
if (mbd.hasBeanClass()) {
return mbd.getBeanClass();
}
if (typesToMatch != null) {
ClassLoader tempClassLoader = getTempClassLoader();
if (tempClassLoader != null) {
if (tempClassLoader instanceof DecoratingClassLoader) {
DecoratingClassLoader dcl = (DecoratingClassLoader) tempClassLoader;
for (Class typeToMatch : typesToMatch) {
dcl.excludeClass(typeToMatch.getName());
}
if (System.getSecurityManager() != null) {
return AccessController.doPrivileged(new PrivilegedExceptionAction<Class>() {
public Class run() throws Exception {
return doResolveBeanClass(mbd, typesToMatch);
}
String className = mbd.getBeanClassName();
return (className != null ? ClassUtils.forName(className, tempClassLoader) : null);
}
}, getAccessControlContext());
}
else {
return doResolveBeanClass(mbd, typesToMatch);
}
return mbd.resolveBeanClass(getBeanClassLoader());
}
catch (PrivilegedActionException pae) {
ClassNotFoundException ex = (ClassNotFoundException) pae.getException();
throw new CannotLoadBeanClassException(mbd.getResourceDescription(), beanName, mbd.getBeanClassName(), (ClassNotFoundException) ex);
}
catch (ClassNotFoundException ex) {
throw new CannotLoadBeanClassException(mbd.getResourceDescription(), beanName, mbd.getBeanClassName(), ex);
throw new CannotLoadBeanClassException(mbd.getResourceDescription(), beanName, mbd.getBeanClassName(), (ClassNotFoundException) ex);
}
catch (LinkageError err) {
throw new CannotLoadBeanClassException(mbd.getResourceDescription(), beanName, mbd.getBeanClassName(), err);
}
}
private Class doResolveBeanClass(final RootBeanDefinition mbd, final Class[] typesToMatch)
throws ClassNotFoundException {
if (typesToMatch != null) {
ClassLoader tempClassLoader = getTempClassLoader();
if (tempClassLoader != null) {
if (tempClassLoader instanceof DecoratingClassLoader) {
DecoratingClassLoader dcl = (DecoratingClassLoader) tempClassLoader;
for (Class<?> typeToMatch : typesToMatch) {
dcl.excludeClass(typeToMatch.getName());
}
}
String className = mbd.getBeanClassName();
return (className != null ? ClassUtils.forName(className, tempClassLoader) : null);
}
}
return mbd.resolveBeanClass(getBeanClassLoader());
}
/**
* Evaluate the given String as contained in a bean definition,
@ -1363,13 +1411,14 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp @@ -1363,13 +1411,14 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp
* @see #registerDependentBean
*/
protected void registerDisposableBeanIfNecessary(String beanName, Object bean, RootBeanDefinition mbd) {
AccessControlContext acc = (System.getSecurityManager() != null ? getAccessControlContext() : null);
if (!mbd.isPrototype() && requiresDestruction(bean, mbd)) {
if (mbd.isSingleton()) {
// Register a DisposableBean implementation that performs all destruction
// work for the given bean: DestructionAwareBeanPostProcessors,
// DisposableBean interface, custom destroy method.
registerDisposableBean(beanName,
new DisposableBeanAdapter(bean, beanName, mbd, getBeanPostProcessors()));
new DisposableBeanAdapter(bean, beanName, mbd, getBeanPostProcessors(), acc));
}
else {
// A bean with a custom scope...
@ -1378,11 +1427,41 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp @@ -1378,11 +1427,41 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp
throw new IllegalStateException("No Scope registered for scope '" + mbd.getScope() + "'");
}
scope.registerDestructionCallback(beanName,
new DisposableBeanAdapter(bean, beanName, mbd, getBeanPostProcessors()));
new DisposableBeanAdapter(bean, beanName, mbd, getBeanPostProcessors(), acc));
}
}
}
/**
* {@inheritDoc}
*
* Delegate the creation of the security context to {@link #getSecurityContextProvider()}.
*/
@Override
protected AccessControlContext getAccessControlContext() {
SecurityContextProvider provider = getSecurityContextProvider();
return (provider != null ? provider.getAccessControlContext(): null);
}
/**
* Return the security context provider for this bean factory.
*
* @return
*/
public SecurityContextProvider getSecurityContextProvider() {
return securityProvider;
}
/**
* Set the security context provider for this bean factory. If a security manager
* is set, interaction with the user code will be executed using the privileged
* of the provided security context.
*
* @param securityProvider
*/
public void setSecurityContextProvider(SecurityContextProvider securityProvider) {
this.securityProvider = securityProvider;
}
//---------------------------------------------------------------------
// Abstract methods to be implemented by subclasses
@ -1442,5 +1521,4 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp @@ -1442,5 +1521,4 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp
*/
protected abstract Object createBean(String beanName, RootBeanDefinition mbd, Object[] args)
throws BeanCreationException;
}

54
org.springframework.beans/src/main/java/org/springframework/beans/factory/support/ConstructorResolver.java

@ -21,6 +21,9 @@ import java.lang.reflect.Constructor; @@ -21,6 +21,9 @@ import java.lang.reflect.Constructor;
import java.lang.reflect.Member;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.security.AccessControlContext;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
@ -99,7 +102,7 @@ class ConstructorResolver { @@ -99,7 +102,7 @@ class ConstructorResolver {
* @return a BeanWrapper for the new instance
*/
public BeanWrapper autowireConstructor(
String beanName, RootBeanDefinition mbd, Constructor[] chosenCtors, Object[] explicitArgs) {
final String beanName, final RootBeanDefinition mbd, Constructor[] chosenCtors, final Object[] explicitArgs) {
BeanWrapperImpl bw = new BeanWrapperImpl();
this.beanFactory.initBeanWrapper(bw);
@ -256,8 +259,25 @@ class ConstructorResolver { @@ -256,8 +259,25 @@ class ConstructorResolver {
}
try {
Object beanInstance = this.beanFactory.getInstantiationStrategy().instantiate(
mbd, beanName, this.beanFactory, constructorToUse, argsToUse);
Object beanInstance = null;
if (System.getSecurityManager() != null) {
final Constructor ctorToUse = constructorToUse;
final Object[] argumentsToUse = argsToUse;
beanInstance = AccessController.doPrivileged(new PrivilegedAction<Object>() {
public Object run() {
return beanFactory.getInstantiationStrategy().instantiate(
mbd, beanName, beanFactory, ctorToUse, argumentsToUse);
}
}, beanFactory.getAccessControlContext());
}
else {
beanInstance = beanFactory.getInstantiationStrategy().instantiate(
mbd, beanName, beanFactory, constructorToUse, argsToUse);
}
bw.setWrappedInstance(beanInstance);
return bw;
}
@ -311,7 +331,7 @@ class ConstructorResolver { @@ -311,7 +331,7 @@ class ConstructorResolver {
* method, or <code>null</code> if none (-> use constructor argument values from bean definition)
* @return a BeanWrapper for the new instance
*/
public BeanWrapper instantiateUsingFactoryMethod(String beanName, RootBeanDefinition mbd, Object[] explicitArgs) {
public BeanWrapper instantiateUsingFactoryMethod(final String beanName, final RootBeanDefinition mbd, final Object[] explicitArgs) {
BeanWrapperImpl bw = new BeanWrapperImpl();
this.beanFactory.initBeanWrapper(bw);
@ -491,8 +511,27 @@ class ConstructorResolver { @@ -491,8 +511,27 @@ class ConstructorResolver {
}
try {
Object beanInstance = this.beanFactory.getInstantiationStrategy().instantiate(
mbd, beanName, this.beanFactory, factoryBean, factoryMethodToUse, argsToUse);
Object beanInstance = null;
if (System.getSecurityManager() != null) {
final Object fb = factoryBean;
final Method factoryMethod = factoryMethodToUse;
final Object[] args = argsToUse;
beanInstance = AccessController.doPrivileged(new PrivilegedAction<Object>() {
public Object run() {
return beanFactory.getInstantiationStrategy().instantiate(
mbd, beanName, beanFactory, fb, factoryMethod, args);
}
}, beanFactory.getAccessControlContext());
}
else {
beanInstance = beanFactory.getInstantiationStrategy().instantiate(
mbd, beanName, beanFactory, factoryBean, factoryMethodToUse, argsToUse);
}
if (beanInstance == null) {
return null;
}
@ -808,5 +847,4 @@ class ConstructorResolver { @@ -808,5 +847,4 @@ class ConstructorResolver {
}
}
}
}
}

33
org.springframework.beans/src/main/java/org/springframework/beans/factory/support/DefaultListableBeanFactory.java

@ -21,6 +21,8 @@ import java.io.Serializable; @@ -21,6 +21,8 @@ import java.io.Serializable;
import java.lang.annotation.Annotation;
import java.lang.ref.Reference;
import java.lang.ref.WeakReference;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
@ -179,10 +181,21 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto @@ -179,10 +181,21 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
* when deciding whether a bean definition should be considered as a
* candidate for autowiring.
*/
public void setAutowireCandidateResolver(AutowireCandidateResolver autowireCandidateResolver) {
public void setAutowireCandidateResolver(final AutowireCandidateResolver autowireCandidateResolver) {
Assert.notNull(autowireCandidateResolver, "AutowireCandidateResolver must not be null");
if (autowireCandidateResolver instanceof BeanFactoryAware) {
((BeanFactoryAware) autowireCandidateResolver).setBeanFactory(this);
if (System.getSecurityManager() != null) {
final BeanFactory target = this;
AccessController.doPrivileged(new PrivilegedAction<Object>() {
public Object run() {
((BeanFactoryAware) autowireCandidateResolver).setBeanFactory(target);
return null;
}
}, getAccessControlContext());
}
else {
((BeanFactoryAware) autowireCandidateResolver).setBeanFactory(this);
}
}
this.autowireCandidateResolver = autowireCandidateResolver;
}
@ -493,8 +506,20 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto @@ -493,8 +506,20 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
if (isFactoryBean(beanName)) {
FactoryBean factory = (FactoryBean) getBean(FACTORY_BEAN_PREFIX + beanName);
if (factory instanceof SmartFactoryBean && ((SmartFactoryBean) factory).isEagerInit()) {
final FactoryBean factory = (FactoryBean) getBean(FACTORY_BEAN_PREFIX + beanName);
boolean isEagerInit = false;
if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
isEagerInit = AccessController.doPrivileged(new PrivilegedAction<Boolean>() {
public Boolean run() {
return Boolean.valueOf(((SmartFactoryBean) factory).isEagerInit());
}
}, getAccessControlContext()).booleanValue();
}
else {
isEagerInit = factory instanceof SmartFactoryBean && ((SmartFactoryBean) factory).isEagerInit();
}
if (isEagerInit) {
getBean(beanName);
}
}

46
org.springframework.beans/src/main/java/org/springframework/beans/factory/support/DisposableBeanAdapter.java

@ -19,6 +19,10 @@ package org.springframework.beans.factory.support; @@ -19,6 +19,10 @@ package org.springframework.beans.factory.support;
import java.io.Serializable;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.security.AccessControlContext;
import java.security.AccessController;
import java.security.PrivilegedActionException;
import java.security.PrivilegedExceptionAction;
import java.util.ArrayList;
import java.util.List;
@ -66,6 +70,7 @@ class DisposableBeanAdapter implements DisposableBean, Runnable, Serializable { @@ -66,6 +70,7 @@ class DisposableBeanAdapter implements DisposableBean, Runnable, Serializable {
private List<DestructionAwareBeanPostProcessor> beanPostProcessors;
private final AccessControlContext acc;
/**
* Create a new DisposableBeanAdapter for the given bean.
@ -76,7 +81,7 @@ class DisposableBeanAdapter implements DisposableBean, Runnable, Serializable { @@ -76,7 +81,7 @@ class DisposableBeanAdapter implements DisposableBean, Runnable, Serializable {
* (potentially DestructionAwareBeanPostProcessor), if any
*/
public DisposableBeanAdapter(Object bean, String beanName, RootBeanDefinition beanDefinition,
List<BeanPostProcessor> postProcessors) {
List<BeanPostProcessor> postProcessors, AccessControlContext acc) {
Assert.notNull(bean, "Bean must not be null");
this.bean = bean;
@ -84,6 +89,8 @@ class DisposableBeanAdapter implements DisposableBean, Runnable, Serializable { @@ -84,6 +89,8 @@ class DisposableBeanAdapter implements DisposableBean, Runnable, Serializable {
this.invokeDisposableBean =
(this.bean instanceof DisposableBean && !beanDefinition.isExternallyManagedDestroyMethod("destroy"));
this.nonPublicAccessAllowed = beanDefinition.isNonPublicAccessAllowed();
this.acc = acc;
String destroyMethodName = beanDefinition.getDestroyMethodName();
if (destroyMethodName != null && !(this.invokeDisposableBean && "destroy".equals(destroyMethodName)) &&
!beanDefinition.isExternallyManagedDestroyMethod(destroyMethodName)) {
@ -131,6 +138,7 @@ class DisposableBeanAdapter implements DisposableBean, Runnable, Serializable { @@ -131,6 +138,7 @@ class DisposableBeanAdapter implements DisposableBean, Runnable, Serializable {
this.nonPublicAccessAllowed = nonPublicAccessAllowed;
this.destroyMethodName = destroyMethodName;
this.beanPostProcessors = postProcessors;
this.acc = null;
}
@ -169,7 +177,18 @@ class DisposableBeanAdapter implements DisposableBean, Runnable, Serializable { @@ -169,7 +177,18 @@ class DisposableBeanAdapter implements DisposableBean, Runnable, Serializable {
logger.debug("Invoking destroy() on bean with name '" + this.beanName + "'");
}
try {
((DisposableBean) this.bean).destroy();
if (System.getSecurityManager() != null) {
AccessController.doPrivileged(new PrivilegedExceptionAction<Object>() {
public Object run() throws Exception {
((DisposableBean) bean).destroy();
return null;
}
}, acc);
}
else {
((DisposableBean) bean).destroy();
}
}
catch (Throwable ex) {
String msg = "Invocation of destroy method failed on bean with name '" + this.beanName + "'";
@ -199,9 +218,9 @@ class DisposableBeanAdapter implements DisposableBean, Runnable, Serializable { @@ -199,9 +218,9 @@ class DisposableBeanAdapter implements DisposableBean, Runnable, Serializable {
* for a method with a single boolean argument (passing in "true",
* assuming a "force" parameter), else logging an error.
*/
private void invokeCustomDestroyMethod(Method destroyMethod) {
private void invokeCustomDestroyMethod(final Method destroyMethod) {
Class[] paramTypes = destroyMethod.getParameterTypes();
Object[] args = new Object[paramTypes.length];
final Object[] args = new Object[paramTypes.length];
if (paramTypes.length == 1) {
args[0] = Boolean.TRUE;
}
@ -211,9 +230,22 @@ class DisposableBeanAdapter implements DisposableBean, Runnable, Serializable { @@ -211,9 +230,22 @@ class DisposableBeanAdapter implements DisposableBean, Runnable, Serializable {
}
ReflectionUtils.makeAccessible(destroyMethod);
try {
destroyMethod.invoke(this.bean, args);
}
catch (InvocationTargetException ex) {
if (System.getSecurityManager() != null) {
try {
AccessController.doPrivileged(new PrivilegedExceptionAction<Object>() {
public Object run() throws Exception {
destroyMethod.invoke(bean, args);
return null;
}
}, acc);
} catch (PrivilegedActionException pax) {
throw (InvocationTargetException) pax.getException();
}
}
else {
destroyMethod.invoke(bean, args);
}
} catch (InvocationTargetException ex) {
String msg = "Invocation of destroy method '" + this.destroyMethodName +
"' failed on bean with name '" + this.beanName + "'";
if (logger.isDebugEnabled()) {

98
org.springframework.beans/src/main/java/org/springframework/beans/factory/support/FactoryBeanRegistrySupport.java

@ -19,6 +19,8 @@ package org.springframework.beans.factory.support; @@ -19,6 +19,8 @@ package org.springframework.beans.factory.support;
import java.security.AccessControlContext;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.security.PrivilegedActionException;
import java.security.PrivilegedExceptionAction;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
@ -50,9 +52,18 @@ public abstract class FactoryBeanRegistrySupport extends DefaultSingletonBeanReg @@ -50,9 +52,18 @@ public abstract class FactoryBeanRegistrySupport extends DefaultSingletonBeanReg
* @return the FactoryBean's object type,
* or <code>null</code> if the type cannot be determined yet
*/
protected Class getTypeForFactoryBean(FactoryBean factoryBean) {
protected Class getTypeForFactoryBean(final FactoryBean factoryBean) {
try {
return factoryBean.getObjectType();
if (System.getSecurityManager() != null) {
return AccessController.doPrivileged(new PrivilegedAction<Class>() {
public Class run() {
return factoryBean.getObjectType();
}
}, getAccessControlContext());
}
else {
return factoryBean.getObjectType();
}
}
catch (Throwable ex) {
// Thrown from the FactoryBean's getObjectType implementation.
@ -112,40 +123,51 @@ public abstract class FactoryBeanRegistrySupport extends DefaultSingletonBeanReg @@ -112,40 +123,51 @@ public abstract class FactoryBeanRegistrySupport extends DefaultSingletonBeanReg
final FactoryBean factory, final String beanName, final boolean shouldPostProcess)
throws BeanCreationException {
AccessControlContext acc = AccessController.getContext();
return AccessController.doPrivileged(new PrivilegedAction<Object>() {
public Object run() {
Object object;
Object object;
try {
if (System.getSecurityManager() != null) {
AccessControlContext acc = getAccessControlContext();
try {
object = factory.getObject();
}
catch (FactoryBeanNotInitializedException ex) {
throw new BeanCurrentlyInCreationException(beanName, ex.toString());
}
catch (Throwable ex) {
throw new BeanCreationException(beanName, "FactoryBean threw exception on object creation", ex);
}
// Do not accept a null value for a FactoryBean that's not fully
// initialized yet: Many FactoryBeans just return null then.
if (object == null && isSingletonCurrentlyInCreation(beanName)) {
throw new BeanCurrentlyInCreationException(
beanName, "FactoryBean which is currently in creation returned null from getObject");
object = AccessController.doPrivileged(new PrivilegedExceptionAction<Object>() {
public Object run() throws Exception {
return factory.getObject();
}
}, acc);
} catch (PrivilegedActionException pae) {
throw pae.getException();
}
}
else {
object = factory.getObject();
}
}
catch (FactoryBeanNotInitializedException ex) {
throw new BeanCurrentlyInCreationException(beanName, ex.toString());
}
catch (Throwable ex) {
throw new BeanCreationException(beanName, "FactoryBean threw exception on object creation", ex);
}
if (object != null && shouldPostProcess) {
try {
object = postProcessObjectFromFactoryBean(object, beanName);
}
catch (Throwable ex) {
throw new BeanCreationException(beanName, "Post-processing of the FactoryBean's object failed", ex);
}
}
// Do not accept a null value for a FactoryBean that's not fully
// initialized yet: Many FactoryBeans just return null then.
if (object == null && isSingletonCurrentlyInCreation(beanName)) {
throw new BeanCurrentlyInCreationException(
beanName, "FactoryBean which is currently in creation returned null from getObject");
}
return object;
if (object != null && shouldPostProcess) {
try {
object = postProcessObjectFromFactoryBean(object, beanName);
}
catch (Throwable ex) {
throw new BeanCreationException(beanName, "Post-processing of the FactoryBean's object failed", ex);
}
}, acc);
}
return object;
}
/**
@ -185,5 +207,15 @@ public abstract class FactoryBeanRegistrySupport extends DefaultSingletonBeanReg @@ -185,5 +207,15 @@ public abstract class FactoryBeanRegistrySupport extends DefaultSingletonBeanReg
super.removeSingleton(beanName);
this.factoryBeanObjectCache.remove(beanName);
}
}
/**
* Returns the security context for this bean factory. If a security manager
* is set, interaction with the user code will be executed using the privileged
* of the security context returned by this method.
*
* @return
*/
protected AccessControlContext getAccessControlContext() {
return AccessController.getContext();
}
}

33
org.springframework.beans/src/main/java/org/springframework/beans/factory/support/SecurityContextProvider.java

@ -0,0 +1,33 @@ @@ -0,0 +1,33 @@
/*
* Copyright 2006-2009 the original author or authors.
*
* 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.springframework.beans.factory.support;
import java.security.AccessControlContext;
/**
* Provider of the security context of the code running inside the bean factory.
*
* @author Costin Leau
*/
public interface SecurityContextProvider {
/**
* Provides a security access control context relevant to a bean factory.
*
* @return bean factory security control context
*/
AccessControlContext getAccessControlContext();
}

22
org.springframework.beans/src/main/java/org/springframework/beans/factory/support/SimpleInstantiationStrategy.java

@ -19,6 +19,9 @@ package org.springframework.beans.factory.support; @@ -19,6 +19,9 @@ package org.springframework.beans.factory.support;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.security.PrivilegedExceptionAction;
import org.springframework.beans.BeanInstantiationException;
import org.springframework.beans.BeanUtils;
@ -46,12 +49,17 @@ public class SimpleInstantiationStrategy implements InstantiationStrategy { @@ -46,12 +49,17 @@ public class SimpleInstantiationStrategy implements InstantiationStrategy {
if (beanDefinition.getMethodOverrides().isEmpty()) {
Constructor constructorToUse = (Constructor) beanDefinition.resolvedConstructorOrFactoryMethod;
if (constructorToUse == null) {
Class clazz = beanDefinition.getBeanClass();
final Class clazz = beanDefinition.getBeanClass();
if (clazz.isInterface()) {
throw new BeanInstantiationException(clazz, "Specified class is an interface");
}
try {
constructorToUse = clazz.getDeclaredConstructor((Class[]) null);
constructorToUse = AccessController.doPrivileged(new PrivilegedExceptionAction<Constructor>() {
public Constructor run() throws Exception {
return clazz.getDeclaredConstructor((Class[]) null);
}
});
beanDefinition.resolvedConstructorOrFactoryMethod = constructorToUse;
}
catch (Exception ex) {
@ -107,11 +115,17 @@ public class SimpleInstantiationStrategy implements InstantiationStrategy { @@ -107,11 +115,17 @@ public class SimpleInstantiationStrategy implements InstantiationStrategy {
public Object instantiate(
RootBeanDefinition beanDefinition, String beanName, BeanFactory owner,
Object factoryBean, Method factoryMethod, Object[] args) {
Object factoryBean, final Method factoryMethod, Object[] args) {
try {
// It's a static method if the target is null.
ReflectionUtils.makeAccessible(factoryMethod);
AccessController.doPrivileged(new PrivilegedAction<Object>() {
public Object run() {
ReflectionUtils.makeAccessible(factoryMethod);
return null;
}
});
return factoryMethod.invoke(factoryBean, args);
}
catch (IllegalArgumentException ex) {

57
org.springframework.beans/src/main/java/org/springframework/beans/factory/support/SimpleSecurityContextProvider.java

@ -0,0 +1,57 @@ @@ -0,0 +1,57 @@
/*
* Copyright 2006-2009 the original author or authors.
*
* 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.springframework.beans.factory.support;
import java.security.AccessControlContext;
import java.security.AccessController;
/**
* Simple #SecurityContextProvider implementation.
*
* @author Costin Leau
*/
public class SimpleSecurityContextProvider implements SecurityContextProvider {
private final AccessControlContext acc;
/**
* Constructs a new <code>SimpleSecurityContextProvider</code> instance.
*
* The security context will be retrieved on each call from the current
* thread.
*/
public SimpleSecurityContextProvider() {
this(null);
}
/**
* Constructs a new <code>SimpleSecurityContextProvider</code> instance.
*
* If the given control context is null, the security context will be
* retrieved on each call from the current thread.
*
* @see AccessController#getContext()
* @param acc
* access control context (can be null)
*/
public SimpleSecurityContextProvider(AccessControlContext acc) {
this.acc = acc;
}
public AccessControlContext getAccessControlContext() {
return (acc == null ? AccessController.getContext() : acc);
}
}

223
org.springframework.beans/src/test/java/org/springframework/beans/factory/support/security/CallbacksSecurityTest.java

@ -0,0 +1,223 @@ @@ -0,0 +1,223 @@
/*
* Copyright 2006-2009 the original author or authors.
*
* 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.springframework.beans.factory.support.security;
import java.lang.reflect.Method;
import java.net.URL;
import java.security.AccessControlContext;
import java.security.AccessController;
import java.security.Permissions;
import java.security.Policy;
import java.security.PrivilegedExceptionAction;
import java.security.ProtectionDomain;
import java.util.PropertyPermission;
import junit.framework.TestCase;
import org.springframework.beans.factory.BeanCreationException;
import org.springframework.beans.factory.support.AbstractBeanFactory;
import org.springframework.beans.factory.support.SecurityContextProvider;
import org.springframework.beans.factory.support.security.support.ConstructorBean;
import org.springframework.beans.factory.support.security.support.CustomCallbackBean;
import org.springframework.beans.factory.xml.XmlBeanFactory;
import org.springframework.core.io.DefaultResourceLoader;
import org.springframework.core.io.Resource;
/**
* @author Costin Leau
*/
public class CallbacksSecurityTest extends TestCase {
private XmlBeanFactory beanFactory;
private SecurityContextProvider provider;
public CallbacksSecurityTest() {
// setup security
if (System.getSecurityManager() == null) {
Policy policy = Policy.getPolicy();
URL policyURL = getClass().getResource("/org/springframework/beans/factory/support/security/policy.all");
System.setProperty("java.security.policy", policyURL.toString());
System.setProperty("policy.allowSystemProperty", "true");
policy.refresh();
System.setSecurityManager(new SecurityManager());
}
}
@Override
protected void setUp() throws Exception {
final ProtectionDomain empty = new ProtectionDomain(null, new Permissions());
provider = new SecurityContextProvider() {
private final AccessControlContext acc = new AccessControlContext(new ProtectionDomain[] { empty });
public AccessControlContext getAccessControlContext() {
return acc;
}
};
DefaultResourceLoader drl = new DefaultResourceLoader();
Resource config = drl.getResource("/org/springframework/beans/factory/support/security/callbacks.xml");
beanFactory = new XmlBeanFactory(config);
beanFactory.setSecurityContextProvider(provider);
}
public void testSecuritySanity() throws Exception {
AccessControlContext acc = provider.getAccessControlContext();
try {
acc.checkPermission(new PropertyPermission("*", "read"));
fail("Acc should not have any permissions");
} catch (SecurityException se) {
// expected
}
final CustomCallbackBean bean = new CustomCallbackBean();
final Method method = bean.getClass().getMethod("destroy", null);
method.setAccessible(true);
try {
AccessController.doPrivileged(new PrivilegedExceptionAction() {
public Object run() throws Exception {
method.invoke(bean, null);
return null;
}
}, acc);
fail("expected security exception");
} catch (Exception ex) {
}
final Class<ConstructorBean> cl = ConstructorBean.class;
try {
AccessController.doPrivileged(new PrivilegedExceptionAction<Object>() {
public Object run() throws Exception {
return cl.newInstance();
}
}, acc);
fail("expected security exception");
} catch (Exception ex) {
}
}
public void testSpringInitBean() throws Exception {
try {
beanFactory.getBean("spring-init");
fail("expected security exception");
} catch (BeanCreationException ex) {
assertTrue(ex.getCause() instanceof SecurityException);
}
}
public void testCustomInitBean() throws Exception {
try {
beanFactory.getBean("custom-init");
fail("expected security exception");
} catch (BeanCreationException ex) {
assertTrue(ex.getCause() instanceof SecurityException);
}
}
public void testSpringDestroyBean() throws Exception {
beanFactory.getBean("spring-destroy");
beanFactory.destroySingletons();
assertNull(System.getProperty("security.destroy"));
}
public void testCustomDestroyBean() throws Exception {
beanFactory.getBean("custom-destroy");
beanFactory.destroySingletons();
assertNull(System.getProperty("security.destroy"));
}
public void testCustomFactoryObject() throws Exception {
try {
beanFactory.getBean("spring-factory");
fail("expected security exception");
} catch (BeanCreationException ex) {
assertTrue(ex.getCause() instanceof SecurityException);
}
}
public void testCustomFactoryType() throws Exception {
assertNull(beanFactory.getType("spring-factory"));
assertNull(System.getProperty("factory.object.type"));
}
public void testCustomStaticFactoryMethod() throws Exception {
try {
beanFactory.getBean("custom-static-factory-method");
fail("expected security exception");
} catch (BeanCreationException ex) {
assertTrue(ex.getMostSpecificCause() instanceof SecurityException);
}
}
public void testCustomInstanceFactoryMethod() throws Exception {
try {
beanFactory.getBean("custom-factory-method");
fail("expected security exception");
} catch (BeanCreationException ex) {
assertTrue(ex.getMostSpecificCause() instanceof SecurityException);
}
}
public void testTrustedFactoryMethod() throws Exception {
try {
beanFactory.getBean("trusted-factory-method");
fail("expected security exception");
} catch (BeanCreationException ex) {
assertTrue(ex.getMostSpecificCause() instanceof SecurityException);
}
}
public void testConstructor() throws Exception {
try {
beanFactory.getBean("constructor");
fail("expected security exception");
} catch (BeanCreationException ex) {
// expected
assertTrue(ex.getMostSpecificCause() instanceof SecurityException);
}
}
public void testContainerPriviledges() throws Exception {
AccessControlContext acc = provider.getAccessControlContext();
AccessController.doPrivileged(new PrivilegedExceptionAction() {
public Object run() throws Exception {
beanFactory.getBean("working-factory-method");
beanFactory.getBean("container-execution");
return null;
}
}, acc);
}
public void testPropertyInjection() throws Exception {
try {
beanFactory.getBean("property-injection");
fail("expected security exception");
} catch (BeanCreationException ex) {
assertTrue(ex.getMessage().contains("security"));
}
beanFactory.getBean("working-property-injection");
}
}

48
org.springframework.beans/src/test/java/org/springframework/beans/factory/support/security/callbacks.xml

@ -0,0 +1,48 @@ @@ -0,0 +1,48 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"
default-lazy-init="true">
<bean name="spring-init" class="org.springframework.beans.factory.support.security.support.InitBean"/>
<bean name="spring-destroy" class="org.springframework.beans.factory.support.security.support.DestroyBean"/>
<bean name="custom-init" class="org.springframework.beans.factory.support.security.support.CustomCallbackBean"
init-method="init"/>
<bean name="custom-destroy" class="org.springframework.beans.factory.support.security.support.CustomCallbackBean"
destroy-method="destroy"/>
<bean name="spring-factory" class="org.springframework.beans.factory.support.security.support.CustomFactoryBean"/>
<bean name="custom-static-factory-method" class="org.springframework.beans.factory.support.security.support.FactoryBean" factory-method="makeStaticInstance"/>
<bean name="factory-bean" class="org.springframework.beans.factory.support.security.support.FactoryBean"/>
<bean name="custom-factory-method" factory-bean="factory-bean" factory-method="makeInstance"/>
<bean name="trusted-factory-method" class="java.lang.System" factory-method="getProperties"/>
<bean name="constructor" class="org.springframework.beans.factory.support.security.support.ConstructorBean"/>
<bean name="working-factory-method" class="org.springframework.beans.factory.support.security.support.FactoryBean" factory-method="protectedStaticInstance"/>
<bean name="container-execution" class="org.springframework.beans.factory.support.security.support.ConstructorBean">
<constructor-arg ref="working-factory-method"/>
</bean>
<bean name="property-injection" class="org.springframework.beans.factory.support.security.support.PropertyBean">
<property name="securityProperty" value="value"/>
</bean>
<bean name="working-property-injection" class="org.springframework.beans.factory.support.security.support.PropertyBean">
<property name="property">
<array>
<ref bean="working-factory-method"/>
</array>
</property>
</bean>
</beans>

3
org.springframework.beans/src/test/java/org/springframework/beans/factory/support/security/policy.all

@ -0,0 +1,3 @@ @@ -0,0 +1,3 @@
grant {
permission java.security.AllPermission;
};

30
org.springframework.beans/src/test/java/org/springframework/beans/factory/support/security/support/ConstructorBean.java

@ -0,0 +1,30 @@ @@ -0,0 +1,30 @@
/*
* Copyright 2006-2009 the original author or authors.
*
* 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.springframework.beans.factory.support.security.support;
/**
* @author Costin Leau
*/
public class ConstructorBean {
public ConstructorBean() {
System.getProperties();
}
public ConstructorBean(Object obj) {
System.out.println("Received object " + obj);
}
}

30
org.springframework.beans/src/test/java/org/springframework/beans/factory/support/security/support/CustomCallbackBean.java

@ -0,0 +1,30 @@ @@ -0,0 +1,30 @@
/*
* Copyright 2006-2009 the original author or authors.
*
* 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.springframework.beans.factory.support.security.support;
/**
* @author Costin Leau
*/
public class CustomCallbackBean {
public void init() {
System.getProperties();
}
public void destroy() {
System.setProperty("security.destroy", "true");
}
}

39
org.springframework.beans/src/test/java/org/springframework/beans/factory/support/security/support/CustomFactoryBean.java

@ -0,0 +1,39 @@ @@ -0,0 +1,39 @@
/*
* Copyright 2006-2009 the original author or authors.
*
* 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.springframework.beans.factory.support.security.support;
import java.util.Properties;
import org.springframework.beans.factory.FactoryBean;
/**
* @author Costin Leau
*/
public class CustomFactoryBean implements FactoryBean<Object> {
public Object getObject() throws Exception {
return System.getProperties();
}
public Class getObjectType() {
System.setProperty("factory.object.type", "true");
return Properties.class;
}
public boolean isSingleton() {
return true;
}
}

28
org.springframework.beans/src/test/java/org/springframework/beans/factory/support/security/support/DestroyBean.java

@ -0,0 +1,28 @@ @@ -0,0 +1,28 @@
/*
* Copyright 2006-2009 the original author or authors.
*
* 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.springframework.beans.factory.support.security.support;
import org.springframework.beans.factory.DisposableBean;
/**
* @author Costin Leau
*/
public class DestroyBean implements DisposableBean {
public void destroy() throws Exception {
System.setProperty("security.destroy", "true");
}
}

36
org.springframework.beans/src/test/java/org/springframework/beans/factory/support/security/support/FactoryBean.java

@ -0,0 +1,36 @@ @@ -0,0 +1,36 @@
/*
* Copyright 2006-2009 the original author or authors.
*
* 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.springframework.beans.factory.support.security.support;
/**
* @author Costin Leau
*/
public class FactoryBean {
public static Object makeStaticInstance() {
System.getProperties();
return new Object();
}
protected static Object protectedStaticInstance() {
return "protectedStaticInstance";
}
public Object makeInstance() {
System.getProperties();
return new Object();
}
}

28
org.springframework.beans/src/test/java/org/springframework/beans/factory/support/security/support/InitBean.java

@ -0,0 +1,28 @@ @@ -0,0 +1,28 @@
/*
* Copyright 2006-2009 the original author or authors.
*
* 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.springframework.beans.factory.support.security.support;
import org.springframework.beans.factory.InitializingBean;
/**
* @author Costin Leau
*/
public class InitBean implements InitializingBean {
public void afterPropertiesSet() throws Exception {
System.getProperties();
}
}

30
org.springframework.beans/src/test/java/org/springframework/beans/factory/support/security/support/PropertyBean.java

@ -0,0 +1,30 @@ @@ -0,0 +1,30 @@
/*
* Copyright 2006-2009 the original author or authors.
*
* 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.springframework.beans.factory.support.security.support;
/**
* @author Costin Leau
*/
public class PropertyBean {
public void setSecurityProperty(Object property) {
System.getProperties();
}
public void setProperty(Object property) {
}
}

41
org.springframework.context/src/main/java/org/springframework/context/support/ApplicationContextAwareProcessor.java

@ -16,11 +16,18 @@ @@ -16,11 +16,18 @@
package org.springframework.context.support;
import java.security.AccessControlContext;
import java.security.AccessController;
import java.security.PrivilegedAction;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.AbstractBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ApplicationEventPublisherAware;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.MessageSourceAware;
import org.springframework.context.ResourceLoaderAware;
@ -56,7 +63,35 @@ class ApplicationContextAwareProcessor implements BeanPostProcessor { @@ -56,7 +63,35 @@ class ApplicationContextAwareProcessor implements BeanPostProcessor {
}
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
public Object postProcessBeforeInitialization(final Object bean, String beanName) throws BeansException {
AccessControlContext acc = null;
if (System.getSecurityManager() != null) {
if (applicationContext instanceof ConfigurableApplicationContext) {
ConfigurableListableBeanFactory factory = ((ConfigurableApplicationContext) applicationContext).getBeanFactory();
if (factory instanceof AbstractBeanFactory) {
acc = ((AbstractBeanFactory) factory).getSecurityContextProvider().getAccessControlContext();
}
}
// optimize - check the bean class before creating the inner class + native call
if (bean instanceof ResourceLoaderAware || bean instanceof ApplicationEventPublisherAware
|| bean instanceof MessageSourceAware || bean instanceof ApplicationContextAware) {
AccessController.doPrivileged(new PrivilegedAction<Object>() {
public Object run() {
doProcess(bean);
return null;
}
}, acc);
}
}
else {
doProcess(bean);
}
return bean;
}
private void doProcess(Object bean) {
if (bean instanceof ResourceLoaderAware) {
((ResourceLoaderAware) bean).setResourceLoader(this.applicationContext);
}
@ -69,11 +104,9 @@ class ApplicationContextAwareProcessor implements BeanPostProcessor { @@ -69,11 +104,9 @@ class ApplicationContextAwareProcessor implements BeanPostProcessor {
if (bean instanceof ApplicationContextAware) {
((ApplicationContextAware) bean).setApplicationContext(this.applicationContext);
}
return bean;
}
public Object postProcessAfterInitialization(Object bean, String name) {
return bean;
}
}
}
Loading…
Cancel
Save