package ysoserial.payloads;
import java.beans.FeatureDescriptor;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import javax.el.BeanELResolver;
import javax.el.ELContext;
import javax.el.ELResolver;
import javax.el.MapELResolver;
import javax.faces.context.FacesContext;
import javax.servlet.ServletContext;
import javax.servlet.ServletRequest;
import org.apache.myfaces.el.CompositeELResolver;
import org.apache.myfaces.el.unified.FacesELContext;
import org.mockito.Matchers;
import org.mockito.Mockito;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
import ysoserial.CustomDeserializer;
import ysoserial.Deserializer;
/**
* @author mbechler
*
*/
public class MyfacesTest extends RemoteClassLoadingTest implements CustomDeserializer {
public MyfacesTest ( String command ) {
super(command);
}
public Class<?> getCustomDeserializer () {
return MyfacesDeserializer.class;
}
/**
* need to use a custom deserializer so that the faces context gets set in the isolated class
*
* @author mbechler
*
*/
public static final class MyfacesDeserializer extends Deserializer {
public static Class<?>[] getExtraDependencies () {
return new Class[] {
MockRequestContext.class, MockELResolver.class
};
}
private static class MockRequestContext implements Answer<Object> {
private Map<String, Object> attributes = new HashMap<String, Object>();
public Object answer ( InvocationOnMock invocation ) throws Throwable {
if ( "setAttribute".equals(invocation.getMethod().getName()) ) {
this.attributes.put(invocation.getArgumentAt(0, String.class), invocation.getArgumentAt(1, Object.class));
return null;
}
else if ( "getAttribute".equals(invocation.getMethod().getName()) ) {
return this.attributes.get(invocation.getArgumentAt(0, String.class));
}
return null;
}
}
private static class MockELResolver extends ELResolver {
private ServletRequest request;
public MockELResolver (ServletRequest req) {
this.request = req;
}
@Override
public Object getValue ( ELContext context, Object base, Object property ) {
if ( base == null && "request".equals(property)) {
context.setPropertyResolved(true);
return this.request;
}
return null;
}
@Override
public Class<?> getType ( ELContext context, Object base, Object property ) {
if ( base == null && "request".equals(property)) {
context.setPropertyResolved(true);
return ServletRequest.class;
}
return null;
}
@Override
public void setValue ( ELContext context, Object base, Object property, Object value ) {
}
@Override
public boolean isReadOnly ( ELContext context, Object base, Object property ) {
return true;
}
@Override
public Iterator<FeatureDescriptor> getFeatureDescriptors ( ELContext context, Object base ) {
return null;
}
@Override
public Class<?> getCommonPropertyType ( ELContext context, Object base ) {
return null;
}
}
public MyfacesDeserializer ( byte[] bytes ) {
super(bytes);
}
@Override
public Object call () throws Exception {
java.lang.reflect.Method setFC = FacesContext.class.getDeclaredMethod("setCurrentInstance", FacesContext.class);
setFC.setAccessible(true);
ClassLoader oldTCCL = Thread.currentThread().getContextClassLoader();
Thread.currentThread().setContextClassLoader(this.getClass().getClassLoader());
FacesContext ctx = createMockFacesContext();
try {
setFC.invoke(null, ctx);
return super.call();
}
finally {
setFC.invoke(null, (FacesContext) null);
Thread.currentThread().setContextClassLoader(oldTCCL);
}
}
private static FacesContext createMockFacesContext () throws MalformedURLException {
FacesContext ctx = Mockito.mock(FacesContext.class);
CompositeELResolver cer = new CompositeELResolver();
FacesELContext elc = new FacesELContext(cer, ctx);
ServletRequest requestMock = Mockito.mock(ServletRequest.class);
ServletContext contextMock = Mockito.mock(ServletContext.class);
URL url = new URL("file:///");
Mockito.when(contextMock.getResource(Matchers.anyString())).thenReturn(url);
Mockito.when(requestMock.getServletContext()).thenReturn(contextMock);
Answer<?> attrContext = new MockRequestContext();
Mockito.when(requestMock.getAttribute(Matchers.anyString())).thenAnswer(attrContext);
Mockito.doAnswer(attrContext).when(requestMock).setAttribute(Matchers.anyString(), Matchers.any());
cer.add(new MockELResolver(requestMock));
cer.add(new BeanELResolver());
cer.add(new MapELResolver());
Mockito.when(ctx.getELContext()).thenReturn(elc);
return ctx;
}
}
}