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
Related
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);
}
}
A week ago, I have studied about ViewExpiredException, and I've read several things about it.
viewExpiredException JSF
How to control web page caching, across all browsers?
Session timeout and ViewExpiredException handling on JSF/PrimeFaces ajax request
My problem, which is some cases, I would like to ignore the ViewExpiredException. These are situations that do not need a "session", and my Beans are #RequestScoped. As an example, the pages login.xhtml, register.xhtml and passwordRecovery.xhtml.
In these cases, it is very strange display an error to the user saying that your session has expired. So if you open the login page and stand still for a while, when he inform your data and click Login, it would be forwarded to an error page. I would just ignore it and let transparent to the user.
So, my solution so far is create a ExceptionHandler to ignore these exceptions:
#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();
// just remove the exception from queue
if (t instanceof ViewExpiredException) {
i.remove();
}
}
getWrapped().handle();
}
Then, I created a filter to check whether the user is logged in, if not then redirected to login page (This filter applies only pages that require authentication):
#Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
if (!loginManagedBean.isLogged()) {
String pathLogin = request.getContextPath() + "/" + LOGIN_VIEW;
if (isAJAXRequest(request)) {
response.setContentType("text/xml");
response.getWriter()
.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>")
.printf("<partial-response><redirect url=\"%s\"></redirect></partial-response>", pathLogin);
return;
}
pathLogin += "?source=" + request.getServletPath();
response.sendRedirect(pathLogin);
return;
}
chain.doFilter(request, response);
}
So when the session expires, does not affect the user experience in the login and registration pages. And on pages I wish session, are handled by the filter.
That would be a good solution? Are there any security risk to ignore ViewExpiredException in a ExceptionHandler?
Ignoring them is not technically bad in this specific case, but it indicates a bad design. It's as if you're using the wrong tool for the job. I.e. those views should actually never expire.
Just make specifically those views stateless.
<f:view transient="true">
...
</f:view>
This can be placed anywhere in the page, even duplicated, but most self-documenting is making it the top level tag of the page, composition or definition.
See also:
What is the usefulness of statelessness in JSF?
I am developing a JSF 2.0 based web application. I am trying to implement a global exception handler which will redirect the user to a generic error page whenever any exception occurs (e.g. NullPointerException,ServletException,ViewExpiredException etc.)
Whenever a NPE occurs in my app, My customnavhandler breakpoint is hit and NavigationHandler code is executed, but somehow redirection to error page is not happening, the requested page remains partially rendered. Any idea what could be wrong here ? One info is that I am throwing an NPE deliberately on the requested page (which was partiallyu rendered after NPE)
My faces-config.xml entry
<factory>
<exception-handler-factory>
com.common.exceptions.CustomExceptionHandlerFactory
</exception-handler-factory>
</factory>
My CustomNavHandler
public class CustomExceptionHandler extends ExceptionHandlerWrapper {
private static final Logger logger = Logger.getLogger("com.gbdreports.common.exception.CustomExceptionHandler");
private final ExceptionHandler wrapped;
public CustomExceptionHandler(ExceptionHandler wrapped) {
this.wrapped = wrapped;
}
#Override
public ExceptionHandler getWrapped() {
return this.wrapped;
}
public void handle() throws FacesException {
final Iterator<ExceptionQueuedEvent> i = getUnhandledExceptionQueuedEvents().iterator();
while (i.hasNext()) {
ExceptionQueuedEvent event = i.next();
ExceptionQueuedEventContext context =
(ExceptionQueuedEventContext) event.getSource();
// get the exception from context
Throwable t = context.getException();
final FacesContext fc = FacesContext.getCurrentInstance();
final ExternalContext externalContext = fc.getExternalContext();
final Map<String, Object> requestMap = fc.getExternalContext().getRequestMap();
final ConfigurableNavigationHandler nav = (ConfigurableNavigationHandler) fc.getApplication().getNavigationHandler();
//here you do what ever you want with exception
try {
//log error ?
logger.error("Severe Exception Occured");
//log.log(Level.SEVERE, "Critical Exception!", t);
//redirect error page
requestMap.put("exceptionMessage", t.getMessage());
nav.performNavigation("/TestPRoject/error.xhtml");
fc.renderResponse();
// remove the comment below if you want to report the error in a jsf error message
//JsfUtil.addErrorMessage(t.getMessage());
}
finally {
//remove it from queue
i.remove(); }
}
//parent hanle
getWrapped().handle();
}
}
My customNavhandler factory
public class CustomExceptionHandlerFactory extends ExceptionHandlerFactory {
private ExceptionHandlerFactory parent;
public CustomExceptionHandlerFactory(ExceptionHandlerFactory parent) {
this.parent = parent;
}
#Override
public ExceptionHandler getExceptionHandler() {
return new CustomExceptionHandler (parent.getExceptionHandler());
}
}
It's most likely because the current request is an ajax (asynchronous) request. The exception handler which you've there is designed for regular (synchronous) requests.
The proper way to change the view in case of an ajax exception is as follows:
String viewId = "/error.xhtml";
ViewHandler viewHandler = context.getApplication().getViewHandler();
context.setViewRoot(viewHandler.createView(context, viewId));
context.getPartialViewContext().setRenderAll(true);
context.renderResponse();
This is however somewhat naive. This won't work if the ajax exception is been thrown in midst of rendering of a ajax response.
I'd suggest to not reinvent the wheel. The JSF utility library OmniFaces has a complete working solution in flavor of FullAjaxExceptionHandler. You can find the full source code here and the showcase example here. It makes use of standard servlet API <error-page> declarations in web.xml. This way the error pages are also reusable for synchronous requests, with a little help of FacesExceptionFilter, also provided by OmniFaces.
See also:
using ExternalContext.dispatch in JSF error handler causes corrupt page rendering
What is the correct way to deal with JSF 2.0 exceptions for AJAXified components?
Unified way to handle both ajax and non ajax requests exception could be done simplifying your code. Instead of
requestMap.put("exceptionMessage", t.getMessage());
nav.performNavigation("/TestPRoject/error.xhtml");
fc.renderResponse();
is enough to use:
fc.getExternalContext().redirect("/TestPRoject/error.xhtml");
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.
I'm trying to implement a remember-me function in my java ee 6 application, but I have issues combining it with the build-in security feature. I have the following configuration in my web.xml:
<login-config>
<auth-method>FORM</auth-method>
<realm-name>my-realm</realm-name>
<form-login-config>
<form-login-page>/login.jsf</form-login-page>
<form-error-page>/login.jsf</form-error-page>
</form-login-config>
</login-config>
What I'm trying to create is a filter that automatically logs a person in of their session is expired, if they have a cookie containing some data. This works, but when the filter is called, the redirect to login.jsf has already come into effect, before I have a change to do anything about it. I assumed that filters are called before java ee's own security system since they actually are called on secured pages, but this seems to not be the case. Is there some way to let the user come to the same page that they requested instead of being redirected to login.jsf?
Filter:
#WebFilter(
filterName="authFilter",
servletNames={
"Faces Servlet"
}
)
public class AuthFilter implements Filter {
public AuthFilter() {
}
#Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) request;
HttpServletResponse res = (HttpServletResponse) response;
User user = (User)req.getSession().getAttribute("user");
if(user == null){
String uuid = CookieUtil.getCookieValue(req, "rememberme");
if(uuid != null){
UserBean userBean = EJBUtil.lookup(UserBean.class);
RememberMe rememberme = userBean.findRememberMe(uuid);
if(rememberme != null){
user = rememberme.getUser();
try{
req.login(user.getEmail(), user.getPasswordDigest());
req.getSession().setAttribute("user", user);
CookieUtil.addCookie(res, "rememberme", uuid, CookieUtil.AGE_ONE_YEAR);
}catch(ServletException e){}
}
else{
CookieUtil.removeCookie(res, "rememberme");
}
}
}
chain.doFilter(request, response);
}
#Override
public void destroy() {
}
#Override
public void init(FilterConfig filterConfig) throws ServletException {
}
}
Container managed authentication is indeed invoked before all filters. This is a security restriction.
You've basically 3 options:
Use programmatic filtering and login instead so that you have more finer grained control.
Do the job in preRenderView event method of the bean associated with login.jsf instead.
Grab a framework which supports "Remember me" facility on top of container managed security transparently, such as Apache Shiro or Spring Security.