8
votes

I have a JSF application that uses Mojarra 2.2.9 and is deployed on WebSphere 8.5.5.4 on clustered environement and javax.faces.STATE_SAVING_METHOD is set to client.

Even though all my application beans are request scoped, sometimes when the user session is valid and the user is doing post request on a page he gets ViewExpiredException. What may be causing this issue and how can I solve it? Will changing the javax.faces.STATE_SAVING_METHOD to server solve it? If so, what is the impact of doing this on memory?

Also, does this have anything to do with cluster environement and maybe there's some missing configuration on the Websphere that will solve the issue?

2
To exclude the obvious, do you have <distributable /> in web.xml? - BalusC
@BalusC, no i don't have it - Mahmoud Saleh
@BalusC, if i configured session affinity in websphere, will i still have to add this tag in the web.xml of my application ? - Mahmoud Saleh
@BalusC Is it possible to get a ViewExpiredException when using client state saving? I am curious because I always thought it was impossible. - hwibell
@hwibell: by default on a single server it's impossible. But in a cluster it can be thrown when the view is serialized in one server and deserialized in other server without having configured the app as distributable and having set jsf/ClientSideSecretKey (but that would have caused a "MAC did not verify" error, not a VEE, so it's kind of weird here). On a single server it can also be thrown if com.sun.faces.clientStateTimeout is set, but this is unlikely the case here. - BalusC

2 Answers

12
votes

This will happen if the client side state is encrypted by one server and decrypted by other server and the servers don't use the same AES key for this. Normally, you should also have seen below warning in server log:

ERROR: MAC did not verify

You need to ensure that you have set jsf/ClientSideSecretKey in web.xml with a fixed AES key, otherwise each server will (re)generate its own AES key during startup/restart (which is used during encrypting view state).

<env-entry>
    <env-entry-name>jsf/ClientSideSecretKey</env-entry-name>
    <env-entry-type>java.lang.String</env-entry-type>
    <env-entry-value>[AES key in Base64 format]</env-entry-value>
</env-entry>

You can use this snippet to generate a random AES256 (32bit) key in Base64 format.

KeyGenerator keyGen = KeyGenerator.getInstance("AES");
keyGen.init(256); // Use 128 for 16bit key.
String key = Base64.getEncoder().encodeToString(keyGen.generateKey().getEncoded());
System.out.println(key); // Prints AES key in Base64 format.

In case you get Java Security: Illegal key size or default parameters? error, install the cryptography extension as instructed in the link, or else generate a random AES128 (16bit) key instead.

After having the key, make absolutely sure you don't publish/opensource your key.

Further you also need to ensure you have added <distributable /> tag to web.xml so JSF will perform more agressive session dirtying and the HTTP sessions (including view scoped beans themselves!) are properly synced across servers.

Another probable cause of ViewExpiredException with client side state saving is that you've set the Mojarra-specific context param com.sun.faces.clientStateTimeout in web.xml which represents the time in seconds before an incoming client side state is considered expired. This is however unlikely the case here as that context param has a rather self-explaining name which you would have spotted by just glancing over web.xml.

See also:

2
votes

You must have the distributable tag in your web.xml as mentioned by balusc