How to redirect to the login page when the session expires? - session

I have three JSF 2.0 web modules and I need to redirect to the login page when the session expires.
I have tried it using a HttpSessionListener, it is calling the sessionDestroyed() event method, but I am not able to forward/redirect the request in there. I think it is becasue there are no HttpServletRequest and HttpServletResponse objects.
I also tried it using a PhaseListener, but it results in a "too many redirects" error in the webbrowser.
public class SessionListener implements PhaseListener {
public PhaseId getPhaseId() {
return PhaseId.RESTORE_VIEW;
}
public void beforePhase(PhaseEvent event) {
if (!FacesContext.getCurrentInstance().isPostback()) {
try {
System.out.println("Session Destroyed");
FacesContext.getCurrentInstance().getExternalContext().redirect("login.jsf");
}
catch (Exception e) {
System.out.println("error" + e);
}
}
}
public void afterPhase(PhaseEvent event) {
try {
System.out.println("Session Created");
}
catch (Exception e) {
System.out.println("error" + e);
}
}
}
Why do those attempts not work and how can I solve it the best?

It's not possible to send a redirect at exactly the moment when the session is expired. The client has namely not sent any HTTP request at that moment which you could then respond with a redirect.
You should just keep your existing authentication mechanism which redirects to the login page when the user is not logged-in anymore. You can at best improve it by adding a check if the user is been redirected to the login page because the session has been expired, or just because he has never logged in before (i.e. it's a fresh new request).
You can check for that by if HttpServletRequest#getRequestedSessionId() doesn't return null (which means that the client has sent a session cookie and thus assumes that the session is still valid) and HttpServletRequest#isRequestedSessionIdValid() returns false (which means that the session has been expired at the server side). You can do that in the very same filter where you're checking for the logged-in user (you do already have one, right? or are you using container managed authentication?).
User user = (User) session.getAttribute("user");
if (user == null) {
String loginURL = request.getContextPath() + "/login.jsf";
if (request.getRequestedSessionId() != null && !request.isRequestedSessionIdValid()) {
response.sendRedirect(loginURL + "?expired=true");
} else {
response.sendRedirect(loginURL);
}
} else {
chain.doFilter(request, response);
}
And then in the login.xhtml page check for it
<h:panelGroup rendered="#{param.expired}">
<p>You have been redirected to the login page, because your session was expired.</p>
</h:panelGroup>
Your phase listener approach makes by the way no sense. It indeed sends a redirect on every single request causing it to run in an infinite loop. The restore view phase has absolutely nothing to do with the session expiration.

Try to use
FacesContext.getCurrentInstance().getApplication().getNavigationHandler().
handleNavigation(context, null, "LoginForm");
But note that you should use Servlet Filter for these purposes, it's better to do not any redirection from PhaseListener because it's really error prone.

Related

Request from html client: how will I know that requested user is logged in or not?

Here is my spring login handler
public class LoginSuccessHandler extends SavedRequestAwareAuthenticationSuccessHandler {
#Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) {
HttpSession session = request.getSession();
LoggedInUser logginUserObj = (LoggedInUser)authentication.getPrincipal();
String userId = logginUserObj.getUserId();
session.setAttribute("userId", userId);
session.setAttribute("userName", logginUserObj.getName());
session.setAttribute("hasPhoto", user.getProperty(UserVertex.profilePhotoUploaded.toString()));
if(logginUserObj.getActivateLink()!=null)
session.setAttribute("activateLink", logginUserObj.getActivateLink());
try {
Object referUrl = session.getAttribute("Referer_url");
if(referUrl != null){
session.removeAttribute("Referer_url");
response.sendRedirect(referUrl.toString());
}
else
response.sendRedirect("profile/"+userId);
} catch (IOException ex) {
logger.error(ex);
}
}
}
My client is in plain html, jQuery (in cordova). So my question is if everytime user makes a request, how will I know that requested user is logged in or not ?
e.g. here is a sample :
$.ajax({
url: "addNewpost",
data:{}
})
Here only a loggedin user can add new post. So when i am calling addNewpost rest service in spring #RestController how will i know that request is from logged in user ?
Since you're using a success handler so before the request goes to success handler it goes to authentication manager.In authentication manager if you have configured any authentication provider there authenticity of the user will be check and if it returns success then the call will go to onAuthenticationSuccess.In the authentication provider you actually look for some values in the request header depending upon the type of authentication provider you are using.If its missing then the user is not logged in.Here is a better picture with one example(Here its also checking authorization for admin)
You can also refer to this link
Hope this gives you a clear picture!!
First you have to make sure that your web app returns 401 unauthorized when you are not logged in
Then with JQuery you use the error callback more or less as in following snippet, usually checking that jqXHR.status is 401 (unauthorized)
$.ajax({url:url, data:{}, error: function(jqXHR, e, x){
alert("Error #" + jqXHR.status + "\n\n\t" + x );
});
Whether the request is from a logged in user, in the server, depends on your security configuration, you should not check in the controller "manually" but just be sure that configuration declarations are correct.
BTW not sure if is the case to redirect to ANY url after login

how to close shiro session

I met an error when hardcode try to logout with shiro.
user do login and logout not through web login/logout url, but backend link.
when login, it works.
Subject currentUser = SecurityUtils.getSubject();
UsernamePasswordToken token = new UsernamePasswordToken(request.getParameter("username"), request.getParameter("password"));
token.setRememberMe(true);
try {
currentUser.login(token);
} catch (AuthenticationException e) {
e.printStackTrace();
}
but when i try to logout, with error:
public void userLogout(String sessionId){
SecurityManager securityManager = SecurityUtils.getSecurityManager();
Subject.Builder builder = new Subject.Builder(securityManager);
builder.sessionId(sessionId);
Subject subject = builder.buildSubject();
if (null != subject) {
try {
subject.logout();
} catch (SessionException e) {
// TODO: handle exception
}
}
}
but met error [org.apache.shiro.session.UnknownSessionException: There is no session with id , then how to manually colse a shiro session?
You shouldn't try to recreate the session and then operate it, you should get the session via the security manager, using the thread the user was logged into, like so:
SecurityUtils.getSubject().logout();
If you somehow want to call logout from a different thread, you can use the SessionDAO interface, but you need to do extra configuration to have shiro use a SessionDAO as described here:
http://shiro.apache.org/session-management.html#SessionManagement-SessionStorage
When you have configured it correctly you can do stuff like:
DefaultSecurityManager securityManager = (DefaultSecurityManager) SecurityUtils.getSecurityManager();
DefaultSessionManager sessionManager = (DefaultSessionManager) securityManager.getSessionManager();
Collection<Session> activeSessions = sessionManager.getSessionDAO().getActiveSessions();
for (Session session: activeSessions){
if (sessionId.equals(session.getId()){
session.stop();
}
}

Display message to user on expired session when using wicket-auth-roles

Hi I have been unable to solve the following problem in Wicket 6.*:
In our webapp we are using wicket-auth-roles to manage authentication/authorization. When session expires, user should be redirected to a page set by getApplicationSettings().setPageExpiredErrorPage(SomePage.class) on his next action. However, if the user tries to access a page which doesn't allow guests, he is redirected to a login page skipping the PageExpiredPage altogether.
My question is - how can I display "Session has expired." message to the user?
Among other things, I have tried session.info("message") during onInvalidate phase of session's lifecycle, however the feedback message is then rendered on the first page after login (not on the login page).
Thank you for your anwsers.
You could use a RequestCycleListener to record when a PageExpiredException is thrown.
public class ExceptionMapperListener extends AbstractRequestCycleListener {
#Override
public IRequestHandler onException(RequestCycle cycle, Exception ex) {
if (ex instanceof PageExpiredException) {
// Record in session or request cycle
// OR
// Create a RenderPageRequestHandler yourself and add a page parameter
// See DefaultExceptionMapper#internalMap(Exception)
}
return null;
}
}
// In Application#init():
getRequestCycleListeners().add(new ExceptionMapperListener());
ORINAL ANSWER
(kept because it could still help...)
I haven't tried it myself since I don't use wicket-auth-roles, but try overriding the method AuthenticatedWebApplication#restartResponseAtSignInPage() with something like this:
if (isSessionExpired()) {
PageParameters params = new PageParameters();
params.add("showSessionExpired", true);
throw new RestartResponseAtInterceptPageException(getSignInPageClass(), params);
} else {
throw new RestartResponseAtInterceptPageException(getSignInPageClass());
}
And then in the SignInPageClass, display the desired message if the showSessionExpired page parameter is present.
I'm not sure how you implement isSessionExpired(), but you seem to have that part already covered.
OR
Depending on how you implemented isSessionExpired(), maybe you could do the following in your SignInPageClass:
if (sessionExpired()) {
session.info("message")
}
After bernie put me on the right path, I eventually figured out a solution to the problem:
First it is required to override RequestCycleListener:
public class SessionExpiredListener extends AbstractRequestCycleListener {
public void onRequestHandlerResolved(RequestCycle cycle, IRequestHandler handler) {
if (handler instanceof IPageRequestHandler) {
IPageRequestHandler pageHandler = (IPageRequestHandler) handler;
HttpServletRequest request = (HttpServletRequest) cycle.getRequest().getContainerRequest();
//check whether the requested session has expired
boolean expired = request.getRequestedSessionId() != null && !request.isRequestedSessionIdValid();
//check whether the requested page can be instantiated with the current session
boolean authorized = Session.get().getAuthorizationStrategy().isInstantiationAuthorized(pageHandler.getPageClass());
if (expired && !authorized) {
throw new PageExpiredException("Session has expired!");
}
}
super.onRequestHandlerResolved(cycle, handler);
}
}
Check for authorized prevents the session-expired message from displaying on log-out or when accessing unprotected pages.
Finally, you must register your listener and PageRequestHandlerTracker in your WebApplication:
getRequestCycleListeners().add(new SessionExpiredListener());
getRequestCycleListeners().add(new PageRequestHandlerTracker());

How to redirect after successfully login to other class in gwt and how to set the session timeout and its response after session timeout in gwt?

can you please tell me how to redirect to next page after successfully login in GWT?
I have created the service interface and its implementions but dont know how to redirect the page after login authentication.
Share your views guyz.
and also tell me how to get sessiontimeout and then redirect automatically to login page in gwt.
Thanx
You can use Window.Location.replace(String newURL) to switch pages.
As for the session timeout, that depens on what kind of session management you are using.
The easiest would be to include the information "session expired" in every RPC call you make, for example with a custom exception:
Server
public String myRpcCall() throws SessionExpiredException {
if(!SessionManager.isSessionValid()) { // depends on your session management
throw new SessionExpiredException;
}
return some_stuff(); // whatever you want to do
}
Client
public doCall() {
AsyncCallback<String> cb = new AsyncCallback<String>() {
#Override
public void onFailure(Throwable caught) {
if(caught instanceof SessionExpiredException) {
// inform the user and redirect to login page
Window.Location.replace("login.html");
}
// handle other errors
}
// TODO onSuccess(String)
};
service.myRpcCall(cb); // your rpc call goes here
}

How to remove user SessionScoped?

I try to do log out function in JSF 2.0. First I give AUTH_KEY for logging user. After log out I remove this user's AUTH_KEY.
My problem is not working log out for the user session that don't remove.
Section of login function:
if (startupInfo.getConnectionId().equals("success")) {
FacesContext.getCurrentInstance().getExternalContext()
.getSessionMap()
.put(AUTH_KEY, loggedUserInfo.getUserId());
return "success";
}
Logout
public String logout() {
FacesContext.getCurrentInstance().getExternalContext().getSessionMap().remove(AUTH_KEY);
return "logout";
}
You should invalidate the HTTP session in your logout method. Removing the user info only doesn't kill the session:
HttpSession session = (HttpSession) FacesContext.getCurrentInstance()
.getExternalContext().getSession(false);
if (session != null) {
session.invalidate();
}

Resources