Handling an expired ViewState in JSF and Richfaces - java

I have a series signup pages that build on each other. When the users session expires I have a Listener that cleans everything up on the server and that works great. But, if the user attempts to do anything else I just want to redirect them back to the first page of the series. However, my filter doesn't seem to work correctly. I keep getting javax.faces.application.ViewExpiredException
What is the best practice for handling this expcetion? I can't really just handle in web.xml because that's too global. Plus the Error page is being rendered from some JSF code - it seems like I need to catch that this is happening using a PhaseListener so the exception doesn't happen in the first place, but I haven't been able to find a good model for how to do this. Any ideas?

Richfaces has their own mechanism for handling ViewExpiredException, look at Richfaces docs.

I think you are the correct track with a phase listener. Essentially set something up in session on the first page. Then in phase listener look for the value in session. If it doesn't exit then do a redirect. The trick is to do it early in the phase listener process.
Not sure exactly where in the process your phase listener is throwing the exception.

The way I handle this is to add a filter to the web.xml only mapped to the urls you want to track. That filter checks if the session is expired, and then forwards to a login page if it is. It should work if the filter is run before any JSF code is run.

The way I have handled this in the past is to use a listener which checks a field in a managed session bean. If the users session times out a listener cleans up the mbean and marks the user as not logged in. Every request is sent through the listener and if the requirements are not met then the user is forced out of the site. I never get ViewExpiredException in my log. The only time this exception has occurred is if the server has been restarted and the user requests a page when having a previous active session.

You can check whether you session is invalidate or not
boolean sessionInValid = httpServletRequest.getRequestedSessionId()
!= null &&
!httpServletRequest.isRequestedSessionIdValid();
Here the boolean variable sessionInValid will return true if the session is invalidate by any means.
You can add this in a filter or a listener then configure this in your web.xml file.

Related

Prevent session's last access time update in Jetty

Is it possible to instruct a Jetty server not to update the session's last access time when a particular servlet is accessed?
Our use case is an HTML page that sends asynchronous requests in the background every 5 miniutes to refresh its contents. The session's timeout is set to 30 minutes.
The unfortunate problem with this configuration is that when a user leaves that page open in a browser's tab, the session never expires because the access time of the session is updated by every asynchronous request.
For correctness' sake I have to admit that I didn't try anything yet because I wasn't able to find any help for my issue on the Internet. If what I'm asking for is not possible, I'm thinking of storing the access time in a session's variable that is controlled directly by the application. This value would have to be checked early before a request is processed (in the doGet and doPost methods of the servlets) and the session would need to be invalidated manually. Is there a better solution?
Servlet can't distinguish if the request is generated by some script or human, since both requests come from a same browser, consequently sending the same JSESSIONID. So you have to mark those requests in order to distinguish its source. You can mark them by some header or request parameter.
I like your idea of storing access time in session's variable (it will piggy back on servlet session expiry)
Your algorithm will be in this case:
if isUser(request){
session.lastRobotAccess == null
}else{
if (session.lastRobotAccess == null) {
session.lastRobotAccess = current_time
} else {
if(current_time - session.lastRobotAccess > session.timeout){
session.invalidate
}
}
}
When request arrives at servlet container it is first processed by the filters (if you have defined) and then by the servlet. Filters are useful for:
A common scenario for a filter is one in which you want to apply
preprocessing or postprocessing to requests or responses for a group
of servlets, not just a single servlet. If you need to modify the
request or response for just one servlet, there is no need to create a
filter—just do what is required directly in the servlet itself.
Since you can reach session from filter, they are more suitable place for your logic. You won't pollute servlet's logic with additional checking, and you can apply it to other servlets. Filters are also part of servlet specification so this will work in any container.
You already knew this things, but I've just put them on "paper" :-D

Allow only one session per user

We have a web-application developed using struts2, spring & hibernate.
The application needs a functionality that one user can login from only one browser.
Say if user x, is logged in on pc-1 browser ff, then he cannot be logged in from any other place.
I tried it by implemention session map and store the sessions in global map, but this fails when user logs off and tries to login again.
Even it fails critically if the user does not logs off and session time-outs, but the map is not cleared.
Any better idea to implement this functionality.
We do not want to obstruct the user to login but do not want users to exploit the application by allowing him to share the creditionals and allow multiple users with same login to happen.
Since you are already using Spring, I would recommend you to integrate your application with Spring Security.
Spring security lets you define maximum sessions allowed per user concurrently.
<session-management>
<concurrency-control max-sessions="1" />
</session-management>
If set when user having valid session tries to login again it will inform user that maximum concurrent access is set to 1.
Read more at the reference documentation of Spring Security: v3.2.x, v4.2.x or v5.1.x.
If spring security is not an option for you then:
Use a SessionInterceptor which will check for session validity, if session is valid it will check if user is already logged in to the application (for this you will have to maintain session somewhere for eg database for every successful login), if valid login is found, redirect user again to login page with custom message, or logout already valid session and then redirect him to login again. If you logout earlier session it would mean any successive action in that browser session will have to deal with invalid session.
If case you are also using Servlet in your application then Interceptor wont work for you, in this case you should use a Filter and follow the same steps as detailed above for Interceptor.
The best solution is to log-off user from other session when he logs in in new session. It is often that user would not logoff when closing browser and restricting him from logging in other window would be the pitfall.
Automaticly closing any previous user sessions is good, because in normal usage, it is no problem, but when sharing login and password, no two persons can work simultanously with your application.
At the login give the user a generated ID/cookie (sessionid suffices) stored with the user data. If a user does a request to the server with an old ID/cookie, say that he logged in elsewhere.
The other way round, forbidding the new login attempt, has its drawbacks - as you've experienced.
Create a map.
At the time of logging check that user id is present into that map or not.
If its not exist then put user id into map, at the time of logout remove that user id.
To be honest I would revisit the reasons why you have to restrict a user to a single login. Whilst preventing them from logging in from two different browsers is easy enough - any of the suggestions provided would work - with the Spring Security option being the easiest to implement if you can - they all break down when your user opens a second tab in the same browser. That is considered to be part of the same session.
Maintain user stack in servlet context,as it will be one for web container.perform a check before user getting logged in, if user name found in servlet context redirect him to login page.
All you should do is add a field in database userprofile table saying: alreadyLogin.
If user logins, make it Y. If user logs out, make it N. Now every time when user tries to login from new location, check this value and prevent login if Value is Y.
As many said, you can have a Map<String, User> (static Map or better an attribute in ServletContext) of (sessionId, user) of active users.
When a user tries to login, first check the existence in theMap.values(), and if it is okay add it to theMap.
Instead of removing from theMap on logout, implement a javax.servlet.http.HttpSessionListener, and on sessionDestroyed method, remove the item from it (the parameter of the method gives you the sessionId). This way if a user closes the browser, after session timeout period, it will be removed automatically.
On logout, invalidate the session, so it will be destroyed, and again this listener get executed.
Don't forget adding the listener to your web.xml.

Seam/JSF - Multiple messages on login failure?

I'm using JBoss Seam 2.2 in my application, and am seeing some strange behavior in the way login failures are handled. When a user fails authentication using #{identity.login}, I see multiple JSF messages being displayed. One has the message key org.jboss.seam.loginFailed, while the other has the key org.jboss.seam.NotLoggedIn. I would obviously expect the first message, as that corresponds to entering an incorrect password. However, why is the second message being displayed? There's no reason for it. I'd like to be able to remove that from the list of messages displayed when it's not necessary, but I haven't found a way to do so. Thoughts?
org.jboss.seam.security.FacesSecurityEvents adds the org.jboss.seam.NotLoggedIn message when it observes the org.jboss.seam.security.notLoggedIn event. The org.jboss.seam.security.notLoggedIn event is raised when an attempt is made to access a resource that requires a certain level of authorization, but the user is not logged in.
After authentication fails, is the user being redirected to a protected page? Do you have any custom login logic that might be accessing a protected resource?
I suggest providing your pages.xml, components.xml, and any custom authentication logic you might have.

Make javax.servlet.http.HttpSession not timeout on certain pages

I'm refactoring an application which was doing its own session timeout management. I noted that the HttpSession supports setting a timeout value.
There is an event listener (HttpSessionListener I assume) that is redirecting to a 'timeout' page. "We're sorry your session expired, heres a link to the login page" kind of thing.
The problem is that when I first hit the app and am sitting on the login page, the session timeout event still fires. So I can be looking at the login page and get redirected to the timeout page.
What I want to happen is that if I am on the login page and only on the login page, that the session timeout does not occur. How do I do this?
I have already tried calling HttpSession.setMaxInactiveInterval(-1) in the default view resolution in the login's ActionBean, but that did not work.
I believe the session is being created, but not necessarily authenticated, whenever any page is accessed.
Where do you have the redirecting happening? If it's something declaratively set somewhere in a configuration file you could remove it and implement the HttpSessionListener interface.
In the sessionDestroyed method u would make the following:
Get the session from the sessionEvent
If the session contained an authentication flag then redirect
U could also keep the last page requested by the user and use that as a reference to determine whether to redirect or not but what do you do if a user is already authenticated and browses to the login page? I do not have a lot of information about your application.
Anyway the HttpSessionListener is the way to go I think.

JSF, actionlistener at facelets

I'm using JSF (Mojarra 1.2) with Richfaces (3.3.2) within some facelets which are used as portlets (I'm using the Jboss Portlet Bridge 2.0 here). Now I'm facing something strange: I've got an actionlistener on my <h:commandButton> which is triggered, when the button is clicked but when I simply reload the page, the action is executed everytime I load the page again. This happens only if I already triggered the action before. Is this behaviour normal?
I should notice that Spring 2.5 is used to manage my beans, the mentioned beans are session-scope beans, maybe this is a interessting point?!
Yes, reloading a HTTP POST request will execute the HTTP POST request again and thus trigger all associated server-side actions again. This issue affects all webapplications in general and is not per se related to JSF.
A well known fix to this is the POST-Redirect-GET (PRG) pattern. Basically you need to redirect the POST request to a GET request immediately after processing the action, so that the result page will be delivered by a HTTP GET request. Refreshing this HTTP GET request won't execute the initial HTTP POST request anymore.
This pattern has however one caveat: since it concerns a brand new request, all request scoped beans are garbaged and renewed in the new request. So if you'd like to retain the data in the new request, you would need to either pass them as GET parameters or to store it in the session scope. Usually just reloading the data in bean's constructor is sufficient. But since you mention to use session scoped beans only (which is however not the best practice, but this aside), this shouldn't be a big concern for you.
Turning on PRG in JSF is relatively easy, just add the following entry to the associated <navigation-case>:
<redirect />
Or if you prefer to fire it programmatically, then make use of ExternalContext#redirect() in the bean's action method:
public void submit(ActionEvent event) {
// ...
FacesContext.getCurrentInstance().getExternalContext().redirect(someURL);
}

Categories

Resources