diff --git a/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/Saml2VersionUtils.java b/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/Saml2VersionUtils.java new file mode 100644 index 00000000000..ede2cc24638 --- /dev/null +++ b/saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/Saml2VersionUtils.java @@ -0,0 +1,111 @@ +/* + * Copyright 2002-2022 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.security.saml2; + +import org.opensaml.core.Version; + +import org.springframework.util.Assert; +import org.springframework.util.ClassUtils; +import org.springframework.util.StringUtils; + +/** + * A Utils class that allows checking the version of the OpenSAML library in the + * classpath. + * + * @author Igor Pelesić + * @since 5.8 + */ + +public final class Saml2VersionUtils { + + private static final String DELIMITER = "\\."; + + private static final String OPEN_SAML_4_VERSION = "4"; + + private Saml2VersionUtils() { + } + + /** + * Checks whether a supported OpenSAML 3 version is found on the classpath. + */ + public static void checkOpenSAML3VersionSupported() { + Assert.state(getVersion().startsWith("3"), "OpenSAML version 3.x.x not found on the classpath"); + } + + /** + * Checks whether a supported OpenSAML 4 version is found on the classpath. + */ + public static void checkOpenSAML4VersionSupported() { + Assert.state(isSaml2VersionGreaterEqual("4.1.0"), + "OpenSAML version higher or equal to 4.1.0 not found on the classpath"); + } + + private static boolean isSaml2VersionGreaterEqual(String requiredVersion) { + String[] splitVersion = getVersion().split(DELIMITER); + String[] splitRequiredVersion = requiredVersion.split(DELIMITER); + + if (splitVersion.length != splitRequiredVersion.length) { + throw new IllegalStateException("unexpected OpenSAML version"); + } + + for (int i = 0; i < splitVersion.length; i++) { + Integer versionNumber = getVersionNumber(splitVersion[i]); + Integer requiredVersionNumber = getVersionNumber(splitRequiredVersion[i]); + if (versionNumber > requiredVersionNumber) { + return true; + } + else if (versionNumber == requiredVersionNumber) { + if (i == splitVersion.length - 1) { + return true; + } + continue; + } + else { + return false; + } + } + + return false; + } + + private static String getVersion() { + String version = Version.getVersion(); + if (StringUtils.hasText(version)) { + return version; + } + + boolean openSaml4ClassPresent = ClassUtils + .isPresent("org.opensaml.core.xml.persist.impl.PassthroughSourceStrategy", null); + + if (openSaml4ClassPresent) { + return OPEN_SAML_4_VERSION; + } + + throw new IllegalStateException("cannot determine OpenSAML version"); + + } + + private static Integer getVersionNumber(String versionStr) { + try { + return Integer.parseInt(versionStr); + } + catch (NumberFormatException ex) { + throw new IllegalStateException("could not parse OpenSAML version"); + } + } + +} diff --git a/saml2/saml2-service-provider/src/opensaml3Main/java/org/springframework/security/saml2/provider/service/authentication/OpenSamlAuthenticationProvider.java b/saml2/saml2-service-provider/src/opensaml3Main/java/org/springframework/security/saml2/provider/service/authentication/OpenSamlAuthenticationProvider.java index 18ec5f77ebb..34a576cbd80 100644 --- a/saml2/saml2-service-provider/src/opensaml3Main/java/org/springframework/security/saml2/provider/service/authentication/OpenSamlAuthenticationProvider.java +++ b/saml2/saml2-service-provider/src/opensaml3Main/java/org/springframework/security/saml2/provider/service/authentication/OpenSamlAuthenticationProvider.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2021 the original author or authors. + * Copyright 2002-2022 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -83,6 +83,7 @@ import org.springframework.security.core.authority.SimpleGrantedAuthority; import org.springframework.security.core.authority.mapping.GrantedAuthoritiesMapper; import org.springframework.security.saml2.Saml2Exception; +import org.springframework.security.saml2.Saml2VersionUtils; import org.springframework.security.saml2.core.OpenSamlInitializationService; import org.springframework.security.saml2.core.Saml2Error; import org.springframework.security.saml2.core.Saml2ErrorCodes; @@ -174,6 +175,7 @@ public final class OpenSamlAuthenticationProvider implements AuthenticationProvi * Creates an {@link OpenSamlAuthenticationProvider} */ public OpenSamlAuthenticationProvider() { + Saml2VersionUtils.checkOpenSAML3VersionSupported(); this.registry = ConfigurationService.get(XMLObjectProviderRegistry.class); this.responseUnmarshaller = (ResponseUnmarshaller) this.registry.getUnmarshallerFactory() .getUnmarshaller(Response.DEFAULT_ELEMENT_NAME); diff --git a/saml2/saml2-service-provider/src/opensaml3Main/java/org/springframework/security/saml2/provider/service/web/authentication/logout/OpenSaml3LogoutRequestResolver.java b/saml2/saml2-service-provider/src/opensaml3Main/java/org/springframework/security/saml2/provider/service/web/authentication/logout/OpenSaml3LogoutRequestResolver.java index db7a4771f8e..7322dbd3d66 100644 --- a/saml2/saml2-service-provider/src/opensaml3Main/java/org/springframework/security/saml2/provider/service/web/authentication/logout/OpenSaml3LogoutRequestResolver.java +++ b/saml2/saml2-service-provider/src/opensaml3Main/java/org/springframework/security/saml2/provider/service/web/authentication/logout/OpenSaml3LogoutRequestResolver.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2021 the original author or authors. + * Copyright 2002-2022 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -24,6 +24,7 @@ import org.opensaml.saml.saml2.core.LogoutRequest; import org.springframework.security.core.Authentication; +import org.springframework.security.saml2.Saml2VersionUtils; import org.springframework.security.saml2.provider.service.authentication.logout.Saml2LogoutRequest; import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistration; import org.springframework.security.saml2.provider.service.web.RelyingPartyRegistrationResolver; @@ -51,6 +52,7 @@ public final class OpenSaml3LogoutRequestResolver implements Saml2LogoutRequestR * Construct a {@link OpenSaml3LogoutRequestResolver} */ public OpenSaml3LogoutRequestResolver(RelyingPartyRegistrationResolver relyingPartyRegistrationResolver) { + Saml2VersionUtils.checkOpenSAML3VersionSupported(); this.logoutRequestResolver = new OpenSamlLogoutRequestResolver(relyingPartyRegistrationResolver); } diff --git a/saml2/saml2-service-provider/src/opensaml3Main/java/org/springframework/security/saml2/provider/service/web/authentication/logout/OpenSaml3LogoutResponseResolver.java b/saml2/saml2-service-provider/src/opensaml3Main/java/org/springframework/security/saml2/provider/service/web/authentication/logout/OpenSaml3LogoutResponseResolver.java index f5071ae2144..a3bb9e472d9 100644 --- a/saml2/saml2-service-provider/src/opensaml3Main/java/org/springframework/security/saml2/provider/service/web/authentication/logout/OpenSaml3LogoutResponseResolver.java +++ b/saml2/saml2-service-provider/src/opensaml3Main/java/org/springframework/security/saml2/provider/service/web/authentication/logout/OpenSaml3LogoutResponseResolver.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2021 the original author or authors. + * Copyright 2002-2022 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -24,6 +24,7 @@ import org.opensaml.saml.saml2.core.LogoutResponse; import org.springframework.security.core.Authentication; +import org.springframework.security.saml2.Saml2VersionUtils; import org.springframework.security.saml2.provider.service.authentication.logout.Saml2LogoutResponse; import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistration; import org.springframework.security.saml2.provider.service.web.RelyingPartyRegistrationResolver; @@ -51,6 +52,7 @@ public final class OpenSaml3LogoutResponseResolver implements Saml2LogoutRespons * Construct a {@link OpenSaml3LogoutResponseResolver} */ public OpenSaml3LogoutResponseResolver(RelyingPartyRegistrationResolver relyingPartyRegistrationResolver) { + Saml2VersionUtils.checkOpenSAML3VersionSupported(); this.logoutResponseResolver = new OpenSamlLogoutResponseResolver(relyingPartyRegistrationResolver); } diff --git a/saml2/saml2-service-provider/src/opensaml4Main/java/org/springframework/security/saml2/provider/service/authentication/OpenSaml4AuthenticationProvider.java b/saml2/saml2-service-provider/src/opensaml4Main/java/org/springframework/security/saml2/provider/service/authentication/OpenSaml4AuthenticationProvider.java index d4ac38f6840..c5092506828 100644 --- a/saml2/saml2-service-provider/src/opensaml4Main/java/org/springframework/security/saml2/provider/service/authentication/OpenSaml4AuthenticationProvider.java +++ b/saml2/saml2-service-provider/src/opensaml4Main/java/org/springframework/security/saml2/provider/service/authentication/OpenSaml4AuthenticationProvider.java @@ -83,6 +83,7 @@ import org.springframework.security.core.AuthenticationException; import org.springframework.security.core.authority.AuthorityUtils; import org.springframework.security.saml2.Saml2Exception; +import org.springframework.security.saml2.Saml2VersionUtils; import org.springframework.security.saml2.core.OpenSamlInitializationService; import org.springframework.security.saml2.core.Saml2Error; import org.springframework.security.saml2.core.Saml2ErrorCodes; @@ -173,6 +174,7 @@ public final class OpenSaml4AuthenticationProvider implements AuthenticationProv * Creates an {@link OpenSaml4AuthenticationProvider} */ public OpenSaml4AuthenticationProvider() { + Saml2VersionUtils.checkOpenSAML4VersionSupported(); XMLObjectProviderRegistry registry = ConfigurationService.get(XMLObjectProviderRegistry.class); this.responseUnmarshaller = (ResponseUnmarshaller) registry.getUnmarshallerFactory() .getUnmarshaller(Response.DEFAULT_ELEMENT_NAME); diff --git a/saml2/saml2-service-provider/src/opensaml4Main/java/org/springframework/security/saml2/provider/service/web/authentication/logout/OpenSaml4LogoutRequestResolver.java b/saml2/saml2-service-provider/src/opensaml4Main/java/org/springframework/security/saml2/provider/service/web/authentication/logout/OpenSaml4LogoutRequestResolver.java index f603c5b177c..3af2619d695 100644 --- a/saml2/saml2-service-provider/src/opensaml4Main/java/org/springframework/security/saml2/provider/service/web/authentication/logout/OpenSaml4LogoutRequestResolver.java +++ b/saml2/saml2-service-provider/src/opensaml4Main/java/org/springframework/security/saml2/provider/service/web/authentication/logout/OpenSaml4LogoutRequestResolver.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2021 the original author or authors. + * Copyright 2002-2022 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -24,6 +24,7 @@ import org.opensaml.saml.saml2.core.LogoutRequest; import org.springframework.security.core.Authentication; +import org.springframework.security.saml2.Saml2VersionUtils; import org.springframework.security.saml2.provider.service.authentication.logout.Saml2LogoutRequest; import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistration; import org.springframework.security.saml2.provider.service.web.RelyingPartyRegistrationResolver; @@ -49,6 +50,7 @@ public final class OpenSaml4LogoutRequestResolver implements Saml2LogoutRequestR * Construct a {@link OpenSaml4LogoutRequestResolver} */ public OpenSaml4LogoutRequestResolver(RelyingPartyRegistrationResolver relyingPartyRegistrationResolver) { + Saml2VersionUtils.checkOpenSAML4VersionSupported(); this.logoutRequestResolver = new OpenSamlLogoutRequestResolver(relyingPartyRegistrationResolver); } diff --git a/saml2/saml2-service-provider/src/opensaml4Main/java/org/springframework/security/saml2/provider/service/web/authentication/logout/OpenSaml4LogoutResponseResolver.java b/saml2/saml2-service-provider/src/opensaml4Main/java/org/springframework/security/saml2/provider/service/web/authentication/logout/OpenSaml4LogoutResponseResolver.java index 9677bb760c1..dad58bcbf96 100644 --- a/saml2/saml2-service-provider/src/opensaml4Main/java/org/springframework/security/saml2/provider/service/web/authentication/logout/OpenSaml4LogoutResponseResolver.java +++ b/saml2/saml2-service-provider/src/opensaml4Main/java/org/springframework/security/saml2/provider/service/web/authentication/logout/OpenSaml4LogoutResponseResolver.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2021 the original author or authors. + * Copyright 2002-2022 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -24,6 +24,7 @@ import org.opensaml.saml.saml2.core.LogoutResponse; import org.springframework.security.core.Authentication; +import org.springframework.security.saml2.Saml2VersionUtils; import org.springframework.security.saml2.provider.service.authentication.logout.Saml2LogoutResponse; import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistration; import org.springframework.security.saml2.provider.service.web.RelyingPartyRegistrationResolver; @@ -49,6 +50,7 @@ public final class OpenSaml4LogoutResponseResolver implements Saml2LogoutRespons * Construct a {@link OpenSaml4LogoutResponseResolver} */ public OpenSaml4LogoutResponseResolver(RelyingPartyRegistrationResolver relyingPartyRegistrationResolver) { + Saml2VersionUtils.checkOpenSAML4VersionSupported(); this.logoutResponseResolver = new OpenSamlLogoutResponseResolver(relyingPartyRegistrationResolver); }