Skip to content

Commit 23903b5

Browse files
Use Reflection to instantiate OpenSAML4 classes
Because the OpenSAML4 classes are compiled using Java 11, we have to rely on reflection to instante those classes since the config module should be compatible with Java 8 Issue gh-10816
1 parent e20323e commit 23903b5

File tree

2 files changed

+107
-35
lines changed

2 files changed

+107
-35
lines changed

config/src/main/java/org/springframework/security/config/annotation/web/configurers/saml2/Saml2LoginConfigurer.java

Lines changed: 48 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,6 @@
3232
import org.springframework.security.config.annotation.web.configurers.CsrfConfigurer;
3333
import org.springframework.security.core.Authentication;
3434
import org.springframework.security.saml2.provider.service.authentication.AbstractSaml2AuthenticationRequest;
35-
import org.springframework.security.saml2.provider.service.authentication.OpenSaml4AuthenticationProvider;
36-
import org.springframework.security.saml2.provider.service.authentication.OpenSaml4AuthenticationRequestFactory;
3735
import org.springframework.security.saml2.provider.service.authentication.OpenSamlAuthenticationProvider;
3836
import org.springframework.security.saml2.provider.service.authentication.OpenSamlAuthenticationRequestFactory;
3937
import org.springframework.security.saml2.provider.service.authentication.Saml2AuthenticationRequestFactory;
@@ -55,6 +53,7 @@
5553
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
5654
import org.springframework.security.web.util.matcher.RequestMatcher;
5755
import org.springframework.util.Assert;
56+
import org.springframework.util.ClassUtils;
5857
import org.springframework.util.StringUtils;
5958

6059
/**
@@ -112,6 +111,8 @@
112111
public final class Saml2LoginConfigurer<B extends HttpSecurityBuilder<B>>
113112
extends AbstractAuthenticationFilterConfigurer<B, Saml2LoginConfigurer<B>, Saml2WebSsoAuthenticationFilter> {
114113

114+
private static final String OPEN_SAML_4_VERSION = "4";
115+
115116
private String loginPage;
116117

117118
private String authenticationRequestUri = "/saml2/authenticate/{registrationId}";
@@ -320,11 +321,9 @@ private Saml2AuthenticationRequestFactory getAuthenticationRequestFactory(B http
320321
return resolver;
321322
}
322323
if (version().startsWith("4")) {
323-
return new OpenSaml4AuthenticationRequestFactory();
324-
}
325-
else {
326-
return new OpenSamlAuthenticationRequestFactory();
324+
return OpenSaml4LoginSupportFactory.getAuthenticationRequestFactory();
327325
}
326+
return new OpenSamlAuthenticationRequestFactory();
328327
}
329328

330329
private Saml2AuthenticationRequestContextResolver getAuthenticationRequestContextResolver(B http) {
@@ -354,18 +353,9 @@ private AuthenticationConverter getAuthenticationConverter(B http) {
354353
return authenticationConverterBean;
355354
}
356355

357-
private String version() {
358-
String version = Version.getVersion();
359-
if (version != null) {
360-
return version;
361-
}
362-
return Version.class.getModule().getDescriptor().version().map(Object::toString)
363-
.orElseThrow(() -> new IllegalStateException("cannot determine OpenSAML version"));
364-
}
365-
366356
private void registerDefaultAuthenticationProvider(B http) {
367357
if (version().startsWith("4")) {
368-
http.authenticationProvider(postProcess(new OpenSaml4AuthenticationProvider()));
358+
http.authenticationProvider(postProcess(OpenSaml4LoginSupportFactory.getAuthenticationProvider()));
369359
}
370360
else {
371361
http.authenticationProvider(postProcess(new OpenSamlAuthenticationProvider()));
@@ -415,6 +405,19 @@ private Saml2AuthenticationRequestRepository<AbstractSaml2AuthenticationRequest>
415405
return repository;
416406
}
417407

408+
private String version() {
409+
String version = Version.getVersion();
410+
if (StringUtils.hasText(version)) {
411+
return version;
412+
}
413+
boolean openSaml4ClassPresent = ClassUtils
414+
.isPresent("org.opensaml.core.xml.persist.impl.PassthroughSourceStrategy", null);
415+
if (openSaml4ClassPresent) {
416+
return OPEN_SAML_4_VERSION;
417+
}
418+
throw new IllegalStateException("cannot determine OpenSAML version");
419+
}
420+
418421
private <C> C getSharedOrBean(B http, Class<C> clazz) {
419422
C shared = http.getSharedObject(clazz);
420423
if (shared != null) {
@@ -442,4 +445,33 @@ private <C> void setSharedObject(B http, Class<C> clazz, C object) {
442445
}
443446
}
444447

448+
private static class OpenSaml4LoginSupportFactory {
449+
450+
private static Saml2AuthenticationRequestFactory getAuthenticationRequestFactory() {
451+
try {
452+
Class<?> authenticationRequestFactory = ClassUtils.forName(
453+
"org.springframework.security.saml2.provider.service.authentication.OpenSaml4AuthenticationRequestFactory",
454+
OpenSaml4LoginSupportFactory.class.getClassLoader());
455+
return (Saml2AuthenticationRequestFactory) authenticationRequestFactory.getDeclaredConstructor()
456+
.newInstance();
457+
}
458+
catch (ReflectiveOperationException ex) {
459+
throw new IllegalStateException("Could not instantiate OpenSaml4AuthenticationRequestFactory", ex);
460+
}
461+
}
462+
463+
private static AuthenticationProvider getAuthenticationProvider() {
464+
try {
465+
Class<?> authenticationProvider = ClassUtils.forName(
466+
"org.springframework.security.saml2.provider.service.authentication.OpenSaml4AuthenticationProvider",
467+
OpenSaml4LoginSupportFactory.class.getClassLoader());
468+
return (AuthenticationProvider) authenticationProvider.getDeclaredConstructor().newInstance();
469+
}
470+
catch (ReflectiveOperationException ex) {
471+
throw new IllegalStateException("Could not instantiate OpenSaml4AuthenticationProvider", ex);
472+
}
473+
}
474+
475+
}
476+
445477
}

config/src/main/java/org/springframework/security/config/annotation/web/configurers/saml2/Saml2LogoutConfigurer.java

Lines changed: 59 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2021 the original author or authors.
2+
* Copyright 2002-2022 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -47,8 +47,6 @@
4747
import org.springframework.security.saml2.provider.service.web.authentication.logout.HttpSessionLogoutRequestRepository;
4848
import org.springframework.security.saml2.provider.service.web.authentication.logout.OpenSaml3LogoutRequestResolver;
4949
import org.springframework.security.saml2.provider.service.web.authentication.logout.OpenSaml3LogoutResponseResolver;
50-
import org.springframework.security.saml2.provider.service.web.authentication.logout.OpenSaml4LogoutRequestResolver;
51-
import org.springframework.security.saml2.provider.service.web.authentication.logout.OpenSaml4LogoutResponseResolver;
5250
import org.springframework.security.saml2.provider.service.web.authentication.logout.Saml2LogoutRequestFilter;
5351
import org.springframework.security.saml2.provider.service.web.authentication.logout.Saml2LogoutRequestRepository;
5452
import org.springframework.security.saml2.provider.service.web.authentication.logout.Saml2LogoutRequestResolver;
@@ -67,6 +65,8 @@
6765
import org.springframework.security.web.util.matcher.AndRequestMatcher;
6866
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
6967
import org.springframework.security.web.util.matcher.RequestMatcher;
68+
import org.springframework.util.ClassUtils;
69+
import org.springframework.util.StringUtils;
7070

7171
/**
7272
* Adds SAML 2.0 logout support.
@@ -113,6 +113,8 @@
113113
public final class Saml2LogoutConfigurer<H extends HttpSecurityBuilder<H>>
114114
extends AbstractHttpConfigurer<Saml2LogoutConfigurer<H>, H> {
115115

116+
private static final String OPEN_SAML_4_VERSION = "4";
117+
116118
private ApplicationContext context;
117119

118120
private RelyingPartyRegistrationRepository relyingPartyRegistrationRepository;
@@ -304,6 +306,19 @@ private Saml2LogoutResponseResolver createSaml2LogoutResponseResolver(
304306
return this.logoutResponseConfigurer.logoutResponseResolver(relyingPartyRegistrationResolver);
305307
}
306308

309+
private String version() {
310+
String version = Version.getVersion();
311+
if (StringUtils.hasText(version)) {
312+
return version;
313+
}
314+
boolean openSaml4ClassPresent = ClassUtils
315+
.isPresent("org.opensaml.core.xml.persist.impl.PassthroughSourceStrategy", null);
316+
if (openSaml4ClassPresent) {
317+
return OPEN_SAML_4_VERSION;
318+
}
319+
throw new IllegalStateException("cannot determine OpenSAML version");
320+
}
321+
307322
private <C> C getBeanOrNull(Class<C> clazz) {
308323
if (this.context == null) {
309324
return null;
@@ -314,15 +329,6 @@ private <C> C getBeanOrNull(Class<C> clazz) {
314329
return this.context.getBean(clazz);
315330
}
316331

317-
private String version() {
318-
String version = Version.getVersion();
319-
if (version != null) {
320-
return version;
321-
}
322-
return Version.class.getModule().getDescriptor().version().map(Object::toString)
323-
.orElseThrow(() -> new IllegalStateException("cannot determine OpenSAML version"));
324-
}
325-
326332
/**
327333
* A configurer for SAML 2.0 LogoutRequest components
328334
*/
@@ -403,7 +409,7 @@ private Saml2LogoutRequestResolver logoutRequestResolver(
403409
return this.logoutRequestResolver;
404410
}
405411
if (version().startsWith("4")) {
406-
return new OpenSaml4LogoutRequestResolver(relyingPartyRegistrationResolver);
412+
return OpenSaml4LogoutSupportFactory.getLogoutRequestResolver(relyingPartyRegistrationResolver);
407413
}
408414
return new OpenSaml3LogoutRequestResolver(relyingPartyRegistrationResolver);
409415
}
@@ -471,13 +477,13 @@ private Saml2LogoutResponseValidator logoutResponseValidator() {
471477

472478
private Saml2LogoutResponseResolver logoutResponseResolver(
473479
RelyingPartyRegistrationResolver relyingPartyRegistrationResolver) {
474-
if (this.logoutResponseResolver == null) {
475-
if (version().startsWith("4")) {
476-
return new OpenSaml4LogoutResponseResolver(relyingPartyRegistrationResolver);
477-
}
478-
return new OpenSaml3LogoutResponseResolver(relyingPartyRegistrationResolver);
480+
if (this.logoutResponseResolver != null) {
481+
return this.logoutResponseResolver;
479482
}
480-
return this.logoutResponseResolver;
483+
if (version().startsWith("4")) {
484+
return OpenSaml4LogoutSupportFactory.getLogoutResponseResolver(relyingPartyRegistrationResolver);
485+
}
486+
return new OpenSaml3LogoutResponseResolver(relyingPartyRegistrationResolver);
481487
}
482488

483489
}
@@ -520,4 +526,38 @@ public void logout(HttpServletRequest request, HttpServletResponse response, Aut
520526

521527
}
522528

529+
private static class OpenSaml4LogoutSupportFactory {
530+
531+
private static Saml2LogoutResponseResolver getLogoutResponseResolver(
532+
RelyingPartyRegistrationResolver relyingPartyRegistrationResolver) {
533+
try {
534+
Class<?> logoutResponseResolver = ClassUtils.forName(
535+
"org.springframework.security.saml2.provider.service.web.authentication.logout.OpenSaml4LogoutResponseResolver",
536+
OpenSaml4LogoutSupportFactory.class.getClassLoader());
537+
return (Saml2LogoutResponseResolver) logoutResponseResolver
538+
.getDeclaredConstructor(RelyingPartyRegistrationResolver.class)
539+
.newInstance(relyingPartyRegistrationResolver);
540+
}
541+
catch (ReflectiveOperationException ex) {
542+
throw new IllegalStateException("Could not instantiate OpenSaml4LogoutResponseResolver", ex);
543+
}
544+
}
545+
546+
private static Saml2LogoutRequestResolver getLogoutRequestResolver(
547+
RelyingPartyRegistrationResolver relyingPartyRegistrationResolver) {
548+
try {
549+
Class<?> logoutRequestResolver = ClassUtils.forName(
550+
"org.springframework.security.saml2.provider.service.web.authentication.logout.OpenSaml4LogoutRequestResolver",
551+
OpenSaml4LogoutSupportFactory.class.getClassLoader());
552+
return (Saml2LogoutRequestResolver) logoutRequestResolver
553+
.getDeclaredConstructor(RelyingPartyRegistrationResolver.class)
554+
.newInstance(relyingPartyRegistrationResolver);
555+
}
556+
catch (ReflectiveOperationException ex) {
557+
throw new IllegalStateException("Could not instantiate OpenSaml4LogoutRequestResolver", ex);
558+
}
559+
}
560+
561+
}
562+
523563
}

0 commit comments

Comments
 (0)