Dans mon application basée sur Spring Boot
1.4, j'utilise Spring Session
pour stocker les données de session dans la base de données avec JDBC
.
Cela fonctionne bien avec la session par défaut. Mais lorsque je veux ajouter une nouvelle session (en ajoutant ?_s=1
à l'URL de l'application), j'obtiens l'exception suivante:
Java.lang.IllegalArgumentException: An invalid character [32] was present in the Cookie value
Quel est le problème ici?
Modifier: Notez que je ne définit pas la valeur du cookie moi-même, Spring Session
le fait. Ainsi, je ne peux pas dire quelle valeur il essaie de définir.
Le stacktrace complet est ici:
Java.lang.IllegalArgumentException: An invalid character [32] was present in the Cookie value
at org.Apache.Tomcat.util.http.Rfc6265CookieProcessor.validateCookieValue(Rfc6265CookieProcessor.Java:160) ~[Tomcat-embed-core-8.5.4.jar:8.5.4]
at org.Apache.Tomcat.util.http.Rfc6265CookieProcessor.generateHeader(Rfc6265CookieProcessor.Java:109) ~[Tomcat-embed-core-8.5.4.jar:8.5.4]
at org.Apache.catalina.connector.Response.generateCookieString(Response.Java:989) ~[Tomcat-embed-core-8.5.4.jar:8.5.4]
at org.Apache.catalina.connector.Response.addCookie(Response.Java:937) ~[Tomcat-embed-core-8.5.4.jar:8.5.4]
at org.Apache.catalina.connector.ResponseFacade.addCookie(ResponseFacade.Java:386) ~[Tomcat-embed-core-8.5.4.jar:8.5.4]
at org.springframework.session.web.http.DefaultCookieSerializer.writeCookieValue(DefaultCookieSerializer.Java:112) ~[spring-session-1.2.1.RELEASE.jar:na]
at org.springframework.session.web.http.CookieHttpSessionStrategy.onNewSession(CookieHttpSessionStrategy.Java:213) ~[spring-session-1.2.1.RELEASE.jar:na]
at org.springframework.session.web.http.SessionRepositoryFilter$SessionRepositoryRequestWrapper.commitSession(SessionRepositoryFilter.Java:247) ~[spring-session-1.2.1.RELEASE.jar:na]
at org.springframework.session.web.http.SessionRepositoryFilter$SessionRepositoryRequestWrapper.access$100(SessionRepositoryFilter.Java:214) ~[spring-session-1.2.1.RELEASE.jar:na]
at org.springframework.session.web.http.SessionRepositoryFilter$SessionRepositoryResponseWrapper.onResponseCommitted(SessionRepositoryFilter.Java:202) ~[spring-session-1.2.1.RELEASE.jar:na]
at org.springframework.session.web.http.OnCommittedResponseWrapper.doOnResponseCommitted(OnCommittedResponseWrapper.Java:226) ~[spring-session-1.2.1.RELEASE.jar:na]
at org.springframework.session.web.http.OnCommittedResponseWrapper.sendRedirect(OnCommittedResponseWrapper.Java:126) ~[spring-session-1.2.1.RELEASE.jar:na]
at javax.servlet.http.HttpServletResponseWrapper.sendRedirect(HttpServletResponseWrapper.Java:138) ~[Tomcat-embed-core-8.5.4.jar:8.5.4]
at javax.servlet.http.HttpServletResponseWrapper.sendRedirect(HttpServletResponseWrapper.Java:138) ~[Tomcat-embed-core-8.5.4.jar:8.5.4]
at org.springframework.security.web.firewall.FirewalledResponse.sendRedirect(FirewalledResponse.Java:41) ~[spring-security-web-4.1.1.RELEASE.jar:4.1.1.RELEASE]
at javax.servlet.http.HttpServletResponseWrapper.sendRedirect(HttpServletResponseWrapper.Java:138) ~[Tomcat-embed-core-8.5.4.jar:8.5.4]
at org.springframework.security.web.util.OnCommittedResponseWrapper.sendRedirect(OnCommittedResponseWrapper.Java:128) ~[spring-security-web-4.1.1.RELEASE.jar:4.1.1.RELEASE]
at javax.servlet.http.HttpServletResponseWrapper.sendRedirect(HttpServletResponseWrapper.Java:138) ~[Tomcat-embed-core-8.5.4.jar:8.5.4]
at org.springframework.security.web.util.OnCommittedResponseWrapper.sendRedirect(OnCommittedResponseWrapper.Java:128) ~[spring-security-web-4.1.1.RELEASE.jar:4.1.1.RELEASE]
at org.springframework.security.web.DefaultRedirectStrategy.sendRedirect(DefaultRedirectStrategy.Java:57) ~[spring-security-web-4.1.1.RELEASE.jar:4.1.1.RELEASE]
at org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint.commence(LoginUrlAuthenticationEntryPoint.Java:169) ~[spring-security-web-4.1.1.RELEASE.jar:4.1.1.RELEASE]
at org.springframework.security.web.access.ExceptionTranslationFilter.sendStartAuthentication(ExceptionTranslationFilter.Java:204) ~[spring-security-web-4.1.1.RELEASE.jar:4.1.1.RELEASE]
at org.springframework.security.web.access.ExceptionTranslationFilter.handleSpringSecurityException(ExceptionTranslationFilter.Java:178) ~[spring-security-web-4.1.1.RELEASE.jar:4.1.1.RELEASE]
at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.Java:134) ~[spring-security-web-4.1.1.RELEASE.jar:4.1.1.RELEASE]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.Java:331) ~[spring-security-web-4.1.1.RELEASE.jar:4.1.1.RELEASE]
at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.Java:137) ~[spring-security-web-4.1.1.RELEASE.jar:4.1.1.RELEASE]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.Java:331) ~[spring-security-web-4.1.1.RELEASE.jar:4.1.1.RELEASE]
at org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.Java:111) ~[spring-security-web-4.1.1.RELEASE.jar:4.1.1.RELEASE]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.Java:331) ~[spring-security-web-4.1.1.RELEASE.jar:4.1.1.RELEASE]
at org.springframework.security.web.authentication.rememberme.RememberMeAuthenticationFilter.doFilter(RememberMeAuthenticationFilter.Java:150) ~[spring-security-web-4.1.1.RELEASE.jar:4.1.1.RELEASE]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.Java:331) ~[spring-security-web-4.1.1.RELEASE.jar:4.1.1.RELEASE]
at org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.Java:169) ~[spring-security-web-4.1.1.RELEASE.jar:4.1.1.RELEASE]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.Java:331) ~[spring-security-web-4.1.1.RELEASE.jar:4.1.1.RELEASE]
at org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.Java:63) ~[spring-security-web-4.1.1.RELEASE.jar:4.1.1.RELEASE]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.Java:331) ~[spring-security-web-4.1.1.RELEASE.jar:4.1.1.RELEASE]
at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.Java:200) ~[spring-security-web-4.1.1.RELEASE.jar:4.1.1.RELEASE]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.Java:331) ~[spring-security-web-4.1.1.RELEASE.jar:4.1.1.RELEASE]
at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.Java:121) ~[spring-security-web-4.1.1.RELEASE.jar:4.1.1.RELEASE]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.Java:331) ~[spring-security-web-4.1.1.RELEASE.jar:4.1.1.RELEASE]
at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.Java:66) ~[spring-security-web-4.1.1.RELEASE.jar:4.1.1.RELEASE]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.Java:107) ~[spring-web-4.3.2.RELEASE.jar:4.3.2.RELEASE]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.Java:331) ~[spring-security-web-4.1.1.RELEASE.jar:4.1.1.RELEASE]
at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.Java:105) ~[spring-security-web-4.1.1.RELEASE.jar:4.1.1.RELEASE]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.Java:331) ~[spring-security-web-4.1.1.RELEASE.jar:4.1.1.RELEASE]
at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.Java:56) ~[spring-security-web-4.1.1.RELEASE.jar:4.1.1.RELEASE]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.Java:107) ~[spring-web-4.3.2.RELEASE.jar:4.3.2.RELEASE]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.Java:331) ~[spring-security-web-4.1.1.RELEASE.jar:4.1.1.RELEASE]
at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.Java:214) ~[spring-security-web-4.1.1.RELEASE.jar:4.1.1.RELEASE]
at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.Java:177) ~[spring-security-web-4.1.1.RELEASE.jar:4.1.1.RELEASE]
at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.Java:346) ~[spring-web-4.3.2.RELEASE.jar:4.3.2.RELEASE]
at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.Java:262) ~[spring-web-4.3.2.RELEASE.jar:4.3.2.RELEASE]
at org.Apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.Java:192) ~[Tomcat-embed-core-8.5.4.jar:8.5.4]
at org.Apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.Java:165) ~[Tomcat-embed-core-8.5.4.jar:8.5.4]
at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.Java:99) ~[spring-web-4.3.2.RELEASE.jar:4.3.2.RELEASE]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.Java:107) ~[spring-web-4.3.2.RELEASE.jar:4.3.2.RELEASE]
at org.Apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.Java:192) ~[Tomcat-embed-core-8.5.4.jar:8.5.4]
at org.Apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.Java:165) ~[Tomcat-embed-core-8.5.4.jar:8.5.4]
at org.springframework.web.filter.HttpPutFormContentFilter.doFilterInternal(HttpPutFormContentFilter.Java:87) ~[spring-web-4.3.2.RELEASE.jar:4.3.2.RELEASE]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.Java:107) ~[spring-web-4.3.2.RELEASE.jar:4.3.2.RELEASE]
at org.Apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.Java:192) ~[Tomcat-embed-core-8.5.4.jar:8.5.4]
at org.Apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.Java:165) ~[Tomcat-embed-core-8.5.4.jar:8.5.4]
at org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.Java:77) ~[spring-web-4.3.2.RELEASE.jar:4.3.2.RELEASE]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.Java:107) ~[spring-web-4.3.2.RELEASE.jar:4.3.2.RELEASE]
at org.Apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.Java:192) ~[Tomcat-embed-core-8.5.4.jar:8.5.4]
at org.Apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.Java:165) ~[Tomcat-embed-core-8.5.4.jar:8.5.4]
at org.springframework.session.web.http.SessionRepositoryFilter.doFilterInternal(SessionRepositoryFilter.Java:164) ~[spring-session-1.2.1.RELEASE.jar:na]
at org.springframework.session.web.http.OncePerRequestFilter.doFilter(OncePerRequestFilter.Java:80) ~[spring-session-1.2.1.RELEASE.jar:na]
at org.Apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.Java:192) ~[Tomcat-embed-core-8.5.4.jar:8.5.4]
at org.Apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.Java:165) ~[Tomcat-embed-core-8.5.4.jar:8.5.4]
at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.Java:197) ~[spring-web-4.3.2.RELEASE.jar:4.3.2.RELEASE]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.Java:107) ~[spring-web-4.3.2.RELEASE.jar:4.3.2.RELEASE]
at org.Apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.Java:192) ~[Tomcat-embed-core-8.5.4.jar:8.5.4]
at org.Apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.Java:165) ~[Tomcat-embed-core-8.5.4.jar:8.5.4]
at org.Apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.Java:198) ~[Tomcat-embed-core-8.5.4.jar:8.5.4]
at org.Apache.catalina.core.StandardContextValve.__invoke(StandardContextValve.Java:108) [Tomcat-embed-core-8.5.4.jar:8.5.4]
at org.Apache.catalina.core.StandardContextValve.invoke(StandardContextValve.Java) [Tomcat-embed-core-8.5.4.jar:8.5.4]
at org.Apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.Java:522) [Tomcat-embed-core-8.5.4.jar:8.5.4]
at org.Apache.catalina.core.StandardHostValve.invoke(StandardHostValve.Java:140) [Tomcat-embed-core-8.5.4.jar:8.5.4]
at org.Apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.Java:79) [Tomcat-embed-core-8.5.4.jar:8.5.4]
at org.Apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.Java:87) [Tomcat-embed-core-8.5.4.jar:8.5.4]
at org.Apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.Java:349) [Tomcat-embed-core-8.5.4.jar:8.5.4]
at org.Apache.coyote.http11.Http11Processor.service(Http11Processor.Java:1110) [Tomcat-embed-core-8.5.4.jar:8.5.4]
at org.Apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.Java:66) [Tomcat-embed-core-8.5.4.jar:8.5.4]
at org.Apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.Java:785) [Tomcat-embed-core-8.5.4.jar:8.5.4]
at org.Apache.Tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.Java:1425) [Tomcat-embed-core-8.5.4.jar:8.5.4]
at org.Apache.Tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.Java:49) [Tomcat-embed-core-8.5.4.jar:8.5.4]
at Java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.Java:1142) [na:1.8.0_101]
at Java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.Java:617) [na:1.8.0_101]
at org.Apache.Tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.Java:61) [Tomcat-embed-core-8.5.4.jar:8.5.4]
at Java.lang.Thread.run(Thread.Java:745) [na:1.8.0_101]
Cela est dû au fait que le traitement des cookies de Tomcat a été modifié par défaut en une implémentation conforme à la norme RFC 6265 dans la version 8.5, ce qui n'autorise pas d'espace (caractère 32), entre autres.
Pour contourner le problème, vous pouvez configurer Tomcat pour utiliser le processeur de cookies hérité. Pour ce faire avec Spring Boot, enregistrez une EmbeddedServletContainerCustomizer
@Bean
comme ceci:
@Bean
public EmbeddedServletContainerCustomizer customizer() {
return container -> {
if (container instanceof TomcatEmbeddedServletContainerFactory) {
TomcatEmbeddedServletContainerFactory Tomcat = (TomcatEmbeddedServletContainerFactory) container;
Tomcat.addContextCustomizers(context -> context.setCookieProcessor(new LegacyCookieProcessor()));
}
};
}
Voir aussi projets-printemps/session-printemps # gh-605 pour suivre les progrès de la résolution de ce problème lors de la session de printemps.
Mettre à jour:
La solution décrite ci-dessus est valable pour Spring Boot 1.x. À partir de Spring Boot 2.0, EmbeddedServletContainerCustomizer
a été remplacé par WebServerFactoryCustomizer
comme décrit dans/ Guide de migration Spring Boot 2.0 .
Notez également qu'à partir de Spring Session 2.0, le cookie de session est codé en Base64 par défaut, ce qui empêche le problème d'origine de se produire.
CookieProcessor est un nouvel élément de configuration introduit dans Tomcat 8.0.15. L'élément CookieProcessor autorise différentes configurations d'analyse des cookies dans chaque application Web ou globalement dans le fichier par défaut conf/context.xml.
Selon la documentation officielle de Apache Tomcat 8 - Référence de configuration Version 8.0.47 :
L'implémentation standard de CookieProcessor est la suivante: org.Apache.Tomcat.util.http.LegacyCookieProcessor. Notez qu'il est prévu que cela passe à org.Apache.Tomcat.util.http.Rfc6265CookieProcessor dans une future version de Tomcat 8.
Plus tard..
Selon la documentation officielle sur Apache Tomcat 8 - Référence de configuration Version 8.5.23:
L'implémentation standard de CookieProcessor est org.Apache.Tomcat.util.http.Rfc6265CookieProcessor.
Pour résoudre ce problème: ajoutez cette ligne dans conf/context.xml à l’emplacement% CATALINA_HOME% (c.-à-d. C:\Apache-Tomcat-8.5.20\conf\context.xml dans mon cas):
<CookieProcessor className="org.Apache.Tomcat.util.http.LegacyCookieProcessor" />
Voici à quoi cela ressemble après avoir ajouté:
<?xml version="1.0" encoding="UTF-8"?>
<Context reloadable="true">
<WatchedResource>WEB-INF/web.xml</WatchedResource>
<WatchedResource>${catalina.base}/conf/web.xml</WatchedResource>
<Transaction factory="bitronix.tm.BitronixUserTransactionObjectFactory"/>
<CookieProcessor className="org.Apache.Tomcat.util.http.LegacyCookieProcessor" />
</Context>
Le cookie de fonction ne peut pas encoder correctement la valeur avec un espace, mais aussi des signes français, etc. Je résous ce problème avec URLEncoder.encode (String arg0, version d'encodage) ici, j'ai utilisé UTF-8 . Voilà la méthode que j'ai créée!
private static void setCookie( HttpServletResponse response, String nom, String valeur, int maxAge )throws IOException {
Cookie cookie = new Cookie( nom, URLEncoder.encode( valeur, "UTF-8" ) );
cookie.setMaxAge( maxAge );
response.addCookie( cookie );
}
N'utilisez pas d'espaces dans le contenu du cookie. Il mentionne les espaces comme caractère invalide.