23
23
24
24
import org .springframework .context .ApplicationContext ;
25
25
import org .springframework .http .HttpMethod ;
26
- import org .springframework .security .authentication .AuthenticationManager ;
27
26
import org .springframework .security .authentication .AuthenticationProvider ;
28
27
import org .springframework .security .authentication .ott .GenerateOneTimeTokenRequest ;
29
28
import org .springframework .security .authentication .ott .InMemoryOneTimeTokenService ;
32
31
import org .springframework .security .authentication .ott .OneTimeTokenService ;
33
32
import org .springframework .security .config .Customizer ;
34
33
import org .springframework .security .config .annotation .web .HttpSecurityBuilder ;
34
+ import org .springframework .security .config .annotation .web .builders .HttpSecurity ;
35
+ import org .springframework .security .config .annotation .web .configuration .EnableWebSecurity ;
36
+ import org .springframework .security .config .annotation .web .configurers .AbstractAuthenticationFilterConfigurer ;
35
37
import org .springframework .security .config .annotation .web .configurers .AbstractHttpConfigurer ;
36
38
import org .springframework .security .core .Authentication ;
37
39
import org .springframework .security .core .userdetails .UserDetailsService ;
49
51
import org .springframework .security .web .authentication .ui .DefaultLoginPageGeneratingFilter ;
50
52
import org .springframework .security .web .authentication .ui .DefaultOneTimeTokenSubmitPageGeneratingFilter ;
51
53
import org .springframework .security .web .authentication .ui .DefaultResourcesFilter ;
52
- import org .springframework .security .web .context .HttpSessionSecurityContextRepository ;
53
- import org .springframework .security .web .context .SecurityContextRepository ;
54
54
import org .springframework .security .web .csrf .CsrfToken ;
55
+ import org .springframework .security .web .util .matcher .RequestMatcher ;
55
56
import org .springframework .util .Assert ;
56
57
import org .springframework .util .StringUtils ;
57
58
58
59
import static org .springframework .security .web .util .matcher .AntPathRequestMatcher .antMatcher ;
59
60
60
- public final class OneTimeTokenLoginConfigurer <H extends HttpSecurityBuilder <H >>
61
- extends AbstractHttpConfigurer <OneTimeTokenLoginConfigurer <H >, H > {
61
+ /**
62
+ * An {@link AbstractHttpConfigurer} for One-Time Token Login.
63
+ *
64
+ * <p>
65
+ * One-Time Token Login provides an application with the capability to have users log in
66
+ * by obtaining a single-use token out of band, for example through email.
67
+ *
68
+ * <p>
69
+ * Defaults are provided for all configuration options, with the only required
70
+ * configuration being
71
+ * {@link #tokenGenerationSuccessHandler(OneTimeTokenGenerationSuccessHandler)}.
72
+ * Alternatively, a {@link OneTimeTokenGenerationSuccessHandler} {@code @Bean} may be
73
+ * registered instead.
74
+ *
75
+ * <h2>Security Filters</h2>
76
+ *
77
+ * The following {@code Filter}s are populated:
78
+ *
79
+ * <ul>
80
+ * <li>{@link DefaultOneTimeTokenSubmitPageGeneratingFilter}</li>
81
+ * <li>{@link GenerateOneTimeTokenFilter}</li>
82
+ * <li>{@link OneTimeTokenAuthenticationFilter}</li>
83
+ * </ul>
84
+ *
85
+ * <h2>Shared Objects Used</h2>
86
+ *
87
+ * The following shared objects are used:
88
+ *
89
+ * <ul>
90
+ * <li>{@link DefaultLoginPageGeneratingFilter} - if {@link #loginPage(String)} is not
91
+ * configured and {@code DefaultLoginPageGeneratingFilter} is available, then a default
92
+ * login page will be made available</li>
93
+ * </ul>
94
+ *
95
+ * @author Marcus Da Coregio
96
+ * @author Daniel Garnier-Moiroux
97
+ * @since 6.4
98
+ * @see HttpSecurity#oneTimeTokenLogin(Customizer)
99
+ * @see DefaultOneTimeTokenSubmitPageGeneratingFilter
100
+ * @see GenerateOneTimeTokenFilter
101
+ * @see OneTimeTokenAuthenticationFilter
102
+ * @see AbstractAuthenticationFilterConfigurer
103
+ */
104
+ public final class OneTimeTokenLoginConfigurer <H extends HttpSecurityBuilder <H >> extends
105
+ AbstractAuthenticationFilterConfigurer <H , OneTimeTokenLoginConfigurer <H >, OneTimeTokenAuthenticationFilter > {
62
106
63
107
private final ApplicationContext context ;
64
108
65
109
private OneTimeTokenService oneTimeTokenService ;
66
110
67
- private AuthenticationConverter authenticationConverter = new OneTimeTokenAuthenticationConverter ();
68
-
69
- private AuthenticationFailureHandler authenticationFailureHandler ;
70
-
71
- private AuthenticationSuccessHandler authenticationSuccessHandler = new SavedRequestAwareAuthenticationSuccessHandler ();
72
-
73
- private String defaultSubmitPageUrl = "/login/ott" ;
111
+ private String defaultSubmitPageUrl = DefaultOneTimeTokenSubmitPageGeneratingFilter .DEFAULT_SUBMIT_PAGE_URL ;
74
112
75
113
private boolean submitPageEnabled = true ;
76
114
77
115
private String loginProcessingUrl = OneTimeTokenAuthenticationFilter .DEFAULT_LOGIN_PROCESSING_URL ;
78
116
79
- private String tokenGeneratingUrl = "/ott/generate" ;
117
+ private String tokenGeneratingUrl = GenerateOneTimeTokenFilter . DEFAULT_GENERATE_URL ;
80
118
81
119
private OneTimeTokenGenerationSuccessHandler oneTimeTokenGenerationSuccessHandler ;
82
120
@@ -85,58 +123,41 @@ public final class OneTimeTokenLoginConfigurer<H extends HttpSecurityBuilder<H>>
85
123
private GenerateOneTimeTokenRequestResolver requestResolver ;
86
124
87
125
public OneTimeTokenLoginConfigurer (ApplicationContext context ) {
126
+ super (new OneTimeTokenAuthenticationFilter (), OneTimeTokenAuthenticationFilter .DEFAULT_LOGIN_PROCESSING_URL );
88
127
this .context = context ;
89
128
}
90
129
91
130
@ Override
92
- public void init (H http ) {
131
+ public void init (H http ) throws Exception {
132
+ super .init (http );
93
133
AuthenticationProvider authenticationProvider = getAuthenticationProvider ();
94
134
http .authenticationProvider (postProcess (authenticationProvider ));
95
- configureDefaultLoginPage (http );
135
+ intiDefaultLoginFilter (http );
96
136
}
97
137
98
- private void configureDefaultLoginPage (H http ) {
138
+ private void intiDefaultLoginFilter (H http ) {
99
139
DefaultLoginPageGeneratingFilter loginPageGeneratingFilter = http
100
140
.getSharedObject (DefaultLoginPageGeneratingFilter .class );
101
- if (loginPageGeneratingFilter == null ) {
141
+ if (loginPageGeneratingFilter == null || isCustomLoginPage () ) {
102
142
return ;
103
143
}
104
144
loginPageGeneratingFilter .setOneTimeTokenEnabled (true );
105
145
loginPageGeneratingFilter .setOneTimeTokenGenerationUrl (this .tokenGeneratingUrl );
106
- if (this .authenticationFailureHandler == null
107
- && StringUtils .hasText (loginPageGeneratingFilter .getLoginPageUrl ())) {
108
- this .authenticationFailureHandler = new SimpleUrlAuthenticationFailureHandler (
109
- loginPageGeneratingFilter .getLoginPageUrl () + "?error" );
146
+
147
+ if (!StringUtils .hasText (loginPageGeneratingFilter .getLoginPageUrl ())) {
148
+ loginPageGeneratingFilter .setLoginPageUrl (DefaultLoginPageGeneratingFilter .DEFAULT_LOGIN_PAGE_URL );
149
+ loginPageGeneratingFilter .setFailureUrl (DefaultLoginPageGeneratingFilter .DEFAULT_LOGIN_PAGE_URL + "?"
150
+ + DefaultLoginPageGeneratingFilter .ERROR_PARAMETER_NAME );
151
+ loginPageGeneratingFilter
152
+ .setLogoutSuccessUrl (DefaultLoginPageGeneratingFilter .DEFAULT_LOGIN_PAGE_URL + "?logout" );
110
153
}
111
154
}
112
155
113
156
@ Override
114
- public void configure (H http ) {
157
+ public void configure (H http ) throws Exception {
158
+ super .configure (http );
115
159
configureSubmitPage (http );
116
160
configureOttGenerateFilter (http );
117
- configureOttAuthenticationFilter (http );
118
- }
119
-
120
- private void configureOttAuthenticationFilter (H http ) {
121
- AuthenticationManager authenticationManager = http .getSharedObject (AuthenticationManager .class );
122
- OneTimeTokenAuthenticationFilter oneTimeTokenAuthenticationFilter = new OneTimeTokenAuthenticationFilter ();
123
- oneTimeTokenAuthenticationFilter .setAuthenticationManager (authenticationManager );
124
- if (this .loginProcessingUrl != null ) {
125
- oneTimeTokenAuthenticationFilter
126
- .setRequiresAuthenticationRequestMatcher (antMatcher (HttpMethod .POST , this .loginProcessingUrl ));
127
- }
128
- oneTimeTokenAuthenticationFilter .setAuthenticationSuccessHandler (this .authenticationSuccessHandler );
129
- oneTimeTokenAuthenticationFilter .setAuthenticationFailureHandler (getAuthenticationFailureHandler ());
130
- oneTimeTokenAuthenticationFilter .setSecurityContextRepository (getSecurityContextRepository (http ));
131
- http .addFilter (postProcess (oneTimeTokenAuthenticationFilter ));
132
- }
133
-
134
- private SecurityContextRepository getSecurityContextRepository (H http ) {
135
- SecurityContextRepository securityContextRepository = http .getSharedObject (SecurityContextRepository .class );
136
- if (securityContextRepository != null ) {
137
- return securityContextRepository ;
138
- }
139
- return new HttpSessionSecurityContextRepository ();
140
161
}
141
162
142
163
private void configureOttGenerateFilter (H http ) {
@@ -170,7 +191,7 @@ private void configureSubmitPage(H http) {
170
191
DefaultOneTimeTokenSubmitPageGeneratingFilter submitPage = new DefaultOneTimeTokenSubmitPageGeneratingFilter ();
171
192
submitPage .setResolveHiddenInputs (this ::hiddenInputs );
172
193
submitPage .setRequestMatcher (antMatcher (HttpMethod .GET , this .defaultSubmitPageUrl ));
173
- submitPage .setLoginProcessingUrl (this .loginProcessingUrl );
194
+ submitPage .setLoginProcessingUrl (this .getLoginProcessingUrl () );
174
195
http .addFilter (postProcess (submitPage ));
175
196
}
176
197
@@ -184,6 +205,11 @@ private AuthenticationProvider getAuthenticationProvider() {
184
205
return this .authenticationProvider ;
185
206
}
186
207
208
+ @ Override
209
+ protected RequestMatcher createLoginProcessingUrlMatcher (String loginProcessingUrl ) {
210
+ return antMatcher (HttpMethod .POST , loginProcessingUrl );
211
+ }
212
+
187
213
/**
188
214
* Specifies the {@link AuthenticationProvider} to use when authenticating the user.
189
215
* @param authenticationProvider
@@ -221,14 +247,25 @@ public OneTimeTokenLoginConfigurer<H> tokenGenerationSuccessHandler(
221
247
* Only POST requests are processed, for that reason make sure that you pass a valid
222
248
* CSRF token if CSRF protection is enabled.
223
249
* @param loginProcessingUrl
224
- * @see org.springframework.security.config.annotation.web.builders. HttpSecurity#csrf(Customizer)
250
+ * @see HttpSecurity#csrf(Customizer)
225
251
*/
226
252
public OneTimeTokenLoginConfigurer <H > loginProcessingUrl (String loginProcessingUrl ) {
227
253
Assert .hasText (loginProcessingUrl , "loginProcessingUrl cannot be null or empty" );
228
- this .loginProcessingUrl = loginProcessingUrl ;
254
+ super .loginProcessingUrl ( loginProcessingUrl ) ;
229
255
return this ;
230
256
}
231
257
258
+ /**
259
+ * Specifies the URL to send users to if login is required. If used with
260
+ * {@link EnableWebSecurity} a default login page will be generated when this
261
+ * attribute is not specified.
262
+ * @param loginPage
263
+ */
264
+ @ Override
265
+ public OneTimeTokenLoginConfigurer <H > loginPage (String loginPage ) {
266
+ return super .loginPage (loginPage );
267
+ }
268
+
232
269
/**
233
270
* Configures whether the default one-time token submit page should be shown. This
234
271
* will prevent the {@link DefaultOneTimeTokenSubmitPageGeneratingFilter} to be
@@ -273,7 +310,7 @@ public OneTimeTokenLoginConfigurer<H> tokenService(OneTimeTokenService oneTimeTo
273
310
*/
274
311
public OneTimeTokenLoginConfigurer <H > authenticationConverter (AuthenticationConverter authenticationConverter ) {
275
312
Assert .notNull (authenticationConverter , "authenticationConverter cannot be null" );
276
- this .authenticationConverter = authenticationConverter ;
313
+ this .getAuthenticationFilter (). setAuthenticationConverter ( authenticationConverter ) ;
277
314
return this ;
278
315
}
279
316
@@ -283,11 +320,13 @@ public OneTimeTokenLoginConfigurer<H> authenticationConverter(AuthenticationConv
283
320
* {@link SimpleUrlAuthenticationFailureHandler}
284
321
* @param authenticationFailureHandler the {@link AuthenticationFailureHandler} to use
285
322
* when authentication fails.
323
+ * @deprecated Use {@link #failureHandler(AuthenticationFailureHandler)} instead
286
324
*/
325
+ @ Deprecated (since = "6.5" )
287
326
public OneTimeTokenLoginConfigurer <H > authenticationFailureHandler (
288
327
AuthenticationFailureHandler authenticationFailureHandler ) {
289
328
Assert .notNull (authenticationFailureHandler , "authenticationFailureHandler cannot be null" );
290
- this . authenticationFailureHandler = authenticationFailureHandler ;
329
+ super . failureHandler ( authenticationFailureHandler ) ;
291
330
return this ;
292
331
}
293
332
@@ -296,22 +335,16 @@ public OneTimeTokenLoginConfigurer<H> authenticationFailureHandler(
296
335
* {@link SavedRequestAwareAuthenticationSuccessHandler} with no additional properties
297
336
* set.
298
337
* @param authenticationSuccessHandler the {@link AuthenticationSuccessHandler}.
338
+ * @deprecated Use {@link #successHandler(AuthenticationSuccessHandler)} instead
299
339
*/
340
+ @ Deprecated (since = "6.5" )
300
341
public OneTimeTokenLoginConfigurer <H > authenticationSuccessHandler (
301
342
AuthenticationSuccessHandler authenticationSuccessHandler ) {
302
343
Assert .notNull (authenticationSuccessHandler , "authenticationSuccessHandler cannot be null" );
303
- this . authenticationSuccessHandler = authenticationSuccessHandler ;
344
+ super . successHandler ( authenticationSuccessHandler ) ;
304
345
return this ;
305
346
}
306
347
307
- private AuthenticationFailureHandler getAuthenticationFailureHandler () {
308
- if (this .authenticationFailureHandler != null ) {
309
- return this .authenticationFailureHandler ;
310
- }
311
- this .authenticationFailureHandler = new SimpleUrlAuthenticationFailureHandler ("/login?error" );
312
- return this .authenticationFailureHandler ;
313
- }
314
-
315
348
/**
316
349
* Use this {@link GenerateOneTimeTokenRequestResolver} when resolving
317
350
* {@link GenerateOneTimeTokenRequest} from {@link HttpServletRequest}. By default,
0 commit comments