I have a web application where if the user session has timedout and they try to login in again i need to redirect them to the last visited page. ONLY for session timeout, if the user logged out i donot want this mapping.
I understand that it can be done using an interceptor and a application scope mapping. But can you give me a code sample for an interceptor that updates current users url? Also my application scope object..how do i say after say 5 hrs of no relogin remove the reference to last page for that user???
What about registering an HttpSessionListener (look at this answer). That way you will be notified when session is destroyed so this is the perfect time when you can save info about last visited page to database.
Your session listener should look like this:
package com.rr87;
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;
public class YourSessionListener implements HttpSessionListener {
#Override
public void sessionDestroyed(HttpSessionEvent event) {
// Implement logic to save last visited page to database...
}
.
.
.
}
To register your session listener, add code below to your Web.xml:
<web-app ...>
<listener>
<listener-class>com.rr87.YourSessionListener</listener-class>
</listener>
</web-app>
And last part of an answer.. You can erase last visited page reference in database on sucesfull logout.
[EDIT]
From the official documentation, regarding session object accessible trough HttpSessionEvent:
The container creates a javax.servlet.http.HttpSessionEvent object
that is input for calls to HttpSessionListener methods. The
HttpSessionEvent class includes the following method, which your
listener can call:
HttpSession getSession()
Use this method to retrieve the session object that was created or
destroyed, from which you can obtain information as desired. See
"Introduction to Servlet Sessions" for information about the
javax.servlet.http.HttpSession interface.
Based on that I think, that you can still get data from 'destroyed' session.
Related
I got a simple spring security application with a user administration.
An admin should be able to create/update/delete users on the database (via hibernate).
If a user is updated, I am reloading the authentication of the user which is currently logged in. That's done with the following code (according to this example):
SecurityContextHolder.getContext().setAuthentication(updatedAuthentication);
My question is:
What can I do if a user is deleted? If I delete a user, already active sessions remain active and I don't know how to update them. I can still navigate to every page I was able to go to before.
Is there a way to tell spring that a session should be revalidated or something like that? Did I miss anything important?
On each request you should check your database for User existence.
Steps :
Take the userid from session, check it is in the database or not.
If not in the database invalidate the session and redirect to login page again.
Wrap those above two stpes in a method and call it on each request. (If common method is there use that or create e Listener)
Also you can check the following link if it helps. http://forum.spring.io/forum/spring-projects/security/35809-how-to-let-admin-to-force-user-to-logout
Another helpful link is http://docs.spring.io/spring-security/site/docs/3.1.x/reference/springsecurity-single.html#list-authenticated-principals
SecurityContextRepository
From Spring Security 3.0, the job of loading and storing the security context is now delegated to a separate strategy interface
You can provide a NullSecurityContextRepository in order to avoid the storage of security context information.
I did something like this:
#EnableWebSecurity
public class CustomSecurityConfiguration extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
// Other security configuration...
http.securityContext().securityContextRepository(new NullSecurityContextRepository());
}
}
I want to write a Hook in Java that is executed if the session of my Liferay 5.2.3 Portal times out.
I managed to write a Hook that is executed whenever the user clicks the logout link with the following setup in the liferay-hook.xml:
<hook>
<event>
<event-class>com.extensions.hooks.LogoutHook</event-class>
<event-type>logout.events.pre</event-type>
</event>
</hook>
However the Logout Hook does not get called if the session times out, but I need to execute the same method on a timeout. I did not find an event-type for a session timeout.
Is there a way to execute a Java-Method when the session times out and identify the User-ID of the ended session?
There is an event which will be triggered upon Session Expiry/TimeOut event of User Session,
# Servlet session destroy event
servlet.session.destroy.events = com.extensions.hooks.CustomPreSessionExpireAction
You can either add this property in liferay-hook.xml or portal.properties [Written in Hook] or portal-ext.properties.
And can be used as ,
public class CustomPreSessionExpireAction extends SessionAction {
#Override
public void run(HttpSession session) throws ActionException {
//Code
}
}
However, We can only use HttpSession here. So, you need to figure out the way to get userId here.
Thanks
I'm creating a GWT application that will be accessed by a POST request, which contains parameters I care about (user id, etc.).
All the reading I've done so far has led me to believe that I should create a servlet (I'm using tomcat) that will handle the POST parameters and then forward to my GWT application. I've gotten this working, but I'm still having trouble passing this data to my application. I've seen 3 suggested approaches:
Save data to context: I have this working right now, but I'm not happy with it. When the servlet is accessed, I parse the parameters and update the context of my GWT web application and then forward to the application where I make an RPC call to read the context. This does what I want it to, but this creates a race condition when multiple users try to access the application at the same and the context is rapidly changing.
Store data in session: I've tried saving the data to the request session in my servlet, and then accessing the session in my RPC, but I always get a new/different session, so I assume I'm mucking this up somewhere.
Save session on servlet
HttpSession session = request.getSession();
session.setAttribute("test", "testValue");
response.sendRedirect(response.encodeRedirectURL("/GWT_Application"));
Access session in RPC
HttpSession session = this.getThreadLocalRequest().getSession();
session.getAttribute("test");
This returns a different session, which results in the "test" attribute being null.
Pass data in URL: My application will be opened in an iframe, meaning Window.location.getParameter() will not be usable.
Any help would be greatly appreciated! I'm still learning GWT and web development in general so don't be afraid to call me out on any obvious or silly mistakes.
Thanks!
SOLUTION
I figured out what the issue was with my session approach: the servlet in which I was previously trying to save the session data was in a separate tomcat web app from my GWT application. Moving them to the same web app solved my problems and it now works. I'm not sure, but I'm guessing that this was a problem because redirecting to another web app switches the context. I'll outline my whole approach in the hopes this saves someone else some time later:
Put your servlet code in the server folder of your GWT project:
package GWTApplication.server;
public class myServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) {
session.setAttribute("myAttribute", request.getParameter("myParam");
// handle rest of POST parameters
response.sendRedirect(response.encodeRedirectURL("/GWTApplication");
}
}
Map servlet in your GWT application's web.xml:
<servlet>
<servlet-name>myServlet</servlet-name>
<servlet-class>GWTApplication.myServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>myServlet</servlet-name>
<url-pattern>/myServlet</url-pattern>
</servlet-mapping>
This servlet should now be accessible at .../GWTApplication/myServlet
Next make a standar RPC. Within whatever method you will be calling in the ServiceImpl class on the server:
HttpSession session = this.getThreadLocalRequest().getSession();
return session.getAttribute("myAttribute");
Finally, make your RPC call in the onModuleLoad() method of you GWT application. As a recap:
Send the original POST request to the servlet
Save POST parameters to session variables
Redirect to GWT application
Make RPC call in onModuleLoad()
Read session variables in ServiceImpl class
You can talk with servlets through RPC call in GWT
You need to make a RPC call in the starting point of GWT application.
Set that data to serverside session and get the session data in servceImpl call of GWT which extends to RemoteServiceServlet.
Example :
YourServiceImpl extends RemoteServiceServlet {
#ovveride
doGet(){
//you can access session here
}
#ovveride
doPost(){
//you can access session here
}
#ovveride
doPut(){
//you can access session here
}
----your other methods
}
A brief Example I wrote here:How to make an GWT server call(GWT RPC?)
Since RemoteServiceServlet extends HttpServlet, you can just override doPost() method to access your POST requests. Don't forget to call super.doPost() EDIT: This doesn't work because the method is finalized in AbstractRemoteServiceServlet so it cannot be overridden.
Also, GWT Servlets POST data using the proprietary GWT RPC format. Read more about that format and how to interpret it here: GWT RPC data format
EDIT
There are several methods you can override in your ServiceImpl class that extends RemoteServiceServlet:
public String processCall(String payload) will give you a String representation of the incoming request.
protected void onAfterRequestDeserialized(RPCRequest rpcRequest) will give you a RPCRequest object that has an array of parameters, along with the method that was called.
public void service(ServletRequest request, ServletResponse response) will give you all the Attributes of the HTTP request.
In my JSF application, I need to redirect the user from Page A to page B if a session attribute such as userRole has a value of "contributor", and to a page C, for example, if it is "author".
I'm told that I have to implement a page listener, or a session listener perhaps. Although I understand writing a listener class is quite straightforward and standard, I don't know how to set it up on the JSF page itself (to listen to the session).
Anybody?
A session listener (HttpSessionListener) is unsuitable since it doesn't have a reference to the current HTTP request/response, which are mandatory in order to change the request/response destination.
Use a filter. To learn more about filters, check our servlet-filters tag info page. Note that session scoped JSF managed beans are by itself stored as HttpSession attribute with the managed bean name as key. You could access them in doFilter() method as follows:
Bean bean = (Bean) ((HttpServletRequest) request).getSession().getAttribute("bean");
Or when it's to be determined based on a POST action, just return a different outcome in the managed bean action method. Then just make use of (implicit) JSF navigation. Pseudo:
public String submit() {
if (user is contributor) return "pageB";
if (user is author) return "pageC";
return "pageA";
}
How to get any http session by id or all currently active http sessions within web application (Java 2 EE) in an elegant way?
Currently I have a WebSessionListener and once session was created I put it in ConcurrentHashMap() (map.put(sessionId, sessionObj)), everything ok, I can retrieve HTTP session from that map in any time by session id, but it looks like the HttpSession objects will never finalize... Even session was invalidated the map still reference on invalidated session object... Also I have read this article and it looks like the WeakHashMap is not acceptable in my case...
In other words I need a possiblity to look in any HttpSession even get all currently active HttpSession and retrieve some attributes from there...
Please advice somebody :)
Update
I need to access HttpSession objects because of follwoing reason:
Sometimes user does some actions/requests that may impact the work of another concurrent user, for example admin should disable user account but this user currently working with the system, in this case I need to show a message to admin e.g. "user XXX is currently working with the system" hence I need to check if any HttpSession which holds credentials of user XXX already exists and active. So this is whay I need such possibility to get any http session or even all sessions.
My current implementation is: SessionManager which knows about all sessions (ConcurrentMap) and HttpSessionListener which put/remove session into SessionManager.
I was concerned about memory issues that may occure and I wanted to discusse this with someone, but currently I am clearly see that everything should works fine because all invalidated session will be removed from map when sessionDestroyed() method will be called...
Many thanks for your replays, but now I understood that problem was just imagination :)
As per your clarification:
Sometimes user does some actions/requests that may impact the work of another concurrent user, for example admin should disable user account but this user currently working with the system, in this case I need to show a message to admin e.g. "user XXX is currently working with the system" hence I need to check if any HttpSession which holds credentials of user XXX already exists and active. So this is whay I need such possibility to get any http session or even all sessions.
For this you actually don't need to know anything about the sessions. You just need to know which users are logged in. For that you can perfectly let the model object representing the logged in user implement HttpSessionBindingListener. I of course assume that you're following the normal idiom to login/logout user by setting/removing the User model as a session attribute.
public class User implements HttpSessionBindingListener {
#Override
public void valueBound(HttpSessionBindingEvent event) {
Set<User> logins = (Set<User>) event.getSession().getServletContext().getAttribute("logins");
logins.add(this);
}
#Override
public void valueUnbound(HttpSessionBindingEvent event) {
Set<User> logins = (Set<User>) event.getSession().getServletContext().getAttribute("logins");
logins.remove(this);
}
// #Override equals() and hashCode() as well!
}
Then somewhere in your admin app, just obtain the logins from ServletContext:
Set<User> logins = (Set<User>) servletContext.getAttribute("logins");
Generally speaking, your servlet container will have its own session manager, which is responsible both for maintaining the lifecycle of the sessions, and associating incoming requests with the appropriate session (via cookies, anchor parameters, whatever strategy it wants).
The elegant way to do this would be to hook into this session manager in whatever way it allows. You could subclass the default one, for example, to allow you to get access to arbitrary sessions.
However, it sounds like what you're doing belies an underlying problem with your architecture. The data contained within a session should be specific to that session, so in general you shouldn't need to look up an arbitrary one in order to provide the standard logic of your web application. And administrative/housekeeping tasks are usually handled for you by the container - so again, you shouldn't need to interfere with this.
If you gave an indication of why you want access to arbitrary sessions, chances are that an alternative approach is more suited to your goals.
Andrzej Doyle is very right. But if you really, really want to manage your own list of sessions, then the way to connect to your container is via the HttpSessionListener - example code.
The listener is called whenever a new session is created, and importantly, it's also called when a session is destroyed; this will allow you to mimic the container's session bookkeeping.
You use your web.xml to register your session listener as a lifecycle listener for your your app.
You can communicate your session list with other processes in the container using the ServletContext, or you can cook up a more dirty scheme using e.g. static class fields.