Skip to content

Commit

Permalink
BZ1232908 CVE-2015-3244 - Security checks on resource serving.
Browse files Browse the repository at this point in the history
  • Loading branch information
jpkrohling committed Jul 16, 2015
1 parent 2ac3c0e commit 4a344e1
Show file tree
Hide file tree
Showing 4 changed files with 90 additions and 28 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Expand Up @@ -10,3 +10,6 @@ overlays
.factorypath
arquillian-settings
phantomjsdriver.log

pom.xml.releaseBackup
release.properties
Expand Up @@ -21,15 +21,24 @@
*/
package org.jboss.portletbridge.bridge.controller;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import com.sun.faces.context.StateContext;

import org.jboss.portletbridge.bridge.config.BridgeConfig;
import org.jboss.portletbridge.bridge.context.BridgeContext;
import org.jboss.portletbridge.bridge.event.BridgePostConstructFacesContextSystemEvent;
import org.jboss.portletbridge.bridge.event.BridgePreReleaseFacesContextSystemEvent;
import org.jboss.portletbridge.bridge.logger.BridgeLogger.Level;
import org.jboss.portletbridge.bridge.scope.BridgeRequestScope;
import org.jboss.portletbridge.bridge.scope.BridgeRequestScopeManager;
import org.jboss.portletbridge.context.AbstractExternalContext;
import org.jboss.portletbridge.context.flash.PortletFlash;
import org.jboss.portletbridge.lifecycle.PortalPhaseListener;
import org.jboss.portletbridge.lifecycle.PublicParameterPhaseListener;
import org.jboss.portletbridge.lifecycle.RenderResponsePhaseListener;
import org.jboss.portletbridge.util.BeanWrapper;
import org.jboss.portletbridge.util.FacesMessageWrapper;
import org.jboss.portletbridge.util.ParameterFunction;
import org.jboss.portletbridge.util.PublicParameterUtil;

import javax.el.ELContext;
import javax.el.ValueExpression;
Expand All @@ -54,6 +63,7 @@
import javax.faces.render.ResponseStateManager;
import javax.portlet.EventRequest;
import javax.portlet.EventResponse;
import javax.portlet.PortletConfig;
import javax.portlet.PortletContext;
import javax.portlet.PortletException;
import javax.portlet.PortletRequest;
Expand All @@ -66,24 +76,18 @@
import javax.portlet.faces.BridgeException;
import javax.portlet.faces.event.EventNavigationResult;

import org.jboss.portletbridge.bridge.config.BridgeConfig;
import org.jboss.portletbridge.bridge.context.BridgeContext;
import org.jboss.portletbridge.bridge.event.BridgePostConstructFacesContextSystemEvent;
import org.jboss.portletbridge.bridge.event.BridgePreReleaseFacesContextSystemEvent;
import org.jboss.portletbridge.bridge.logger.BridgeLogger.Level;
import org.jboss.portletbridge.bridge.scope.BridgeRequestScope;
import org.jboss.portletbridge.bridge.scope.BridgeRequestScopeManager;
import org.jboss.portletbridge.context.AbstractExternalContext;
import org.jboss.portletbridge.context.flash.PortletFlash;
import org.jboss.portletbridge.lifecycle.PortalPhaseListener;
import org.jboss.portletbridge.lifecycle.PublicParameterPhaseListener;
import org.jboss.portletbridge.lifecycle.RenderResponsePhaseListener;
import org.jboss.portletbridge.util.BeanWrapper;
import org.jboss.portletbridge.util.FacesMessageWrapper;
import org.jboss.portletbridge.util.ParameterFunction;
import org.jboss.portletbridge.util.PublicParameterUtil;

import com.sun.faces.context.StateContext;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

/**
* @author <a href="http://community.jboss.org/people/kenfinni">Ken Finnigan</a>
Expand All @@ -98,6 +102,7 @@ public class Jsf20ControllerImpl implements BridgeController {
private static final String MANAGED_BEANS_WRAPPER = "org.jboss.portletbridge.managedBeansHolder";
private static final String REQUEST_SCOPE_ID = "__pbrReqScopeId";
private static final String FACES_EXECUTED_DURING_ACTION_REQUEST = "facesDuringAction";
private static final String AUTOMATIC_RESOURCE_DISPATCHING = "javax.portlet.automaticResourceDispatching";

public Jsf20ControllerImpl(BridgeConfig bridgeConfig) {
this.bridgeConfig = bridgeConfig;
Expand Down Expand Up @@ -297,7 +302,9 @@ public void renderResource(BridgeContext bridgeContext) throws BridgeException {
// JSF2 Resource
resourceHandler.handleResourceRequest(facesContext);
} else if (null != resourceId) {
renderNonFacesResource(bridgeContext, resourceId);
if (isAutomaticResourceDispatchingEnabled(bridgeContext)) {
renderNonFacesResource(bridgeContext, resourceId);
}
} else {
renderFacesResource(bridgeContext, facesContext, facesLifecycle);
}
Expand Down Expand Up @@ -648,6 +655,12 @@ protected void renderNonFacesResource(BridgeContext bridgeContext, String resour
PortletException, IOException {

if (null != resourceId) {
try {
resourceId = new URI(resourceId).normalize().getPath();
} catch (URISyntaxException e) {
throw new IOException("Unable to normalize the path to the resourceId");
}

PortletContext portletContext = bridgeContext.getPortletContext();
PortletRequestDispatcher dispatcher = portletContext.getRequestDispatcher(resourceId);

Expand All @@ -670,11 +683,38 @@ protected void renderNonFacesResource(BridgeContext bridgeContext, String resour
((ResourceResponse) bridgeContext.getPortletResponse()).setContentType(mimeType);
}

// some security checks
String excludedResources = portletContext.getInitParameter(ResourceHandler.RESOURCE_EXCLUDES_PARAM_NAME);
if (null == excludedResources || excludedResources.isEmpty()) {
excludedResources = ResourceHandler.RESOURCE_EXCLUDES_DEFAULT_VALUE;
}

if (isProtectedResource(resourceId) || isExcludedResource(excludedResources, resourceId)) {
FacesContext context = FacesContext.getCurrentInstance();
if (null != context) {
throw new IOException("The requested resource is protected.");
}
return;
}

dispatcher.forward(bridgeContext.getPortletRequest(), bridgeContext.getPortletResponse());
}
}
}

private boolean isExcludedResource(String excludedResources, String resourceId) {
String extension = resourceId.substring(resourceId.indexOf('.'));
return Arrays.asList(excludedResources.split(",")).contains(extension);
}

private boolean isProtectedResource(String resourceId) {
String resourceIdCleaned = resourceId.toUpperCase();
return resourceIdCleaned.startsWith("/WEB-INF/") ||
resourceIdCleaned.startsWith("/META-INF/") ||
resourceIdCleaned.startsWith("WEB-INF/") ||
resourceIdCleaned.startsWith("META-INF/");
}

protected FacesContext getFacesContext(BridgeContext bridgeContext, Lifecycle facesLifecycle) throws FacesException {
FacesContext facesContext = getFacesContextFactory().getFacesContext(bridgeContext.getPortletContext(),
bridgeContext.getPortletRequest(), bridgeContext.getPortletResponse(), facesLifecycle);
Expand Down Expand Up @@ -788,4 +828,14 @@ protected void performPreExecuteTasks(FacesContext facesContext, Lifecycle faces
protected String stateContextListenerClassname() {
return "com.sun.faces.context.StateContext$AddRemoveListener";
}

private boolean isAutomaticResourceDispatchingEnabled(BridgeContext bridgeContext) {
Object o = bridgeContext.getPortletRequest().getAttribute("javax.portlet.config");
if (o instanceof PortletConfig) {
PortletConfig portletConfig = (PortletConfig) o;
String autoDispatch = portletConfig.getInitParameter(AUTOMATIC_RESOURCE_DISPATCHING);
return "true".equalsIgnoreCase(autoDispatch);
}
return false;
}
}
8 changes: 8 additions & 0 deletions examples/richfaces-showcase/src/main/webapp/WEB-INF/web.xml
Expand Up @@ -8,6 +8,14 @@
<param-name>javax.portlet.faces.RENDER_POLICY</param-name>
<param-value>ALWAYS_DELEGATE</param-value>
</context-param>
<context-param>
<param-name>javax.faces.RESOURCE_EXCLUDES</param-name>
<param-value>.class .jsp .jspx .properties .xhtml .doc</param-value>
</context-param>
<context-param>
<param-name>javax.portlet.automaticResourceDispatching</param-name>
<param-value>true</param-value>
</context-param>
<context-param>
<param-name>javax.faces.FACELETS_LIBRARIES</param-name>
<param-value>/WEB-INF/app-tags.taglib.xml</param-value>
Expand Down
1 change: 1 addition & 0 deletions pom.xml
Expand Up @@ -469,6 +469,7 @@
<autoVersionSubmodules>true</autoVersionSubmodules>
<pushChanges>false</pushChanges>
<localCheckout>true</localCheckout>
<tagNameFormat>@{project.version}</tagNameFormat>
</configuration>
</plugin>
</plugins>
Expand Down

0 comments on commit 4a344e1

Please sign in to comment.