Keep a session alive for an indefinite amount of time - jsf

Is there a way to keep a page's session active without resorting to sending the state to the client? I'm not able to set the STATE_SAVING_METHOD to client and I'd prefer to not use the a4j:keepalive.
I've tried using a simple hidden iframe that submits to the Bean in question but it invalidates the main page.
I am using JSF 1.2 and myfaces.
This is to get around a ViewExpiredException on a page that does not require the user to log in. The majority of the existing site requires the user to log in.

Implement an ajax poll as a "heartbeat" to keep the session alive. At its simplest you can achieve this as follows with help of a little jQuery to avoid boilerplate code of 100 lines to get it to work across all different browsers the world is aware of:
<script src="http://code.jquery.com/jquery-latest.min.js"></script>
<script>
$(document).ready(function() {
setInterval(function() {
$.get("${pageContext.request.contextPath}/poll");
}, ${(pageContext.session.maxInactiveInterval - 10) * 1000});
});
</script>
The ${pageContext.session.maxInactiveInterval} prints the remaining seconds the session has yet to live according to the server side configuration (which is by the way controllable by <session-timeout> in web.xml) and is been deducted with 10 seconds, just to be on time before it automatically expires, and converted to milliseconds so that it suits what setInterval() expects.
The $.get() sends an ajax GET request on the given URL. For the above example, you need to map a servlet on the URL pattern of /poll and does basically the following in the doGet() method:
request.getSession(); // Keep session alive.
That should be it.

BalusC's answer helped me to meet this requirement in my app, but since I'm using PrimeFaces, I wanted to share how BalusC's answer inspired the code i'm using to do this.
xhtml page
<p:poll listener="#{pf_usersController.keepUserSessionAlive()}"
interval="#{session.maxInactiveInterval - 10}" />
bean
public void keepUserSessionAlive() {
FacesContext context = FacesContext.getCurrentInstance();
HttpServletRequest request = (HttpServletRequest) context.getExternalContext().getRequest();
request.getSession();
}
as always, thank you, BalusC!
EDIT: An enduser put this to the test this morning, and it is working great! my app usually forces session timeout 15 minutes after full page refresh (redirect to sessionExpired.xhtml via meta refresh based on session.maxInactiveInterval and session timeout value in web.xml); if user is on one page doing a bunch of AJAX requests, session will timeout, since AJAX != full page refresh, but this code allowed enduser to 'keep session alive' while enduser was on payroll page in the app, and session stayed alive for 1 to 2 hours! :)

Related

Java EE Container based Certificate authentication logout

In our Java EE application we use container based certificate authentication. We have created JAASLoginModule, which implements LoginModule interface with all required methods. We have configured our Wildfly and TomEE server to use this module both for authentication and ssl channel security, and everything goes smoothly with user login:
the user opens the browser and the app;
selects a certificate;
a JSF session is created, and now he is logged in;
A different story is with the logout. Just destroying the JSF session is not enough - after logout, if you just click back, the browser will get the certificate info from cache, recreate a session and lets you do the same stuff. Sometimes even browser restart does not help.
I could not find an effective way to call the logout method from the LoginModule from the JSF managed bean.
Any way to solve this problem?
Your problem is directly with the browser, so what you need is to tell the browser to "restart" the cache from your page every time it logs out, this, in order for it to think it's the first time the client is trying to get into that page. Kind of the same that private windows in Chrome and Firefox do.
Try this code:
//...
response.setHeader("Cache-Control","no-cache"); //Forces caches to obtain a new copy of the page from the origin server
response.setHeader("Cache-Control","no-store"); //Directs caches not to store the page under any circumstance
response.setDateHeader("Expires", 0); //Causes the proxy cache to see the page as "stale"
response.setHeader("Pragma","no-cache"); //HTTP 1.0 backward compatibility
//can check userId or something likes this.In this sample, i checked with userName.
String userName = (String) session.getAttribute("User");
if (null == userName) {
request.setAttribute("Error", "Session has ended. Please login.");
RequestDispatcher rd = request.getRequestDispatcher("login.jsp");
rd.forward(request, response);
}
Source: How to clear browser cache using java

Writing plain HTML in a JSF based web application

I have this use case in a JSF application.
Supposed in a JSF web application, I have a button that calls an external service that returns a complete HTML response then how can I show that HTML response to my users browsers?
The sequence of events are like this.
In user browser, my application is displayed. A button is there that user can click.
Clicking the button will call an external service. The external service will return information about a certain HTML tags. The HTML is complete with both head/body and with javascript. Currently the service can be implemented thru REST service or a plain DB call then
How can I display that HTML tag in my user browser?
Is this possible to write non-JSF output in a JSF web application?
Just to add, I think my problem is how to write an HTML in my backing bean and write it back to the users browser.
Just write it outright to the HTTP response body whereafter you instruct JSF that the response is manually completed. The principle is not much different from How to provide a file download from a JSF backing bean?, except that you need to set content disposition to inline (which is already the default anyway).
public void writeHtmlResponse() throws IOException {
FacesContext fc = FacesContext.getCurrentInstance();
ExternalContext ec = fc.getExternalContext();
ec.setResponseContentType("text/html;charset=UTF-8");
ec.setResponseCharacterEncoding("UTF-8");
ec.getResponseOutputStream().write(html.getBytes("UTF-8"));
fc.responseComplete(); // Important! Otherwise JSF will attempt to render the response which obviously will fail since it's already written with a file and closed.
}

How to write servlet filter to destroy all cookies related to domain on browser

I am new to servlet filter.
I am using JSF 2.2, Wildfly 8.1. I have figured out that if user clicks log out link when session is already expired then when user logs in again the system will continiously fire exception of session expired. BalusC wrote to write servlet filter which will delete all cookies of specific domain before user will see welcome page.
How to write servlet filter which will destroy all cookies related to specific domain (domain.com) when new session will start? I played with it and absolutely confused. sorry for my a little experience in jsf.
I think you need to set cookie.setMaxAge(0);for all the cookie for that domain.
Inside your filter(which should be used for Logout request only) or in Logout servlet(if any) you can write below line to delete all cookie.
Cookie[] cookies = req.getCookies();
if(cookies != null){
for(Cookie cookie : cookies){
cookie.setValue("");
cookie.setPath("/");
cookie.setMaxAge(0);
resp.addCookie(cookie)
}
}

JSF to Bean to JSF

So I'm having a problem trying to pass a String value.
The String value is entered through a login page as username.
The JSF then calls the Bean to verify log in information then proceeds to another JSF page.
I was wondering how to pass the username along to the new JSF page. Thank you.
If you're performing a navigation instead of a redirect, then you basically don't need to do anything. The information is also just available in the navigated page.
E.g. in login page,
<h:inputText value="#{bean.username}" />
and in the navigated page:
<p>You have entered the following username: #{bean.username}</p>
If you're however performing a redirect instead of a navigation, then you basically need to store the information in a bit broader scope. You didn't clearly elaborate the concrete functional requirement in the question, but if I guess it right, you just wanted to remember the currently logged-in user for the remaining of the HTTP session. In that case, just store it in the session scope during the login action.
public String login() {
// ...
User user = userService.find(username, password);
// ...
externalContext.getSessionMap().put("user", user);
// ...
return "nextpage?faces-redirect=true";
}
This way it's available by #{user} throughout the entire HTTP session.
<p>You're logged in as #{user.name}.</p>
You can also use <t:saveState> without using session scope. <t:saveState> is longer than the request scope but shorter than session scope.
This may help you : http://myfaces.apache.org/tomahawk-project/tomahawk12/tagdoc/t_saveState.html

How to detect session has been invalidated in JSF 2?

In my application I have a quit button, on clicking of which the session for the current user is invalidated by the following piece of the code..
FacesContext.getCurrentInstance().getExternalContext().invalidateSession();
And I redirect the user to a different page.
But now I want if user click on the back button I will take him to the start page of the application instead of the last page visted by him.
I have an application phase listener which sets the page cache related headers to 'none', now all I want is to detect that for that user session has been invalidated.
But I guess whenever the user is clicking the back button it is creating a new session for the user. Is there any way to prevent it?
How to detect session has been invalidated in JSF 2?
Check if the user has requested a session ID which is not valid.
HttpServletRequest request = (HttpServletRequest) externalContext.getRequest();
if (request.getRequestedSessionId() != null && !request.isRequestedSessionIdValid()) {
// Session has been invalidated during the previous request.
}
it is creating a new session for the user. Is there any way to prevent it?
Just don't let your application code create the session then. The session will implicitly be created when your application needs to store something in the session, e.g. view or session scoped beans, or the view state of a <h:form>, etc.
I have an application phase listener which sets the page cache related headers to 'none'
A servlet filter is a better place for this. See also Avoid back button on JSF web application

Resources