16
16
17
17
package org .springframework .security .config .annotation .web .configurers ;
18
18
19
+ import java .util .ArrayList ;
20
+ import java .util .List ;
21
+
22
+ import org .springframework .context .ApplicationContext ;
23
+ import org .springframework .context .ApplicationContextAware ;
24
+ import org .springframework .security .authentication .password .ChangePasswordAdvice ;
25
+ import org .springframework .security .authentication .password .ChangePasswordAdvisor ;
26
+ import org .springframework .security .authentication .password .ChangePasswordServiceAdvisor ;
27
+ import org .springframework .security .authentication .password .DelegatingChangePasswordAdvisor ;
28
+ import org .springframework .security .authentication .password .UserDetailsPasswordManager ;
19
29
import org .springframework .security .config .annotation .web .HttpSecurityBuilder ;
30
+ import org .springframework .security .core .userdetails .UserDetails ;
31
+ import org .springframework .security .crypto .factory .PasswordEncoderFactories ;
32
+ import org .springframework .security .crypto .password .PasswordEncoder ;
20
33
import org .springframework .security .web .RequestMatcherRedirectFilter ;
21
34
import org .springframework .security .web .authentication .UsernamePasswordAuthenticationFilter ;
35
+ import org .springframework .security .web .authentication .password .ChangeCompromisedPasswordAdvisor ;
36
+ import org .springframework .security .web .authentication .password .ChangePasswordAdviceHandler ;
37
+ import org .springframework .security .web .authentication .password .ChangePasswordAdviceRepository ;
38
+ import org .springframework .security .web .authentication .password .ChangePasswordAdvisingFilter ;
39
+ import org .springframework .security .web .authentication .password .ChangePasswordProcessingFilter ;
40
+ import org .springframework .security .web .authentication .password .DefaultChangePasswordPageGeneratingFilter ;
41
+ import org .springframework .security .web .authentication .password .HttpSessionChangePasswordAdviceRepository ;
42
+ import org .springframework .security .web .authentication .password .SimpleChangePasswordAdviceHandler ;
43
+ import org .springframework .security .web .savedrequest .RequestCacheAwareFilter ;
44
+ import org .springframework .security .web .servlet .util .matcher .PathPatternRequestMatcher ;
22
45
import org .springframework .util .Assert ;
23
46
24
47
/**
28
51
* @since 5.6
29
52
*/
30
53
public final class PasswordManagementConfigurer <B extends HttpSecurityBuilder <B >>
31
- extends AbstractHttpConfigurer <PasswordManagementConfigurer <B >, B > {
54
+ extends AbstractHttpConfigurer <PasswordManagementConfigurer <B >, B > implements ApplicationContextAware {
32
55
33
56
private static final String WELL_KNOWN_CHANGE_PASSWORD_PATTERN = "/.well-known/change-password" ;
34
57
35
- private static final String DEFAULT_CHANGE_PASSWORD_PAGE = "/change-password" ;
58
+ private static final String DEFAULT_CHANGE_PASSWORD_PAGE = DefaultChangePasswordPageGeneratingFilter .DEFAULT_CHANGE_PASSWORD_URL ;
59
+
60
+ private ApplicationContext context ;
61
+
62
+ private boolean customChangePasswordPage = false ;
36
63
37
64
private String changePasswordPage = DEFAULT_CHANGE_PASSWORD_PAGE ;
38
65
66
+ private String changePasswordProcessingUrl = ChangePasswordProcessingFilter .DEFAULT_PASSWORD_CHANGE_PROCESSING_URL ;
67
+
68
+ private ChangePasswordAdviceRepository changePasswordAdviceRepository ;
69
+
70
+ private ChangePasswordAdvisor changePasswordAdvisor ;
71
+
72
+ private ChangePasswordAdviceHandler changePasswordAdviceHandler ;
73
+
74
+ private UserDetailsPasswordManager userDetailsPasswordManager ;
75
+
39
76
/**
40
77
* Sets the change password page. Defaults to
41
78
* {@link PasswordManagementConfigurer#DEFAULT_CHANGE_PASSWORD_PAGE}.
@@ -45,9 +82,76 @@ public final class PasswordManagementConfigurer<B extends HttpSecurityBuilder<B>
45
82
public PasswordManagementConfigurer <B > changePasswordPage (String changePasswordPage ) {
46
83
Assert .hasText (changePasswordPage , "changePasswordPage cannot be empty" );
47
84
this .changePasswordPage = changePasswordPage ;
85
+ this .customChangePasswordPage = true ;
86
+ return this ;
87
+ }
88
+
89
+ public PasswordManagementConfigurer <B > changePasswordProcessingUrl (String changePasswordProcessingUrl ) {
90
+ this .changePasswordProcessingUrl = changePasswordProcessingUrl ;
91
+ return this ;
92
+ }
93
+
94
+ public PasswordManagementConfigurer <B > changePasswordAdviceRepository (
95
+ ChangePasswordAdviceRepository changePasswordAdviceRepository ) {
96
+ this .changePasswordAdviceRepository = changePasswordAdviceRepository ;
97
+ return this ;
98
+ }
99
+
100
+ public PasswordManagementConfigurer <B > changePasswordAdvisor (ChangePasswordAdvisor changePasswordAdvisor ) {
101
+ this .changePasswordAdvisor = changePasswordAdvisor ;
102
+ return this ;
103
+ }
104
+
105
+ public PasswordManagementConfigurer <B > changePasswordAdviceHandler (
106
+ ChangePasswordAdviceHandler changePasswordAdviceHandler ) {
107
+ this .changePasswordAdviceHandler = changePasswordAdviceHandler ;
48
108
return this ;
49
109
}
50
110
111
+ public PasswordManagementConfigurer <B > userDetailsPasswordManager (
112
+ UserDetailsPasswordManager userDetailsPasswordManager ) {
113
+ this .userDetailsPasswordManager = userDetailsPasswordManager ;
114
+ return this ;
115
+ }
116
+
117
+ @ Override
118
+ public void init (B http ) throws Exception {
119
+ UserDetailsPasswordManager passwordManager = (this .userDetailsPasswordManager == null )
120
+ ? this .context .getBeanProvider (UserDetailsPasswordManager .class ).getIfUnique ()
121
+ : this .userDetailsPasswordManager ;
122
+
123
+ if (passwordManager == null ) {
124
+ return ;
125
+ }
126
+
127
+ ChangePasswordAdviceRepository changePasswordAdviceRepository = (this .changePasswordAdviceRepository != null )
128
+ ? this .changePasswordAdviceRepository
129
+ : this .context .getBeanProvider (ChangePasswordAdviceRepository .class )
130
+ .getIfUnique (HttpSessionChangePasswordAdviceRepository ::new );
131
+
132
+ ChangePasswordAdvisor changePasswordAdvisor = (this .changePasswordAdvisor != null ) ? this .changePasswordAdvisor
133
+ : this .context .getBeanProvider (ChangePasswordAdvisor .class ).getIfUnique (() -> {
134
+ List <ChangePasswordAdvisor > advisors = new ArrayList <>();
135
+ advisors .add (new ChangeCompromisedPasswordAdvisor ());
136
+ advisors .add (new ChangePasswordServiceAdvisor (passwordManager ));
137
+ return new DelegatingChangePasswordAdvisor (advisors );
138
+ });
139
+
140
+ http .setSharedObject (ChangePasswordAdviceRepository .class , changePasswordAdviceRepository );
141
+ http .setSharedObject (UserDetailsPasswordManager .class , passwordManager );
142
+ http .setSharedObject (ChangePasswordAdvisor .class , changePasswordAdvisor );
143
+
144
+ FormLoginConfigurer form = http .getConfigurer (FormLoginConfigurer .class );
145
+ String passwordParameter = (form != null ) ? form .getPasswordParameter () : "password" ;
146
+ http .getConfigurer (SessionManagementConfigurer .class )
147
+ .addSessionAuthenticationStrategy ((authentication , request , response ) -> {
148
+ UserDetails user = (UserDetails ) authentication .getPrincipal ();
149
+ String password = request .getParameter (passwordParameter );
150
+ ChangePasswordAdvice advice = changePasswordAdvisor .advise (user , password );
151
+ changePasswordAdviceRepository .savePasswordAdvice (request , response , advice );
152
+ });
153
+ }
154
+
51
155
/**
52
156
* {@inheritDoc}
53
157
*/
@@ -56,6 +160,42 @@ public void configure(B http) throws Exception {
56
160
RequestMatcherRedirectFilter changePasswordFilter = new RequestMatcherRedirectFilter (
57
161
getRequestMatcherBuilder ().matcher (WELL_KNOWN_CHANGE_PASSWORD_PATTERN ), this .changePasswordPage );
58
162
http .addFilterBefore (postProcess (changePasswordFilter ), UsernamePasswordAuthenticationFilter .class );
163
+
164
+ if (http .getSharedObject (UserDetailsPasswordManager .class ) == null ) {
165
+ return ;
166
+ }
167
+
168
+ PasswordEncoder passwordEncoder = this .context .getBeanProvider (PasswordEncoder .class )
169
+ .getIfUnique (PasswordEncoderFactories ::createDelegatingPasswordEncoder );
170
+
171
+ ChangePasswordAdviceHandler changePasswordAdviceHandler = (this .changePasswordAdviceHandler != null )
172
+ ? this .changePasswordAdviceHandler : this .context .getBeanProvider (ChangePasswordAdviceHandler .class )
173
+ .getIfUnique (() -> new SimpleChangePasswordAdviceHandler (this .changePasswordPage ));
174
+
175
+ if (!this .customChangePasswordPage ) {
176
+ DefaultChangePasswordPageGeneratingFilter page = new DefaultChangePasswordPageGeneratingFilter ();
177
+ http .addFilterBefore (page , RequestCacheAwareFilter .class );
178
+ }
179
+
180
+ ChangePasswordProcessingFilter processing = new ChangePasswordProcessingFilter (
181
+ http .getSharedObject (UserDetailsPasswordManager .class ));
182
+ processing
183
+ .setRequestMatcher (PathPatternRequestMatcher .withDefaults ().matcher (this .changePasswordProcessingUrl ));
184
+ processing .setChangePasswordAdvisor (http .getSharedObject (ChangePasswordAdvisor .class ));
185
+ processing .setChangePasswordAdviceRepository (http .getSharedObject (ChangePasswordAdviceRepository .class ));
186
+ processing .setPasswordEncoder (passwordEncoder );
187
+ processing .setSecurityContextHolderStrategy (getSecurityContextHolderStrategy ());
188
+ http .addFilterBefore (processing , RequestCacheAwareFilter .class );
189
+
190
+ ChangePasswordAdvisingFilter advising = new ChangePasswordAdvisingFilter ();
191
+ advising .setChangePasswordAdviceRepository (http .getSharedObject (ChangePasswordAdviceRepository .class ));
192
+ advising .setChangePasswordAdviceHandler (changePasswordAdviceHandler );
193
+ http .addFilterBefore (advising , RequestCacheAwareFilter .class );
194
+ }
195
+
196
+ @ Override
197
+ public void setApplicationContext (ApplicationContext context ) {
198
+ this .context = context ;
59
199
}
60
200
61
201
}
0 commit comments