Spring JDBC session causes duplicate entry exception - spring-mvc

In my Spring Boot project, there are REST and MVC controllers. Where the MVC part should have session. This part goes fine, but when you come from a MVC page with session and start using Swagger from the browser to the API I start to see these messages on the REST API endpoints:
org.springframework.dao.DuplicateKeyException: PreparedStatementCallback; SQL [INSERT INTO SPRING_SESSION_ATTRIBUTES(SESSION_PRIMARY_ID, ATTRIBUTE_NAME, ATTRIBUTE_BYTES) VALUES (?, ?, ?)Duplicate entry '7a69e3fe-dd7f-4a1d-85bb-2dcd617225dd-SPRING_SECURITY_SAVED_REQUE' for key 'PRIMARY'; nested exception is com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException: Duplicate entry '7a69e3fe-dd7f-4a1d-85bb-2dcd617225dd-SPRING_SECURITY_SAVED_REQUE' for key 'PRIMARY'
at org.springframework.jdbc.support.SQLErrorCodeSQLExceptionTranslator.doTranslate(SQLErrorCodeSQLExceptionTranslator.java:242)
at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:72)
at org.springframework.jdbc.core.JdbcTemplate.translateException(JdbcTemplate.java:1402)
at org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:620)
at org.springframework.jdbc.core.JdbcTemplate.update(JdbcTemplate.java:850)
at org.springframework.jdbc.core.JdbcTemplate.update(JdbcTemplate.java:905)
at org.springframework.session.jdbc.JdbcOperationsSessionRepository.insertSessionAttributes(JdbcOperationsSessionRepository.java:515)
at org.springframework.session.jdbc.JdbcOperationsSessionRepository.access$300(JdbcOperationsSessionRepository.java:131)
at org.springframework.session.jdbc.JdbcOperationsSessionRepository$2.doInTransactionWithoutResult(JdbcOperationsSessionRepository.java:413)
at org.springframework.transaction.support.TransactionCallbackWithoutResult.doInTransaction(TransactionCallbackWithoutResult.java:36)
at org.springframework.transaction.support.TransactionTemplate.execute(TransactionTemplate.java:140)
at org.springframework.session.jdbc.JdbcOperationsSessionRepository.save(JdbcOperationsSessionRepository.java:393)
at org.springframework.session.jdbc.JdbcOperationsSessionRepository.save(JdbcOperationsSessionRepository.java:131)
at org.springframework.session.web.http.SessionRepositoryFilter$SessionRepositoryRequestWrapper.saveSession(SessionRepositoryFilter.java:377)
at org.springframework.session.web.http.SessionRepositoryFilter$SessionRepositoryRequestWrapper.commitSession(SessionRepositoryFilter.java:233)
at org.springframework.session.web.http.SessionRepositoryFilter$SessionRepositoryRequestWrapper.access$100(SessionRepositoryFilter.java:197)
at org.springframework.session.web.http.SessionRepositoryFilter.doFilterInternal(SessionRepositoryFilter.java:150)
at org.springframework.session.web.http.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:81)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.apache.catalina.core.ApplicationDispatcher.invoke(ApplicationDispatcher.java:728)
at org.apache.catalina.core.ApplicationDispatcher.processRequest(ApplicationDispatcher.java:472)
at org.apache.catalina.core.ApplicationDispatcher.doForward(ApplicationDispatcher.java:395)
at org.apache.catalina.core.ApplicationDispatcher.forward(ApplicationDispatcher.java:316)
at org.apache.catalina.core.StandardHostValve.custom(StandardHostValve.java:395)
at org.apache.catalina.core.StandardHostValve.status(StandardHostValve.java:254)
at org.apache.catalina.core.StandardHostValve.throwable(StandardHostValve.java:349)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:175)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:81)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:87)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:342)
at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:803)
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66)
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:790)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1468)
at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.lang.Thread.run(Thread.java:745)
Caused by: com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException: Duplicate entry '7a69e3fe-dd7f-4a1d-85bb-2dcd617225dd-SPRING_SECURITY_SAVED_REQUE' for key 'PRIMARY'
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
at com.mysql.jdbc.Util.handleNewInstance(Util.java:425)
at com.mysql.jdbc.Util.getInstance(Util.java:408)
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:936)
at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3976)
at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3912)
at com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java:2530)
at com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.java:2683)
at com.mysql.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:2486)
at com.mysql.jdbc.PreparedStatement.executeInternal(PreparedStatement.java:1858)
at com.mysql.jdbc.PreparedStatement.executeUpdateInternal(PreparedStatement.java:2079)
at com.mysql.jdbc.PreparedStatement.executeUpdateInternal(PreparedStatement.java:2013)
at com.mysql.jdbc.PreparedStatement.executeLargeUpdate(PreparedStatement.java:5104)
at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:1998)
at com.zaxxer.hikari.pool.ProxyPreparedStatement.executeUpdate(ProxyPreparedStatement.java:61)
at com.zaxxer.hikari.pool.HikariProxyPreparedStatement.executeUpdate(HikariProxyPreparedStatement.java)
at org.springframework.jdbc.core.JdbcTemplate.lambda$update$0(JdbcTemplate.java:855)
at org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:605)
... 36 common frames omitted
My security configuration looks like this:
#Configuration
#EnableResourceServer
public class ResourceServerConfiguration extends ResourceServerConfigurerAdapter {
#Override
public void configure(HttpSecurity http) throws Exception {
http
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED)
.and()
.cors().and()
.authorizeRequests()
.antMatchers(
"/",
"/index.html",
"/oauth2-redirect.html",
"/favicon-*.png",
"/swagger-*",
"/swagger.json"
).permitAll()
.anyRequest().authenticated();
}
}

Appereantly there is a bug in delta session handling: https://github.com/spring-projects/spring-session/pull/1070
This should be fixed in version Spring Session 2.0.4.RELEASE, I worked on version Spring Session 2.0.3.RELEASE and have now downgraded to Spring Session 1.3.2.RELEASE which resolved my issues (which is in spring boot 1.5.13.RELEASE).
Will try again when version 2.0.4.RELEASE is out.
UPDATE: I tested the SNAPSHOT version, suggested here
<dependency>
<groupId>org.springframework.session</groupId>
<artifactId>spring-session-jdbc</artifactId>
<version>2.0.4.BUILD-SNAPSHOT</version>
</dependency>
This is resolving my issue.

Need to use sql query that will ignore duplicate. Spring already have the correct one, you just need to enable it:
#Configuration
class DatabaseConfig {
#Bean
public MySqlJdbcIndexedSessionRepositoryCustomizer sessionRepositoryCustomizer() {
return new MySqlJdbcIndexedSessionRepositoryCustomizer();
// or PostgreSqlJdbcIndexedSessionRepositoryCustomizer
}
}

Related

Error creating bean with name 'springSecurityFilterChain' defined in class path resource

I am new to Spring Security. I am using okta OIDC application to secure my Resource Server.
I have the following application.yml
okta:
oauth2:
client-id: {client-id}
issuer: https://{okta-domain}.okta.com
I have the following security configuration :
#Configuration
#EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter{
#Override
protected void configure(HttpSecurity http) throws Exception{
http.authorizeRequests().antMatchers("/").permitAll();
}
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth
.inMemoryAuthentication()
.withUser("user").password("user_pwd").roles("USER").and()
.withUser("admin").password("admin_pwd").roles("USER", "ADMIN");
}
}
I am getting the following error after adding the above piece of code:
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'springSecurityFilterChain' defined in class path resource [org/springframework/security/config/annotation/web/configuration/WebSecurityConfiguration.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [javax.servlet.Filter]: Factory method 'springSecurityFilterChain' threw exception; nested exception is java.lang.IllegalStateException: Can't configure anyRequest after itself
at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:655) ~[spring-beans-5.2.9.RELEASE.jar:5.2.9.RELEASE]
at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:483) ~[spring-beans-5.2.9.RELEASE.jar:5.2.9.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1336) ~[spring-beans-5.2.9.RELEASE.jar:5.2.9.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1176) ~[spring-beans-5.2.9.RELEASE.jar:5.2.9.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:556) ~[spring-beans-5.2.9.RELEASE.jar:5.2.9.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:516) ~[spring-beans-5.2.9.RELEASE.jar:5.2.9.RELEASE]
at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:324) ~[spring-beans-5.2.9.RELEASE.jar:5.2.9.RELEASE]
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) ~[spring-beans-5.2.9.RELEASE.jar:5.2.9.RELEASE]
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:322) ~[spring-beans-5.2.9.RELEASE.jar:5.2.9.RELEASE]
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:202) ~[spring-beans-5.2.9.RELEASE.jar:5.2.9.RELEASE]
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:311) ~[spring-beans-5.2.9.RELEASE.jar:5.2.9.RELEASE]
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:202) ~[spring-beans-5.2.9.RELEASE.jar:5.2.9.RELEASE]
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:897) ~[spring-beans-5.2.9.RELEASE.jar:5.2.9.RELEASE]
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:879) ~[spring-context-5.2.9.RELEASE.jar:5.2.9.RELEASE]
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:551) ~[spring-context-5.2.9.RELEASE.jar:5.2.9.RELEASE]
at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:143) ~[spring-boot-2.3.4.RELEASE.jar:2.3.4.RELEASE]
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:758) [spring-boot-2.3.4.RELEASE.jar:2.3.4.RELEASE]
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:750) [spring-boot-2.3.4.RELEASE.jar:2.3.4.RELEASE]
at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:397) [spring-boot-2.3.4.RELEASE.jar:2.3.4.RELEASE]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:315) [spring-boot-2.3.4.RELEASE.jar:2.3.4.RELEASE]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1237) [spring-boot-2.3.4.RELEASE.jar:2.3.4.RELEASE]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1226) [spring-boot-2.3.4.RELEASE.jar:2.3.4.RELEASE]
at com.symbiose.OAuthResourceServerApplication.main(OAuthResourceServerApplication.java:13) [classes/:na]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_241]
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source) ~[na:1.8.0_241]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source) ~[na:1.8.0_241]
at java.lang.reflect.Method.invoke(Unknown Source) ~[na:1.8.0_241]
at org.springframework.boot.devtools.restart.RestartLauncher.run(RestartLauncher.java:49) [spring-boot-devtools-2.3.4.RELEASE.jar:2.3.4.RELEASE]
Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [javax.servlet.Filter]: Factory method 'springSecurityFilterChain' threw exception; nested exception is java.lang.IllegalStateException: Can't configure anyRequest after itself
at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:185) ~[spring-beans-5.2.9.RELEASE.jar:5.2.9.RELEASE]
at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:650) ~[spring-beans-5.2.9.RELEASE.jar:5.2.9.RELEASE]
... 27 common frames omitted
Caused by: java.lang.IllegalStateException: Can't configure anyRequest after itself
at org.springframework.util.Assert.state(Assert.java:76) ~[spring-core-5.2.9.RELEASE.jar:5.2.9.RELEASE]
at org.springframework.security.config.annotation.web.AbstractRequestMatcherRegistry.anyRequest(AbstractRequestMatcherRegistry.java:74) ~[spring-security-config-5.3.4.RELEASE.jar:5.3.4.RELEASE]
at org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter.configure(ResourceServerConfigurerAdapter.java:30) ~[spring-security-oauth2-2.3.4.RELEASE.jar:na]
at org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfiguration.configure(ResourceServerConfiguration.java:154) ~[spring-security-oauth2-2.3.4.RELEASE.jar:na]
at org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter.getHttp(WebSecurityConfigurerAdapter.java:231) ~[spring-security-config-5.3.4.RELEASE.jar:5.3.4.RELEASE]
at org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter.init(WebSecurityConfigurerAdapter.java:322) ~[spring-security-config-5.3.4.RELEASE.jar:5.3.4.RELEASE]
at org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter.init(WebSecurityConfigurerAdapter.java:94) ~[spring-security-config-5.3.4.RELEASE.jar:5.3.4.RELEASE]
at org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfiguration$$EnhancerBySpringCGLIB$$4941180f.init(<generated>) ~[spring-security-oauth2-2.3.4.RELEASE.jar:na]
at org.springframework.security.config.annotation.AbstractConfiguredSecurityBuilder.init(AbstractConfiguredSecurityBuilder.java:370) ~[spring-security-config-5.3.4.RELEASE.jar:5.3.4.RELEASE]
at org.springframework.security.config.annotation.AbstractConfiguredSecurityBuilder.doBuild(AbstractConfiguredSecurityBuilder.java:324) ~[spring-security-config-5.3.4.RELEASE.jar:5.3.4.RELEASE]
at org.springframework.security.config.annotation.AbstractSecurityBuilder.build(AbstractSecurityBuilder.java:41) ~[spring-security-config-5.3.4.RELEASE.jar:5.3.4.RELEASE]
at org.springframework.security.config.annotation.web.configuration.WebSecurityConfiguration.springSecurityFilterChain(WebSecurityConfiguration.java:104) ~[spring-security-config-5.3.4.RELEASE.jar:5.3.4.RELEASE]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_241]
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source) ~[na:1.8.0_241]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source) ~[na:1.8.0_241]
at java.lang.reflect.Method.invoke(Unknown Source) ~[na:1.8.0_241]
at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:154) ~[spring-beans-5.2.9.RELEASE.jar:5.2.9.RELEASE]
... 28 common frames omitted
Also, how do I validate the user and password dynamically without hard coding the values as above in the "InMemoryAuthentication". For ex: I have created few people and added them in User and Admin groups as per my requirement in Okta, added the user and admin groups to my OIDC SPA App.
In that case, the users with specific user or admin role will be logging in which I need to capture and restrict access to few APIs in case of user ROLE. How do I configure the above code to dynamically verify the logged in user?
There are a few questions in here, so I'll attempt to answer them.
First, you are configuring both Basic Auth and an OAuth resource server.
My suggestion is to keep it simple and JUST use OAuth. You can configure them both, but you will need to explicitly do so in your WebSecurityConfigurerAdapter
i.e. in configure() add:
// require authentication for ALL endpoints
http.authorizeRequests().anyRequest().authenticated();
// enable resource server to process JWTs
http.oauth2ResourceServer().jwt();
One issue you have is you have this line:
http.authorizeRequests().antMatchers("/").permitAll();
This allows ALL unauthenticated requests.
If you do NOT define a WebSecurityConfigurerAdapter at all, the default is the first code block I posted.
I usually recommend to start with the defaults. The default is a secure application :)
Once you have that working, you can add a custom WebSecurityConfigurerAdapter. but start with a similar default configuration.
Next, start allowing any unauthenticated paths, something like:
http.authorizeRequests()
// Allow anon access to the root application
.antMatchers("/", "/index.html").permitAll()
// Require authentication for ALL other requests
.anyRequest().authenticated();
// enable resource server, process JWTs
http.oauth2ResourceServer().jwt();
Finally, add other authentication sources (in your case basic auth if needed).
For role-based security you have a couple of options too, you can either add them via annotations or in your WebSecurityConfigurerAdapter.
This post should walk you through everything in a bit more detail: https://developer.okta.com/blog/2019/06/20/spring-preauthorize

IllegalArgumentException: No handler can be found for the key 'javax.security.auth.Subject.container'

I am basically following this tutorial:
https://www.ibm.com/developerworks/java/library/j-javaee8-security-api-4/index.html?ca=drs-
My development environment: TomEE 8.0 M1 Plume
pom.xml
<dependency>
<groupId>org.glassfish.soteria</groupId>
<artifactId>javax.security.enterprise</artifactId>
<version>1.0</version>
</dependency>
<dependency>
<groupId>javax</groupId>
<artifactId>javaee-api</artifactId>
<version>8.0</version>
<scope>provided</scope>
</dependency>
ApplicationConfig:
#CustomFormAuthenticationMechanismDefinition(
loginToContinue = #LoginToContinue(
loginPage = "/login.xhtml",
errorPage = "/login.xhtml?error",
useForwardToLogin = true
)
)
#ApplicationScoped
#Named
public class ApplicationConfig {
}
TestServlet:
#WebServlet("/test")
public class TestServlet extends HttpServlet {
#Inject
SecurityContext securityContext;
#Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
securityContext.isCallerInRole("admin");
}
}
Go to http://localhost:8080/test, I get this exception:
05-Dec-2018 16:38:39.132 SEVERE [http-nio-8080-exec-219] org.apache.catalina.core.StandardWrapperValve.invoke Servlet.service() for servlet [servlet.TestServlet] in context with path [] threw exception
java.lang.IllegalArgumentException: No handler can be found for the key 'javax.security.auth.Subject.container'
at javax.security.jacc.PolicyContext.getContext(PolicyContext.java:91)
at org.glassfish.soteria.authorization.JACC$2.run(JACC.java:175)
at java.security.AccessController.doPrivileged(Native Method)
at org.glassfish.soteria.authorization.JACC.getFromContext(JACC.java:173)
at org.glassfish.soteria.authorization.JACC.getSubject(JACC.java:73)
at org.glassfish.soteria.authorization.JACC.isCallerInRole(JACC.java:78)
at org.glassfish.soteria.authorization.spi.impl.ReflectionAndJaccCallerDetailsResolver.isCallerInRole(ReflectionAndJaccCallerDetailsResolver.java:82)
at org.glassfish.soteria.SecurityContextImpl.isCallerInRole(SecurityContextImpl.java:89)
at servlet.TestServlet.doGet(TestServlet.java:20)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:634)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:741)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.apache.openejb.server.httpd.EEFilter.doFilter(EEFilter.java:65)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:199)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96)
at org.apache.tomee.catalina.OpenEJBValve.invoke(OpenEJBValve.java:44)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:607)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:139)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92)
at org.apache.tomee.catalina.OpenEJBSecurityListener$RequestCapturer.invoke(OpenEJBSecurityListener.java:97)
at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:668)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343)
at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:408)
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66)
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:770)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1415)
at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.lang.Thread.run(Thread.java:745)
I am from Spring and Spring Security background but new to CDI and EJB.
Could you please tell me how to configure that handler or am I missing something?
Thank you!
The error is caused since TomEE does not fully implement JACC on which the default authorization SPI ("ReflectionAndJaccCallerDetailsResolver") of Soteria depends.
Note that TomEE does in fact support JACC, just not fully.
There's a couple of options here (from easy to more challenging):
The obvious; wait for TomEE 8 final which should make this work one way or the other (using either their own EE Security implementation or otherwise)
Implement the SPI that Soteria uses for authorization and call TomEE/Tomcat native APIs to do the same thing that the default implementation is now using JACC for.
Contribute to TomEE and implement the missing bits in their JACC implementation (or contribute to Tomcat with a web only implementation). There's a JIRA for that already, see TOMEE-1912
I've been planning to provide an example for 2. and make the SPI more obvious in Soteria 1.1, but unfortunately haven't got around to that yet.

ClassCastException: ServletRequestHandledEvent cannot be cast to WebServerInitializedEvent

I am having Spring-Boot w Vaadin project where I had to define some Spring-MVC REST controllers. While using Vaadin UI all is working fine. But when I invoke any of the REST controllers functionality wise all seems working but I can see in logs there is an exception thrown.
1102038 2017-08-09 09:36:12.223 [ajp-nio-8009-exec-5] DEBUG o.s.c.e.SimpleApplicationEventMulticaster - Non-matching event type for listener: org.springframework.boot.web.context.ServerPortInfoApplicationContextInitializer$$Lambda$102/980450043#270a6b1b
java.lang.ClassCastException: org.springframework.web.context.support.ServletRequestHandledEvent cannot be cast to org.springframework.boot.web.context.WebServerInitializedEvent
at org.springframework.context.event.SimpleApplicationEventMulticaster.invokeListener(SimpleApplicationEventMulticaster.java:167)
at org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:139)
at org.springframework.context.support.AbstractApplicationContext.publishEvent(AbstractApplicationContext.java:399)
at org.springframework.context.support.AbstractApplicationContext.publishEvent(AbstractApplicationContext.java:353)
at org.springframework.web.servlet.FrameworkServlet.publishRequestHandledEvent(FrameworkServlet.java:1078)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1009)
at org.springframework.web.servlet.FrameworkServlet.doPut(FrameworkServlet.java:892)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:651)
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:855)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:729)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:230)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165)
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:192)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165)
at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:116)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:192)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165)
at org.jasig.cas.client.session.SingleSignOutFilter.doFilter(SingleSignOutFilter.java:97)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:192)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165)
at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilterAbstractAuthenticationProcessingFilter.java:200)
Thanks to the source code availability I started debugging and found that if I override org.springframework.context.event.GenericApplicationListenerAdapter.supportsEventType(ResolvableType eventType) like bellow everything is going back to normal.
#Override
#SuppressWarnings("unchecked")
public boolean supportsEventType(ResolvableType eventType) {
if (this.delegate instanceof SmartApplicationListener) {
Class<? extends ApplicationEvent> eventClass = (Class<? extends ApplicationEvent>) eventType.resolve();
return (eventClass != null &&
((SmartApplicationListener) this.delegate).supportsEventType(eventClass));
} else
return (this.declaredEventType == null ||
(this.declaredEventType.isAssignableFrom(eventType) &&
!this.declaredEventType.getType().toString().equals("E")));
}
(I have added !this.declaredEventType.getType().toString().equals("E") to the last return statement)
Question:
Should I stick with this hack or just might miss something in a configuration?
Thanks in advance.
You haven't missed anything in your configuration. The ClassCastException is due to a bug in Spring Framework 5.0 RC3. It's been fixed in the latest snapshots. You could stick with your hack for now, or you could switch to using Spring Framework snapshots (that are available from https://repo.spring.io/snapshot) by overriding spring.version in your pom.xml or build.gradle.

Spring Session store user credential only

I am currently Spring MVC 4 with Spring Data Neo4j/MongoDB/JPA. Everything works find until I need to use Spring Session Data Redis to share sessions between servers. The problem is that Spring Session intercept all the HttpSession and store them in Redis. Thus the following exception is seen:
org.springframework.data.redis.serializer.SerializationException: Cannot serialize; nested exception is org.springframework.core.serializer.support.SerializationFailedException: Failed to serialize object using DefaultSerializer; nested exception is java.lang.IllegalArgumentException: DefaultSerializer requires a Serializable payload but received an object of type [org.neo4j.ogm.session.Neo4jSession]
at org.springframework.data.redis.serializer.JdkSerializationRedisSerializer.serialize(JdkSerializationRedisSerializer.java:92)
at org.springframework.data.redis.core.AbstractOperations.rawHashValue(AbstractOperations.java:168)
at org.springframework.data.redis.core.DefaultHashOperations.putAll(DefaultHashOperations.java:129)
at org.springframework.data.redis.core.DefaultBoundHashOperations.putAll(DefaultBoundHashOperations.java:86)
at org.springframework.session.data.redis.RedisOperationsSessionRepository$RedisSession.saveDelta(RedisOperationsSessionRepository.java:778)
at org.springframework.session.data.redis.RedisOperationsSessionRepository$RedisSession.access$000(RedisOperationsSessionRepository.java:670)
at org.springframework.session.data.redis.RedisOperationsSessionRepository.save(RedisOperationsSessionRepository.java:388)
at org.springframework.session.data.redis.RedisOperationsSessionRepository.save(RedisOperationsSessionRepository.java:245)
at org.springframework.session.web.http.SessionRepositoryFilter$SessionRepositoryRequestWrapper.commitSession(SessionRepositoryFilter.java:244)
at org.springframework.session.web.http.SessionRepositoryFilter$SessionRepositoryRequestWrapper.access$100(SessionRepositoryFilter.java:214)
at org.springframework.session.web.http.SessionRepositoryFilter.doFilterInternal(SessionRepositoryFilter.java:167)
at org.springframework.session.web.http.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:80)
at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:346)
at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:262)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:240)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:207)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:212)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:106)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:502)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:141)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:79)
at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:616)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:88)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:522)
at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1095)
at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:672)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1502)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.run(NioEndpoint.java:1458)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.lang.Thread.run(Thread.java:745)
Caused by: org.springframework.core.serializer.support.SerializationFailedException: Failed to serialize object using DefaultSerializer; nested exception is java.lang.IllegalArgumentException: DefaultSerializer requires a Serializable payload but received an object of type [org.neo4j.ogm.session.Neo4jSession]
at org.springframework.core.serializer.support.SerializingConverter.convert(SerializingConverter.java:68)
at org.springframework.core.serializer.support.SerializingConverter.convert(SerializingConverter.java:35)
at org.springframework.data.redis.serializer.JdkSerializationRedisSerializer.serialize(JdkSerializationRedisSerializer.java:90)
... 31 more
Caused by: java.lang.IllegalArgumentException: DefaultSerializer requires a Serializable payload but received an object of type [org.neo4j.ogm.session.Neo4jSession]
at org.springframework.core.serializer.DefaultSerializer.serialize(DefaultSerializer.java:43)
at org.springframework.core.serializer.support.SerializingConverter.convert(SerializingConverter.java:63)
... 33 more
from which I think the Neo4jSession is not serializable. Thus, how can I configure Spring Session to only store client session in Redis and locally for sessions of Spring Data.
some codes:
web.xml
<filter>
<filter-name>springSessionRepositoryFilter</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
<filter-name>springSessionRepositoryFilter</filter-name>
<url-pattern>/*</url-pattern>
<dispatcher>REQUEST</dispatcher>
<dispatcher>ERROR</dispatcher>
</filter-mapping>
Config.class
#EnableRedisHttpSession
public class Config {
#Bean
public static ConfigureRedisAction configureRedisAction() {
return ConfigureRedisAction.NO_OP;
}
#Bean
public JedisConnectionFactory connectionFactory() {
JedisConnectionFactory connection = new JedisConnectionFactory();
connection.setHostName("myhost.aliyuncs.com");
connection.setPassword("xxxx");
connection.setPort(6379);
return connection;
}
}
Many thanks.
Problem temporarily solved. I change scope of the Neo4jSession to request, so that it doesn't store with the session.

undertow + Spring WebApplicationInitializer - Double initialization

I am migrating an old web app. It was written with old web.xml-style, now we want to programmatically build the servlet.
This is a Spring MVC app, deployed as a WAR module in an EAR under Wildfly 10.0.0.Final.
I wrote my implementation of Spring's WebApplicationInitializer (still using Spring XML config at the moment, to preceed step by step - next step will be to migrate to JavaConfig). Though I'm stuck here because the servlet is initialized twice, and the second time the initilization fails due to a filter's name conflict - NullPointerException after filter creation.
This is my initilizer:
public class MyWebApplicationInitializer implements WebApplicationInitializer {
private static final Logger log = LoggerFactory.getLogger(MyWebApplicationInitializer.class);
/**
* #see org.springframework.web.WebApplicationInitializer#onStartup(javax.servlet.ServletContext)
*/
#Override
public void onStartup(ServletContext container) throws ServletException {
log.debug("******* Initializing Web App *******");
XmlWebApplicationContext rootContext = new XmlWebApplicationContext();
rootContext.setConfigLocation("classpath:META-INF/spring/application-context.xml");
XmlWebApplicationContext webContext = new XmlWebApplicationContext();
webContext.setConfigLocation("classpath:META-INF/spring/mvc-context.xml");
container.addListener(new ContextLoaderListener(rootContext));
ServletRegistration.Dynamic dispatcher = container.addServlet("dispatcher", new DispatcherServlet(webContext));
dispatcher.setLoadOnStartup(1);
dispatcher.addMapping("/");
container.addFilter("log4jEnhancementFilter", Log4jEnhancementFilter.class);
log.info("******* Web App correctly initialized *******");
}
}
A bit of log below:
[ServerService Thread Pool -- 74]:[INFO] # 2016-04-19 07:19:27,725: io.undertow.servlet.spec.ServletContextImpl.log:313: Spring WebApplicationInitializers detected on classpath: [com.xyz.web.servlet.MyWebApplicationInitializer#6356dd91]
[ServerService Thread Pool -- 74]:[DEBUG] # 2016-04-19 07:19:27,725: com.xyz.web.servlet.MyWebApplicationInitializer.onStartup:44: ******* Initializing Web App *******
...
[ServerService Thread Pool -- 74]:[INFO] # 2016-04-19 07:19:27,796: com.xyz.web.servlet.MyWebApplicationInitializer.onStartup:59: ******* Web App correctly initialized *******
...
[ServerService Thread Pool -- 74]:[INFO] # 2016-04-19 07:19:27,797: io.undertow.servlet.spec.ServletContextImpl.log:313: Spring WebApplicationInitializers detected on classpath: [com.xyz.web.servlet.MyWebApplicationInitializer#427d3c64]
[ServerService Thread Pool -- 74]:[DEBUG] # 2016-04-19 07:19:27,797: com.xyz.web.servlet.MyWebApplicationInitializer.onStartup:44: ******* Initializing Web App *******
07:19:27,800 ERROR [org.jboss.msc.service.fail] (ServerService Thread Pool -- 74) MSC000001: Failed to start service jboss.undertow.deployment.default-server.default-host./www: org.jboss.msc.service.StartException in service jboss.undertow.deployment.default-server.default-host./www: java.lang.RuntimeException: java.lang.NullPointerException
at org.wildfly.extension.undertow.deployment.UndertowDeploymentService$1.run(UndertowDeploymentService.java:85)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:745)
at org.jboss.threads.JBossThread.run(JBossThread.java:320)
Caused by: java.lang.RuntimeException: java.lang.NullPointerException
at io.undertow.servlet.core.DeploymentManagerImpl.deploy(DeploymentManagerImpl.java:231)
at org.wildfly.extension.undertow.deployment.UndertowDeploymentService.startContext(UndertowDeploymentService.java:100)
at org.wildfly.extension.undertow.deployment.UndertowDeploymentService$1.run(UndertowDeploymentService.java:82)
... 6 more
Caused by: java.lang.NullPointerException
at com.xyz.web.servlet.MyWebApplicationInitializer.onStartup(MyWebApplicationInitializer.java:54)
at org.springframework.web.SpringServletContainerInitializer.onStartup(SpringServletContainerInitializer.java:175)
at io.undertow.servlet.core.DeploymentManagerImpl.deploy(DeploymentManagerImpl.java:184)
... 8 more
As you can see there is a double servlet's initilization; the first succeeds, the second fails due to the NPE.
What am I doing wrong and how can I fix it?

Resources