2424
2525import  org .springframework .context .ApplicationContext ;
2626import  org .springframework .http .HttpMethod ;
27- import  org .springframework .security .authentication .AuthenticationManager ;
2827import  org .springframework .security .authentication .AuthenticationProvider ;
2928import  org .springframework .security .authentication .ott .GenerateOneTimeTokenRequest ;
3029import  org .springframework .security .authentication .ott .InMemoryOneTimeTokenService ;
3332import  org .springframework .security .authentication .ott .OneTimeTokenService ;
3433import  org .springframework .security .config .Customizer ;
3534import  org .springframework .security .config .annotation .web .HttpSecurityBuilder ;
35+ import  org .springframework .security .config .annotation .web .builders .HttpSecurity ;
36+ import  org .springframework .security .config .annotation .web .configuration .EnableWebSecurity ;
37+ import  org .springframework .security .config .annotation .web .configurers .AbstractAuthenticationFilterConfigurer ;
3638import  org .springframework .security .config .annotation .web .configurers .AbstractHttpConfigurer ;
3739import  org .springframework .security .core .Authentication ;
3840import  org .springframework .security .core .userdetails .UserDetailsService ;
3941import  org .springframework .security .web .authentication .AuthenticationConverter ;
4042import  org .springframework .security .web .authentication .AuthenticationFailureHandler ;
41- import  org .springframework .security .web .authentication .AuthenticationFilter ;
4243import  org .springframework .security .web .authentication .AuthenticationSuccessHandler ;
4344import  org .springframework .security .web .authentication .SavedRequestAwareAuthenticationSuccessHandler ;
4445import  org .springframework .security .web .authentication .SimpleUrlAuthenticationFailureHandler ;
4546import  org .springframework .security .web .authentication .ott .DefaultGenerateOneTimeTokenRequestResolver ;
4647import  org .springframework .security .web .authentication .ott .GenerateOneTimeTokenFilter ;
4748import  org .springframework .security .web .authentication .ott .GenerateOneTimeTokenRequestResolver ;
4849import  org .springframework .security .web .authentication .ott .OneTimeTokenAuthenticationConverter ;
50+ import  org .springframework .security .web .authentication .ott .OneTimeTokenAuthenticationFilter ;
4951import  org .springframework .security .web .authentication .ott .OneTimeTokenGenerationSuccessHandler ;
5052import  org .springframework .security .web .authentication .ui .DefaultLoginPageGeneratingFilter ;
5153import  org .springframework .security .web .authentication .ui .DefaultOneTimeTokenSubmitPageGeneratingFilter ;
5254import  org .springframework .security .web .authentication .ui .DefaultResourcesFilter ;
53- import  org .springframework .security .web .context .HttpSessionSecurityContextRepository ;
54- import  org .springframework .security .web .context .SecurityContextRepository ;
5555import  org .springframework .security .web .csrf .CsrfToken ;
56+ import  org .springframework .security .web .util .matcher .RequestMatcher ;
5657import  org .springframework .util .Assert ;
5758import  org .springframework .util .StringUtils ;
5859
5960import  static  org .springframework .security .web .util .matcher .AntPathRequestMatcher .antMatcher ;
6061
61- public  final  class  OneTimeTokenLoginConfigurer <H  extends  HttpSecurityBuilder <H >>
62- 		extends  AbstractHttpConfigurer <OneTimeTokenLoginConfigurer <H >, H > {
62+ /** 
63+  * An {@link AbstractHttpConfigurer} for One-Time Token Login. 
64+  * 
65+  * <p> 
66+  * One-Time Token Login provides an application with the capability to have users log in 
67+  * by obtaining a single-use token out of band, for example through email. 
68+  * 
69+  * <p> 
70+  * Defaults are provided for all configuration options, with the only required 
71+  * configuration being 
72+  * {@link #tokenGenerationSuccessHandler(OneTimeTokenGenerationSuccessHandler)}. 
73+  * Alternatively, a {@link OneTimeTokenGenerationSuccessHandler} {@code @Bean} may be 
74+  * registered instead. 
75+  * 
76+  * <h2>Security Filters</h2> 
77+  * 
78+  * The following {@code Filter}s are populated: 
79+  * 
80+  * <ul> 
81+  * <li>{@link DefaultOneTimeTokenSubmitPageGeneratingFilter}</li> 
82+  * <li>{@link GenerateOneTimeTokenFilter}</li> 
83+  * <li>{@link OneTimeTokenAuthenticationFilter}</li> 
84+  * </ul> 
85+  * 
86+  * <h2>Shared Objects Used</h2> 
87+  * 
88+  * The following shared objects are used: 
89+  * 
90+  * <ul> 
91+  * <li>{@link DefaultLoginPageGeneratingFilter} - if {@link #loginPage(String)} is not 
92+  * configured and {@code DefaultLoginPageGeneratingFilter} is available, then a default 
93+  * login page will be made available</li> 
94+  * </ul> 
95+  * 
96+  * @author Marcus Da Coregio 
97+  * @author Daniel Garnier-Moiroux 
98+  * @since 6.4 
99+  * @see HttpSecurity#oneTimeTokenLogin(Customizer) 
100+  * @see DefaultOneTimeTokenSubmitPageGeneratingFilter 
101+  * @see GenerateOneTimeTokenFilter 
102+  * @see OneTimeTokenAuthenticationFilter 
103+  * @see AbstractAuthenticationFilterConfigurer 
104+  */ 
105+ public  final  class  OneTimeTokenLoginConfigurer <H  extends  HttpSecurityBuilder <H >> extends 
106+ 		AbstractAuthenticationFilterConfigurer <H , OneTimeTokenLoginConfigurer <H >, OneTimeTokenAuthenticationFilter > {
63107
64108	private  final  ApplicationContext  context ;
65109
66110	private  OneTimeTokenService  oneTimeTokenService ;
67111
68- 	private  AuthenticationConverter  authenticationConverter  = new  OneTimeTokenAuthenticationConverter ();
69- 
70- 	private  AuthenticationFailureHandler  authenticationFailureHandler ;
71- 
72- 	private  AuthenticationSuccessHandler  authenticationSuccessHandler  = new  SavedRequestAwareAuthenticationSuccessHandler ();
73- 
74- 	private  String  defaultSubmitPageUrl  = "/login/ott" ;
112+ 	private  String  defaultSubmitPageUrl  = DefaultOneTimeTokenSubmitPageGeneratingFilter .DEFAULT_SUBMIT_PAGE_URL ;
75113
76114	private  boolean  submitPageEnabled  = true ;
77115
78- 	private  String  loginProcessingUrl  = "/login/ott" ;
79- 
80- 	private  String  tokenGeneratingUrl  = "/ott/generate" ;
116+ 	private  String  tokenGeneratingUrl  = GenerateOneTimeTokenFilter .DEFAULT_GENERATE_URL ;
81117
82118	private  OneTimeTokenGenerationSuccessHandler  oneTimeTokenGenerationSuccessHandler ;
83119
@@ -86,55 +122,51 @@ public final class OneTimeTokenLoginConfigurer<H extends HttpSecurityBuilder<H>>
86122	private  GenerateOneTimeTokenRequestResolver  requestResolver ;
87123
88124	public  OneTimeTokenLoginConfigurer (ApplicationContext  context ) {
125+ 		super (new  OneTimeTokenAuthenticationFilter (), OneTimeTokenAuthenticationFilter .DEFAULT_LOGIN_PROCESSING_URL );
89126		this .context  = context ;
90127	}
91128
92129	@ Override 
93- 	public  void  init (H  http ) {
130+ 	public  void  init (H  http ) throws  Exception  {
131+ 		super .init (http );
94132		AuthenticationProvider  authenticationProvider  = getAuthenticationProvider (http );
95133		http .authenticationProvider (postProcess (authenticationProvider ));
96- 		configureDefaultLoginPage (http );
134+ 		intiDefaultLoginFilter (http );
135+ 	}
136+ 
137+ 	private  AuthenticationProvider  getAuthenticationProvider (H  http ) {
138+ 		if  (this .authenticationProvider  != null ) {
139+ 			return  this .authenticationProvider ;
140+ 		}
141+ 		UserDetailsService  userDetailsService  = getContext ().getBean (UserDetailsService .class );
142+ 		this .authenticationProvider  = new  OneTimeTokenAuthenticationProvider (getOneTimeTokenService (http ),
143+ 				userDetailsService );
144+ 		return  this .authenticationProvider ;
97145	}
98146
99- 	private  void  configureDefaultLoginPage (H  http ) {
147+ 	private  void  intiDefaultLoginFilter (H  http ) {
100148		DefaultLoginPageGeneratingFilter  loginPageGeneratingFilter  = http 
101149			.getSharedObject (DefaultLoginPageGeneratingFilter .class );
102- 		if  (loginPageGeneratingFilter  == null ) {
150+ 		if  (loginPageGeneratingFilter  == null  ||  isCustomLoginPage () ) {
103151			return ;
104152		}
105153		loginPageGeneratingFilter .setOneTimeTokenEnabled (true );
106154		loginPageGeneratingFilter .setOneTimeTokenGenerationUrl (this .tokenGeneratingUrl );
107- 		if  (this .authenticationFailureHandler  == null 
108- 				&& StringUtils .hasText (loginPageGeneratingFilter .getLoginPageUrl ())) {
109- 			this .authenticationFailureHandler  = new  SimpleUrlAuthenticationFailureHandler (
110- 					loginPageGeneratingFilter .getLoginPageUrl () + "?error" );
155+ 
156+ 		if  (!StringUtils .hasText (loginPageGeneratingFilter .getLoginPageUrl ())) {
157+ 			loginPageGeneratingFilter .setLoginPageUrl (DefaultLoginPageGeneratingFilter .DEFAULT_LOGIN_PAGE_URL );
158+ 			loginPageGeneratingFilter .setFailureUrl (DefaultLoginPageGeneratingFilter .DEFAULT_LOGIN_PAGE_URL  + "?" 
159+ 					+ DefaultLoginPageGeneratingFilter .ERROR_PARAMETER_NAME );
160+ 			loginPageGeneratingFilter 
161+ 				.setLogoutSuccessUrl (DefaultLoginPageGeneratingFilter .DEFAULT_LOGIN_PAGE_URL  + "?logout" );
111162		}
112163	}
113164
114165	@ Override 
115- 	public  void  configure (H  http ) {
166+ 	public  void  configure (H  http ) throws  Exception  {
167+ 		super .configure (http );
116168		configureSubmitPage (http );
117169		configureOttGenerateFilter (http );
118- 		configureOttAuthenticationFilter (http );
119- 	}
120- 
121- 	private  void  configureOttAuthenticationFilter (H  http ) {
122- 		AuthenticationManager  authenticationManager  = http .getSharedObject (AuthenticationManager .class );
123- 		AuthenticationFilter  oneTimeTokenAuthenticationFilter  = new  AuthenticationFilter (authenticationManager ,
124- 				this .authenticationConverter );
125- 		oneTimeTokenAuthenticationFilter .setSecurityContextRepository (getSecurityContextRepository (http ));
126- 		oneTimeTokenAuthenticationFilter .setRequestMatcher (antMatcher (HttpMethod .POST , this .loginProcessingUrl ));
127- 		oneTimeTokenAuthenticationFilter .setFailureHandler (getAuthenticationFailureHandler ());
128- 		oneTimeTokenAuthenticationFilter .setSuccessHandler (this .authenticationSuccessHandler );
129- 		http .addFilter (postProcess (oneTimeTokenAuthenticationFilter ));
130- 	}
131- 
132- 	private  SecurityContextRepository  getSecurityContextRepository (H  http ) {
133- 		SecurityContextRepository  securityContextRepository  = http .getSharedObject (SecurityContextRepository .class );
134- 		if  (securityContextRepository  != null ) {
135- 			return  securityContextRepository ;
136- 		}
137- 		return  new  HttpSessionSecurityContextRepository ();
138170	}
139171
140172	private  void  configureOttGenerateFilter (H  http ) {
@@ -166,18 +198,13 @@ private void configureSubmitPage(H http) {
166198		DefaultOneTimeTokenSubmitPageGeneratingFilter  submitPage  = new  DefaultOneTimeTokenSubmitPageGeneratingFilter ();
167199		submitPage .setResolveHiddenInputs (this ::hiddenInputs );
168200		submitPage .setRequestMatcher (antMatcher (HttpMethod .GET , this .defaultSubmitPageUrl ));
169- 		submitPage .setLoginProcessingUrl (this .loginProcessingUrl );
201+ 		submitPage .setLoginProcessingUrl (this .getLoginProcessingUrl () );
170202		http .addFilter (postProcess (submitPage ));
171203	}
172204
173- 	private  AuthenticationProvider  getAuthenticationProvider (H  http ) {
174- 		if  (this .authenticationProvider  != null ) {
175- 			return  this .authenticationProvider ;
176- 		}
177- 		UserDetailsService  userDetailsService  = getContext ().getBean (UserDetailsService .class );
178- 		this .authenticationProvider  = new  OneTimeTokenAuthenticationProvider (getOneTimeTokenService (http ),
179- 				userDetailsService );
180- 		return  this .authenticationProvider ;
205+ 	@ Override 
206+ 	protected  RequestMatcher  createLoginProcessingUrlMatcher (String  loginProcessingUrl ) {
207+ 		return  antMatcher (HttpMethod .POST , loginProcessingUrl );
181208	}
182209
183210	/** 
@@ -217,14 +244,25 @@ public OneTimeTokenLoginConfigurer<H> tokenGenerationSuccessHandler(
217244	 * Only POST requests are processed, for that reason make sure that you pass a valid 
218245	 * CSRF token if CSRF protection is enabled. 
219246	 * @param loginProcessingUrl 
220- 	 * @see org.springframework.security.config.annotation.web.builders. HttpSecurity#csrf(Customizer) 
247+ 	 * @see HttpSecurity#csrf(Customizer) 
221248	 */ 
222249	public  OneTimeTokenLoginConfigurer <H > loginProcessingUrl (String  loginProcessingUrl ) {
223250		Assert .hasText (loginProcessingUrl , "loginProcessingUrl cannot be null or empty" );
224- 		this .loginProcessingUrl  =  loginProcessingUrl ;
251+ 		super .loginProcessingUrl ( loginProcessingUrl ) ;
225252		return  this ;
226253	}
227254
255+ 	/** 
256+ 	 * Specifies the URL to send users to if login is required. If used with 
257+ 	 * {@link EnableWebSecurity} a default login page will be generated when this 
258+ 	 * attribute is not specified. 
259+ 	 * @param loginPage 
260+ 	 */ 
261+ 	@ Override 
262+ 	public  OneTimeTokenLoginConfigurer <H > loginPage (String  loginPage ) {
263+ 		return  super .loginPage (loginPage );
264+ 	}
265+ 
228266	/** 
229267	 * Configures whether the default one-time token submit page should be shown. This 
230268	 * will prevent the {@link DefaultOneTimeTokenSubmitPageGeneratingFilter} to be 
@@ -269,7 +307,7 @@ public OneTimeTokenLoginConfigurer<H> tokenService(OneTimeTokenService oneTimeTo
269307	 */ 
270308	public  OneTimeTokenLoginConfigurer <H > authenticationConverter (AuthenticationConverter  authenticationConverter ) {
271309		Assert .notNull (authenticationConverter , "authenticationConverter cannot be null" );
272- 		this .authenticationConverter  =  authenticationConverter ;
310+ 		this .getAuthenticationFilter (). setAuthenticationConverter ( authenticationConverter ) ;
273311		return  this ;
274312	}
275313
@@ -279,11 +317,13 @@ public OneTimeTokenLoginConfigurer<H> authenticationConverter(AuthenticationConv
279317	 * {@link SimpleUrlAuthenticationFailureHandler} 
280318	 * @param authenticationFailureHandler the {@link AuthenticationFailureHandler} to use 
281319	 * when authentication fails. 
320+ 	 * @deprecated Use {@link #failureHandler(AuthenticationFailureHandler)} instead 
282321	 */ 
322+ 	@ Deprecated (since  = "6.5" )
283323	public  OneTimeTokenLoginConfigurer <H > authenticationFailureHandler (
284324			AuthenticationFailureHandler  authenticationFailureHandler ) {
285325		Assert .notNull (authenticationFailureHandler , "authenticationFailureHandler cannot be null" );
286- 		this . authenticationFailureHandler  =  authenticationFailureHandler ;
326+ 		super . failureHandler ( authenticationFailureHandler ) ;
287327		return  this ;
288328	}
289329
@@ -292,22 +332,16 @@ public OneTimeTokenLoginConfigurer<H> authenticationFailureHandler(
292332	 * {@link SavedRequestAwareAuthenticationSuccessHandler} with no additional properties 
293333	 * set. 
294334	 * @param authenticationSuccessHandler the {@link AuthenticationSuccessHandler}. 
335+ 	 * @deprecated Use {@link #successHandler(AuthenticationSuccessHandler)} instead 
295336	 */ 
337+ 	@ Deprecated (since  = "6.5" )
296338	public  OneTimeTokenLoginConfigurer <H > authenticationSuccessHandler (
297339			AuthenticationSuccessHandler  authenticationSuccessHandler ) {
298340		Assert .notNull (authenticationSuccessHandler , "authenticationSuccessHandler cannot be null" );
299- 		this . authenticationSuccessHandler  =  authenticationSuccessHandler ;
341+ 		super . successHandler ( authenticationSuccessHandler ) ;
300342		return  this ;
301343	}
302344
303- 	private  AuthenticationFailureHandler  getAuthenticationFailureHandler () {
304- 		if  (this .authenticationFailureHandler  != null ) {
305- 			return  this .authenticationFailureHandler ;
306- 		}
307- 		this .authenticationFailureHandler  = new  SimpleUrlAuthenticationFailureHandler ("/login?error" );
308- 		return  this .authenticationFailureHandler ;
309- 	}
310- 
311345	/** 
312346	 * Use this {@link GenerateOneTimeTokenRequestResolver} when resolving 
313347	 * {@link GenerateOneTimeTokenRequest} from {@link HttpServletRequest}. By default, 
0 commit comments