Skip to content

Commit f9fc34a

Browse files
committed
Updates
- Update Checkstyle - Simplify Naming - Add password action to User and UserDetails
1 parent efdd412 commit f9fc34a

File tree

24 files changed

+438
-252
lines changed

24 files changed

+438
-252
lines changed

config/src/main/java/org/springframework/security/config/annotation/web/configuration/WebMvcSecurityConfiguration.java

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -37,9 +37,9 @@
3737
import org.springframework.security.core.context.SecurityContextHolderStrategy;
3838
import org.springframework.security.web.FilterChainProxy;
3939
import org.springframework.security.web.SecurityFilterChain;
40-
import org.springframework.security.web.authentication.password.ChangePasswordAdviceMethodArgumentResolver;
41-
import org.springframework.security.web.authentication.password.ChangePasswordAdviceRepository;
42-
import org.springframework.security.web.authentication.password.HttpSessionChangePasswordAdviceRepository;
40+
import org.springframework.security.web.authentication.password.HttpSessionPasswordAdviceRepository;
41+
import org.springframework.security.web.authentication.password.PasswordAdviceMethodArgumentResolver;
42+
import org.springframework.security.web.authentication.password.PasswordAdviceRepository;
4343
import org.springframework.security.web.debug.DebugFilter;
4444
import org.springframework.security.web.firewall.HttpFirewall;
4545
import org.springframework.security.web.firewall.RequestRejectedHandler;
@@ -75,7 +75,7 @@ class WebMvcSecurityConfiguration implements WebMvcConfigurer, ApplicationContex
7575

7676
private AnnotationTemplateExpressionDefaults templateDefaults;
7777

78-
private ChangePasswordAdviceRepository changePasswordAdviceRepository = new HttpSessionChangePasswordAdviceRepository();
78+
private PasswordAdviceRepository passwordAdviceRepository = new HttpSessionPasswordAdviceRepository();
7979

8080
@Override
8181
@SuppressWarnings("deprecation")
@@ -93,8 +93,8 @@ public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentRes
9393
currentSecurityContextArgumentResolver.setTemplateDefaults(this.templateDefaults);
9494
argumentResolvers.add(currentSecurityContextArgumentResolver);
9595
argumentResolvers.add(new CsrfTokenArgumentResolver());
96-
ChangePasswordAdviceMethodArgumentResolver resolver = new ChangePasswordAdviceMethodArgumentResolver();
97-
resolver.setChangePasswordAdviceRepository(this.changePasswordAdviceRepository);
96+
PasswordAdviceMethodArgumentResolver resolver = new PasswordAdviceMethodArgumentResolver();
97+
resolver.setPasswordAdviceRepository(this.passwordAdviceRepository);
9898
argumentResolvers.add(resolver);
9999
}
100100

@@ -112,8 +112,8 @@ public void setApplicationContext(ApplicationContext applicationContext) throws
112112
if (applicationContext.getBeanNamesForType(AnnotationTemplateExpressionDefaults.class).length == 1) {
113113
this.templateDefaults = applicationContext.getBean(AnnotationTemplateExpressionDefaults.class);
114114
}
115-
if (applicationContext.getBeanNamesForType(ChangePasswordAdviceRepository.class).length == 1) {
116-
this.changePasswordAdviceRepository = applicationContext.getBean(ChangePasswordAdviceRepository.class);
115+
if (applicationContext.getBeanNamesForType(PasswordAdviceRepository.class).length == 1) {
116+
this.passwordAdviceRepository = applicationContext.getBean(PasswordAdviceRepository.class);
117117
}
118118
}
119119

@@ -220,7 +220,7 @@ private static Filter createDoFilterDelegate(List<? extends Filter> filters) {
220220

221221
/**
222222
* Find the FilterChainProxy in a List of Filter
223-
* @param filters
223+
* @param filterssetChangePass
224224
* @return non-null FilterChainProxy
225225
* @throws IllegalStateException if the FilterChainProxy cannot be found
226226
*/

config/src/main/java/org/springframework/security/config/annotation/web/configurers/PasswordManagementConfigurer.java

Lines changed: 23 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -18,18 +18,15 @@
1818

1919
import org.springframework.context.ApplicationContext;
2020
import org.springframework.context.ApplicationContextAware;
21-
import org.springframework.security.authentication.password.ChangePasswordAdvisor;
22-
import org.springframework.security.authentication.password.CompositeChangePasswordAdvisor;
23-
import org.springframework.security.authentication.password.UserDetailsChangePasswordAdvisor;
24-
import org.springframework.security.authentication.password.UserDetailsPasswordManager;
21+
import org.springframework.security.authentication.password.PasswordAdvisor;
22+
import org.springframework.security.authentication.password.UserDetailsPasswordAdvisor;
2523
import org.springframework.security.config.annotation.web.HttpSecurityBuilder;
2624
import org.springframework.security.web.RequestMatcherRedirectFilter;
2725
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
28-
import org.springframework.security.web.authentication.password.ChangeCompromisedPasswordAdvisor;
29-
import org.springframework.security.web.authentication.password.ChangePasswordAdviceRepository;
30-
import org.springframework.security.web.authentication.password.ChangePasswordAdviceSessionAuthenticationStrategy;
31-
import org.springframework.security.web.authentication.password.ChangePasswordAdvisingFilter;
32-
import org.springframework.security.web.authentication.password.HttpSessionChangePasswordAdviceRepository;
26+
import org.springframework.security.web.authentication.password.HttpSessionPasswordAdviceRepository;
27+
import org.springframework.security.web.authentication.password.PasswordAdviceRepository;
28+
import org.springframework.security.web.authentication.password.PasswordAdviceSessionAuthenticationStrategy;
29+
import org.springframework.security.web.authentication.password.PasswordAdvisingFilter;
3330
import org.springframework.security.web.savedrequest.RequestCache;
3431
import org.springframework.security.web.savedrequest.RequestCacheAwareFilter;
3532
import org.springframework.util.Assert;
@@ -53,11 +50,9 @@ public final class PasswordManagementConfigurer<B extends HttpSecurityBuilder<B>
5350

5451
private String changePasswordPage = DEFAULT_CHANGE_PASSWORD_PAGE;
5552

56-
private ChangePasswordAdviceRepository changePasswordAdviceRepository;
53+
private PasswordAdviceRepository passwordAdviceRepository;
5754

58-
private ChangePasswordAdvisor changePasswordAdvisor;
59-
60-
private UserDetailsPasswordManager userDetailsPasswordManager;
55+
private PasswordAdvisor passwordAdvisor;
6156

6257
/**
6358
* Sets the change password page. Defaults to
@@ -72,55 +67,36 @@ public PasswordManagementConfigurer<B> changePasswordPage(String changePasswordP
7267
return this;
7368
}
7469

75-
public PasswordManagementConfigurer<B> changePasswordAdviceRepository(
76-
ChangePasswordAdviceRepository changePasswordAdviceRepository) {
77-
this.changePasswordAdviceRepository = changePasswordAdviceRepository;
70+
public PasswordManagementConfigurer<B> passwordAdviceRepository(PasswordAdviceRepository passwordAdviceRepository) {
71+
this.passwordAdviceRepository = passwordAdviceRepository;
7872
return this;
7973
}
8074

81-
public PasswordManagementConfigurer<B> changePasswordAdvisor(ChangePasswordAdvisor changePasswordAdvisor) {
82-
this.changePasswordAdvisor = changePasswordAdvisor;
83-
return this;
84-
}
85-
86-
public PasswordManagementConfigurer<B> userDetailsPasswordManager(
87-
UserDetailsPasswordManager userDetailsPasswordManager) {
88-
this.userDetailsPasswordManager = userDetailsPasswordManager;
75+
public PasswordManagementConfigurer<B> passwordAdvisor(PasswordAdvisor passwordAdvisor) {
76+
this.passwordAdvisor = passwordAdvisor;
8977
return this;
9078
}
9179

9280
@Override
9381
public void init(B http) throws Exception {
94-
UserDetailsPasswordManager passwordManager = (this.userDetailsPasswordManager == null)
95-
? this.context.getBeanProvider(UserDetailsPasswordManager.class).getIfUnique()
96-
: this.userDetailsPasswordManager;
82+
PasswordAdviceRepository passwordAdviceRepository = (this.passwordAdviceRepository != null)
83+
? this.passwordAdviceRepository : this.context.getBeanProvider(PasswordAdviceRepository.class)
84+
.getIfUnique(HttpSessionPasswordAdviceRepository::new);
9785

98-
if (passwordManager == null) {
99-
return;
100-
}
86+
PasswordAdvisor passwordAdvisor = (this.passwordAdvisor != null) ? this.passwordAdvisor
87+
: this.context.getBeanProvider(PasswordAdvisor.class).getIfUnique(UserDetailsPasswordAdvisor::new);
10188

102-
ChangePasswordAdviceRepository changePasswordAdviceRepository = (this.changePasswordAdviceRepository != null)
103-
? this.changePasswordAdviceRepository
104-
: this.context.getBeanProvider(ChangePasswordAdviceRepository.class)
105-
.getIfUnique(HttpSessionChangePasswordAdviceRepository::new);
106-
107-
ChangePasswordAdvisor changePasswordAdvisor = (this.changePasswordAdvisor != null) ? this.changePasswordAdvisor
108-
: this.context.getBeanProvider(ChangePasswordAdvisor.class)
109-
.getIfUnique(() -> CompositeChangePasswordAdvisor.of(new UserDetailsChangePasswordAdvisor(),
110-
new ChangeCompromisedPasswordAdvisor()));
111-
112-
http.setSharedObject(ChangePasswordAdviceRepository.class, changePasswordAdviceRepository);
113-
http.setSharedObject(UserDetailsPasswordManager.class, passwordManager);
89+
http.setSharedObject(PasswordAdviceRepository.class, passwordAdviceRepository);
11490

11591
String passwordParameter = "password";
11692
FormLoginConfigurer<B> form = http.getConfigurer(FormLoginConfigurer.class);
11793
if (form != null) {
11894
passwordParameter = form.getPasswordParameter();
11995
}
120-
ChangePasswordAdviceSessionAuthenticationStrategy sessionAuthenticationStrategy = new ChangePasswordAdviceSessionAuthenticationStrategy(
96+
PasswordAdviceSessionAuthenticationStrategy sessionAuthenticationStrategy = new PasswordAdviceSessionAuthenticationStrategy(
12197
passwordParameter);
122-
sessionAuthenticationStrategy.setChangePasswordAdviceRepository(changePasswordAdviceRepository);
123-
sessionAuthenticationStrategy.setChangePasswordAdvisor(changePasswordAdvisor);
98+
sessionAuthenticationStrategy.setPasswordAdviceRepository(passwordAdviceRepository);
99+
sessionAuthenticationStrategy.setPasswordAdvisor(passwordAdvisor);
124100
http.getConfigurer(SessionManagementConfigurer.class)
125101
.addSessionAuthenticationStrategy(sessionAuthenticationStrategy);
126102
}
@@ -134,12 +110,8 @@ public void configure(B http) throws Exception {
134110
getRequestMatcherBuilder().matcher(WELL_KNOWN_CHANGE_PASSWORD_PATTERN), this.changePasswordPage);
135111
http.addFilterBefore(postProcess(changePasswordFilter), UsernamePasswordAuthenticationFilter.class);
136112

137-
if (http.getSharedObject(UserDetailsPasswordManager.class) == null) {
138-
return;
139-
}
140-
141-
ChangePasswordAdvisingFilter advising = new ChangePasswordAdvisingFilter(this.changePasswordPage);
142-
advising.setChangePasswordAdviceRepository(http.getSharedObject(ChangePasswordAdviceRepository.class));
113+
PasswordAdvisingFilter advising = new PasswordAdvisingFilter(this.changePasswordPage);
114+
advising.setPasswordAdviceRepository(http.getSharedObject(PasswordAdviceRepository.class));
143115
advising.setRequestCache(http.getSharedObject(RequestCache.class));
144116
http.addFilterBefore(advising, RequestCacheAwareFilter.class);
145117
}

config/src/test/java/org/springframework/security/config/annotation/web/configurers/PasswordManagementConfigurerTests.java

Lines changed: 33 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -29,26 +29,27 @@
2929
import org.springframework.context.annotation.Configuration;
3030
import org.springframework.http.ResponseEntity;
3131
import org.springframework.mock.web.MockHttpSession;
32-
import org.springframework.security.authentication.password.ChangePasswordAdvice;
33-
import org.springframework.security.authentication.password.ChangePasswordAdvisor;
3432
import org.springframework.security.authentication.password.PasswordAction;
35-
import org.springframework.security.authentication.password.UserDetailsPasswordManager;
33+
import org.springframework.security.authentication.password.PasswordAdvice;
34+
import org.springframework.security.authentication.password.UpdatePasswordAdvisor;
3635
import org.springframework.security.config.Customizer;
3736
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
3837
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
3938
import org.springframework.security.config.test.SpringTestContext;
4039
import org.springframework.security.config.test.SpringTestContextExtension;
4140
import org.springframework.security.core.annotation.AuthenticationPrincipal;
4241
import org.springframework.security.core.userdetails.PasswordEncodedUser;
42+
import org.springframework.security.core.userdetails.User;
4343
import org.springframework.security.core.userdetails.UserDetails;
4444
import org.springframework.security.core.userdetails.UserDetailsService;
4545
import org.springframework.security.crypto.factory.PasswordEncoderFactories;
4646
import org.springframework.security.crypto.password.PasswordEncoder;
4747
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
48+
import org.springframework.security.provisioning.UserDetailsManager;
4849
import org.springframework.security.web.SecurityFilterChain;
49-
import org.springframework.security.web.authentication.password.ChangeCompromisedPasswordAdvisor;
50-
import org.springframework.security.web.authentication.password.ChangePasswordAdviceRepository;
51-
import org.springframework.security.web.authentication.password.HttpSessionChangePasswordAdviceRepository;
50+
import org.springframework.security.web.authentication.password.CompromisedPasswordAdvisor;
51+
import org.springframework.security.web.authentication.password.HttpSessionPasswordAdviceRepository;
52+
import org.springframework.security.web.authentication.password.PasswordAdviceRepository;
5253
import org.springframework.test.web.servlet.MockMvc;
5354
import org.springframework.test.web.servlet.MvcResult;
5455
import org.springframework.web.bind.annotation.GetMapping;
@@ -155,7 +156,7 @@ void whenAdminSetsExpiredAdviceThenUserLoginRedirectsToResetPassword() throws Ex
155156
}
156157

157158
@Test
158-
void whenCompromisedThenUserLoginAllowed() throws Exception {
159+
void whenShouldChangeThenUserLoginAllowed() throws Exception {
159160
this.spring.register(PasswordManagementConfig.class, AdminController.class, HomeController.class).autowire();
160161
MvcResult result = this.mvc
161162
.perform(post("/login").with(csrf()).param("username", "user").param("password", "password"))
@@ -165,7 +166,7 @@ void whenCompromisedThenUserLoginAllowed() throws Exception {
165166
MockHttpSession session = (MockHttpSession) result.getRequest().getSession();
166167
this.mvc.perform(get("/").session(session))
167168
.andExpect(status().isOk())
168-
.andExpect(content().string(containsString("compromised")));
169+
.andExpect(content().string(containsString("SHOULD_CHANGE")));
169170
}
170171

171172
@Configuration
@@ -206,27 +207,26 @@ SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
206207
static class PasswordManagementConfig {
207208

208209
@Bean
209-
SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
210+
SecurityFilterChain securityFilterChain(HttpSecurity http, UserDetailsService users) throws Exception {
210211
// @formatter:off
211212
http
212-
.authorizeHttpRequests((authz) -> authz
213-
.requestMatchers("/admin/**").hasRole("ADMIN")
214-
.anyRequest().authenticated()
215-
)
216-
.formLogin(Customizer.withDefaults())
217-
.passwordManagement(Customizer.withDefaults());
213+
.authorizeHttpRequests((authz) -> authz
214+
.requestMatchers("/admin/**").hasRole("ADMIN")
215+
.anyRequest().authenticated()
216+
)
217+
.formLogin(Customizer.withDefaults())
218+
.passwordManagement(Customizer.withDefaults());
218219
// @formatter:on
219220
return http.build();
220221
}
221222

222223
@Bean
223-
UserDetailsService users() {
224-
String adminPassword = UUID.randomUUID().toString();
225-
UserDetails compromised = PasswordEncodedUser.user();
226-
UserDetails admin = PasswordEncodedUser.withUserDetails(PasswordEncodedUser.admin())
227-
.password(adminPassword)
224+
InMemoryUserDetailsManager users() {
225+
UserDetails shouldChange = User.withUserDetails(PasswordEncodedUser.user())
226+
.passwordAction(PasswordAction.SHOULD_CHANGE)
228227
.build();
229-
return new InMemoryUserDetailsManager(compromised, admin);
228+
UserDetails admin = PasswordEncodedUser.admin();
229+
return new InMemoryUserDetailsManager(shouldChange, admin);
230230
}
231231

232232
}
@@ -235,13 +235,10 @@ UserDetailsService users() {
235235
@RestController
236236
static class AdminController {
237237

238-
private final UserDetailsService users;
239-
240-
private final UserDetailsPasswordManager passwords;
238+
private final UserDetailsManager users;
241239

242-
AdminController(UserDetailsService users, UserDetailsPasswordManager passwords) {
240+
AdminController(InMemoryUserDetailsManager users) {
243241
this.users = users;
244-
this.passwords = passwords;
245242
}
246243

247244
@GetMapping("/advice/{username}")
@@ -259,7 +256,8 @@ ResponseEntity<PasswordAction> expirePassword(@PathVariable("username") String u
259256
if (user == null) {
260257
return ResponseEntity.notFound().build();
261258
}
262-
this.passwords.savePasswordAction(user, PasswordAction.MUST_CHANGE);
259+
UserDetails mustChange = User.withUserDetails(user).passwordAction(PasswordAction.MUST_CHANGE).build();
260+
this.users.updateUser(mustChange);
263261
URI uri = URI.create("/admin/passwords/advice/" + username);
264262
return ResponseEntity.created(uri).body(PasswordAction.MUST_CHANGE);
265263
}
@@ -269,32 +267,32 @@ ResponseEntity<PasswordAction> expirePassword(@PathVariable("username") String u
269267
@RestController
270268
static class HomeController {
271269

272-
private final UserDetailsPasswordManager passwords;
270+
private final InMemoryUserDetailsManager passwords;
273271

274-
private final ChangePasswordAdvisor changePasswordAdvisor = new ChangeCompromisedPasswordAdvisor();
272+
private final UpdatePasswordAdvisor passwordAdvisor = new CompromisedPasswordAdvisor();
275273

276-
private final ChangePasswordAdviceRepository changePasswordAdviceRepository = new HttpSessionChangePasswordAdviceRepository();
274+
private final PasswordAdviceRepository passwordAdviceRepository = new HttpSessionPasswordAdviceRepository();
277275

278276
private final PasswordEncoder encoder = PasswordEncoderFactories.createDelegatingPasswordEncoder();
279277

280-
HomeController(UserDetailsPasswordManager passwords) {
278+
HomeController(InMemoryUserDetailsManager passwords) {
281279
this.passwords = passwords;
282280
}
283281

284282
@GetMapping
285-
ChangePasswordAdvice index(ChangePasswordAdvice advice) {
283+
PasswordAdvice index(PasswordAdvice advice) {
286284
return advice;
287285
}
288286

289287
@PostMapping("/change-password")
290288
ResponseEntity<?> changePassword(@AuthenticationPrincipal UserDetails user,
291289
@RequestParam("password") String password, HttpServletRequest request, HttpServletResponse response) {
292-
ChangePasswordAdvice advice = this.changePasswordAdvisor.advise(user, password);
290+
PasswordAdvice advice = this.passwordAdvisor.advise(user, null, password);
293291
if (advice.getAction() != PasswordAction.ABSTAIN) {
294292
return ResponseEntity.badRequest().body(advice);
295293
}
296-
this.passwords.updatePassword(user, this.encoder.encode(password));
297-
this.changePasswordAdviceRepository.removePasswordAdvice(request, response);
294+
this.passwords.changePassword(null, this.encoder.encode(password));
295+
this.passwordAdviceRepository.removePasswordAdvice(request, response);
298296
return ResponseEntity.ok().build();
299297
}
300298

0 commit comments

Comments
 (0)