Skip to content

Commit e9bd11e

Browse files
vpavicphilwebb
authored andcommitted
Fix NoClassDefFound when missing Spring Security
Update Spring Session auto-configuration to ensure that the `DefaultCookieSerializer` doesn't break when Spring Security is not present on the classpath. Closes gh-16889
1 parent 5fc67c5 commit e9bd11e

File tree

3 files changed

+105
-6
lines changed

3 files changed

+105
-6
lines changed

spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/session/SessionAutoConfiguration.java

Lines changed: 32 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,9 @@
2323

2424
import javax.annotation.PostConstruct;
2525

26+
import org.springframework.beans.BeansException;
2627
import org.springframework.beans.factory.ObjectProvider;
28+
import org.springframework.beans.factory.config.BeanPostProcessor;
2729
import org.springframework.boot.WebApplicationType;
2830
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
2931
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
@@ -53,6 +55,7 @@
5355
import org.springframework.context.annotation.Import;
5456
import org.springframework.context.annotation.ImportSelector;
5557
import org.springframework.core.type.AnnotationMetadata;
58+
import org.springframework.security.web.authentication.RememberMeServices;
5659
import org.springframework.session.ReactiveSessionRepository;
5760
import org.springframework.session.Session;
5861
import org.springframework.session.SessionRepository;
@@ -92,8 +95,8 @@ static class ServletSessionConfiguration {
9295

9396
@Bean
9497
@Conditional(DefaultCookieSerializerCondition.class)
95-
public DefaultCookieSerializer cookieSerializer(ServerProperties serverProperties,
96-
ObjectProvider<SpringSessionRememberMeServices> springSessionRememberMeServices) {
98+
public DefaultCookieSerializer cookieSerializer(
99+
ServerProperties serverProperties) {
97100
Cookie cookie = serverProperties.getServlet().getSession().getCookie();
98101
DefaultCookieSerializer cookieSerializer = new DefaultCookieSerializer();
99102
PropertyMapper map = PropertyMapper.get().alwaysApplyingWhenNonNull();
@@ -104,9 +107,6 @@ public DefaultCookieSerializer cookieSerializer(ServerProperties serverPropertie
104107
map.from(cookie::getSecure).to(cookieSerializer::setUseSecureCookie);
105108
map.from(cookie::getMaxAge).to((maxAge) -> cookieSerializer
106109
.setCookieMaxAge((int) maxAge.getSeconds()));
107-
springSessionRememberMeServices.ifAvailable((
108-
rememberMeServices) -> cookieSerializer.setRememberMeRequestAttribute(
109-
SpringSessionRememberMeServices.REMEMBER_ME_LOGIN_ATTR));
110110
return cookieSerializer;
111111
}
112112

@@ -118,6 +118,33 @@ static class ServletSessionRepositoryConfiguration {
118118

119119
}
120120

121+
@Configuration
122+
@ConditionalOnClass(RememberMeServices.class)
123+
static class RememberMeServicesConfiguration {
124+
125+
@Bean
126+
public BeanPostProcessor rememberMeServicesBeanPostProcessor(
127+
ObjectProvider<SpringSessionRememberMeServices> springSessionRememberMeServices) {
128+
return new BeanPostProcessor() {
129+
130+
@Override
131+
public Object postProcessBeforeInitialization(Object bean,
132+
String beanName) throws BeansException {
133+
if (bean instanceof DefaultCookieSerializer) {
134+
DefaultCookieSerializer cookieSerializer = (DefaultCookieSerializer) bean;
135+
springSessionRememberMeServices
136+
.ifAvailable((rememberMeServices) -> cookieSerializer
137+
.setRememberMeRequestAttribute(
138+
SpringSessionRememberMeServices.REMEMBER_ME_LOGIN_ATTR));
139+
}
140+
return bean;
141+
}
142+
143+
};
144+
}
145+
146+
}
147+
121148
}
122149

123150
@Configuration

spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/session/AbstractSessionAutoConfigurationTests.java

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2012-2018 the original author or authors.
2+
* Copyright 2012-2019 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -16,10 +16,16 @@
1616

1717
package org.springframework.boot.autoconfigure.session;
1818

19+
import java.util.Collections;
20+
1921
import org.springframework.boot.test.context.assertj.AssertableReactiveWebApplicationContext;
2022
import org.springframework.boot.test.context.assertj.AssertableWebApplicationContext;
23+
import org.springframework.context.annotation.Bean;
24+
import org.springframework.context.annotation.Configuration;
25+
import org.springframework.session.MapSessionRepository;
2126
import org.springframework.session.ReactiveSessionRepository;
2227
import org.springframework.session.SessionRepository;
28+
import org.springframework.session.config.annotation.web.http.EnableSpringHttpSession;
2329
import org.springframework.session.web.http.SessionRepositoryFilter;
2430
import org.springframework.web.server.session.WebSessionManager;
2531

@@ -51,4 +57,15 @@ protected <T extends ReactiveSessionRepository<?>> T validateSessionRepository(
5157
return type.cast(repository);
5258
}
5359

60+
@Configuration
61+
@EnableSpringHttpSession
62+
static class SessionRepositoryConfiguration {
63+
64+
@Bean
65+
public MapSessionRepository mySessionRepository() {
66+
return new MapSessionRepository(Collections.emptyMap());
67+
}
68+
69+
}
70+
5471
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
/*
2+
* Copyright 2012-2019 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.boot.autoconfigure.session;
18+
19+
import org.junit.Test;
20+
import org.junit.runner.RunWith;
21+
22+
import org.springframework.boot.autoconfigure.AutoConfigurations;
23+
import org.springframework.boot.test.context.runner.WebApplicationContextRunner;
24+
import org.springframework.boot.testsupport.runner.classpath.ClassPathExclusions;
25+
import org.springframework.boot.testsupport.runner.classpath.ModifiedClassPathRunner;
26+
import org.springframework.session.web.http.DefaultCookieSerializer;
27+
28+
import static org.assertj.core.api.Assertions.assertThat;
29+
30+
/**
31+
* Tests for {@link SessionAutoConfiguration} when Spring Security is not on the
32+
* classpath.
33+
*
34+
* @author Vedran Pavic
35+
*/
36+
@RunWith(ModifiedClassPathRunner.class)
37+
@ClassPathExclusions("spring-security-*")
38+
public class SessionAutoConfigurationWithoutSecurityTests
39+
extends AbstractSessionAutoConfigurationTests {
40+
41+
private final WebApplicationContextRunner contextRunner = new WebApplicationContextRunner()
42+
.withConfiguration(AutoConfigurations.of(SessionAutoConfiguration.class));
43+
44+
@Test
45+
public void sessionCookieConfigurationIsAppliedToAutoConfiguredCookieSerializer() {
46+
this.contextRunner.withUserConfiguration(SessionRepositoryConfiguration.class)
47+
.run((context) -> {
48+
DefaultCookieSerializer cookieSerializer = context
49+
.getBean(DefaultCookieSerializer.class);
50+
assertThat(cookieSerializer).hasFieldOrPropertyWithValue(
51+
"rememberMeRequestAttribute", null);
52+
});
53+
}
54+
55+
}

0 commit comments

Comments
 (0)