24
24
25
25
import org .springframework .context .ApplicationContext ;
26
26
import org .springframework .http .HttpMethod ;
27
- import org .springframework .security .authentication .AuthenticationManager ;
28
27
import org .springframework .security .authentication .AuthenticationProvider ;
29
28
import org .springframework .security .authentication .ott .GenerateOneTimeTokenRequest ;
30
29
import org .springframework .security .authentication .ott .InMemoryOneTimeTokenService ;
33
32
import org .springframework .security .authentication .ott .OneTimeTokenService ;
34
33
import org .springframework .security .config .Customizer ;
35
34
import 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 ;
36
38
import org .springframework .security .config .annotation .web .configurers .AbstractHttpConfigurer ;
37
39
import org .springframework .security .core .Authentication ;
38
40
import org .springframework .security .core .userdetails .UserDetailsService ;
39
41
import org .springframework .security .web .authentication .AuthenticationConverter ;
40
42
import org .springframework .security .web .authentication .AuthenticationFailureHandler ;
41
- import org .springframework .security .web .authentication .AuthenticationFilter ;
42
43
import org .springframework .security .web .authentication .AuthenticationSuccessHandler ;
43
44
import org .springframework .security .web .authentication .SavedRequestAwareAuthenticationSuccessHandler ;
44
45
import org .springframework .security .web .authentication .SimpleUrlAuthenticationFailureHandler ;
45
46
import org .springframework .security .web .authentication .ott .DefaultGenerateOneTimeTokenRequestResolver ;
46
47
import org .springframework .security .web .authentication .ott .GenerateOneTimeTokenFilter ;
47
48
import org .springframework .security .web .authentication .ott .GenerateOneTimeTokenRequestResolver ;
48
49
import org .springframework .security .web .authentication .ott .OneTimeTokenAuthenticationConverter ;
50
+ import org .springframework .security .web .authentication .ott .OneTimeTokenAuthenticationFilter ;
49
51
import org .springframework .security .web .authentication .ott .OneTimeTokenGenerationSuccessHandler ;
50
52
import org .springframework .security .web .authentication .ui .DefaultLoginPageGeneratingFilter ;
51
53
import org .springframework .security .web .authentication .ui .DefaultOneTimeTokenSubmitPageGeneratingFilter ;
52
54
import org .springframework .security .web .authentication .ui .DefaultResourcesFilter ;
53
- import org .springframework .security .web .context .HttpSessionSecurityContextRepository ;
54
- import org .springframework .security .web .context .SecurityContextRepository ;
55
55
import org .springframework .security .web .csrf .CsrfToken ;
56
+ import org .springframework .security .web .util .matcher .RequestMatcher ;
56
57
import org .springframework .util .Assert ;
57
58
import org .springframework .util .StringUtils ;
58
59
59
60
import static org .springframework .security .web .util .matcher .AntPathRequestMatcher .antMatcher ;
60
61
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 > {
63
107
64
108
private final ApplicationContext context ;
65
109
66
110
private OneTimeTokenService oneTimeTokenService ;
67
111
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 ;
75
113
76
114
private boolean submitPageEnabled = true ;
77
115
78
- private String loginProcessingUrl = "/login/ott" ;
79
-
80
- private String tokenGeneratingUrl = "/ott/generate" ;
116
+ private String tokenGeneratingUrl = GenerateOneTimeTokenFilter .DEFAULT_GENERATE_URL ;
81
117
82
118
private OneTimeTokenGenerationSuccessHandler oneTimeTokenGenerationSuccessHandler ;
83
119
@@ -86,55 +122,51 @@ public final class OneTimeTokenLoginConfigurer<H extends HttpSecurityBuilder<H>>
86
122
private GenerateOneTimeTokenRequestResolver requestResolver ;
87
123
88
124
public OneTimeTokenLoginConfigurer (ApplicationContext context ) {
125
+ super (new OneTimeTokenAuthenticationFilter (), OneTimeTokenAuthenticationFilter .DEFAULT_LOGIN_PROCESSING_URL );
89
126
this .context = context ;
90
127
}
91
128
92
129
@ Override
93
- public void init (H http ) {
130
+ public void init (H http ) throws Exception {
131
+ super .init (http );
94
132
AuthenticationProvider authenticationProvider = getAuthenticationProvider (http );
95
133
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 ;
97
145
}
98
146
99
- private void configureDefaultLoginPage (H http ) {
147
+ private void intiDefaultLoginFilter (H http ) {
100
148
DefaultLoginPageGeneratingFilter loginPageGeneratingFilter = http
101
149
.getSharedObject (DefaultLoginPageGeneratingFilter .class );
102
- if (loginPageGeneratingFilter == null ) {
150
+ if (loginPageGeneratingFilter == null || isCustomLoginPage () ) {
103
151
return ;
104
152
}
105
153
loginPageGeneratingFilter .setOneTimeTokenEnabled (true );
106
154
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" );
111
162
}
112
163
}
113
164
114
165
@ Override
115
- public void configure (H http ) {
166
+ public void configure (H http ) throws Exception {
167
+ super .configure (http );
116
168
configureSubmitPage (http );
117
169
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 ();
138
170
}
139
171
140
172
private void configureOttGenerateFilter (H http ) {
@@ -166,18 +198,13 @@ private void configureSubmitPage(H http) {
166
198
DefaultOneTimeTokenSubmitPageGeneratingFilter submitPage = new DefaultOneTimeTokenSubmitPageGeneratingFilter ();
167
199
submitPage .setResolveHiddenInputs (this ::hiddenInputs );
168
200
submitPage .setRequestMatcher (antMatcher (HttpMethod .GET , this .defaultSubmitPageUrl ));
169
- submitPage .setLoginProcessingUrl (this .loginProcessingUrl );
201
+ submitPage .setLoginProcessingUrl (this .getLoginProcessingUrl () );
170
202
http .addFilter (postProcess (submitPage ));
171
203
}
172
204
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 );
181
208
}
182
209
183
210
/**
@@ -217,14 +244,25 @@ public OneTimeTokenLoginConfigurer<H> tokenGenerationSuccessHandler(
217
244
* Only POST requests are processed, for that reason make sure that you pass a valid
218
245
* CSRF token if CSRF protection is enabled.
219
246
* @param loginProcessingUrl
220
- * @see org.springframework.security.config.annotation.web.builders. HttpSecurity#csrf(Customizer)
247
+ * @see HttpSecurity#csrf(Customizer)
221
248
*/
222
249
public OneTimeTokenLoginConfigurer <H > loginProcessingUrl (String loginProcessingUrl ) {
223
250
Assert .hasText (loginProcessingUrl , "loginProcessingUrl cannot be null or empty" );
224
- this .loginProcessingUrl = loginProcessingUrl ;
251
+ super .loginProcessingUrl ( loginProcessingUrl ) ;
225
252
return this ;
226
253
}
227
254
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
+
228
266
/**
229
267
* Configures whether the default one-time token submit page should be shown. This
230
268
* will prevent the {@link DefaultOneTimeTokenSubmitPageGeneratingFilter} to be
@@ -269,7 +307,7 @@ public OneTimeTokenLoginConfigurer<H> tokenService(OneTimeTokenService oneTimeTo
269
307
*/
270
308
public OneTimeTokenLoginConfigurer <H > authenticationConverter (AuthenticationConverter authenticationConverter ) {
271
309
Assert .notNull (authenticationConverter , "authenticationConverter cannot be null" );
272
- this .authenticationConverter = authenticationConverter ;
310
+ this .getAuthenticationFilter (). setAuthenticationConverter ( authenticationConverter ) ;
273
311
return this ;
274
312
}
275
313
@@ -279,11 +317,13 @@ public OneTimeTokenLoginConfigurer<H> authenticationConverter(AuthenticationConv
279
317
* {@link SimpleUrlAuthenticationFailureHandler}
280
318
* @param authenticationFailureHandler the {@link AuthenticationFailureHandler} to use
281
319
* when authentication fails.
320
+ * @deprecated Use {@link #failureHandler(AuthenticationFailureHandler)} instead
282
321
*/
322
+ @ Deprecated (since = "6.5" )
283
323
public OneTimeTokenLoginConfigurer <H > authenticationFailureHandler (
284
324
AuthenticationFailureHandler authenticationFailureHandler ) {
285
325
Assert .notNull (authenticationFailureHandler , "authenticationFailureHandler cannot be null" );
286
- this . authenticationFailureHandler = authenticationFailureHandler ;
326
+ super . failureHandler ( authenticationFailureHandler ) ;
287
327
return this ;
288
328
}
289
329
@@ -292,22 +332,16 @@ public OneTimeTokenLoginConfigurer<H> authenticationFailureHandler(
292
332
* {@link SavedRequestAwareAuthenticationSuccessHandler} with no additional properties
293
333
* set.
294
334
* @param authenticationSuccessHandler the {@link AuthenticationSuccessHandler}.
335
+ * @deprecated Use {@link #successHandler(AuthenticationSuccessHandler)} instead
295
336
*/
337
+ @ Deprecated (since = "6.5" )
296
338
public OneTimeTokenLoginConfigurer <H > authenticationSuccessHandler (
297
339
AuthenticationSuccessHandler authenticationSuccessHandler ) {
298
340
Assert .notNull (authenticationSuccessHandler , "authenticationSuccessHandler cannot be null" );
299
- this . authenticationSuccessHandler = authenticationSuccessHandler ;
341
+ super . successHandler ( authenticationSuccessHandler ) ;
300
342
return this ;
301
343
}
302
344
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
-
311
345
/**
312
346
* Use this {@link GenerateOneTimeTokenRequestResolver} when resolving
313
347
* {@link GenerateOneTimeTokenRequest} from {@link HttpServletRequest}. By default,
0 commit comments