Invalidate Http Session in JSF2 on Logout - session

Version :
Apache MyFaces 2.1.14
Rich Faces 4.3.5
Issue :
I want to invalidate JSF session when user clicks on Logout page.
I have decided to use PreRenderViewEvent for the same.
Below is the design for the same :
When logout page is being rendered , call a listener method in back end bean through PreRenderViewEvent.
Invalidate JSF session in java method like : FacesContext.getCurrentInstance().getExternalContext().invalidateSession();
My question is : is this a right approach in invalidating session ? Or is there any better approach available ?
Code :
<!-- call this in Logout.xhtml page -->
<f:event listener="#{bean.invalidateSession}" type="preRenderView" />
EDIT 1:
Let me elaborate the context of the question.
I have two web applications in my system.
When a user clicks on Logout button it always goes to webApp1.
The requirement is to invalidate session in webApp1 and then redirect to webApp2 where again invalidate the session.
The preRenderView event will be used when webapp1 LogOut page is being rendered. The listener there will invalidate the session and redirect to webapp2 LogOut page like below code :
public void logOut(ComponentSystemEvent event) throws IOException{
//logoutAction param will be read from request
String redirectUrl = "/webapp2/Logout.xhtml?action="+logoutAction;
FacesContext.getCurrentInstance().getExternalContext().invalidateSession();
FacesContext.getCurrentInstance().getExternalContext().redirect(redirectUrl);
}

I usually just add a button to my template :
<h:commandLink action="#{loginBean.logout()}" value="Logout" rendered="#{!empty loginBean.account}" />
This button calls my "login" manager bean, which contains an attribute Account account, populated with the user's parameters. It's also only rendered if the user is connected.
public String logout()
{
setAccount(null);
FacesContext.getCurrentInstance().getExternalContext().getSessionMap().clear();
FacesContext.getCurrentInstance().getExternalContext().invalidateSession();
NavigationUtils.redirect("/admin/login");
return "";
}

Related

Pass parameters from webflow to redirected page

I have this issue.
I redirect the user to /login page after registration, but I want to pass attribute from end-state of webflow to login.html that says something like "you have registered successfully". How can I accomplish that?
Edit: By the way I use thymeleaf.
when User clicks on Signup button the method which handles the registration there you need to add Model and insert the message as the attribute and pass to the login page.
example:
//Suppose these is the method which handles the registeration
void register(Model model)
{
model.addAttribute("Message","You are successFully Login");
return "loginPage";
}
And in login.jsp you can get the Message object as:
${Message}

partial-response on session expire

We have a JSF 2.0, Primefaces 5.0, Spring Security 3.2.3.RELEASE application.
To handle session timeout, I am using primefaces idleMonitor and p:dialog & javascript to display a countdown popup and redirect them back to login page.
I have also implemented a custom CacheControlPhaseListener so that the pages are not cached. I set the no-cache in the response headers in the CacheControlPhaseListener.
<lifecycle><phase-listener id="nocache">com..filter.CacheControlPhaseListener</phase-listener></lifecycle>
I also have error handling configured in my web.xml:
<error-page>
<exception-type>javax.faces.application.ViewExpiredException</exception-type>
<location>/error.jsf</location></error-page>
I have also implemented a ViewExpiredHandler that extends ViewHandlerWrapper
#Override
public UIViewRoot restoreView(FacesContext ctx, String viewId)
{
UIViewRoot viewRoot = super.restoreView(ctx, viewId);
try
{
if (viewRoot == null)
{
viewRoot = super.createView(ctx, viewId);
ctx.setViewRoot(viewRoot);
}
}
catch (Exception e)
{
e.printStackTrace();
}
return viewRoot;
}
The problem I am still having is:
1. When the session expires on a idle page (E.g. Search page) and if some ajax action is triggered on a page, even though I logout, when I navigate back to the page (e.g. Login-> Home-> Search page). I see a partial-response xml error:
<partial-response><changes><update id="blGridId"><table id="blGridId" style="width:100%;">
<tbody>
<tr>
<td><div id="blTableId" class="ui-datatable ui-widget ui-datatable-scrollable ui-datatable-resizable"><div id="sublTableId_paginator_top" class="ui-paginator ui-paginator-top ui-widget-header ui-corner-top" role="navigation"><span class="ui-paginator-prev ui-state-default ui-corner-all ui-state-disabled"><span class="ui-icon ui-icon-seek-prev">p</span></span><span class="ui-paginator-next ui-state-default ui-corner-all ui-state-disabled"><span class="ui-icon ui-icon-seek-next">p</span></span></div><div class="ui-widget-header ui-datatable-scrollable-header"><div class="ui-datatable-scrollable-header-box"><table role="grid"><thead id="blTableId_head"><tr role="row"><th id="blTableId:j_idt101" class="ui-state-default ui-resizable-column" role="columnheader" style="width:34px; #width:37px;"><span class="ui-column-title"><span style="word-wrap: break-word;white-space: normal;">Client </span></span></th><th id="blTableId:j_idt104" class="ui-state-default
2. If I hit a browser refresh, it loads back the page and I can continue with the actions.
Please let me know what I need to do in addition to the above to resolve the partial-response error. Do I need to add a servlet filter to invalidate the session?
I would really appreciate any help and feedback on this as it is high priority.
I had got the same issue when session had been expired. I thought it was too late, but maybe would be helpful for others who has issues like me.
The root cause is Spring Security saves the last request before redirecting client to do the authentication. After then, Spring security would try to perform the request again when user visits the page of last request. Unfortunately, the request was ajax/partial and its view was expired -> partial xml content was returned.
Easy way to get rid of this issue is removing the saving behavior of Spring Security. SavedRequestAwareAuthenticationSuccessHandler class is used to handle these kind of behaviours. Configure as:
<bean id="authenticationFilter" class="org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter"
p:authenticationManager-ref="authenticationManager"
p:authenticationFailureHandler-ref="authenticationFailureHandler"
p:authenticationSuccessHandler-ref="authenticationSuccessHandler"
p:usernameParameter="username"
p:passwordParameter="password">
</bean>
...
<bean id="authenticationSuccessHandler" class="org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler"
p:defaultTargetUrl="/"
p:alwaysUseDefaultTargetUrl="true"/>
Hope it would help.

JSF AJAX and normal redirect to login and back to previous page

Current status :
If any session time out occurs, redirectToLogin function in FacesAjaxAwareUserFilter will be executed. From there I can redirect to any page I need. I get the URI in all cases.
It's all working fine and big thanks to BalusC. :)
Now the second part which makes the issue
Redirect to login and come back to the previous page.
For Eg :
Page 5----> Login------> Page 5
I have appended the redirect URI to the login URI and retrieved the values from the bean.
But the problem is that I have 2 pages before the user login. A login mode selection page (ie; google authentication or default login) and the page that reads the username and password.
How can I pass the redirect URI through both the pages.?
This is the code I have used to redirect at Ajax time out and in normal session time out.
Class FacesAjaxAwareUserFilter
if ("partial/ajax".equals(request.getHeader("Faces-Request"))) {
res.setContentType("text/xml");
res.setCharacterEncoding("UTF-8");
res.getWriter().printf(FACES_REDIRECT_XML, request.getContextPath() + getLoginUrl()+"?redirectUrlPattern="+request.getRequestURI());
}
else {
if (request.getRequestedSessionId()!=null && (!SecurityUtils.getSubject().isAuthenticated() || !request.isRequestedSessionIdValid())) {
response.sendRedirect(getLoginUrl()+"?redirectUrlPattern="+request.getRequestURI());
return;
}
super.redirectToLogin(req, res);
}
Method used is FullAjaxExceptionHandlerFactory in Omniface.
I have used a method of appending the values to the URI, but it fails to identify whether the session is expired or a session not created (when a user logs in at first).
Problem Code
if (request.getRequestedSessionId()!=null && (!SecurityUtils.getSubject().isAuthenticated() || !request.isRequestedSessionIdValid()))
I am looking for a way to identify the expired session from new session created before login.
Wish to implement this in a Better Way.
A method which will not append present URI with the redirect URL is most welcomed.
I have founded out a solution but still i don't find it as the best solution. Any other answer for doing it is greatly appreciated.
Step 1
Configure the application to detect Ajax Timeout and normal timeout. This is how i did it..!!
Step 2
Finding the URI when session timeout occurs, using this.
FacesAjaxAwareUserFilter will grab the ServletRequest and ServletResponse for you.
form that you can convert that to HttpServletRequest and HttpServletResponse using this
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response= (HttpServletResponse) res;
The request.getRequestURI() will get you the redirect URI
String redirectURI=request.getRequestURI();
Now you want to save this to some storage so that you can use it in any place you want. The only way i found is to append it with URL using this.
res.getWriter().printf(FACES_REDIRECT_XML, request.getContextPath() + "/sessionexpired"+"?redirectUrlPattern="+request.getRequestURI());
or
response.sendRedirect("/sessionexpired"+"?redirectUrlPattern="+request.getRequestURI());
Now on the page load of my sessionExpiry page bean, i used this to grab the value passed through the URL
redirectUrl=FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap().get("redirectUrlPattern");
Now using JavaScript i set that value of redirectUrl to localStorage. This is how you can save values to local storage.
This is my sessionexpiry.xhtml page.
<script type="text/javascript">
function setRedirectURIToLocalStorage(){
if(typeof(Storage)!=="undefined")
{
localStorage.redirectURI=document.getElementById("redirectUrl").value;
window.location.href="/login";
}
}
</script>
</h:head>
<h:body id="body" onload="setRedirectURIToLocalStorage()">
<f:view contentType="text/html">
<h:form prependId="false" >
<h:inputHidden id="redirectUrl" value="#{sessionExpBean.redirectUrl}" />
<h:outputText value="Session Expired... Redirecting...!!"></h:outputText>
</h:form>
</f:view>
</h:body>
The page will call setRedirectURIToLocalStorage() function onLoad
and then it set the values to the localStorage. Thus the redirect
value is available all across the browser. You can use that in any
page you need.!! All you need to do is to check in this variable
localStorage.redirectURI

How to handle authentication in Angular JS application

I am implementing an auth system in my angular js app.
What I am planning it like below:
Get user info(name and pass from login form)
Check whether user exists or not
if exists server respond with a session cookie and frontend will redirect to a certain page.
then user will do some task which will generate API request
API request should have cookie information that was sent on step 3
server check whether the cookie was generated or not and if cookie was found then respond with the API request results. And in my service I am doing something like
MyApp.service('myAuth', function($http, $q) {
this.authHeader = null;
this.checkAuth = function(){
//do api call and if success sets this.authHeader = response
}
this.isAuthenticaed = function(){
this.authHeader ? return this.authHeder : return false;
}
After submitting the login form I will call checkAuth and get my session cookie back from my server, how I can add the cookie information while doing the next REST call and also when user will navigate throughout the application after log in I do want to check each time isAuthenticaed true or false, in Angularjs when it will navigate to another page does it resets after setting it true from the first call? And is my approach 1-6 good or do you have any specific suggestions?
Btw I checked previous so entries but those are not what I want to know.
I am not sure about your backend, but this is how I would do it
Create a separate login page (dedicated url not angular sub view or
modal dialog).
If the user is not authenticated redirect to this login
page. This is done by server redirects. This page may or may not use
angular framework, as it just involves sending a user\password to
server.
Make a POST (not AJAX request) from the login page, and verify on server.
On the server set the auth cookie. (Different frameworks do it differently. ASP.Net sets form authentication cookie.)
Once the user is authenticated redirect user to the actual angular app and load all its components.
This saves any code require to manage authentication on client side in Angular. If the user lands on this page he is authenticated and has the cookie.
Also default browser behavior is to send all cookies associated with a domain with each request, so you don't have to worry if angular is sending some cookie or not.
I use the http-auth-interceptor. http://ngmodules.org/modules/http-auth-interceptor
In my backend (asp.net mvc) I build a simple Authentication Service and return an http error 401 if the user is not authenticated.
Then I handle the error with a login-view in the SPA site.
The ideas put forth by the previous answers will work, but I think they're overkill. You don't need anything this complex.
how I can add the cookie information while doing the next REST call
Turn on withCredentials by default inside $httpProvider like so:
app.config(['$httpProvider', function($httpProvider) {
$httpProvider.defaults.withCredentials = true;
}]);
Then remove the wildcard (if you had one) from the CORS-related headers, and set allow-credentials, on the server side. In my case, using Python + Flask + Flask-Restful, it's super easy and looks like this:
import Flask
from flask_restful import Api
app = Flask(__name__)
api = Api(app)
api.decorators = [cors.crossdomain(origin='http://localhost:8100', credentials=True)]
Now cookies will be set and returned automatically and transparently by the browser. See these threads for more info:
$http response Set-Cookie not accessible
Angularjs $http does not seem to understand "Set-Cookie" in the response
when user will navigate throughout the application after log in I do want to check each time isAuthenticaed true or false
As suggested above, have the server return 401 if the auth session expires or is deleted, and use $httpInterceptor in Angular to catch this like so:
app.config(function($httpProvider) {
var interceptor =
function($q, $rootScope) {
return {
'response': function(response) {
return response;
},
'responseError': function(rejection) {
if (rejection.status==401) {
// Modify this part to suit your needs.
// In my case I broadcast a message which is
// picked up elsewhere to show the login screen.
if (!rejection.config.url.endsWith('/login'))
{
$rootScope.$broadcast('auth:loginRequired');
}
}
return $q.reject(rejection)
}
}
};
$httpProvider.interceptors.push(interceptor);
});
(Disclosure: I'm one of the developers of UserApp)
You could use the third-party service UserApp for this, together with the AngularJS module.
Check out the getting started guide, or take the course on Codecademy. Here's some examples of how it works:
Login form with error handling:
<form ua-login ua-error="error-msg">
<input name="login" placeholder="Username"><br>
<input name="password" placeholder="Password" type="password"><br>
<button type="submit">Log in</button>
<p id="error-msg"></p>
</form>
User info is accessed using the user service: user.current.email
Or in the template: <span>{{ user.email }}</span>
Signup form with error handling:
<form ua-signup ua-error="error-msg">
<input name="first_name" placeholder="Your name"><br>
<input name="login" ua-is-email placeholder="Email"><br>
<input name="password" placeholder="Password" type="password"><br>
<button type="submit">Create account</button>
<p id="error-msg"></p>
</form>
ua-is-email means that the username is the same as the email.
How to specify which routes that should be public, and which route that is the login form:
$routeProvider.when('/login', {templateUrl: 'partials/login.html', public: true, login: true});
$routeProvider.when('/signup', {templateUrl: 'partials/signup.html', public: true});
The .otherwise() route should be set to where you want your users to be redirected after login. Example:
$routeProvider.otherwise({redirectTo: '/home'});
Log out link:
<a href="#" ua-logout>Log Out</a>
Hide elements that should only be visible when logged in:
<div ng-show="user.authorized">Welcome {{ user.first_name }}!</div>
And to authenticate to your back-end services, just use user.token() to get the session token and send it with the AJAX request. At the back-end, use the UserApp API to check if the token is valid or not.
If you need any help, just let me know :)

MVC3 Razor Engine execution/rendering order

I have a few links (login, logout, and register) in the _layout template, where the links are shown depending on whether the user is logged in. Like so:
if (User.Identity.IsAuthenticated)
{
<span class="username">#User.Identity.Name</span>
<span class="link">#Html.ActionLink("Logout", "Logout", "Account")</span>
}
else
{
<span class="link">#Html.ActionLink("Login", "Login", "Account")</span>
<span class="link">#Html.ActionLink("Register", "Register", "Account")</span>
}
Problem is that the logout link is still displayed the first time the user logs out of the system (I would expect that to be immediately replaced with the login, and register links) - that is until the page is refreshed, or the user moves to another page. Here is the logout action code:
public ActionResult Logout()
{
FormsAuthentication.SignOut();
Session.Abandon();
return View();
}
I have gone through this link - http://mvcdev.com/differences-between-asp-net-razor-and-web-forms-view-engines/ - which explains the execution order of the Razor engine, but in my case it seems to be executing differently. Ideally I would expect the FormsAuthentication.SignOut() to execute before the User.Identity.IsAuthenticated in the _layout.
What am I doing wrong? Thanks!
That's normal, you need to redirect after logging out:
public ActionResult Logout()
{
FormsAuthentication.SignOut();
Session.Abandon();
return RedirectToAction("Index");
}
The reason this happens is because when the client requested the Logout link he was still authenticated (he sent the authentication cookie along with the request). Then inside the controller action you are logging him out (FormsAuthentication.SignOut()) which does nothing more than mark the authentication cookie for removal on subsequent requests. Then you return a view, and inside this view of course the user is still authenticated as this view executes under the same request and the cookie is still present.

Resources