We recently upgraded a major platform from jsf 1.2 to 2.0. After upgrading we're getting several ViewExpiredException errors each hour. From reading up on the topic it seems that this is an expected exception when sessions expire, however we've reviewed the access logs and we are getting these exceptions even when requests are only 5 minutes apart in some cases.
My questions are as follows:
1) Other than session expiration, what other conditions might cause ViewExpiredException?
2) The exception we're logging doesn't contain much detail about the exact condition that is causing the exception (missing session, corrupt session, unable to restore a particular component). Is there a way to introduce additional logging to find out the very specific situation that is triggering this exception in each case?
Mojarra 2.0.4-b09
Tomcat 6
Using Memcached Session Manager for session replication
Any help is appreciated. Thanks!
Other than session expiration, what other conditions might cause ViewExpiredException?
The enduser has requested/created too much views within a session and is submitting to an old view. The default max views per session is 15. In other words, if the enduser opens 16 browser windows/tabs on a page with a form within the same session and submits to the first one, then the user can get ViewExpiredException.
The max views per session is configureable in web.xml by
<context-param>
<param-name>com.sun.faces.numberOfViewsInSession</param-name>
<param-value>15</param-value>
</context-param>
See also Mojarra FAQ for other parameters.
Is there a way to introduce additional logging to find out the very specific situation that is triggering this exception in each case?
Not through JSF and/or a ViewExpiredException. The whole exception just means that the view is not present in the session anymore. This can in turn indeed have more underlying causes. Logging the session creation and destroy using a HttpSessionListener and logging the session attribute modifications by HttpSessionAttributeListener may be helpful.
Update as per the comments, pressing the browser back button on a cached page containing a form and then submitting the form thereafter could indeed also cause ViewExpiredException when the view is been expired. This can be solved in following two ways, preferably in a combination of them:
Instruct the browser to not cache the pages.
Do not use POST forms for plain page-to-page navigation.
For more detail, see this answer.
Related
I have a basic question about JSF ManagedBeans for which I can't find a answer.
Suppose I have a bean MyBean with two methods method1 and method2 and a JSF page with a command link
<h:commandLink action="#{myBean.method1}">
</h:commandLink>
Is it possible for someone to analyse the source code of the page and call method2 instead of method1?
Answer
No, this is not possible by design.
Reasoning
Technically the client can only tell the server "The user clicked a html element with a certain id".
This event is then processed by JSF on the server-side, the component with the corresponding id is looked up and in this case the method "#{myBean.method1}" is executed.
As you can see, the client can not[!] tell the server what to do with this event.
Sources
JSF 2.2 Spec - 3.4 Event and Listener Model
Caveat
JSF is stateful and there are multiple ways to hold this state. The default is to hold state information server-side (e.g. in the users HttpSession).
Another option is to transfer (encrypted) state to and from the client. This is still conceptionally secure, but there *might* be bugs with client side state saving. Such a bug *could* be exploitable to do something like you described.
Yes, it is always possible to modify code (or markup-language) on the client-side. Your "action" will be called through some forms and/or Javascript-Methods - everything visible to experienced users.
But that's not an issue of JSF-2 only - this applies for every language which allows insights from the client side.
You shouldn't apply "security through obscurity" (https://en.wikipedia.org/wiki/Security_through_obscurity) but rather make sure, that you can handle this on the server-side.
If a user, who has access to two urls modifies url1 to url2 - that's fine, why not? (Could be bookmarked) - But YOU should take care of the modified request, if he is not allowed to access url2.
I'm using Myfaces 2.2 with Client-side state saving. I see that the ViewScoped beans & data stored in viewmap is lost after the user session is destroyed.
I came to know, not sure if it is correct, that this is the expected behavior but then what's the way to avoid view expired exceptions after session destroy?
My problem is that I destroy the user session pretty quickly after some inactivity period(like after 20 minutes) but I want the viewscope data to survive even after that(when using client saving) so that when the user comes back after session destroy, he doesn't need to do a page refresh. I dont know why & how this is so implemented but It is very normal that the user may be busy reading some section of website or be away for 20 minutes, & as he comes back & interacts with opened pages, how would I make that work without the state ?
I think this is a common requirement for any public websites.
I think the internally used jsf viewstate is not lost, if I use client side state saving(as my pages still work), but then why are those viewscoped beans scoped that were also serialized to page along with the viewstate.
If this the designed behavior, Is there any way I could make the view scoped data survive session expiration ?
An answer that I got from the myfaces users mailing list:
viewRoot.getAttributes() map could be used to persist the viewscoped values even after session destroys. Thus instead of storing values to viewRoot.getViewMap(), store in the map returned by viewRoot.getAttributes(). However care should to be taken to ensure that the stored values are serializable.
For ages I've been puzzled about why after login I sometimes don't directed to the application welcome page. I've finally figured it out (years after everyone else):
I login successfully via j_security_check and go to the welcome page
wait for session timeout
click on h:link which sends a GET request
because it's a GET and not a POST my custom ViewExpiredException
handler doesn't kick in
container security redirects to the login page because the session
has timed out. Because of the session timeout+container security the
get request (from h:link) isn't seen by the application, in either a phase listener
or filter.
I successfully login again
j_security_check redirects me to the page which triggered the
authentication, in this case the target of the GET request.
The last bit I'd not understood, I assumed it would always go to the welcome page.
My problem is that my current design requires that after login I always show the welcome page. The welcome page has a preRenderView event which sets up some context information in a session scoped bean after login and increments a few counters etc...
This context information is required by backing bean code for other pages, and presently if I don't go through the welcome page first there'll be an exception.
In terms of fixing it I've looked at the following options:
Ideally there'd be an #PostLogin method that could be called, which would cleanly solve all my problems. I use JSF (Mojarra) with Myfaces CODI but I don't see anything which does what I want.
I could add some more code to my filter, but I need to persist some data (i.e. login count), it doesn't look like a nice option. Maybe I'm wrong.
I make all the preRenderView methods of potential targets of j_security_check (pages called with GET) handle the case where they are called directly from j_seecurity_check. I can see this being what I have to do but it seems like a lot of hassle.
Write a Server Authentication Module for glassfish to override j_security_check behavior.
How is this normally handled? I've started hitting this problem after moving to GETs for simple navigation cases after years of abusing POSTs, and the custom exception handler doesn't work. If anyone has any guidance on this issue I'd appreciate it, at least I know what's going on now. Hopefully I've missed something obvious!
Thanks
O/S
Ideally there'd be an #PostLogin method that could be called, which would cleanly solve all my problems. I use JSF (Mojarra) with Myfaces CODI but I don't see anything which does what I want.
There is indeed no such thing.
I could add some more code to my filter, but I need to persist some data (i.e. login count), it doesn't look like a nice option. Maybe I'm wrong.
That would indeed be the "easiest" way. Basically:
UserPrincipal user = request.getUserPrincipal();
HttpSession session = request.getSession();
if (user != null && session.getAttribute("user") == null) {
session.setAttribute("user", user);
// First-time login. You can do your intercepting thing here.
response.sendRedirect(request.getContextPath() + "/welcome.xhtml");
}
I make all the preRenderView methods of potential targets of j_security_check (pages called with GET) handle the case where they are called directly from j_seecurity_check. I can see this being what I have to do but it seems like a lot of hassle.
That's not DRY.
Write a Server Authentication Module for glassfish to override j_security_check behavior.
Can't answer that as I've never done that.
In a jsf application I have a table with summarized data. If I'm interested in the details I can click on a row an see the details in another page.
If the managed bean of the 'master' page is ion view scope it is re-created every time I return back from the 'detail' page and I don't think it is a good idea if the user is supposed to check the details more times. I can solve putting the bean in sessions cope but this way the bean (and the data) are kept in memory also when the user is interacting with the application in a completely different section. Probably I would need a custom scope but:
the documentation about custom scope is poor and I'm a bit frightened about people complaining it has bugs and doesn't work well.
the scenario I'm dealing with seems to me quite general, so I wonder why there is no ready solution for it.
Thanks
Filippo
If the detail page has to be idempotent (i.e. it's permalinkable, bookmarkable, searchbot-crawlable), just use two request or view scoped beans and use a GET link with the entity ID as request parameter to go from master page to detail page. See also Creating master-detail pages for entities, how to link them and which bean scope to choose for a concrete example.
If the detail page does not need to be idempotent, then you can always conditionally render the master and detail in the very same view or even display the detail in some modal dialog from the master page on. This way you can continue with a single view scoped bean.
In JSF side you must not be too much worried about the DB performance cost. Rather configure and finetune it in the persistence layer. In JPA for example you can setup a second level cache. If you've much more than 500~1000 items, then consider database-level pagination.
It may be valid to reload the master page each time e.g. if the data could have changed after viewing the details page. However, if you want to keep the data available for longer than #ViewScoped your options are:
You should be using JEE6 of which JSF 2.0 is a part of, so look at Conversation Scope (part of CDI)
Some additional scopes for JEE6 CDI is available through the MyFaces CODI
Potentially use Session Scope and make sure you tidy up when a Request hits which is not for the Master or Details page
Rework your design to use Ajax, so if clicking a record on the Master page its details load in the same view. You could then use #ViewScoped
My preference would be to look at the Conversation Scope. You don't mention which JSF implementation you are running or in which environment.
I would like to set a particular page (one that does not require a user to sign in to use) to have a STATE_SAVING_METHOD of client rather than server while the rest of the pages use server. Is there a way to set it on a per-page basis?
I would like to do this to get around the dreaded ViewExpiredException.
There is no way. This is however been requested as new feature. See also JSF spec issue 1056.
To solve the particular ViewExpiredException issue, you need to look for alternative ways. You can just ask a new question here about specifically the issue you have. There are always ways to go around it.
The state saving method is set once in web.xml and is there for the whole app. If you don't want that particular view to expire you could do an ajax poll that "pings" the page in a specific interval of time and thus avoiding view expired exception. Kinda workaround but this is the way with stateful frameworks.