Change session time with service - session

I would like to create a service/servlet that gets a time in minutes and change the session timeout value, meaning I want to change
<session-config>
<session-timeout>1</session-timeout>
</session-config>
I know that
request.getSession(true).setMaxInactiveInterval(seconds);
changes only the current seesion and not all sessions.

Without somehow extending and depending upon Tomcat's own classes, I wouldn't know how you could change the default <session-timeout> programmatically once this has been set.
An alternative method might be to store a mutable session timeout value separately (perhaps in the database) - which your service could be responsible for updating/retrieving. You could then use a HttpSessionListener to modify the timeout for newly created sessions based on this value.
For example:
public class SessionTimeoutModifier implements HttpSessionListener {
public void sessionCreated(HttpSessionEvent event) {
int timeout = sessionService.getSessionTimeout(); // Gets your value
event.getSession().setMaxInactiveInterval(timeout); // Override default
}
...
A web front end (servlet) could then be developed which could mutate your session timeout via sessionService.setSessionTimeout(value).
Not the exact answer you're looking for but one possible way of achieving it.

Related

How to set a timeout to a specific service function in Spring Boot?

I am creating an app in which some actions in the service need to be asynchronous.
I set the global timeout for 1 minute in the AsyncConfigurer.
This is OK for most of the actions, but in some actions, I need to set a longer timeout. For example in the following service action:
#Async
public Object someLongFunction() {
Can someone tell me how to set a specific timeout for a specific action?
Just change the return type of the function to java.util.concurrent.Future
It has java.util.concurrent.Future#get(long, java.util.concurrent.TimeUnit) method that you can leverage to define custom timeout

Only one User using entire web application at a time - Spring boot

In spring boot application only one user should be using the certain page at a time (let's call it home.jsp). Another users should be redirected to different page(let's call it another_home.jsp) if they appear when accessing that same url. User doesn't login and just uses the application as it is. Any policy can be used for home.jsp could be first-come-first-serve or any other.
If more than one users are using application at a time only one user should be using home.html and all rest of the others should be using another_home.jsp.
As no login is needed in the application I believe I need anonymous sessions. Also, session needs to be expired after some time of inactivity. I've searched spring security but couldn't find anything.
I think that you don't even need spring security. Simple http session will work too. As far as I can see you just want to allocate the stream to one user and for that you need first user's session id which you can compare against whenever the requests come again. So store session id and expire after some timeout with some Time object or Date object.
In properties
server.servlet.session.timeout = 600 // 10 minutes
Something like this
private String currSessionId = null;
private Date lastDate = new Date();
private Integer TIMEOUT = 600000; // 10 minutes
public String loadHomePage(Model model) {
if(currSessionId!=null && new Date().getTime()- lastDate.getTime()>TIMEOUT){
currSessionId = null;
}
if(currSessionId==null){
currSessionId = session.getId();
lastDate = new Date();
return "home";
}else{
if(session.getId().equals(currSessionId)){
return "home";
}else{
return "another_home";
}
}
}
This is as simple as it gets when you don't have logged in users to manage and also don't need to remember previous state where user left off. Let me know if it helps.
You need to create a serverside state that is either empty or stores the identifier of the visitor that is currently claiming /home.jsp.
This could be a field on a singleton Bean, or an entity in the database.
It has to expire automatically, or it will prevent new visitors forever to make a claim.
As long as the state is empty, the first visitors identifier will be stored in this state.
And from that moment on, you will redirect all other visitors to another_home.jsp
So the Controllers Code would be something like this
if(visitorHoldsTheClaim()) {
return "home.jsp"
} else if (noClaimActive()) {
createClaimForVisitor();
return "home.jsp"
} else {
return "redirect:/another_home.jsp"
}
Depending on your implementation, these methods will do different things.
I'd usually recommend against serverside session state (more about this in Roy Fieldings Dissertation),
but for your use case, you need a way to identify a visitor over many requests.
A session would certainly be a very simple way to achieve this.
You can at least minimize session usage by only creating one session at a time - the one for the visitor that holds the claim.
In this case you'd never have more than one open session, and the visitor that owns the session is the visitor that holds the claim.
So in this case, the implementation would be be something like this:
if(currentUserHasASession()) { // checks if the current user has a session, but !!!does not create a new session if it does not exist!!! careful, HttpServletRequest.getSession(true) would create it!
return "home.jsp"
} else if (serverHasNoSessions()) { // https://stackoverflow.com/questions/49539076/how-can-i-get-a-list-of-all-sessions-in-spring
createSessionForUser(); // HttpServletRequest.getSession(true)
return "home.jsp"
} else {
return "redirect:/another_home.jsp"
}
Keep in mind that this only works if you do not create Sessions in another place.
So you have to configure Spring Boot/Spring Security to not create Sessions. How to make spring boot never issue session cookie?
Also keep concurrency in mind. For example, if you had only one server instance, you could put this code into a synchronized method to avoid two visitors creating a claim at the same time.
So... first of all, this sounds like a bad idea. I would be curious why you would need such an unusual behavior. There might be more sensible approaches for it.
Like Gregor said, the redirect code part is rather straightforward:
if(pageLock.getUser() == null) {
pageLock.setUser(user);
}
if(user.equals(pageLock.getUser())) {
return "home.jsp"
} else {
return "redirect:/another_home.jsp"
}
What is actually more tricky is the part when "expiring" the lock. It's likely the user will simply close the browser and not click on "logout" (or whatever), leaving the lock forever. On the other extreme, the user might be gone for a lunch break but its browser still has the page open for hours.
So that's the first thing you wanna add: some keep-alive mechanism on the page, regularly prolonging the lock, and some expiration checker, releasing the lock if nothing was received for a while.
...but like I said in the beginning, the whole thing sounds fishy.

What are the advantages of using timeout property in Spring framework?

When I read this tutorial about transaction, I notice timeout property, which I have never used before in any of REST services I have developed.
For example, in this code:
#Service
#Transactional(
isolation = Isolation.READ_COMMITTED,
propagation = Propagation.SUPPORTS,
readOnly = false,
timeout = 30)
public class CarService {
#Autowired
private CarRepository carRepository;
#Transactional(
rollbackFor = IllegalArgumentException.class,
noRollbackFor = EntityExistsException.class,
rollbackForClassName = "IllegalArgumentException",
noRollbackForClassName = "EntityExistsException")
public Car save(Car car) {
return carRepository.save(car);
}
}
What is the benefit or advantage of using timeout property? is it a good practice to use it? can anyone tell me about use-cases of timeout property?
As Spring Docs explain:
Timeout enables client to control how long the transaction runs before timing out and being rolled back automatically by the
underlying transaction infrastructure.
So, the benefit is evidently obvious - to control how long the transaction (and queries under that) may be lasting, until they're rolled back.
Q: Why controlling the transaction time is useful/good?
A: If you are deliberately expecting your transaction not to take too long - it's a good time to use this configuration; if you're expecting that your transaction might take longer than its default maximum time, it is, agian, helpful to provide this configuration.
One is to stop records being locked for long and unable to serve any other requests.
Let says you are booking a ticket. On the final submission page, it is talking so long and will your user wait forever? So you set http client time out. But now you have the http client time out, what happens if you don't have transaction time out? You displayed error to user saying it didn't succeed but your transaction takes it time as it does not have any timeout and commits after the your http client has timed out.
All of the above answers are correct, but something you should note is that:
this property exclusively designed for use with Propagation.REQUIRED
or Propagation.REQUIRES_NEW since it only applies to newly started
transactions.
as documentations describes.

Strategy for logging Tomcat expired sessions

My web application logs user logins and logouts on a database table, so that we keep track of user activity.
This works well when users explicitly login or logout, since the underlying authentication code is responsible for these logging events.
However, when the user leaves the computer idle for 30 minutes, the web session will expire and we'll have one Login event without the corresponding Logout event.
The only strategy I've thought for resolving this is to have a javascript event that triggers before the 30 minutes defined in the web.xml and that kicks the user out before the session expires. However, that has the limitation of needing javascript, and when someone uses multiple tabs it can have some unexpected results (i.e., user is using tab2 and session is expired in tab1).
What would you suggest for this case?
You want to use an HttpSessionListener. It's a standard interface defined by the Servlet Specification for exactly this kind of situation.
See below for a caveat.
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;
public class LogoutListener implements HttpSessionListener {
#Override
public void sessionDestroyed(HttpSessionEvent event) {
HttpSession session = event.getSession();
// NOTE: You need to store some kind of user identification
// in the session. My example just has a "username"
// in here.
String username = session.getAttribute("username");
// If the username is null, there was no logged-in user
// to log-out (e.g. non-authenticated user).
if(null != username) {
// NOTE: Obviously, this needs to call your existing
// "logout"-recording code. Just an example.
MyDBUtilities.registerLogout(username, System.currentTimeMillis());
}
}
#Override
public void sessionCreated(HttpSessionEvent event) {
// Ignore
}
}
If you use the code above, you'll find that users who don't explicitly log out will get a single logout record, and users who do explicitly log out will get two. Why? Because you are likely using your "logout" action to write the "logout" record and then the session listener runs immediately afterward and makes a second audit entry.
There are two obvious solutions to this problem:
Stop recording the logout event in your "logout" action, and let the event handler log all logouts
Remove the user's "username" session attribute when you log them out and the event handler will ignore the event
use a session listener to update the database when the session expires.
This is a simple example of how to implement session.
https://www.mkyong.com/servlet/a-simple-httpsessionlistener-example-active-sessions-counter/

Vaadin session setMaxInactiveInterval UI response inconsistant

I have set the max inactive interval for Vaadin session as following.
VaadinSession.getCurrent().getSession().setMaxInactiveInterval(60);
Added a session destroy listener as following for testing.
servletService.addSessionDestroyListener(new SessionDestroyListener() {
public void sessionDestroy(SessionDestroyEvent event) {
System.out.println("SESSION TIMEOUT");
}
});
This listener get called at the desired time on the server side.
However I cannot see "Session Expired" message on the browser side at the same time. Normally it gets displayed between 4th and 5th minutes.
Is there a way to get both of these at the same time in a consistent manner.
Also note that we are not using push and it is not an option for us at the moment.
Doing client side polling will reset last active time of the sessions and can keep the session active forever if poll interval is lesser than maxInactiveInterval.
Vaadin application keeps Client Side and Server Side communication during session life-cycle. There is parameter calls heartbeatInterval with default value 5 mins (300s). So it is means that every 5 mins Client Side ask Server if session still alive. That is why, when Session is destroyed you see message in Console and only after some period of time you see Session Expired message in a Browser.
You can change heartbeatInterval property and set smaller value (in seconds), but remember that you need to set closeIdleSessions=true explicitly as well. In example below I set this value to 1 second.
#VaadinServletConfiguration(heartbeatInterval=1, closeIdleSessions=true, productionMode = false, ui = MyUI.class)
public static class Servlet extends VaadinServlet {
}
The problem :
Your session is invalidated on the server side, everything is good. But the problem is that your client is never notified of this event. You have to do an interaction with the server to get a Session Expired message, like pressing the button, refreshing the page, etc...
How to fix this?
To fix this, you have some solutions:
Use #Push annotation see Documentation
Force client-side refresh using getPage().reload()
Change nothing and your session timeout will appear on next Client-Side action
Implement a "Session lookup" on client side to watch every X seconds if the session is still valid, if it is expired, simply call Page.getCurrent.reload() from client side.
Be careful with #Push
Depending on the application server you are Using, you may need to update it to support #Push (I had to with tomcat7, because tomcat7 doesn't support WebSocket)
Following solution worked for me in this scenario of not having #Push enabled as well as without any custom js widgets.
First set maxInactiveInterval as following in the main class. Showing only the code related to this solution.
public class MyApplication extends UI {
#Override
protected void init(VaadinRequest request) {
VaadinSession.getCurrent().getSession().setMaxInactiveInterval(sessionTimeout);
}
}
We have to default session expired message as following. This has been suggested in a Vaadin forum as a solution and it said it should work within 15 seconds of session timeout.
public class CustomInitServlet extends VaadinServlet {
getService().setSystemMessagesProvider(
new SystemMessagesProvider() {
#Override
public SystemMessages getSystemMessages(SystemMessagesInfo systemMessagesInfo) {
CustomizedSystemMessages customizedSystemMessages = new CustomizedSystemMessages();
customizedSystemMessages.setSessionExpiredMessage(null);
customizedSystemMessages.setSessionExpiredCaption(null);
customizedSystemMessages.setSessionExpiredNotificationEnabled(true);
return customizedSystemMessages;
}
});
// other code
}
Then in the web.xml added high heartbeat interval which will be higher than the maxInactiveInterval.
<context-param>
<param-name>heartbeatInterval</param-name>
<param-value>1200</param-value>
</context-param>

Resources