Setting the header referrer on Primefaces action - jsf

This is a follow up to a previous question: Error using JSF protected views when opening a new tab
I am using faces-config protected views to protect against CSRF. I ran into problems earlier with links opened in a new tab that I resolved by adding
rel="noopener noreferrer"
to all new tab links.
But now I' running into the same issue with commandButtons.
I have
<p:commandButton value="Submit"
action="#{bean.submit}" />
And submit() returns a string with the new view. But I still get the following error:
javax.faces.application.ProtectedViewException: JSF1099: Referer [sic] header value http://.../updatestatus.xhtml?javax.faces.Token=1534516398157&cr=45309 does not appear to be a protected view. Preventing display of viewId /finance/commitmentregister/view.xhtml
at com.sun.faces.lifecycle.RestoreViewPhase.maybeTakeProtectedViewAction(Unknown Source)
Is there a way to set no referer or opener on the Primefaces commandbutton?
Edit:
Maybe not the answer I was looking for, but I got around the problem by adding a servlet request wrapper in a filter to return null when asked for the referer.
Further edit:
Adding the rough outline of how my code looks with the wrapper fix:
#WebFilter(filterName = "UserLoginFilter", urlPatterns = { "*.xhtml" })
public class UserLoginFilter implements Filter {
#Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
HttpServletRequestWrapper wrapper = new HttpServletRequestWrapper(httpServletRequest) {
#Override
public String getHeader(String name) {
if (name.equalsIgnoreCase("referer")) {
return null;
} else {
return super.getHeader(name);
}
}
};
chain.doFilter(wrapper, response);
}
}

Related

Dynamic Directory in Java EE Web Application

I have created a Java EE application that uses JSF. In my web directory, I have a file named index.xhtml. My goal is to serve different content on this webpage based upon the parent directory's name.
For example:
http://localhost:8080/myapp/1/index.xhtml would print You accessed through "1".
http://localhost:8080/myapp/1234/index.xhtml would print You accessed through "1234".
I do not want to create a directory for every single possible number; it should be completely dynamic.
Additionally, I need my navigation rules to still be usable. So if I have a navigation rule such as this:
<navigation-rule>
<display-name>*</display-name>
<from-view-id>*</from-view-id>
<navigation-case>
<from-outcome>index</from-outcome>
<to-view-id>/index.xhtml</to-view-id>
<redirect />
</navigation-case>
</navigation-rule>
Then if I am in the directory 1234, it will still redirect to the index.xhtml page within 1234.
Is this possible? How can I do this?
In order to forward /[number]/index.xhtml to /index.xhtml whereby [number] is been stored as a request attribute, you need a servlet filter. The doFilter() implementation can look like this:
#WebFilter("/*")
public class YourFilter implements Filter {
#Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
String[] paths = request.getRequestURI().substring(request.getContextPath().length()).split("/");
if (paths.length == 3 && paths[2].equals("index.xhtml") && paths[1].matches("[0-9]{1,9}")) {
request.setAttribute("directory", Integer.valueOf(paths[1]));
request.getRequestDispatcher("/index.xhtml").forward(req, res);
}
else {
chain.doFilter(req, res);
}
}
// ...
}
It makes sure the number matches 1 to 9 latin digits and stores it as a request attribute identified by directory and finally forwards to /index.xhtml in context root. If nothing maches, it simply continues the request as if nothing special happened.
In the /index.xhtml you can access the number by #{directory}.
<p>You accessed through "#{directory}"</p>
Then, in order to make sure JSF navigation (and <h:form>!) keeps working, you need a custom view handler which overrides the getActionURL() to prepend the URL with the path represented by directory request attribute, if any. Here's a kickoff example:
public class YourViewHandler extends ViewHandlerWrapper {
private ViewHandler wrapped;
public YourViewHandler(ViewHandler wrapped) {
this.wrapped = wrapped;
}
#Override
public String getActionURL(FacesContext context, String viewId) {
String actionURL = super.getActionURL(context, viewId);
if (actionURL.endsWith("/index.xhtml")) {
Integer directory = (Integer) context.getExternalContext().getRequestMap().get("directory");
if (directory != null) {
actionURL = actionURL.substring(0, actionURL.length() - 11) + directory + "/index.xhtml";
}
}
return actionURL;
}
#Override
public ViewHandler getWrapped() {
return wrapped;
}
}
In order to get it to run, register in faces-config.xml as below.
<application>
<view-handler>com.example.YourViewHandler</view-handler>
</application>
This is also pretty much how JSF targeted URL rewrite engines such as PrettyFaces work.
See also:
How to use a servlet filter in Java to change an incoming servlet request url?
How to create user-friendly and seo-friendly urls in jsf?
Get rewritten URL with query string

Execute commandButton-beanFunction in WEB-INF/page.xhtml coming from forward

I'm using Java EE for an enterprise application on Glassfish 4.1, I've the following components:
a Java Servlet:
protected void processRequest(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html;charset=UTF-8");
this.setUser(um.getLoggedUser());
final String indexPath = "/Index.xhtml";
final String creatorPath = "/WEB-INF/HiddenPages/EventPageCreator.xhtml";
if(creator())
request.getRequestDispatcher("/WEB-INF/HiddenPages/Creator.xhtml").forward(request, response);
else
response.sendRedirect("/Index.xhtml");
}
The creator page that is under WEB-INF,is the page in which arises the problem:
It's related to a ManagedBean method.
<h:form><p:menubar>
<p:menuitem action="#{bean.logout()}" value="Logout" ajax="false">
</p:menuitem></p:menubar></h:form>
The bean:
#ManagedBean
#RequestScoped
public class Bean(){
public void logout(){
System.out.println("logout");
}
}
The problem is that the page Creator.xhtlm is rightly loaded with all the css and also the properties given by that bean. The problem is that once I click on the logout menuitem it doesn't call the related function and an 500 Internal Error occurs, java.lang.IllegalStateException: Cannot forward after response has been committed.

Primefaces component not respond after the session expired

I have a filter which checks the session. My filter:
public class FilterLogin implements Filter{
FilterConfig fc;
#Override
public void init(FilterConfig filterConfig) throws ServletException {
//throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
fc = filterConfig;
}
#Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
//throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
HttpServletRequest req = (HttpServletRequest) request;
HttpServletResponse resp = (HttpServletResponse) response;
HttpSession session = req.getSession(true);
if (session.getAttribute("loginMB") == null) {
resp.sendRedirect("/home.xhtml");
} else {
chain.doFilter(request, response);
}
}
#Override
public void destroy() {
//throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
}
web.xml:
<filter>
<filter-name>filter</filter-name>
<filter-class>pl.ePrzychodnia.filter.LoginFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>filter</filter-name>
<url-pattern>/protected/*</url-pattern>
</filter-mapping>
<error-page>
<exception-type>javax.faces.application.ViewExpiredException</exception-type>
<location>/home.xhtml</location>
</error-page>
When the session is expired I should go to the site home.xhtml. But when the session is expired and I want click the navigation menu in the page, the component is not reacting to the click...
When I do not use Primefaces everything works correctly. When I use primefaces in my project I have this error. What could be the cause?
I try use a global exception handler but i have a little problem. I copy class from this site http://wmarkito.wordpress.com/2012/04/05/adding-global-exception-handling-using-jsf-2-x-exceptionhandler/
and edited in class CustomExceptionHandler:
try {
//log error ?
log.log(Level.SEVERE, "Critical Exception!", t);
//redirect error page
requestMap.put("exceptionMessage", t.getMessage());
nav.handleNavigation(fc, null, "/home");
fc.renderResponse();
// remove the comment below if you want to report the error in a jsf error message
//JsfUtil.addErrorMessage(t.getMessage());
}
I change: nav.handleNavigation(fc, null, "/error"); to nav.handleNavigation(fc, null, "/home");
But when session timeout i not reditect to home.xhtml page only go to the page when I clicked and i have a example error:
SEVERE: Critical Exception!
javax.faces.application.ViewExpiredException: viewId:/protected/admin/about.xhtml - View /protected/admin/about.xhtml could not be restored.
when i clicked reference to about page when my session expired. I see a incomplete about.xhtml page instead home.xhtml
Most possibly, you make an ajax call to the managed bean. That is why error navigation does not work in web xml. The error will be send to JavaScript callback onerror if the action is invoked as ajax request.
You can add a global exception handler to application if you want to handle errors on server side. Adding global exception handling using JSF tutorial is a good one to follow.
Furthermore, you can use FullAjaxExceptionHandler feature of OmniFaces

Removing JSESSIONID in URL without using Filter and Wrapper

I have created a Filter listening on an url-pattern of /* which replaces the HttpServletRequest with a HttpServletRequestWrapper implementation.
I have a Servlet and in this Servlet am using h:graphicImage to render images fetching from Apache web server.
<h:graphicImage value="/locationInMyWebServer/myImage.jgp"></h:graphicImage>
When I hit the URL for accessing this page (containing image), the image was not getting displayed as JSESSIONID was getting appended to my image name. The URL that was getting formed was like below.
http:/myDomain/myServlet/../myImage.jpg;JSESSIONID=ABCDEFGHIJKLMM
Hence, I have used the Filter (more details about this filter is here) as stated in the beginning of my question.
From this Servlet there is a link for logging in. When a User logs in, same JSESSIONID is getting retained even after authentication. Since, Session ID is same before logging in and after a user logs in, this is leading to Session-fixation attacks.
How can I avoid using this filter and also solve my problem of JSESSIONID getting appended to images when I use h:graphicImage
PS: I can't use <img src> because my h:graphicImage is inside h:commandLink
Session Id was different before logging in and after logging in , before using this Filter
I have added the relevant code below.
Below code is from my web.xml which has entry for Filter
<filter>
<filter-name>URLSessionFilter</filter-name>
<filter-class>myPackage.web.filter.URLSessionFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>URLSessionFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<filter>
Code in my URLSessionFilter is below,
public class URLSessionFilter implements Filter
{
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException
{
if (!(request instanceof HttpServletRequest))
{
chain.doFilter(request, response);
return;
}
HttpServletResponse httpResponse = (HttpServletResponse)response;
HttpServletResponseWrapper wrappedResponse = new HttpServletResponseWrapper(httpResponse)
{
public String encodeRedirectUrl(String url)
{
return url;
}
public String encodeRedirectURL(String url) {
return url; }
public String encodeUrl(String url) {
return url; }
public String encodeURL(String url) {
return url;
}
};
chain.doFilter(request, wrappedResponse);
}
public void init(FilterConfig filterConfig)
{
}
public void destroy()
{
}
}
There is a link in my Servlet on click of which login page will be displayed. Code is below,
<h:commandLink action="#{myBean.myMethod}">
<h:graphicImage value="/myLocInWebserver/myImage.jpg">
</h:commandLink>
In myBean.myMethod , am doing some DB clean up activities and redirecting to login page.
Another way is avoid the servlet container interpreting something as a URL. To accomplish that, you would avoid any of the special JSP or JSF tags, and directly use HTML tags. In your case - that could look like follows:
<h:commandLink action="#{myBean.myMethod}">
<img src="#{request.contextPath}/myLocInWebserver/myImage.jpg"/>
</h:commandLink>
No more <h:graphicImage> ...
You would still want your context path to be prefixed without any hardcoding - hence the use of #{request.contextPath}.
I recently came to this solution, as I was integrating JavaMelody with my application, and provided a link for admins to the tool. However somehow JavaMelody fails with the ;jsessionid appended. Hence, I am currently generating the URL as follows:
<a href="#{request.contextPath}/monitoring"
target="_blank"
class="ui-link ui-widget"
>
Java Melody Performance Monitoring
</a>
instead of the typical JSF solution
<p:link value="Java Melody Performance Monitoring"
href="/monitoring"
target="_blank"
/>
Which simply won't work.
The benefit of this solution is that I can now control this on a URL by URL basis, and I do not have to worry about setting <tracking-mode>COOKIE</tracking-mode> globally.

Why use a JSF ExceptionHandlerFactory instead of <error-page> redirection?

All of the ExceptionHandlerFactory examples I have come across so far redirect a user to a viewExpired.jsf page in the event that a ViewExpiredException is caught:
public class ViewExpiredExceptionExceptionHandler extends ExceptionHandlerWrapper {
private ExceptionHandler wrapped;
public ViewExpiredExceptionExceptionHandler(ExceptionHandler wrapped) {
this.wrapped = wrapped;
}
#Override
public ExceptionHandler getWrapped() {
return this.wrapped;
}
#Override
public void handle() throws FacesException {
for (Iterator<ExceptionQueuedEvent> i = getUnhandledExceptionQueuedEvents().iterator(); i.hasNext();) {
ExceptionQueuedEvent event = i.next();
ExceptionQueuedEventContext context = (ExceptionQueuedEventContext) event.getSource();
Throwable t = context.getException();
if (t instanceof ViewExpiredException) {
ViewExpiredException vee = (ViewExpiredException) t;
FacesContext facesContext = FacesContext.getCurrentInstance();
Map<String, Object> requestMap = facesContext.getExternalContext().getRequestMap();
NavigationHandler navigationHandler = facesContext.getApplication().getNavigationHandler();
try {
// Push some useful stuff to the request scope for use in the page
requestMap.put("currentViewId", vee.getViewId());
navigationHandler.handleNavigation(facesContext, null, "/viewExpired");
facesContext.renderResponse();
} finally {
i.remove();
}
}
}
// At this point, the queue will not contain any ViewExpiredEvents. Therefore, let the parent handle them.
getWrapped().handle();
}
}
It seems to me that the following simple web.xml configuration is fundamentally the same and a lot simpler:
<error-page>
<exception-type>javax.faces.application.ViewExpiredException</exception-type>
<location>/viewExpired.jsf</location>
</error-page>
This prompts the question - why would one use an ExceptionHandlerFactory?
The particular example does only one useful thing: it saves the view ID as a request attribute so that you can use for example
<h:link value="Go back to previous page" outcome="#{currentViewId}" />
But this is not tremendously useful as the raw request URI is already available by the <error-page>'s default request attribute javax.servlet.error.request_uri.
<h:outputLink value="#{requestScope['javax.servlet.error.request_uri']}">Go back to previous page</h:outputLink>
However one thing what a custom ExceptionHandler is really useful for is that it allows you to deal with exceptions during ajax requests. By default they have namely no single form of helpful feedback in the client side. Only in Mojarra with project stage set to "Development" you'll see a bare JavaScript alert message with the exception message. But that's it. There is no single form of feedback in "Production" stage. With a custom ExceptionHandler you would be able to parse the web.xml to find the error page locations, create a new UIViewRoot with it and force JSF to set ajax rendering to #all.
So, basically:
String errorPageLocation = "/WEB-INF/errorpages/500.xhtml";
context.setViewRoot(context.getApplication().getViewHandler().createView(context, errorPageLocation));
context.getPartialViewContext().setRenderAll(true);
context.renderResponse();
See also this related question: What is the correct way to deal with JSF 2.0 exceptions for AJAXified components? and this blog: Full Ajax Exception Handler.
It depends what do you want to do when you recive ViewExpiredException.
If you just want to display to a user error page you can do it like you said.
This post show you how to programmatically intercept the
ViewExpiredException and do something nice with it.

Resources