21
21
22
22
import javax .servlet .Filter ;
23
23
24
+ import org .joda .time .DateTime ;
25
+
24
26
import org .springframework .beans .factory .NoSuchBeanDefinitionException ;
25
27
import org .springframework .context .ApplicationContext ;
26
28
import org .springframework .security .authentication .AuthenticationManager ;
41
43
import org .springframework .security .saml2 .provider .service .web .DefaultSaml2AuthenticationRequestContextResolver ;
42
44
import org .springframework .security .saml2 .provider .service .web .Saml2AuthenticationRequestContextResolver ;
43
45
import org .springframework .security .saml2 .provider .service .web .Saml2AuthenticationTokenConverter ;
46
+ import org .springframework .security .saml2 .provider .service .web .authentication .OpenSamlAuthenticationRequestResolver ;
47
+ import org .springframework .security .saml2 .provider .service .web .authentication .Saml2AuthenticationRequestRedirectFilter ;
48
+ import org .springframework .security .saml2 .provider .service .web .authentication .Saml2AuthenticationRequestResolver ;
44
49
import org .springframework .security .web .authentication .AuthenticationConverter ;
45
50
import org .springframework .security .web .authentication .LoginUrlAuthenticationEntryPoint ;
46
51
import org .springframework .security .web .authentication .ui .DefaultLoginPageGeneratingFilter ;
49
54
import org .springframework .util .Assert ;
50
55
import org .springframework .util .StringUtils ;
51
56
57
+ import static org .springframework .security .saml2 .provider .service .web .authentication .OpenSamlAuthenticationRequestResolver .OpenSamlAuthenticationRequestPartial ;
58
+
52
59
/**
53
60
* An {@link AbstractHttpConfigurer} for SAML 2.0 Login, which leverages the SAML 2.0 Web
54
61
* Browser Single Sign On (WebSSO) Flow.
@@ -106,9 +113,11 @@ public final class Saml2LoginConfigurer<B extends HttpSecurityBuilder<B>>
106
113
107
114
private String loginPage ;
108
115
109
- private String loginProcessingUrl = Saml2WebSsoAuthenticationFilter . DEFAULT_FILTER_PROCESSES_URI ;
116
+ private String authenticationRequestUri = "/saml2/authenticate/{registrationId}" ;
110
117
111
- private AuthenticationRequestEndpointConfig authenticationRequestEndpoint = new AuthenticationRequestEndpointConfig ();
118
+ private Saml2AuthenticationRequestResolver authenticationRequestResolver ;
119
+
120
+ private String loginProcessingUrl = Saml2WebSsoAuthenticationFilter .DEFAULT_FILTER_PROCESSES_URI ;
112
121
113
122
private RelyingPartyRegistrationRepository relyingPartyRegistrationRepository ;
114
123
@@ -167,6 +176,20 @@ public Saml2LoginConfigurer<B> loginPage(String loginPage) {
167
176
return this ;
168
177
}
169
178
179
+ /**
180
+ * Use this {@link Saml2AuthenticationRequestResolver} for generating SAML 2.0
181
+ * Authentication Requests.
182
+ * @param authenticationRequestResolver
183
+ * @return the {@link Saml2LoginConfigurer} for further configuration
184
+ * @since 5.5
185
+ */
186
+ public Saml2LoginConfigurer <B > authenticationRequestResolver (
187
+ Saml2AuthenticationRequestResolver authenticationRequestResolver ) {
188
+ Assert .notNull (authenticationRequestResolver , "authenticationRequestResolver cannot be null" );
189
+ this .authenticationRequestResolver = authenticationRequestResolver ;
190
+ return this ;
191
+ }
192
+
170
193
@ Override
171
194
public Saml2LoginConfigurer <B > loginProcessingUrl (String loginProcessingUrl ) {
172
195
Assert .hasText (loginProcessingUrl , "loginProcessingUrl cannot be empty" );
@@ -182,7 +205,7 @@ protected RequestMatcher createLoginProcessingUrlMatcher(String loginProcessingU
182
205
183
206
/**
184
207
* {@inheritDoc}
185
- *
208
+ * <p>
186
209
* Initializes this filter chain for SAML 2 Login. The following actions are taken:
187
210
* <ul>
188
211
* <li>The WebSSO endpoint has CSRF disabled, typically {@code /login/saml2/sso}</li>
@@ -209,8 +232,8 @@ public void init(B http) throws Exception {
209
232
super .init (http );
210
233
}
211
234
else {
212
- Map <String , String > providerUrlMap = getIdentityProviderUrlMap (
213
- this .authenticationRequestEndpoint . filterProcessingUrl , this . relyingPartyRegistrationRepository );
235
+ Map <String , String > providerUrlMap = getIdentityProviderUrlMap (this . authenticationRequestUri ,
236
+ this .relyingPartyRegistrationRepository );
214
237
boolean singleProvider = providerUrlMap .size () == 1 ;
215
238
if (singleProvider ) {
216
239
// Setup auto-redirect to provider login page
@@ -230,14 +253,25 @@ public void init(B http) throws Exception {
230
253
231
254
/**
232
255
* {@inheritDoc}
233
- *
256
+ * <p>
234
257
* During the {@code configure} phase, a
235
258
* {@link Saml2WebSsoAuthenticationRequestFilter} is added to handle SAML 2.0
236
259
* AuthNRequest redirects
237
260
*/
238
261
@ Override
239
262
public void configure (B http ) throws Exception {
240
- http .addFilter (this .authenticationRequestEndpoint .build (http ));
263
+ if (declaredAuthenticationRequestRedirectComponents (http )) {
264
+ http .addFilter (getAuthenticationRequestRedirectFilter (http ));
265
+ }
266
+ else if (declaredWebSsoAuthenticationRequestComponents (http )) {
267
+ http .addFilter (postProcess (getWebSsoAuthenticationRequestFilter (http )));
268
+ }
269
+ else {
270
+ Saml2WebSsoAuthenticationRequestFilter filter = getWebSsoAuthenticationRequestFilter (http );
271
+ filter .setRedirectMatcher ((request ) -> false );
272
+ http .addFilter (postProcess (filter ));
273
+ http .addFilter (getAuthenticationRequestRedirectFilter (http ));
274
+ }
241
275
super .configure (http );
242
276
if (this .authenticationManager == null ) {
243
277
registerDefaultAuthenticationProvider (http );
@@ -247,6 +281,61 @@ public void configure(B http) throws Exception {
247
281
}
248
282
}
249
283
284
+ private boolean declaredWebSsoAuthenticationRequestComponents (B http ) {
285
+ boolean declaredContextResolver = getBeanOrNull (http , Saml2AuthenticationRequestContextResolver .class ) != null ;
286
+ boolean declaredFactory = getBeanOrNull (http , Saml2AuthenticationRequestFactory .class ) != null ;
287
+ return (declaredContextResolver || declaredFactory );
288
+ }
289
+
290
+ private boolean declaredAuthenticationRequestRedirectComponents (B http ) {
291
+ boolean declaredResolver = this .authenticationRequestResolver != null
292
+ || getBeanOrNull (http , Saml2AuthenticationRequestResolver .class ) != null ;
293
+ return declaredResolver ;
294
+ }
295
+
296
+ private Saml2WebSsoAuthenticationRequestFilter getWebSsoAuthenticationRequestFilter (B http ) {
297
+ return new Saml2WebSsoAuthenticationRequestFilter (getAuthenticationRequestContextResolver (http ),
298
+ getAuthenticationRequestFactory (http ));
299
+ }
300
+
301
+ private Filter getAuthenticationRequestRedirectFilter (B http ) {
302
+ if (this .authenticationRequestResolver != null ) {
303
+ return new Saml2AuthenticationRequestRedirectFilter (this .authenticationRequestResolver );
304
+ }
305
+ this .authenticationRequestResolver = getBeanOrNull (http , Saml2AuthenticationRequestResolver .class );
306
+ if (authenticationRequestResolver != null ) {
307
+ return new Saml2AuthenticationRequestRedirectFilter (authenticationRequestResolver );
308
+ }
309
+ OpenSamlAuthenticationRequestResolver delegate = new OpenSamlAuthenticationRequestResolver (
310
+ new DefaultRelyingPartyRegistrationResolver (this .relyingPartyRegistrationRepository ));
311
+ this .authenticationRequestResolver = (request ) -> {
312
+ OpenSamlAuthenticationRequestPartial partial = delegate .resolveAuthenticationRequest (request );
313
+ if (partial == null ) {
314
+ return null ;
315
+ }
316
+ return partial .authnRequest ((authnRequest ) -> authnRequest .setIssueInstant (DateTime .now ()));
317
+ };
318
+ return new Saml2AuthenticationRequestRedirectFilter (this .authenticationRequestResolver );
319
+ }
320
+
321
+ private Saml2AuthenticationRequestFactory getAuthenticationRequestFactory (B http ) {
322
+ Saml2AuthenticationRequestFactory resolver = getSharedOrBean (http , Saml2AuthenticationRequestFactory .class );
323
+ if (resolver != null ) {
324
+ return resolver ;
325
+ }
326
+ return new OpenSamlAuthenticationRequestFactory ();
327
+ }
328
+
329
+ private Saml2AuthenticationRequestContextResolver getAuthenticationRequestContextResolver (B http ) {
330
+ Saml2AuthenticationRequestContextResolver resolver = getBeanOrNull (http ,
331
+ Saml2AuthenticationRequestContextResolver .class );
332
+ if (resolver != null ) {
333
+ return resolver ;
334
+ }
335
+ return new DefaultSaml2AuthenticationRequestContextResolver (
336
+ new DefaultRelyingPartyRegistrationResolver (this .relyingPartyRegistrationRepository ));
337
+ }
338
+
250
339
private AuthenticationConverter getAuthenticationConverter (B http ) {
251
340
if (this .authenticationConverter == null ) {
252
341
return new Saml2AuthenticationTokenConverter (
@@ -275,8 +364,8 @@ private void initDefaultLoginFilter(B http) {
275
364
return ;
276
365
}
277
366
loginPageGeneratingFilter .setSaml2LoginEnabled (true );
278
- loginPageGeneratingFilter .setSaml2AuthenticationUrlToProviderName (this . getIdentityProviderUrlMap (
279
- this .authenticationRequestEndpoint . filterProcessingUrl , this .relyingPartyRegistrationRepository ));
367
+ loginPageGeneratingFilter .setSaml2AuthenticationUrlToProviderName (
368
+ this .getIdentityProviderUrlMap ( this . authenticationRequestUri , this .relyingPartyRegistrationRepository ));
280
369
loginPageGeneratingFilter .setLoginPageUrl (this .getLoginPage ());
281
370
loginPageGeneratingFilter .setFailureUrl (this .getFailureUrl ());
282
371
}
@@ -320,38 +409,4 @@ private <C> void setSharedObject(B http, Class<C> clazz, C object) {
320
409
}
321
410
}
322
411
323
- private final class AuthenticationRequestEndpointConfig {
324
-
325
- private String filterProcessingUrl = "/saml2/authenticate/{registrationId}" ;
326
-
327
- private AuthenticationRequestEndpointConfig () {
328
- }
329
-
330
- private Filter build (B http ) {
331
- Saml2AuthenticationRequestFactory authenticationRequestResolver = getResolver (http );
332
- Saml2AuthenticationRequestContextResolver contextResolver = getContextResolver (http );
333
- return postProcess (
334
- new Saml2WebSsoAuthenticationRequestFilter (contextResolver , authenticationRequestResolver ));
335
- }
336
-
337
- private Saml2AuthenticationRequestFactory getResolver (B http ) {
338
- Saml2AuthenticationRequestFactory resolver = getSharedOrBean (http , Saml2AuthenticationRequestFactory .class );
339
- if (resolver == null ) {
340
- resolver = new OpenSamlAuthenticationRequestFactory ();
341
- }
342
- return resolver ;
343
- }
344
-
345
- private Saml2AuthenticationRequestContextResolver getContextResolver (B http ) {
346
- Saml2AuthenticationRequestContextResolver resolver = getBeanOrNull (http ,
347
- Saml2AuthenticationRequestContextResolver .class );
348
- if (resolver == null ) {
349
- return new DefaultSaml2AuthenticationRequestContextResolver (new DefaultRelyingPartyRegistrationResolver (
350
- Saml2LoginConfigurer .this .relyingPartyRegistrationRepository ));
351
- }
352
- return resolver ;
353
- }
354
-
355
- }
356
-
357
412
}
0 commit comments