1616
1717package  org .springframework .security .config .annotation .web .configurers ;
1818
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 ;
1929import  org .springframework .security .config .annotation .web .HttpSecurityBuilder ;
2030import  org .springframework .security .config .annotation .web .RequestMatcherFactory ;
31+ import  org .springframework .security .core .userdetails .UserDetails ;
32+ import  org .springframework .security .crypto .factory .PasswordEncoderFactories ;
33+ import  org .springframework .security .crypto .password .PasswordEncoder ;
2134import  org .springframework .security .web .RequestMatcherRedirectFilter ;
2235import  org .springframework .security .web .authentication .UsernamePasswordAuthenticationFilter ;
36+ import  org .springframework .security .web .authentication .password .ChangeCompromisedPasswordAdvisor ;
37+ import  org .springframework .security .web .authentication .password .ChangePasswordAdviceHandler ;
38+ import  org .springframework .security .web .authentication .password .ChangePasswordAdviceRepository ;
39+ import  org .springframework .security .web .authentication .password .ChangePasswordAdvisingFilter ;
40+ import  org .springframework .security .web .authentication .password .ChangePasswordProcessingFilter ;
41+ import  org .springframework .security .web .authentication .password .DefaultChangePasswordPageGeneratingFilter ;
42+ import  org .springframework .security .web .authentication .password .HttpSessionChangePasswordAdviceRepository ;
43+ import  org .springframework .security .web .authentication .password .SimpleChangePasswordAdviceHandler ;
44+ import  org .springframework .security .web .savedrequest .RequestCacheAwareFilter ;
45+ import  org .springframework .security .web .servlet .util .matcher .PathPatternRequestMatcher ;
2346import  org .springframework .util .Assert ;
2447
2548/** 
2952 * @since 5.6 
3053 */ 
3154public  final  class  PasswordManagementConfigurer <B  extends  HttpSecurityBuilder <B >>
32- 		extends  AbstractHttpConfigurer <PasswordManagementConfigurer <B >, B > {
55+ 		extends  AbstractHttpConfigurer <PasswordManagementConfigurer <B >, B > implements   ApplicationContextAware   {
3356
3457	private  static  final  String  WELL_KNOWN_CHANGE_PASSWORD_PATTERN  = "/.well-known/change-password" ;
3558
36- 	private  static  final  String  DEFAULT_CHANGE_PASSWORD_PAGE  = "/change-password" ;
59+ 	private  static  final  String  DEFAULT_CHANGE_PASSWORD_PAGE  = DefaultChangePasswordPageGeneratingFilter .DEFAULT_CHANGE_PASSWORD_URL ;
60+ 
61+ 	private  ApplicationContext  context ;
62+ 
63+ 	private  boolean  customChangePasswordPage  = false ;
3764
3865	private  String  changePasswordPage  = DEFAULT_CHANGE_PASSWORD_PAGE ;
3966
67+ 	private  String  changePasswordProcessingUrl  = ChangePasswordProcessingFilter .DEFAULT_PASSWORD_CHANGE_PROCESSING_URL ;
68+ 
69+ 	private  ChangePasswordAdviceRepository  changePasswordAdviceRepository ;
70+ 
71+ 	private  ChangePasswordAdvisor  changePasswordAdvisor ;
72+ 
73+ 	private  ChangePasswordAdviceHandler  changePasswordAdviceHandler ;
74+ 
75+ 	private  UserDetailsPasswordManager  userDetailsPasswordManager ;
76+ 
4077	/** 
4178	 * Sets the change password page. Defaults to 
4279	 * {@link PasswordManagementConfigurer#DEFAULT_CHANGE_PASSWORD_PAGE}. 
@@ -46,9 +83,76 @@ public final class PasswordManagementConfigurer<B extends HttpSecurityBuilder<B>
4683	public  PasswordManagementConfigurer <B > changePasswordPage (String  changePasswordPage ) {
4784		Assert .hasText (changePasswordPage , "changePasswordPage cannot be empty" );
4885		this .changePasswordPage  = changePasswordPage ;
86+ 		this .customChangePasswordPage  = true ;
87+ 		return  this ;
88+ 	}
89+ 
90+ 	public  PasswordManagementConfigurer <B > changePasswordProcessingUrl (String  changePasswordProcessingUrl ) {
91+ 		this .changePasswordProcessingUrl  = changePasswordProcessingUrl ;
92+ 		return  this ;
93+ 	}
94+ 
95+ 	public  PasswordManagementConfigurer <B > changePasswordAdviceRepository (
96+ 			ChangePasswordAdviceRepository  changePasswordAdviceRepository ) {
97+ 		this .changePasswordAdviceRepository  = changePasswordAdviceRepository ;
98+ 		return  this ;
99+ 	}
100+ 
101+ 	public  PasswordManagementConfigurer <B > changePasswordAdvisor (ChangePasswordAdvisor  changePasswordAdvisor ) {
102+ 		this .changePasswordAdvisor  = changePasswordAdvisor ;
103+ 		return  this ;
104+ 	}
105+ 
106+ 	public  PasswordManagementConfigurer <B > changePasswordAdviceHandler (
107+ 			ChangePasswordAdviceHandler  changePasswordAdviceHandler ) {
108+ 		this .changePasswordAdviceHandler  = changePasswordAdviceHandler ;
49109		return  this ;
50110	}
51111
112+ 	public  PasswordManagementConfigurer <B > userDetailsPasswordManager (
113+ 			UserDetailsPasswordManager  userDetailsPasswordManager ) {
114+ 		this .userDetailsPasswordManager  = userDetailsPasswordManager ;
115+ 		return  this ;
116+ 	}
117+ 
118+ 	@ Override 
119+ 	public  void  init (B  http ) throws  Exception  {
120+ 		UserDetailsPasswordManager  passwordManager  = (this .userDetailsPasswordManager  == null )
121+ 				? this .context .getBeanProvider (UserDetailsPasswordManager .class ).getIfUnique ()
122+ 				: this .userDetailsPasswordManager ;
123+ 
124+ 		if  (passwordManager  == null ) {
125+ 			return ;
126+ 		}
127+ 
128+ 		ChangePasswordAdviceRepository  changePasswordAdviceRepository  = (this .changePasswordAdviceRepository  != null )
129+ 				? this .changePasswordAdviceRepository 
130+ 				: this .context .getBeanProvider (ChangePasswordAdviceRepository .class )
131+ 					.getIfUnique (HttpSessionChangePasswordAdviceRepository ::new );
132+ 
133+ 		ChangePasswordAdvisor  changePasswordAdvisor  = (this .changePasswordAdvisor  != null ) ? this .changePasswordAdvisor 
134+ 				: this .context .getBeanProvider (ChangePasswordAdvisor .class ).getIfUnique (() -> {
135+ 					List <ChangePasswordAdvisor > advisors  = new  ArrayList <>();
136+ 					advisors .add (new  ChangeCompromisedPasswordAdvisor ());
137+ 					advisors .add (new  ChangePasswordServiceAdvisor (passwordManager ));
138+ 					return  new  DelegatingChangePasswordAdvisor (advisors );
139+ 				});
140+ 
141+ 		http .setSharedObject (ChangePasswordAdviceRepository .class , changePasswordAdviceRepository );
142+ 		http .setSharedObject (UserDetailsPasswordManager .class , passwordManager );
143+ 		http .setSharedObject (ChangePasswordAdvisor .class , changePasswordAdvisor );
144+ 
145+ 		FormLoginConfigurer  form  = http .getConfigurer (FormLoginConfigurer .class );
146+ 		String  passwordParameter  = (form  != null ) ? form .getPasswordParameter () : "password" ;
147+ 		http .getConfigurer (SessionManagementConfigurer .class )
148+ 			.addSessionAuthenticationStrategy ((authentication , request , response ) -> {
149+ 				UserDetails  user  = (UserDetails ) authentication .getPrincipal ();
150+ 				String  password  = request .getParameter (passwordParameter );
151+ 				ChangePasswordAdvice  advice  = changePasswordAdvisor .advise (user , password );
152+ 				changePasswordAdviceRepository .savePasswordAdvice (request , response , advice );
153+ 			});
154+ 	}
155+ 
52156	/** 
53157	 * {@inheritDoc} 
54158	 */ 
@@ -57,6 +161,42 @@ public void configure(B http) throws Exception {
57161		RequestMatcherRedirectFilter  changePasswordFilter  = new  RequestMatcherRedirectFilter (
58162				RequestMatcherFactory .matcher (WELL_KNOWN_CHANGE_PASSWORD_PATTERN ), this .changePasswordPage );
59163		http .addFilterBefore (postProcess (changePasswordFilter ), UsernamePasswordAuthenticationFilter .class );
164+ 
165+ 		if  (http .getSharedObject (UserDetailsPasswordManager .class ) == null ) {
166+ 			return ;
167+ 		}
168+ 
169+ 		PasswordEncoder  passwordEncoder  = this .context .getBeanProvider (PasswordEncoder .class )
170+ 			.getIfUnique (PasswordEncoderFactories ::createDelegatingPasswordEncoder );
171+ 
172+ 		ChangePasswordAdviceHandler  changePasswordAdviceHandler  = (this .changePasswordAdviceHandler  != null )
173+ 				? this .changePasswordAdviceHandler  : this .context .getBeanProvider (ChangePasswordAdviceHandler .class )
174+ 					.getIfUnique (() -> new  SimpleChangePasswordAdviceHandler (this .changePasswordPage ));
175+ 
176+ 		if  (!this .customChangePasswordPage ) {
177+ 			DefaultChangePasswordPageGeneratingFilter  page  = new  DefaultChangePasswordPageGeneratingFilter ();
178+ 			http .addFilterBefore (page , RequestCacheAwareFilter .class );
179+ 		}
180+ 
181+ 		ChangePasswordProcessingFilter  processing  = new  ChangePasswordProcessingFilter (
182+ 				http .getSharedObject (UserDetailsPasswordManager .class ));
183+ 		processing 
184+ 			.setRequestMatcher (PathPatternRequestMatcher .withDefaults ().matcher (this .changePasswordProcessingUrl ));
185+ 		processing .setChangePasswordAdvisor (http .getSharedObject (ChangePasswordAdvisor .class ));
186+ 		processing .setChangePasswordAdviceRepository (http .getSharedObject (ChangePasswordAdviceRepository .class ));
187+ 		processing .setPasswordEncoder (passwordEncoder );
188+ 		processing .setSecurityContextHolderStrategy (getSecurityContextHolderStrategy ());
189+ 		http .addFilterBefore (processing , RequestCacheAwareFilter .class );
190+ 
191+ 		ChangePasswordAdvisingFilter  advising  = new  ChangePasswordAdvisingFilter ();
192+ 		advising .setChangePasswordAdviceRepository (http .getSharedObject (ChangePasswordAdviceRepository .class ));
193+ 		advising .setChangePasswordAdviceHandler (changePasswordAdviceHandler );
194+ 		http .addFilterBefore (advising , RequestCacheAwareFilter .class );
195+ 	}
196+ 
197+ 	@ Override 
198+ 	public  void  setApplicationContext (ApplicationContext  context ) {
199+ 		this .context  = context ;
60200	}
61201
62202}
0 commit comments