+ added fine grained privileged blocks to preserve the caller security stack when invoking the callee
This commit is contained in:
parent
81eb11486d
commit
af8af8c633
|
|
@ -24,6 +24,7 @@ import java.lang.reflect.Method;
|
||||||
import java.lang.reflect.Modifier;
|
import java.lang.reflect.Modifier;
|
||||||
import java.security.AccessControlContext;
|
import java.security.AccessControlContext;
|
||||||
import java.security.AccessController;
|
import java.security.AccessController;
|
||||||
|
import java.security.PrivilegedAction;
|
||||||
import java.security.PrivilegedActionException;
|
import java.security.PrivilegedActionException;
|
||||||
import java.security.PrivilegedExceptionAction;
|
import java.security.PrivilegedExceptionAction;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
|
@ -557,8 +558,18 @@ public class BeanWrapperImpl extends AbstractPropertyAccessor implements BeanWra
|
||||||
}
|
}
|
||||||
final Method readMethod = pd.getReadMethod();
|
final Method readMethod = pd.getReadMethod();
|
||||||
try {
|
try {
|
||||||
if (!Modifier.isPublic(readMethod.getDeclaringClass().getModifiers())) {
|
if (!Modifier.isPublic(readMethod.getDeclaringClass().getModifiers()) && !readMethod.isAccessible()) {
|
||||||
|
if (System.getSecurityManager() != null) {
|
||||||
|
AccessController.doPrivileged(new PrivilegedAction<Object>() {
|
||||||
|
public Object run() {
|
||||||
readMethod.setAccessible(true);
|
readMethod.setAccessible(true);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
readMethod.setAccessible(true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Object value = null;
|
Object value = null;
|
||||||
|
|
@ -852,8 +863,18 @@ public class BeanWrapperImpl extends AbstractPropertyAccessor implements BeanWra
|
||||||
else {
|
else {
|
||||||
if (isExtractOldValueForEditor() && pd.getReadMethod() != null) {
|
if (isExtractOldValueForEditor() && pd.getReadMethod() != null) {
|
||||||
final Method readMethod = pd.getReadMethod();
|
final Method readMethod = pd.getReadMethod();
|
||||||
if (!Modifier.isPublic(readMethod.getDeclaringClass().getModifiers())) {
|
if (!Modifier.isPublic(readMethod.getDeclaringClass().getModifiers()) && !readMethod.isAccessible()) {
|
||||||
|
if (System.getSecurityManager()!= null) {
|
||||||
|
AccessController.doPrivileged(new PrivilegedAction<Object>() {
|
||||||
|
public Object run() {
|
||||||
readMethod.setAccessible(true);
|
readMethod.setAccessible(true);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
readMethod.setAccessible(true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
if (System.getSecurityManager() != null) {
|
if (System.getSecurityManager() != null) {
|
||||||
|
|
@ -882,8 +903,18 @@ public class BeanWrapperImpl extends AbstractPropertyAccessor implements BeanWra
|
||||||
pv.getOriginalPropertyValue().conversionNecessary = (valueToApply != originalValue);
|
pv.getOriginalPropertyValue().conversionNecessary = (valueToApply != originalValue);
|
||||||
}
|
}
|
||||||
final Method writeMethod = pd.getWriteMethod();
|
final Method writeMethod = pd.getWriteMethod();
|
||||||
if (!Modifier.isPublic(writeMethod.getDeclaringClass().getModifiers())) {
|
if (!Modifier.isPublic(writeMethod.getDeclaringClass().getModifiers()) && !writeMethod.isAccessible()) {
|
||||||
|
if (System.getSecurityManager()!= null) {
|
||||||
|
AccessController.doPrivileged(new PrivilegedAction<Object>() {
|
||||||
|
public Object run() {
|
||||||
writeMethod.setAccessible(true);
|
writeMethod.setAccessible(true);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
writeMethod.setAccessible(true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
final Object value = valueToApply;
|
final Object value = valueToApply;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1496,8 +1496,15 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
|
||||||
if (logger.isDebugEnabled()) {
|
if (logger.isDebugEnabled()) {
|
||||||
logger.debug("Invoking init method '" + initMethodName + "' on bean with name '" + beanName + "'");
|
logger.debug("Invoking init method '" + initMethodName + "' on bean with name '" + beanName + "'");
|
||||||
}
|
}
|
||||||
ReflectionUtils.makeAccessible(initMethod);
|
|
||||||
if (System.getSecurityManager() != null) {
|
if (System.getSecurityManager() != null) {
|
||||||
|
AccessController.doPrivileged(new PrivilegedExceptionAction<Object>() {
|
||||||
|
public Object run() throws Exception {
|
||||||
|
ReflectionUtils.makeAccessible(initMethod);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
try {
|
try {
|
||||||
AccessController.doPrivileged(new PrivilegedExceptionAction<Object>() {
|
AccessController.doPrivileged(new PrivilegedExceptionAction<Object>() {
|
||||||
|
|
||||||
|
|
@ -1514,6 +1521,7 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
try {
|
try {
|
||||||
|
ReflectionUtils.makeAccessible(initMethod);
|
||||||
initMethod.invoke(bean, (Object[]) null);
|
initMethod.invoke(bean, (Object[]) null);
|
||||||
}
|
}
|
||||||
catch (InvocationTargetException ex) {
|
catch (InvocationTargetException ex) {
|
||||||
|
|
|
||||||
|
|
@ -209,17 +209,8 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp
|
||||||
final String name, final Class<T> requiredType, final Object[] args, final boolean typeCheckOnly)
|
final String name, final Class<T> requiredType, final Object[] args, final boolean typeCheckOnly)
|
||||||
throws BeansException {
|
throws BeansException {
|
||||||
|
|
||||||
if (System.getSecurityManager() != null) {
|
|
||||||
return AccessController.doPrivileged(new PrivilegedAction<T>() {
|
|
||||||
public T run() {
|
|
||||||
return doGetBeanRaw(name, requiredType, args, typeCheckOnly);
|
return doGetBeanRaw(name, requiredType, args, typeCheckOnly);
|
||||||
}
|
}
|
||||||
});
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return doGetBeanRaw(name, requiredType, args, typeCheckOnly);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/**
|
/**
|
||||||
* Return an instance, which may be shared or independent, of the specified bean.
|
* Return an instance, which may be shared or independent, of the specified bean.
|
||||||
* @param name the name of the bean to retrieve
|
* @param name the name of the bean to retrieve
|
||||||
|
|
@ -1446,7 +1437,7 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp
|
||||||
@Override
|
@Override
|
||||||
protected AccessControlContext getAccessControlContext() {
|
protected AccessControlContext getAccessControlContext() {
|
||||||
SecurityContextProvider provider = getSecurityContextProvider();
|
SecurityContextProvider provider = getSecurityContextProvider();
|
||||||
return (provider != null ? provider.getAccessControlContext(): null);
|
return (provider != null ? provider.getAccessControlContext(): AccessController.getContext());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -385,8 +385,23 @@ class ConstructorResolver {
|
||||||
// Need to determine the factory method...
|
// Need to determine the factory method...
|
||||||
// Try all methods with this name to see if they match the given arguments.
|
// Try all methods with this name to see if they match the given arguments.
|
||||||
factoryClass = ClassUtils.getUserClass(factoryClass);
|
factoryClass = ClassUtils.getUserClass(factoryClass);
|
||||||
Method[] rawCandidates = (mbd.isNonPublicAccessAllowed() ?
|
Method[] rawCandidates = null;
|
||||||
ReflectionUtils.getAllDeclaredMethods(factoryClass) : factoryClass.getMethods());
|
|
||||||
|
final Class factoryClazz = factoryClass;
|
||||||
|
if (System.getSecurityManager() != null) {
|
||||||
|
|
||||||
|
rawCandidates = AccessController.doPrivileged(new PrivilegedAction<Method[]>() {
|
||||||
|
public Method[] run() {
|
||||||
|
return (mbd.isNonPublicAccessAllowed() ?
|
||||||
|
ReflectionUtils.getAllDeclaredMethods(factoryClazz) : factoryClazz.getMethods());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
rawCandidates = (mbd.isNonPublicAccessAllowed() ?
|
||||||
|
ReflectionUtils.getAllDeclaredMethods(factoryClazz) : factoryClazz.getMethods());
|
||||||
|
}
|
||||||
|
|
||||||
List<Method> candidateSet = new ArrayList<Method>();
|
List<Method> candidateSet = new ArrayList<Method>();
|
||||||
for (Method candidate : rawCandidates) {
|
for (Method candidate : rawCandidates) {
|
||||||
if (Modifier.isStatic(candidate.getModifiers()) == isStatic &&
|
if (Modifier.isStatic(candidate.getModifiers()) == isStatic &&
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,7 @@ import java.lang.reflect.InvocationTargetException;
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
import java.security.AccessControlContext;
|
import java.security.AccessControlContext;
|
||||||
import java.security.AccessController;
|
import java.security.AccessController;
|
||||||
|
import java.security.PrivilegedAction;
|
||||||
import java.security.PrivilegedActionException;
|
import java.security.PrivilegedActionException;
|
||||||
import java.security.PrivilegedExceptionAction;
|
import java.security.PrivilegedExceptionAction;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
|
@ -81,7 +82,7 @@ class DisposableBeanAdapter implements DisposableBean, Runnable, Serializable {
|
||||||
* @param postProcessors the List of BeanPostProcessors
|
* @param postProcessors the List of BeanPostProcessors
|
||||||
* (potentially DestructionAwareBeanPostProcessor), if any
|
* (potentially DestructionAwareBeanPostProcessor), if any
|
||||||
*/
|
*/
|
||||||
public DisposableBeanAdapter(Object bean, String beanName, RootBeanDefinition beanDefinition,
|
public DisposableBeanAdapter(final Object bean, String beanName, RootBeanDefinition beanDefinition,
|
||||||
List<BeanPostProcessor> postProcessors, AccessControlContext acc) {
|
List<BeanPostProcessor> postProcessors, AccessControlContext acc) {
|
||||||
|
|
||||||
Assert.notNull(bean, "Bean must not be null");
|
Assert.notNull(bean, "Bean must not be null");
|
||||||
|
|
@ -92,15 +93,27 @@ class DisposableBeanAdapter implements DisposableBean, Runnable, Serializable {
|
||||||
this.nonPublicAccessAllowed = beanDefinition.isNonPublicAccessAllowed();
|
this.nonPublicAccessAllowed = beanDefinition.isNonPublicAccessAllowed();
|
||||||
this.acc = acc;
|
this.acc = acc;
|
||||||
|
|
||||||
String destroyMethodName = beanDefinition.getDestroyMethodName();
|
final String destroyMethodName = beanDefinition.getDestroyMethodName();
|
||||||
if (destroyMethodName != null && !(this.invokeDisposableBean && "destroy".equals(destroyMethodName)) &&
|
if (destroyMethodName != null && !(this.invokeDisposableBean && "destroy".equals(destroyMethodName)) &&
|
||||||
!beanDefinition.isExternallyManagedDestroyMethod(destroyMethodName)) {
|
!beanDefinition.isExternallyManagedDestroyMethod(destroyMethodName)) {
|
||||||
this.destroyMethodName = destroyMethodName;
|
this.destroyMethodName = destroyMethodName;
|
||||||
try {
|
try {
|
||||||
|
if (System.getSecurityManager() != null) {
|
||||||
|
AccessController.doPrivileged(new PrivilegedAction<Object>() {
|
||||||
|
public Object run() {
|
||||||
|
destroyMethod = (nonPublicAccessAllowed ?
|
||||||
|
BeanUtils.findMethodWithMinimalParameters(bean.getClass(), destroyMethodName) :
|
||||||
|
BeanUtils.findMethodWithMinimalParameters(bean.getClass().getMethods(), destroyMethodName));
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else {
|
||||||
this.destroyMethod = (this.nonPublicAccessAllowed ?
|
this.destroyMethod = (this.nonPublicAccessAllowed ?
|
||||||
BeanUtils.findMethodWithMinimalParameters(bean.getClass(), destroyMethodName) :
|
BeanUtils.findMethodWithMinimalParameters(bean.getClass(), destroyMethodName) :
|
||||||
BeanUtils.findMethodWithMinimalParameters(bean.getClass().getMethods(), destroyMethodName));
|
BeanUtils.findMethodWithMinimalParameters(bean.getClass().getMethods(), destroyMethodName));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
catch (IllegalArgumentException ex) {
|
catch (IllegalArgumentException ex) {
|
||||||
throw new BeanDefinitionValidationException("Couldn't find a unique destroy method on bean with name '" +
|
throw new BeanDefinitionValidationException("Couldn't find a unique destroy method on bean with name '" +
|
||||||
this.beanName + ": " + ex.getMessage());
|
this.beanName + ": " + ex.getMessage());
|
||||||
|
|
@ -229,9 +242,15 @@ class DisposableBeanAdapter implements DisposableBean, Runnable, Serializable {
|
||||||
logger.debug("Invoking destroy method '" + this.destroyMethodName +
|
logger.debug("Invoking destroy method '" + this.destroyMethodName +
|
||||||
"' on bean with name '" + this.beanName + "'");
|
"' on bean with name '" + this.beanName + "'");
|
||||||
}
|
}
|
||||||
ReflectionUtils.makeAccessible(destroyMethod);
|
|
||||||
try {
|
try {
|
||||||
if (System.getSecurityManager() != null) {
|
if (System.getSecurityManager() != null) {
|
||||||
|
AccessController.doPrivileged(new PrivilegedAction<Object>() {
|
||||||
|
public Object run() {
|
||||||
|
ReflectionUtils.makeAccessible(destroyMethod);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
try {
|
try {
|
||||||
AccessController.doPrivileged(new PrivilegedExceptionAction<Object>() {
|
AccessController.doPrivileged(new PrivilegedExceptionAction<Object>() {
|
||||||
public Object run() throws Exception {
|
public Object run() throws Exception {
|
||||||
|
|
@ -244,6 +263,7 @@ class DisposableBeanAdapter implements DisposableBean, Runnable, Serializable {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
ReflectionUtils.makeAccessible(destroyMethod);
|
||||||
destroyMethod.invoke(bean, args);
|
destroyMethod.invoke(bean, args);
|
||||||
}
|
}
|
||||||
} catch (InvocationTargetException ex) {
|
} catch (InvocationTargetException ex) {
|
||||||
|
|
|
||||||
|
|
@ -89,9 +89,18 @@ public class SimpleInstantiationStrategy implements InstantiationStrategy {
|
||||||
|
|
||||||
public Object instantiate(
|
public Object instantiate(
|
||||||
RootBeanDefinition beanDefinition, String beanName, BeanFactory owner,
|
RootBeanDefinition beanDefinition, String beanName, BeanFactory owner,
|
||||||
Constructor ctor, Object[] args) {
|
final Constructor ctor, Object[] args) {
|
||||||
|
|
||||||
if (beanDefinition.getMethodOverrides().isEmpty()) {
|
if (beanDefinition.getMethodOverrides().isEmpty()) {
|
||||||
|
if (System.getSecurityManager() != null) {
|
||||||
|
// use own privileged to change accessibility (when security is on)
|
||||||
|
AccessController.doPrivileged(new PrivilegedAction<Object>() {
|
||||||
|
public Object run() {
|
||||||
|
ReflectionUtils.makeAccessible(ctor);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
return BeanUtils.instantiateClass(ctor, args);
|
return BeanUtils.instantiateClass(ctor, args);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|
|
||||||
|
|
@ -25,18 +25,26 @@ import java.security.Principal;
|
||||||
import java.security.PrivilegedAction;
|
import java.security.PrivilegedAction;
|
||||||
import java.security.PrivilegedExceptionAction;
|
import java.security.PrivilegedExceptionAction;
|
||||||
import java.security.ProtectionDomain;
|
import java.security.ProtectionDomain;
|
||||||
import java.util.Iterator;
|
|
||||||
import java.util.PropertyPermission;
|
import java.util.PropertyPermission;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
|
import javax.security.auth.AuthPermission;
|
||||||
import javax.security.auth.Subject;
|
import javax.security.auth.Subject;
|
||||||
|
|
||||||
import junit.framework.TestCase;
|
import junit.framework.TestCase;
|
||||||
|
|
||||||
|
import org.springframework.beans.BeansException;
|
||||||
|
import org.springframework.beans.factory.BeanClassLoaderAware;
|
||||||
import org.springframework.beans.factory.BeanCreationException;
|
import org.springframework.beans.factory.BeanCreationException;
|
||||||
|
import org.springframework.beans.factory.BeanFactory;
|
||||||
|
import org.springframework.beans.factory.BeanFactoryAware;
|
||||||
|
import org.springframework.beans.factory.BeanNameAware;
|
||||||
|
import org.springframework.beans.factory.DisposableBean;
|
||||||
|
import org.springframework.beans.factory.InitializingBean;
|
||||||
|
import org.springframework.beans.factory.SmartFactoryBean;
|
||||||
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
|
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
|
||||||
|
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||||
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
|
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
|
||||||
import org.springframework.beans.factory.support.RootBeanDefinition;
|
|
||||||
import org.springframework.beans.factory.support.SecurityContextProvider;
|
import org.springframework.beans.factory.support.SecurityContextProvider;
|
||||||
import org.springframework.beans.factory.support.security.support.ConstructorBean;
|
import org.springframework.beans.factory.support.security.support.ConstructorBean;
|
||||||
import org.springframework.beans.factory.support.security.support.CustomCallbackBean;
|
import org.springframework.beans.factory.support.security.support.CustomCallbackBean;
|
||||||
|
|
@ -45,6 +53,13 @@ import org.springframework.core.io.DefaultResourceLoader;
|
||||||
import org.springframework.core.io.Resource;
|
import org.springframework.core.io.Resource;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Security test case. Checks whether the container uses its privileges for its
|
||||||
|
* internal work but does not leak them when touching/calling user code.
|
||||||
|
*
|
||||||
|
*t The first half of the test case checks that permissions are downgraded when
|
||||||
|
* calling user code while the second half that the caller code permission get
|
||||||
|
* through and Spring doesn't override the permission stack.
|
||||||
|
*
|
||||||
* @author Costin Leau
|
* @author Costin Leau
|
||||||
*/
|
*/
|
||||||
public class CallbacksSecurityTests extends TestCase {
|
public class CallbacksSecurityTests extends TestCase {
|
||||||
|
|
@ -52,35 +67,158 @@ public class CallbacksSecurityTests extends TestCase {
|
||||||
private XmlBeanFactory beanFactory;
|
private XmlBeanFactory beanFactory;
|
||||||
private SecurityContextProvider provider;
|
private SecurityContextProvider provider;
|
||||||
|
|
||||||
|
private static class NonPrivilegedBean {
|
||||||
|
|
||||||
private static class TestSecuredBean {
|
private String expectedName;
|
||||||
|
public static boolean destroyed = false;
|
||||||
|
|
||||||
private String userName;
|
public NonPrivilegedBean(String expected) {
|
||||||
|
this.expectedName = expected;
|
||||||
|
checkCurrentContext();
|
||||||
|
}
|
||||||
|
|
||||||
public void init() {
|
public void init() {
|
||||||
AccessControlContext acc = AccessController.getContext();
|
checkCurrentContext();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void destroy() {
|
||||||
|
checkCurrentContext();
|
||||||
|
destroyed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setProperty(Object value) {
|
||||||
|
checkCurrentContext();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Object getProperty() {
|
||||||
|
checkCurrentContext();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void checkCurrentContext() {
|
||||||
|
assertEquals(expectedName, getCurrentSubjectName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class NonPrivilegedSpringCallbacksBean implements
|
||||||
|
InitializingBean, DisposableBean, BeanClassLoaderAware,
|
||||||
|
BeanFactoryAware, BeanNameAware {
|
||||||
|
|
||||||
|
private String expectedName;
|
||||||
|
public static boolean destroyed = false;
|
||||||
|
|
||||||
|
public NonPrivilegedSpringCallbacksBean(String expected) {
|
||||||
|
this.expectedName = expected;
|
||||||
|
checkCurrentContext();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void afterPropertiesSet() {
|
||||||
|
checkCurrentContext();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void destroy() {
|
||||||
|
checkCurrentContext();
|
||||||
|
destroyed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setBeanName(String name) {
|
||||||
|
checkCurrentContext();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setBeanClassLoader(ClassLoader classLoader) {
|
||||||
|
checkCurrentContext();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setBeanFactory(BeanFactory beanFactory)
|
||||||
|
throws BeansException {
|
||||||
|
checkCurrentContext();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void checkCurrentContext() {
|
||||||
|
assertEquals(expectedName, getCurrentSubjectName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class NonPrivilegedFactoryBean implements SmartFactoryBean {
|
||||||
|
private String expectedName;
|
||||||
|
|
||||||
|
public NonPrivilegedFactoryBean(String expected) {
|
||||||
|
this.expectedName = expected;
|
||||||
|
checkCurrentContext();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isEagerInit() {
|
||||||
|
checkCurrentContext();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isPrototype() {
|
||||||
|
checkCurrentContext();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Object getObject() throws Exception {
|
||||||
|
checkCurrentContext();
|
||||||
|
return new Object();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Class getObjectType() {
|
||||||
|
checkCurrentContext();
|
||||||
|
return Object.class;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isSingleton() {
|
||||||
|
checkCurrentContext();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void checkCurrentContext() {
|
||||||
|
assertEquals(expectedName, getCurrentSubjectName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class NonPrivilegedFactory {
|
||||||
|
|
||||||
|
private final String expectedName;
|
||||||
|
|
||||||
|
public NonPrivilegedFactory(String expected) {
|
||||||
|
this.expectedName = expected;
|
||||||
|
assertEquals(expectedName, getCurrentSubjectName());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Object makeStaticInstance(String expectedName) {
|
||||||
|
assertEquals(expectedName, getCurrentSubjectName());
|
||||||
|
return new Object();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Object makeInstance() {
|
||||||
|
assertEquals(expectedName, getCurrentSubjectName());
|
||||||
|
return new Object();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String getCurrentSubjectName() {
|
||||||
|
final AccessControlContext acc = AccessController.getContext();
|
||||||
|
|
||||||
|
return AccessController.doPrivileged(new PrivilegedAction<String>() {
|
||||||
|
|
||||||
|
public String run() {
|
||||||
Subject subject = Subject.getSubject(acc);
|
Subject subject = Subject.getSubject(acc);
|
||||||
System.out.println("Current acc is " +acc +" subject = " + subject);
|
|
||||||
if (subject == null) {
|
if (subject == null) {
|
||||||
return;
|
return null;
|
||||||
}
|
|
||||||
setNameFromPrincipal(subject.getPrincipals());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setNameFromPrincipal(Set<Principal> principals) {
|
Set<Principal> principals = subject.getPrincipals();
|
||||||
|
|
||||||
if (principals == null) {
|
if (principals == null) {
|
||||||
return;
|
return null;
|
||||||
}
|
}
|
||||||
for (Iterator<Principal> it = principals.iterator(); it.hasNext();) {
|
for (Principal p : principals) {
|
||||||
Principal p = it.next();
|
return p.getName();
|
||||||
this.userName = p.getName();
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
});
|
||||||
public String getUserName() {
|
|
||||||
return this.userName;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class TestPrincipal implements Principal {
|
private static class TestPrincipal implements Principal {
|
||||||
|
|
@ -115,7 +253,9 @@ public class CallbacksSecurityTests extends TestCase {
|
||||||
// setup security
|
// setup security
|
||||||
if (System.getSecurityManager() == null) {
|
if (System.getSecurityManager() == null) {
|
||||||
Policy policy = Policy.getPolicy();
|
Policy policy = Policy.getPolicy();
|
||||||
URL policyURL = getClass().getResource("/org/springframework/beans/factory/support/security/policy.all");
|
URL policyURL = getClass()
|
||||||
|
.getResource(
|
||||||
|
"/org/springframework/beans/factory/support/security/policy.all");
|
||||||
System.setProperty("java.security.policy", policyURL.toString());
|
System.setProperty("java.security.policy", policyURL.toString());
|
||||||
System.setProperty("policy.allowSystemProperty", "true");
|
System.setProperty("policy.allowSystemProperty", "true");
|
||||||
policy.refresh();
|
policy.refresh();
|
||||||
|
|
@ -127,10 +267,12 @@ public class CallbacksSecurityTests extends TestCase {
|
||||||
@Override
|
@Override
|
||||||
protected void setUp() throws Exception {
|
protected void setUp() throws Exception {
|
||||||
|
|
||||||
final ProtectionDomain empty = new ProtectionDomain(null, new Permissions());
|
final ProtectionDomain empty = new ProtectionDomain(null,
|
||||||
|
new Permissions());
|
||||||
|
|
||||||
provider = new SecurityContextProvider() {
|
provider = new SecurityContextProvider() {
|
||||||
private final AccessControlContext acc = new AccessControlContext(new ProtectionDomain[] { empty });
|
private final AccessControlContext acc = new AccessControlContext(
|
||||||
|
new ProtectionDomain[] { empty });
|
||||||
|
|
||||||
public AccessControlContext getAccessControlContext() {
|
public AccessControlContext getAccessControlContext() {
|
||||||
return acc;
|
return acc;
|
||||||
|
|
@ -138,9 +280,9 @@ public class CallbacksSecurityTests extends TestCase {
|
||||||
};
|
};
|
||||||
|
|
||||||
DefaultResourceLoader drl = new DefaultResourceLoader();
|
DefaultResourceLoader drl = new DefaultResourceLoader();
|
||||||
Resource config = drl.getResource("/org/springframework/beans/factory/support/security/callbacks.xml");
|
Resource config = drl
|
||||||
|
.getResource("/org/springframework/beans/factory/support/security/callbacks.xml");
|
||||||
beanFactory = new XmlBeanFactory(config);
|
beanFactory = new XmlBeanFactory(config);
|
||||||
|
|
||||||
beanFactory.setSecurityContextProvider(provider);
|
beanFactory.setSecurityContextProvider(provider);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -171,7 +313,8 @@ public class CallbacksSecurityTests extends TestCase {
|
||||||
|
|
||||||
final Class<ConstructorBean> cl = ConstructorBean.class;
|
final Class<ConstructorBean> cl = ConstructorBean.class;
|
||||||
try {
|
try {
|
||||||
AccessController.doPrivileged(new PrivilegedExceptionAction<Object>() {
|
AccessController.doPrivileged(
|
||||||
|
new PrivilegedExceptionAction<Object>() {
|
||||||
|
|
||||||
public Object run() throws Exception {
|
public Object run() throws Exception {
|
||||||
return cl.newInstance();
|
return cl.newInstance();
|
||||||
|
|
@ -247,7 +390,7 @@ public class CallbacksSecurityTests extends TestCase {
|
||||||
|
|
||||||
public void testTrustedFactoryMethod() throws Exception {
|
public void testTrustedFactoryMethod() throws Exception {
|
||||||
try {
|
try {
|
||||||
beanFactory.getBean("trusted-factory-method");
|
beanFactory.getBean("privileged-static-factory-method");
|
||||||
fail("expected security exception");
|
fail("expected security exception");
|
||||||
} catch (BeanCreationException ex) {
|
} catch (BeanCreationException ex) {
|
||||||
assertTrue(ex.getMostSpecificCause() instanceof SecurityException);
|
assertTrue(ex.getMostSpecificCause() instanceof SecurityException);
|
||||||
|
|
@ -290,20 +433,62 @@ public class CallbacksSecurityTests extends TestCase {
|
||||||
|
|
||||||
public void testInitSecurityAwarePrototypeBean() {
|
public void testInitSecurityAwarePrototypeBean() {
|
||||||
final DefaultListableBeanFactory lbf = new DefaultListableBeanFactory();
|
final DefaultListableBeanFactory lbf = new DefaultListableBeanFactory();
|
||||||
RootBeanDefinition bd = new RootBeanDefinition(TestSecuredBean.class);
|
BeanDefinitionBuilder bdb = BeanDefinitionBuilder
|
||||||
bd.setScope(ConfigurableBeanFactory.SCOPE_PROTOTYPE);
|
.genericBeanDefinition(NonPrivilegedBean.class).setScope(
|
||||||
bd.setInitMethodName("init");
|
ConfigurableBeanFactory.SCOPE_PROTOTYPE)
|
||||||
lbf.registerBeanDefinition("test", bd);
|
.setInitMethodName("init").setDestroyMethodName("destroy")
|
||||||
|
.addConstructorArgValue("user1");
|
||||||
|
lbf.registerBeanDefinition("test", bdb.getBeanDefinition());
|
||||||
final Subject subject = new Subject();
|
final Subject subject = new Subject();
|
||||||
subject.getPrincipals().add(new TestPrincipal("user1"));
|
subject.getPrincipals().add(new TestPrincipal("user1"));
|
||||||
|
|
||||||
TestSecuredBean bean = (TestSecuredBean) Subject.doAsPrivileged(subject,
|
NonPrivilegedBean bean = (NonPrivilegedBean) Subject.doAsPrivileged(
|
||||||
new PrivilegedAction() {
|
subject, new PrivilegedAction() {
|
||||||
public Object run() {
|
public Object run() {
|
||||||
return lbf.getBean("test");
|
return lbf.getBean("test");
|
||||||
}
|
}
|
||||||
}, null);
|
}, null);
|
||||||
assertNotNull(bean);
|
assertNotNull(bean);
|
||||||
assertEquals(null, bean.getUserName());
|
}
|
||||||
|
|
||||||
|
public void testTrustedExecution() throws Exception {
|
||||||
|
beanFactory.setSecurityContextProvider(null);
|
||||||
|
|
||||||
|
Permissions perms = new Permissions();
|
||||||
|
perms.add(new AuthPermission("getSubject"));
|
||||||
|
ProtectionDomain pd = new ProtectionDomain(null, perms);
|
||||||
|
|
||||||
|
AccessControlContext acc = new AccessControlContext(
|
||||||
|
new ProtectionDomain[] { pd });
|
||||||
|
|
||||||
|
final Subject subject = new Subject();
|
||||||
|
subject.getPrincipals().add(new TestPrincipal("user1"));
|
||||||
|
|
||||||
|
// request the beans from non-privileged code
|
||||||
|
Subject.doAsPrivileged(subject, new PrivilegedAction<Object>() {
|
||||||
|
|
||||||
|
public Object run() {
|
||||||
|
// sanity check
|
||||||
|
assertEquals("user1", getCurrentSubjectName());
|
||||||
|
assertEquals(false, NonPrivilegedBean.destroyed);
|
||||||
|
|
||||||
|
beanFactory.getBean("trusted-spring-callbacks");
|
||||||
|
beanFactory.getBean("trusted-custom-init-destroy");
|
||||||
|
// the factory is a prototype - ask for multiple instances
|
||||||
|
beanFactory.getBean("trusted-spring-factory");
|
||||||
|
beanFactory.getBean("trusted-spring-factory");
|
||||||
|
beanFactory.getBean("trusted-spring-factory");
|
||||||
|
|
||||||
|
beanFactory.getBean("trusted-factory-bean");
|
||||||
|
beanFactory.getBean("trusted-static-factory-method");
|
||||||
|
beanFactory.getBean("trusted-factory-method");
|
||||||
|
beanFactory.getBean("trusted-property-injection");
|
||||||
|
beanFactory.getBean("trusted-working-property-injection");
|
||||||
|
|
||||||
|
beanFactory.destroySingletons();
|
||||||
|
assertEquals(true, NonPrivilegedBean.destroyed);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}, provider.getAccessControlContext());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -23,8 +23,6 @@
|
||||||
|
|
||||||
<bean name="custom-factory-method" factory-bean="factory-bean" factory-method="makeInstance"/>
|
<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="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="working-factory-method" class="org.springframework.beans.factory.support.security.support.FactoryBean" factory-method="protectedStaticInstance"/>
|
||||||
|
|
@ -45,4 +43,45 @@
|
||||||
</property>
|
</property>
|
||||||
</bean>
|
</bean>
|
||||||
|
|
||||||
|
<bean name="privileged-static-factory-method" class="java.lang.System" factory-method="getProperties"/>
|
||||||
|
|
||||||
|
<!-- check trusted beans -->
|
||||||
|
<bean name="trusted-spring-callbacks" class="org.springframework.beans.factory.support.security.CallbacksSecurityTests$NonPrivilegedSpringCallbacksBean">
|
||||||
|
<constructor-arg value="user1"/>
|
||||||
|
</bean>
|
||||||
|
|
||||||
|
<bean name="trusted-custom-init-destroy" class="org.springframework.beans.factory.support.security.CallbacksSecurityTests$NonPrivilegedBean"
|
||||||
|
init-method="init" destroy-method="destroy">
|
||||||
|
<constructor-arg value="user1"/>
|
||||||
|
</bean>
|
||||||
|
|
||||||
|
<bean name="trusted-spring-factory" class="org.springframework.beans.factory.support.security.CallbacksSecurityTests$NonPrivilegedFactoryBean">
|
||||||
|
<constructor-arg value="user1"/>
|
||||||
|
</bean>
|
||||||
|
|
||||||
|
<bean name="trusted-static-factory-method" class="org.springframework.beans.factory.support.security.CallbacksSecurityTests$NonPrivilegedFactory"
|
||||||
|
factory-method="makeStaticInstance">
|
||||||
|
<constructor-arg value="user1"/>
|
||||||
|
</bean>
|
||||||
|
|
||||||
|
<bean name="trusted-factory-bean" class="org.springframework.beans.factory.support.security.CallbacksSecurityTests$NonPrivilegedFactory">
|
||||||
|
<constructor-arg value="user1"/>
|
||||||
|
</bean>
|
||||||
|
|
||||||
|
<bean name="trusted-factory-method" factory-bean="trusted-factory-bean" factory-method="makeInstance"/>
|
||||||
|
|
||||||
|
<bean name="trusted-property-injection" class="org.springframework.beans.factory.support.security.CallbacksSecurityTests$NonPrivilegedBean">
|
||||||
|
<constructor-arg value="user1"/>
|
||||||
|
<property name="property" value="value"/>
|
||||||
|
</bean>
|
||||||
|
|
||||||
|
<bean name="trusted-working-property-injection" class="org.springframework.beans.factory.support.security.CallbacksSecurityTests$NonPrivilegedBean">
|
||||||
|
<constructor-arg value="user1"/>
|
||||||
|
<property name="property">
|
||||||
|
<map>
|
||||||
|
<entry key-ref="trusted-property-injection" value-ref="trusted-factory-method"/>
|
||||||
|
</map>
|
||||||
|
</property>
|
||||||
|
</bean>
|
||||||
|
|
||||||
</beans>
|
</beans>
|
||||||
Loading…
Reference in New Issue