Using Tomcat to prevent concurrent User session from same PC - session

I have looked at a few good examples on SO here such as
How to Prevent Concurrent User Logins in PHP/MySQL Site?
and they describe the problem I'm trying solve. Basically only allow a given user to open One and Only one session at a time, be it from the same PC or 2 different PCs.
So querying a DB for a LoggedIN/Not LoggedIN flag is the simplest workable solution.
How to implement this is my problem.
Having session validation added to each page which gets run each time the page is requested is not workable as it would require modifying all our JSPs ( Long story but we don't have a common Header file )
Is there any way I can reconfigure Tomcat to run some validation checks on each request to query the DB ? Maybe using valves or some other means? I don't have a lot of Tomcat experience so this is why I ask.
Thnx

Instead of changing all your JSP files, you can look at using a Filter. The filter will allow you to intercept the requests and perform some level of validation on the request.
Then however you decide to check for active sessions is up to you.
public class SessionCheckFilter implements Filter {
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
throws IOException, ServletException {
//Your validation code here.
boolean returnValue = YourClass.performSessionValidation();
if(returnValue){
//Do Something
}else{
//Do Something else
}
//standard filter call
chain.doFilter(req, res);
}
And then in the web.xml map the servlet to your code. (change according to your needs)
<filter>
<filter-name>SessionCheckFilter</filter-name>
<filter-class>com.stackoverflow.SessionCheckFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>SessionCheckFilter</filter-name>
<url-pattern>*.jsp</url-pattern>
</filter-mapping>
For more information see the servlet-filter info page here on SO

Related

New session for each call to the Spring Boot server with JWT problem

I'm working to limit the number of sessions per user in Spring Boot, so as to limit the number of devices it can connect.
this is my WebSecurityConfigurerAdapter:
http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED).maximumSessions(10).maxSessionsPreventsLogin(true);
I tried to change SessionCreationPolicy in various states, or not declare it:
http.sessionManagement().maximumSessions(10).maxSessionsPreventsLogin(true);
every time I call the server, a new session is generated, up to exceeding the declared limit, so I am no longer authorized to make a call.
I noticed that the creation of the new session takes place in GenericFilterBean, exactly after running filterChain.doFilter (req, response)
I carry the file GenericFilterBean:
#Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain filterChain)
{
...
**filterChain.doFilter(req, response);**
...
}
do you know the way to avoid that every call to the server generates a new session? My goal is one session for each device.
Thanks a lot for availability !!!

Count AsyncResponse calls in spring boot metrics

I have a JAX-RS service backend written in Spring boot 2 and using micrometer for metrics.
By default the metrics contain very nice http metrics as http_server_requests_seconds_count.
These work great for normal GET and PUT requests. One method in my service uses JAX-RS AsyncRequest though.
#GET
#Produces(APPLICATION_JSON)
#Path("next/{position}")
public void getNext(
#PathParam("position") Long position,
#Suspended final AsyncResponse response) throws InterruptedException {
...
// Somewhere in the code in another thread I invoke
response.resume(entity);
...
}
These calls do not seem to be counted at all. Is there a way to enable counting them?
If not should I simply feed the same counters manually from my code?

Why filter chain is called twice for an asynchronous endpoint

I'm developing a Spring boot based app. I noticed that for asynchronous endpoints authentication filter is called twice, for regular endpoints it's called once. I couldn't find the reason, but I found an issue in the net https://jira.spring.io/browse/SPR-12608 , where it's said that filters for async endpoints are called twice, before and after async endpoint execution. It would explain double authentication call. I'd like to know is this expected behavior, why it's done like that and how to avoid double authentication.
UPD:
I found a way how to avoid filter being firing second time after async endpoint finished. The thing I need to do is to analyse what kind of dispatcher is assigned to the request, if it's async - proceed further on filter chain. I added the following method to the filter:
#Override
public final void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
if (request.getDispatcherType() == DispatcherType.ASYNC) {
filterChain.doFilter(request, response);
} else {
super.doFilter(request, response, filterChain);
}
}
I am seeing exactly the same behavior and I think it is related to the fact that asynchronous call is being split into 2 phases.
At first, regular container thread is kicked and an interim response is generated, but that response is not being returned to the client it is being held back until async dispatcher competes. Once async thread is done processing interim response is replaced with the real one from async thread and returned to the client.
Both threads go through the same filter chain. Therefore you see duplicate invocation.
If you want your filter to be invoked once you should extend from OncePerRequestFilter. It will check if your filter was already invoked during the course of the request (even though the request handling consists of 2 stages each of them handled by their own threads).
I had the same problem with a concrete implementation of the class AbstractAuthenticationProcessingFilter, I belive to solve it It's better create a custom implementation of whaterver class that implements OncePerRequestFilter, in my particular case I created an implementation of AuthenticationFilter.

Change session time with service

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.

Cache HTTP Response in Spring MVC Rest service

I have a spring MVC rest service that returns data in XML. I would like to cache this xml response. How can I achieve this? Is it possible to do this using mvc:interceptors?
You could make this work, but I think there are better solutions.
First, if you want to use Spring MVC interceptors, you'll use the postHandle method to store something in your cache and the preHandle to check the cache and possible circumvent processing. The question is, what do you store in the cache. You would need to store the complete response. This means that you would have to easily get the full response from your ModelAndView in postHandle. This may or may not be easy, depending on how you're doing things.
You're most likely better off using a different caching mechanism all together. I recommend caching at the web server level. This is especially true if you're looking to cache in the interceptor level as that is right "next" to the web server and I don't see any benefit in re-inventing the wheel there. Apache has a cache module. So does nginx. Varnish is pretty awesome too.
I should also mention that you should not cache until you've determined that you need to (don't prematurely optimize). This is a waste of your time and effort. Secondly, when you've determined that you do have performance issues that need to be fixed (and caching is the correct solution), you should cache the right data in the right place.
Now, say you've determined that you do have a performance problem and some sort of caching is a good solution. The next thing to determine is what can be cached. If, for every URL, you return the same data, then caching at the web server (Apache, nginx, Varnish, etc.) level will be your best bet.
Often, you will have cases where two clients will hit the same URL and get different data. This is most easily seen on a site like Facebook. I see different data when I'm logged in than my friend sees. In this case, you will not be able to cache at the web server level. You will need to cache inside your application. Usually this means caching at the database level.
I couldn't disagree with the optimization part of the solution more.
Web requests are inherently slow as you're loading data from a remote location, possibly a few thousand miles away. Each call must suffer a full TCP round-trip time for at least the packets themselves, possibly the connect and fin for each request, which for connect is a three packet synchronous exchange before you start to transfer data.
US coast-to-coast latency is about 50ms on a good day, so every connection suffers a 150ms penalty, which for most implementations is incurred for every request.
Caching the response on the client-side removes this latency entirely, and if the service has correct headers on their response, is trivial. If they don't, you'll have to define a caching policy, which for the most part isn't particularly difficult. Most API calls are either real-time or not.
In my opinion, caching REST responses isn't premature optimization, it's common sense.
Don't use spring cache it is not what you need. You need to reduce load to your Server, not speed up your inner spring application execution.
Try use som HTTP-related caching strategies.
You can add one of HTTP-headers to your requests
#cache expires in 3600 seconds
cache-control: private, max-age=3600
#hash of your content
ETag: "e6811cdbcedf972c5e8105a89f637d39-gzip"
# redirect caching to any HTTP header
vary: User-Agent
Detailed description of caching techniques
Spring example
#RequestMapping (value = "/resource/1.pdf", produces = "application/octet-stream")
public ResponseEntity<InputStreamResource> getAttachement (#RequestParam (value = "id") Long fileId)
{
InputStreamResource isr = new InputStreamResource(javaInputStream);
HttpHeaders headers = new HttpHeaders();
//other headers
headers.setCacheControl("private, max-age=3600");
return new ResponseEntity<>(irs, headers, HttpStatus.OK);
}
I use this and it works with awesome speed.
Really easy to use spring + ehcache:
1)Controller:
#Cacheable("my.json")
#RequestMapping("/rest/list.json")
public ResponseEntity list(#RequestParam(value = "page", defaultValue = "0", required = false)
int pageNum,
#RequestParam(value = "search", required = false)
String search) throws IOException {
...
}
2) At ehcache.xml some like this:
<cache name="my.json" maxElementsInMemory="10000" eternal="true" overflowToDisk="false"/>
3) Configure spring. I'm using spring javaconf style:
#Configuration
#EnableCaching
public class ApplicationConfiguration {
#Bean
public EhCacheManagerFactoryBean ehCacheManagerFactoryBean() throws MalformedURLException {
EhCacheManagerFactoryBean ehCacheManagerFactoryBean = new EhCacheManagerFactoryBean();
ehCacheManagerFactoryBean.setConfigLocation(new ClassPathResource("ehcache.xml"));
return ehCacheManagerFactoryBean;
}
#Bean
#Autowired
public EhCacheCacheManager cacheManager(EhCacheManagerFactoryBean ehcache) {
EhCacheCacheManager ehCacheCacheManager = new EhCacheCacheManager();
ehCacheCacheManager.setCacheManager(ehcache.getObject());
return ehCacheCacheManager;
}
}
At the application level, I would go with a plain Java cache as EHCache. EHCache is pretty easy to integrate with methods on Spring beans. You could annotate your service methods as #Cacheable and it's done. Check it out at EHCache Spring Annotations.
At the HTTP level, Spring MVC provides a useful ETag filter. But I think it would be better if you could configure this kind of caching at the server level more than at app level.
As of Spring 3.1, you can use the #Cachable annotation. There is also support for conditional caching, and some sibling annotations like #CachePut, #CacheEvict and #Caching for more fine grained control.
Spring currently supports two different cache managers, one that is backed by a ConcurrentHashMap and one that is backed by Ehcache.
Lastly, don't forget to read the details about how to enable the annotations.

Resources