Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@
public final class Saml2LoginConfigurer<B extends HttpSecurityBuilder<B>>
extends AbstractAuthenticationFilterConfigurer<B, Saml2LoginConfigurer<B>, Saml2WebSsoAuthenticationFilter> {

private static final boolean USE_OPENSAML_5 = Version.getVersion().startsWith("5");
private static final boolean USE_OPENSAML_5 = useOpenSaml5(Version.class);

private String loginPage;

Expand Down Expand Up @@ -521,6 +521,26 @@ private <C> void setSharedObject(B http, Class<C> clazz, C object) {
}
}

/**
* Determine whether OpenSAML 5 is on the classpath (or module path). OpenSAML's
* {@link Version#getVersion()} relies on {@link Package#getImplementationVersion()},
* which is {@code null} when OpenSAML is loaded as a named module from the Java
* module path. In that case, fall back to the module's descriptor version. When
* neither is available, assume OpenSAML 5 since it is the only version supported.
* @param versionClass a class from the {@code org.opensaml.core} package, used to
* look up the package/module version
* @return {@code true} if OpenSAML 5 is in use (or its version could not be
* determined), {@code false} otherwise
*/
static boolean useOpenSaml5(Class<?> versionClass) {
String version = versionClass.getPackage().getImplementationVersion();
if (version == null) {
Module module = versionClass.getModule();
version = module.isNamed() ? module.getDescriptor().rawVersion().orElse(null) : null;
}
return version == null || version.startsWith("5");
}

static class PathQueryRequestMatcher implements RequestMatcher {

private final RequestMatcher matcher;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@
public final class Saml2LogoutConfigurer<H extends HttpSecurityBuilder<H>>
extends AbstractHttpConfigurer<Saml2LogoutConfigurer<H>, H> {

private static final boolean USE_OPENSAML_5 = Version.getVersion().startsWith("5");
private static final boolean USE_OPENSAML_5 = useOpenSaml5(Version.class);

private ApplicationContext context;

Expand Down Expand Up @@ -307,6 +307,21 @@ private <C> C getBeanOrNull(Class<C> clazz) {
return this.context.getBeanProvider(clazz).getIfAvailable();
}

/**
* {@link Version#getVersion()} relies on {@link Package#getImplementationVersion()},
* which is {@code null} when OpenSAML is loaded as a named module from the Java
* module path. In that case, fall back to the module's descriptor version. When
* neither is available, assume OpenSAML 5 since it is the only version supported.
*/
static boolean useOpenSaml5(Class<?> versionClass) {
String version = versionClass.getPackage().getImplementationVersion();
if (version == null) {
Module module = versionClass.getModule();
version = module.isNamed() ? module.getDescriptor().rawVersion().orElse(null) : null;
}
return version == null || version.startsWith("5");
}

/**
* A configurer for SAML 2.0 LogoutRequest components
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@
public class Saml2MetadataConfigurer<H extends HttpSecurityBuilder<H>>
extends AbstractHttpConfigurer<Saml2LogoutConfigurer<H>, H> {

private static final boolean USE_OPENSAML_5 = Version.getVersion().startsWith("5");
private static final boolean USE_OPENSAML_5 = useOpenSaml5(Version.class);

private final ApplicationContext context;

Expand Down Expand Up @@ -176,4 +176,19 @@ private <C> C getBeanOrNull(Class<C> clazz) {
return this.context.getBeanProvider(clazz).getIfAvailable();
}

/**
* {@link Version#getVersion()} relies on {@link Package#getImplementationVersion()},
* which is {@code null} when OpenSAML is loaded as a named module from the Java
* module path. In that case, fall back to the module's descriptor version. When
* neither is available, assume OpenSAML 5 since it is the only version supported.
*/
static boolean useOpenSaml5(Class<?> versionClass) {
String version = versionClass.getPackage().getImplementationVersion();
if (version == null) {
Module module = versionClass.getModule();
version = module.isNamed() ? module.getDescriptor().rawVersion().orElse(null) : null;
}
return version == null || version.startsWith("5");
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@
*/
final class Saml2LoginBeanDefinitionParserUtils {

private static final boolean USE_OPENSAML_5 = Version.getVersion().startsWith("5");
private static final boolean USE_OPENSAML_5 = useOpenSaml5(Version.class);

private static final String ATT_RELYING_PARTY_REGISTRATION_REPOSITORY_REF = "relying-party-registration-repository-ref";

Expand Down Expand Up @@ -120,4 +120,19 @@ static BeanDefinition createDefaultAuthenticationConverter(BeanMetadataElement r
.getBeanDefinition();
}

/**
* {@link Version#getVersion()} relies on {@link Package#getImplementationVersion()},
* which is {@code null} when OpenSAML is loaded as a named module from the Java
* module path. In that case, fall back to the module's descriptor version. When
* neither is available, assume OpenSAML 5 since it is the only version supported.
*/
static boolean useOpenSaml5(Class<?> versionClass) {
String version = versionClass.getPackage().getImplementationVersion();
if (version == null) {
Module module = versionClass.getModule();
version = module.isNamed() ? module.getDescriptor().rawVersion().orElse(null) : null;
}
return version == null || version.startsWith("5");
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@
*/
final class Saml2LogoutBeanDefinitionParserUtils {

private static final boolean USE_OPENSAML_5 = Version.getVersion().startsWith("5");
private static final boolean USE_OPENSAML_5 = useOpenSaml5(Version.class);

private static final String ATT_RELYING_PARTY_REGISTRATION_REPOSITORY_REF = "relying-party-registration-repository-ref";

Expand Down Expand Up @@ -124,4 +124,19 @@ static BeanMetadataElement getLogoutRequestResolver(Element element, BeanMetadat
"Spring Security does not support OpenSAML " + Version.getVersion() + ". Please use OpenSAML 5");
}

/**
* {@link Version#getVersion()} relies on {@link Package#getImplementationVersion()},
* which is {@code null} when OpenSAML is loaded as a named module from the Java
* module path. In that case, fall back to the module's descriptor version. When
* neither is available, assume OpenSAML 5 since it is the only version supported.
*/
static boolean useOpenSaml5(Class<?> versionClass) {
String version = versionClass.getPackage().getImplementationVersion();
if (version == null) {
Module module = versionClass.getModule();
version = module.isNamed() ? module.getDescriptor().rawVersion().orElse(null) : null;
}
return version == null || version.startsWith("5");
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.ArgumentCaptor;
import org.opensaml.core.Version;
import org.opensaml.core.xml.config.XMLObjectProviderRegistrySupport;
import org.opensaml.core.xml.io.Marshaller;
import org.opensaml.saml.saml2.core.Assertion;
Expand Down Expand Up @@ -431,6 +432,19 @@ public void saml2LoginWhenCustomAuthenticationProviderThenUses() throws Exceptio
verify(provider).authenticate(any());
}

// gh-19628
@Test
public void useOpenSaml5WhenImplementationVersionUnavailableThenDoesNotThrow() {
// simulates OpenSAML being loaded from the Java module path, where
// Package#getImplementationVersion() returns null
assertThat(Saml2LoginConfigurer.useOpenSaml5(getClass())).isTrue();
}

@Test
public void useOpenSaml5WhenOpenSamlVersionClassThenMatchesRuntimeVersion() {
assertThat(Saml2LoginConfigurer.useOpenSaml5(Version.class)).isEqualTo(Version.getVersion().startsWith("5"));
}

private void performSaml2Login(String expected) throws IOException, ServletException {
// setup authentication parameters
this.request.setRequestURI("/login/saml2/sso/registration-id");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.opensaml.core.Version;
import org.opensaml.saml.saml2.core.LogoutRequest;
import org.opensaml.xmlsec.signature.support.SignatureConstants;

Expand Down Expand Up @@ -557,6 +558,19 @@ public void saml2LogoutWhenLogoutFilterPostProcessedThenUses() {

}

// gh-19628
@Test
public void useOpenSaml5WhenImplementationVersionUnavailableThenDoesNotThrow() {
// simulates OpenSAML being loaded from the Java module path, where
// Package#getImplementationVersion() returns null
assertThat(Saml2LogoutConfigurer.useOpenSaml5(getClass())).isTrue();
}

@Test
public void useOpenSaml5WhenOpenSamlVersionClassThenMatchesRuntimeVersion() {
assertThat(Saml2LogoutConfigurer.useOpenSaml5(Version.class)).isEqualTo(Version.getVersion().startsWith("5"));
}

private <T> T getBean(Class<T> clazz) {
return this.spring.getContext().getBean(clazz);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import jakarta.servlet.http.HttpServletRequest;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.opensaml.core.Version;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
Expand All @@ -42,6 +43,7 @@
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.test.web.servlet.MockMvc;

import static org.assertj.core.api.Assertions.assertThat;
import static org.hamcrest.Matchers.containsString;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.BDDMockito.given;
Expand Down Expand Up @@ -134,6 +136,19 @@ void saml2MetadataWhenBuilderBeanWithBasePathThenMetadataUrlIgnoresBasePath() th
.andExpect(content().string(containsString("md:EntityDescriptor")));
}

// gh-19628
@Test
void useOpenSaml5WhenImplementationVersionUnavailableThenDoesNotThrow() {
// simulates OpenSAML being loaded from the Java module path, where
// Package#getImplementationVersion() returns null
assertThat(Saml2MetadataConfigurer.useOpenSaml5(getClass())).isTrue();
}

@Test
void useOpenSaml5WhenOpenSamlVersionClassThenMatchesRuntimeVersion() {
assertThat(Saml2MetadataConfigurer.useOpenSaml5(Version.class)).isEqualTo(Version.getVersion().startsWith("5"));
}

@EnableWebSecurity
@Configuration
@Import(RelyingPartyRegistrationConfig.class)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.ArgumentCaptor;
import org.opensaml.core.Version;
import org.opensaml.core.xml.config.XMLObjectProviderRegistrySupport;
import org.opensaml.core.xml.io.Marshaller;
import org.opensaml.saml.saml2.core.Assertion;
Expand Down Expand Up @@ -346,6 +347,20 @@ public void authenticateWhenCustomLoginProcessingUrlAndCustomAuthenticationConve
verify(this.authenticationConverter).convert(any(HttpServletRequest.class));
}

// gh-19628
@Test
public void useOpenSaml5WhenImplementationVersionUnavailableThenDoesNotThrow() {
// simulates OpenSAML being loaded from the Java module path, where
// Package#getImplementationVersion() returns null
assertThat(Saml2LoginBeanDefinitionParserUtils.useOpenSaml5(getClass())).isTrue();
}

@Test
public void useOpenSaml5WhenOpenSamlVersionClassThenMatchesRuntimeVersion() {
assertThat(Saml2LoginBeanDefinitionParserUtils.useOpenSaml5(Version.class))
.isEqualTo(Version.getVersion().startsWith("5"));
}

private RelyingPartyRegistration relyingPartyRegistrationWithVerifyingCredential() {
given(this.repository.findByRegistrationId(anyString())).willReturn(registration);
return registration;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.opensaml.core.Version;
import org.opensaml.saml.saml2.core.LogoutRequest;
import org.opensaml.xmlsec.signature.support.SignatureConstants;

Expand Down Expand Up @@ -399,6 +400,20 @@ public void saml2LogoutWhenCustomLogoutRequestRepositoryThenUses() throws Except
verify(getBean(Saml2LogoutRequestRepository.class)).saveLogoutRequest(eq(logoutRequest), any(), any());
}

// gh-19628
@Test
public void useOpenSaml5WhenImplementationVersionUnavailableThenDoesNotThrow() {
// simulates OpenSAML being loaded from the Java module path, where
// Package#getImplementationVersion() returns null
assertThat(Saml2LogoutBeanDefinitionParserUtils.useOpenSaml5(getClass())).isTrue();
}

@Test
public void useOpenSaml5WhenOpenSamlVersionClassThenMatchesRuntimeVersion() {
assertThat(Saml2LogoutBeanDefinitionParserUtils.useOpenSaml5(Version.class))
.isEqualTo(Version.getVersion().startsWith("5"));
}

private <T> T getBean(Class<T> clazz) {
return this.spring.getContext().getBean(clazz);
}
Expand Down