Reputation: 862
I am using JSF 2.2. I am trying to use JSF as a pure templating language. However, there is one problem. Any user who is creating a JSF page in my environment can do something like this:
#{session.getAttribute('user').getApiKey()}
Here I have a user object that is stored in the session and getApiKey() method is a getter in that class.
Is there 'web.xml' configuration or some other trick that I can use to disable session object completely on a JSF page?
Upvotes: 2
Views: 1212
Reputation: 862
Here is what I did to solve this problem. This class essentially revokes access to all the core objects on the page. Additionally, I've added a utility variable to give access to the context path. I have tried this and it seems to WORK!.
package com.example.templates.jsf;
import javax.el.ELContext;
import javax.el.ELException;
import javax.el.PropertyNotFoundException;
import javax.faces.component.UIComponent;
import javax.faces.context.ExternalContext;
import javax.faces.context.FacesContext;
import com.sun.faces.component.CompositeComponentStackManager;
import com.sun.faces.el.ImplicitObjectELResolver;
import com.sun.faces.util.MessageUtils;
/**
* This class revokes access to server page context objects
*/
public class CustomImplicitObjectELResolver extends ImplicitObjectELResolver {
public static final int CONTEXT_PATH = 19;
public CustomImplicitObjectELResolver(){
super();
// Revoke access to variables that can potentially
// give access to internal class objects.
IMPLICIT_OBJECTS.remove("facesContext");
IMPLICIT_OBJECTS.remove("session");
IMPLICIT_OBJECTS.remove("sessionScope");
IMPLICIT_OBJECTS.remove("application");
IMPLICIT_OBJECTS.remove("applicationScope");
IMPLICIT_OBJECTS.remove("request");
IMPLICIT_OBJECTS.remove("requestScope");
IMPLICIT_OBJECTS.remove("view");
IMPLICIT_OBJECTS.remove("viewScope");
IMPLICIT_OBJECTS.remove("initParam");
IMPLICIT_OBJECTS.remove("component");
IMPLICIT_OBJECTS.remove("cookie");
IMPLICIT_OBJECTS.remove("header");
IMPLICIT_OBJECTS.remove("headerValues");
IMPLICIT_OBJECTS.remove("flowScope");
// My own utility method
IMPLICIT_OBJECTS.put("contextPath", CONTEXT_PATH);
}
@Override
public Object getValue(ELContext context,Object base, Object property)
throws ELException {
// variable resolution is a special case of property resolution
// where the base is null.
if (base != null) {
return null;
}
if (property == null) {
String message = MessageUtils.getExceptionMessageString
(MessageUtils.NULL_PARAMETERS_ERROR_MESSAGE_ID, "property");
throw new PropertyNotFoundException(message);
}
Integer index = IMPLICIT_OBJECTS.get(property.toString());
if (index == null) {
return null;
} else {
FacesContext facesContext = (FacesContext) context.getContext(FacesContext.class);
ExternalContext extCtx = facesContext.getExternalContext();
switch (index) {
case COMPOSITE_COMPONENT:
// The following five lines violate the specification.
// The specification states that the 'cc' implicit object
// always evaluates to the current composite component,
// however, this isn't desirable behavior when passing
// attributes between nested composite components, so we
// need to alter the behavior so that the components behave
// as the user would expect.
/* BEGIN DEVIATION */
CompositeComponentStackManager manager =
CompositeComponentStackManager.getManager(facesContext);
Object o = manager.peek();
/* END DEVIATION */
if (o == null) {
o = UIComponent.getCurrentCompositeComponent(facesContext);
}
context.setPropertyResolved(o != null);
return o;
case PARAM:
context.setPropertyResolved(true);
return extCtx.getRequestParameterMap();
case PARAM_VALUES:
context.setPropertyResolved(true);
return extCtx.getRequestParameterValuesMap();
case CONTEXT_PATH:
context.setPropertyResolved(true);
return extCtx.getRequestContextPath();
case RESOURCE:
context.setPropertyResolved(true);
return facesContext.getApplication().getResourceHandler();
default:
return null;
}
}
}
}
Next, in faces-config.xml, add the following entry:
<application>
<el-resolver>
com.example.templates.jsf.CustomImplicitObjectELResolver
</el-resolver>
</application>
Upvotes: 0
Reputation: 70564
Maybe. The implicit variables are contributed by a particular ELResolver. Removing that one from the list of ELResolvers, or prepending an own resolver that always returns null for all implicit variables to that list, should do the trick.
Off hand, I don't know whether JSF offers a public API do this, or the spec even permits something like that.
Either way, if you just need a templating engine, there are easier options that customizing a stateful, component-based web application framework ...
Upvotes: 1
Reputation: 1108632
Is there 'web.xml' configuration or some other trick that I can use to disable session object completely on a JSF page?
No.
Parse the template manually against a whitelist of allowed tags, attributes and EL expressions (note: don't use a blacklist, hackers will find ways you wouldn't have imagined). For instance, the following expressions have the same effect as #{session.getAttribute('user').getApiKey()}
:
#{request.session.getAttribute('user').apiKey}
#{sessionScope.user.apiKey}
#{user.apiKey}
#{facesContext.externalContext.sessionMap.user.apiKey}
#{facesContext.externalContext.session.getAttribute('user').apiKey}
After all, JSF/Facelets is likely the wrong tool for the job of offering clients some kind of a template which will be executed in the server. Rather look for BB/Wiki/Markdown-like markup or whitelisted HTML which you display via <h:outputText escape="false">
.
Upvotes: 2