Created
December 28, 2019 12:02
-
-
Save BohdanLevchenko/74d78b1634185402cf0453fe843bc31e to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package io.tomcat.sessionfreeze; | |
import org.apache.catalina.Manager; | |
import org.apache.catalina.Session; | |
import org.apache.catalina.connector.Request; | |
import org.apache.catalina.connector.Response; | |
import org.apache.catalina.valves.ValveBase; | |
import org.apache.juli.logging.Log; | |
import org.apache.juli.logging.LogFactory; | |
import org.springframework.boot.SpringApplication; | |
import org.springframework.boot.autoconfigure.SpringBootApplication; | |
import org.springframework.boot.context.embedded.EmbeddedServletContainerCustomizer; | |
import org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedServletContainerFactory; | |
import org.springframework.context.annotation.Bean; | |
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; | |
import org.springframework.security.config.annotation.web.builders.HttpSecurity; | |
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; | |
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; | |
import org.springframework.web.bind.annotation.*; | |
import javax.servlet.ServletException; | |
import javax.servlet.http.HttpSession; | |
import java.io.IOException; | |
import java.lang.reflect.Proxy; | |
import java.security.Principal; | |
@SpringBootApplication | |
public class SessionfreezeApplication { | |
public static void main(String[] args) { | |
SpringApplication.run(SessionfreezeApplication.class, args); | |
} | |
@EnableWebSecurity | |
static class Security extends WebSecurityConfigurerAdapter { | |
@Override | |
protected void configure(HttpSecurity http) throws Exception { | |
http.formLogin().and().csrf().disable().authorizeRequests().mvcMatchers("/**").authenticated(); | |
} | |
@Override | |
protected void configure(AuthenticationManagerBuilder auth) throws Exception { | |
auth.inMemoryAuthentication().withUser("admin").password("admin").roles("ADMIN"); | |
} | |
} | |
@RestController | |
@RequestMapping("/") | |
static class HomeController { | |
@GetMapping | |
public String index(Principal principal, HttpSession session) { | |
return "Hello " + principal.getName() + ". This is tracked resource."; | |
} | |
} | |
@RestController | |
@RequestMapping("/untracked") | |
static class UntrackedController { | |
@GetMapping | |
public String index(Principal principal) { | |
return "Hello " + principal.getName() + ". This is untracked resource"; | |
} | |
} | |
@Bean | |
TomcatEmbeddedServletContainerFactory tomcatEmbeddedServletContainerFactory() { | |
TomcatEmbeddedServletContainerFactory factory = new TomcatEmbeddedServletContainerFactory(); | |
factory.addContextValves(new TestValve()); | |
return factory; | |
} | |
public static class TestValve extends ValveBase { | |
private final Log log = LogFactory.getLog(getClass()); | |
private Session getSession(final Manager manager, String requestedSessionId) { | |
if (manager == null) { | |
return null; | |
} | |
if (requestedSessionId != null) { | |
Session session; | |
try { | |
session = manager.findSession(requestedSessionId); | |
} catch (IOException e) { | |
session = null; | |
} | |
if ((session != null) && !session.isValid()) { | |
session = null; | |
} | |
if (session != null) { | |
return session; | |
} | |
} | |
return null; | |
} | |
@Override | |
public void invoke(Request request, Response response) throws IOException, ServletException { | |
final Manager manager = request.getContext().getManager(); | |
final Session session = getSession(manager, request.getRequestedSessionId()); | |
final boolean proxied = session instanceof WrappedSession; | |
final String target = request.getRequestURL().toString(); | |
if (session != null) { | |
int timeIdle = (int) (session.getIdleTimeInternal() / 1000L); | |
log.debug("Session time idle: " + timeIdle); | |
} | |
final boolean normalUrl = !(target.contains("untracked") || target.contains("favicon")); | |
if (normalUrl && proxied) { | |
log.debug("Switching back to normal session for url: " + target); | |
final Session original = ((WrappedSession) session).unwrap(); | |
original.access(); | |
manager.remove(session); | |
manager.add(original); | |
getNext().invoke(request, response); | |
return; | |
} | |
if (session != null && !normalUrl) { | |
if (!(proxied)) { | |
final Session decorator = (Session) Proxy.newProxyInstance(this.getClass().getClassLoader(), | |
new Class[] {Session.class, WrappedSession.class}, (proxy, method, args) -> { | |
if (method.getName().equalsIgnoreCase("access")) { | |
log.debug("NOOP[access()]"); | |
return null; | |
} | |
if (method.getName().equalsIgnoreCase("endAccess")) { | |
log.debug("NOOP[endAccess()]"); | |
return null; | |
} | |
if (method.getName().equalsIgnoreCase("unwrap")) { | |
return session; | |
} | |
return method.invoke(session, args); | |
}); | |
log.debug("Stop tracking last access time for url: " + target); | |
manager.remove(session); | |
manager.add(decorator); | |
} | |
} | |
getNext().invoke(request, response); | |
} | |
} | |
interface WrappedSession { | |
Session unwrap(); | |
} | |
@Bean | |
EmbeddedServletContainerCustomizer customizer() { | |
return container -> container.setSessionTimeout(65); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment