From a109a12697b6b6ac400a5914e6c9b575129b9ff4 Mon Sep 17 00:00:00 2001 From: strehle Date: Tue, 7 Jan 2025 09:15:31 +0100 Subject: [PATCH] WIP: initialize OpenSAML in one class --- .../saml/OpenSaml4AuthenticationProvider.java | 33 ++---------- .../uaa/provider/saml/OpenSamlXmlUtils.java | 51 +++++++++++++++++++ ...ml2BearerGrantAuthenticationConverter.java | 30 ++--------- .../uaa/provider/saml/Saml2Utils.java | 1 + 4 files changed, 62 insertions(+), 53 deletions(-) diff --git a/server/src/main/java/org/cloudfoundry/identity/uaa/provider/saml/OpenSaml4AuthenticationProvider.java b/server/src/main/java/org/cloudfoundry/identity/uaa/provider/saml/OpenSaml4AuthenticationProvider.java index e484a0f1335..b85e8dc58c8 100644 --- a/server/src/main/java/org/cloudfoundry/identity/uaa/provider/saml/OpenSaml4AuthenticationProvider.java +++ b/server/src/main/java/org/cloudfoundry/identity/uaa/provider/saml/OpenSaml4AuthenticationProvider.java @@ -17,13 +17,9 @@ package org.cloudfoundry.identity.uaa.provider.saml; import lombok.Getter; -import net.shibboleth.utilities.java.support.xml.ParserPool; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; -import org.opensaml.core.config.ConfigurationService; import org.opensaml.core.xml.XMLObject; -import org.opensaml.core.xml.config.XMLObjectProviderRegistry; -import org.opensaml.core.xml.config.XMLObjectProviderRegistrySupport; import org.opensaml.core.xml.schema.XSAny; import org.opensaml.core.xml.schema.XSBoolean; import org.opensaml.core.xml.schema.XSBooleanValue; @@ -52,8 +48,6 @@ import org.opensaml.saml.saml2.core.StatusCode; import org.opensaml.saml.saml2.core.SubjectConfirmation; import org.opensaml.saml.saml2.core.SubjectConfirmationData; -import org.opensaml.saml.saml2.core.impl.AuthnRequestUnmarshaller; -import org.opensaml.saml.saml2.core.impl.ResponseUnmarshaller; import org.opensaml.saml.security.impl.SAMLSignatureProfileValidator; import org.opensaml.xmlsec.signature.support.SignaturePrevalidator; import org.opensaml.xmlsec.signature.support.SignatureTrustEngine; @@ -65,7 +59,6 @@ import org.springframework.security.core.AuthenticationException; import org.springframework.security.core.authority.AuthorityUtils; import org.springframework.security.saml2.Saml2Exception; -import org.springframework.security.saml2.core.OpenSamlInitializationService; import org.springframework.security.saml2.core.Saml2Error; import org.springframework.security.saml2.core.Saml2ErrorCodes; import org.springframework.security.saml2.core.Saml2ResponseValidatorResult; @@ -108,23 +101,11 @@ public final class OpenSaml4AuthenticationProvider implements AuthenticationProvider { static { - OpenSamlInitializationService.initialize(); + OpenSamlXmlUtils.initialize(); } private final Log logger = LogFactory.getLog(this.getClass()); - private final ResponseUnmarshaller responseUnmarshaller; - - private static final AuthnRequestUnmarshaller authnRequestUnmarshaller; - - static { - XMLObjectProviderRegistry registry = ConfigurationService.get(XMLObjectProviderRegistry.class); - authnRequestUnmarshaller = (AuthnRequestUnmarshaller) registry.getUnmarshallerFactory() - .getUnmarshaller(AuthnRequest.DEFAULT_ELEMENT_NAME); - } - - private final ParserPool parserPool; - private final Converter responseSignatureValidator = createDefaultResponseSignatureValidator(); private final Consumer responseElementsDecrypter = createDefaultResponseElementsDecrypter(); @@ -143,10 +124,6 @@ public final class OpenSaml4AuthenticationProvider implements AuthenticationProv * Creates an {@link OpenSaml4AuthenticationProvider} */ public OpenSaml4AuthenticationProvider() { - XMLObjectProviderRegistry registry = ConfigurationService.get(XMLObjectProviderRegistry.class); - this.responseUnmarshaller = (ResponseUnmarshaller) registry.getUnmarshallerFactory() - .getUnmarshaller(Response.DEFAULT_ELEMENT_NAME); - this.parserPool = registry.getParserPool(); } /** @@ -348,10 +325,10 @@ public boolean supports(Class authentication) { private Response parseResponse(String response) throws Saml2Exception, Saml2AuthenticationException { try { - Document document = this.parserPool + Document document = OpenSamlXmlUtils.getParserPool() .parse(new ByteArrayInputStream(response.getBytes(StandardCharsets.UTF_8))); Element element = document.getDocumentElement(); - return (Response) this.responseUnmarshaller.unmarshall(element); + return (Response) OpenSamlXmlUtils.getResponseUnmarshaller().unmarshall(element); } catch (Exception ex) { throw createAuthenticationException(Saml2ErrorCodes.MALFORMED_RESPONSE_DATA, ex.getMessage(), ex); } @@ -621,10 +598,10 @@ private static AuthnRequest parseRequest(AbstractSaml2AuthenticationRequest requ samlRequest = new String(Saml2Utils.samlDecode(samlRequest), StandardCharsets.UTF_8); } try { - Document document = XMLObjectProviderRegistrySupport.getParserPool() + Document document = OpenSamlXmlUtils.getParserPool() .parse(new ByteArrayInputStream(samlRequest.getBytes(StandardCharsets.UTF_8))); Element element = document.getDocumentElement(); - return (AuthnRequest) authnRequestUnmarshaller.unmarshall(element); + return (AuthnRequest) OpenSamlXmlUtils.getAuthnRequestUnmarshaller().unmarshall(element); } catch (Exception ex) { String message = "Failed to deserialize associated authentication request [" + ex.getMessage() + "]"; throw createAuthenticationException(Saml2ErrorCodes.MALFORMED_REQUEST_DATA, message, ex); diff --git a/server/src/main/java/org/cloudfoundry/identity/uaa/provider/saml/OpenSamlXmlUtils.java b/server/src/main/java/org/cloudfoundry/identity/uaa/provider/saml/OpenSamlXmlUtils.java index 86c7e33a28c..bdb5f359ad0 100644 --- a/server/src/main/java/org/cloudfoundry/identity/uaa/provider/saml/OpenSamlXmlUtils.java +++ b/server/src/main/java/org/cloudfoundry/identity/uaa/provider/saml/OpenSamlXmlUtils.java @@ -1,8 +1,11 @@ package org.cloudfoundry.identity.uaa.provider.saml; import lombok.extern.slf4j.Slf4j; +import net.shibboleth.utilities.java.support.xml.ParserPool; import org.cloudfoundry.identity.uaa.provider.SamlIdentityProviderDefinition; +import org.opensaml.core.config.ConfigurationService; import org.opensaml.core.xml.XMLObject; +import org.opensaml.core.xml.config.XMLObjectProviderRegistry; import org.opensaml.core.xml.schema.XSAny; import org.opensaml.core.xml.schema.XSBase64Binary; import org.opensaml.core.xml.schema.XSBoolean; @@ -12,6 +15,13 @@ import org.opensaml.core.xml.schema.XSQName; import org.opensaml.core.xml.schema.XSString; import org.opensaml.core.xml.schema.XSURI; +import org.opensaml.saml.saml2.core.Assertion; +import org.opensaml.saml.saml2.core.AuthnRequest; +import org.opensaml.saml.saml2.core.Response; +import org.opensaml.saml.saml2.core.impl.AssertionUnmarshaller; +import org.opensaml.saml.saml2.core.impl.AuthnRequestUnmarshaller; +import org.opensaml.saml.saml2.core.impl.ResponseUnmarshaller; +import org.springframework.security.saml2.core.OpenSamlInitializationService; import javax.xml.namespace.QName; import java.time.Instant; @@ -19,6 +29,47 @@ @Slf4j public final class OpenSamlXmlUtils { + static { + OpenSamlInitializationService.initialize(); + } + + static { + XMLObjectProviderRegistry registry = ConfigurationService.get(XMLObjectProviderRegistry.class); + authnRequestUnmarshaller = (AuthnRequestUnmarshaller) registry.getUnmarshallerFactory() + .getUnmarshaller(AuthnRequest.DEFAULT_ELEMENT_NAME); + responseUnmarshaller = (ResponseUnmarshaller) registry.getUnmarshallerFactory() + .getUnmarshaller(Response.DEFAULT_ELEMENT_NAME); + assertionUnmarshaller = (AssertionUnmarshaller) registry.getUnmarshallerFactory() + .getUnmarshaller(Assertion.DEFAULT_ELEMENT_NAME); + parserPool = registry.getParserPool(); + } + + private static final ResponseUnmarshaller responseUnmarshaller; + private static final AuthnRequestUnmarshaller authnRequestUnmarshaller; + private static final AssertionUnmarshaller assertionUnmarshaller; + + private static final ParserPool parserPool; + + public static boolean initialize() { + return parserPool != null; + } + + protected static ParserPool getParserPool() { + return parserPool; + } + + protected static AuthnRequestUnmarshaller getAuthnRequestUnmarshaller() { + return authnRequestUnmarshaller; + } + + protected static ResponseUnmarshaller getResponseUnmarshaller() { + return responseUnmarshaller; + } + + protected static AssertionUnmarshaller getAssertionUnmarshaller() { + return assertionUnmarshaller; + } + private OpenSamlXmlUtils() { throw new java.lang.UnsupportedOperationException("This is a utility class and cannot be instantiated"); } diff --git a/server/src/main/java/org/cloudfoundry/identity/uaa/provider/saml/Saml2BearerGrantAuthenticationConverter.java b/server/src/main/java/org/cloudfoundry/identity/uaa/provider/saml/Saml2BearerGrantAuthenticationConverter.java index cad26192b5f..62b35cec06e 100644 --- a/server/src/main/java/org/cloudfoundry/identity/uaa/provider/saml/Saml2BearerGrantAuthenticationConverter.java +++ b/server/src/main/java/org/cloudfoundry/identity/uaa/provider/saml/Saml2BearerGrantAuthenticationConverter.java @@ -17,7 +17,6 @@ package org.cloudfoundry.identity.uaa.provider.saml; import lombok.extern.slf4j.Slf4j; -import net.shibboleth.utilities.java.support.xml.ParserPool; import org.cloudfoundry.identity.uaa.authentication.BackwardsCompatibleTokenEndpointAuthenticationFilter; import org.cloudfoundry.identity.uaa.authentication.UaaAuthentication; import org.cloudfoundry.identity.uaa.authentication.UaaPrincipal; @@ -31,15 +30,11 @@ import org.cloudfoundry.identity.uaa.web.UaaSavedRequestAwareAuthenticationSuccessHandler; import org.cloudfoundry.identity.uaa.zone.IdentityZone; import org.cloudfoundry.identity.uaa.zone.beans.IdentityZoneManager; -import org.opensaml.core.config.ConfigurationService; -import org.opensaml.core.xml.config.XMLObjectProviderRegistry; import org.opensaml.saml.common.assertion.ValidationContext; import org.opensaml.saml.saml2.assertion.SAML2AssertionValidationParameters; import org.opensaml.saml.saml2.core.Assertion; import org.opensaml.saml.saml2.core.Issuer; import org.opensaml.saml.saml2.core.Response; -import org.opensaml.saml.saml2.core.impl.AssertionUnmarshaller; -import org.opensaml.saml.saml2.core.impl.ResponseUnmarshaller; import org.springframework.context.ApplicationEvent; import org.springframework.context.ApplicationEventPublisher; import org.springframework.context.ApplicationEventPublisherAware; @@ -51,7 +46,6 @@ import org.springframework.security.core.AuthenticationException; import org.springframework.security.core.authority.AuthorityUtils; import org.springframework.security.saml2.Saml2Exception; -import org.springframework.security.saml2.core.OpenSamlInitializationService; import org.springframework.security.saml2.core.Saml2Error; import org.springframework.security.saml2.core.Saml2ErrorCodes; import org.springframework.security.saml2.core.Saml2ResponseValidatorResult; @@ -97,21 +91,7 @@ public final class Saml2BearerGrantAuthenticationConverter implements Authentica ApplicationEventPublisherAware { static { - OpenSamlInitializationService.initialize(); - } - - private static final AssertionUnmarshaller assertionUnmarshaller; - private static final ResponseUnmarshaller responseUnMarshaller; - - private static final ParserPool parserPool; - - static { - XMLObjectProviderRegistry registry = ConfigurationService.get(XMLObjectProviderRegistry.class); - assertionUnmarshaller = (AssertionUnmarshaller) registry.getUnmarshallerFactory() - .getUnmarshaller(Assertion.DEFAULT_ELEMENT_NAME); - responseUnMarshaller = (ResponseUnmarshaller) registry.getUnmarshallerFactory() - .getUnmarshaller(Response.DEFAULT_ELEMENT_NAME); - parserPool = registry.getParserPool(); + OpenSamlXmlUtils.initialize(); } private final Converter assertionSignatureValidator = OpenSaml4AuthenticationProvider.createDefaultAssertionSignatureValidator(); @@ -301,10 +281,10 @@ public Authentication authenticate(Authentication authentication) throws Authent private static Assertion parseAssertion(String assertion) throws Saml2Exception, Saml2AuthenticationException { try { - Document document = parserPool + Document document = OpenSamlXmlUtils.getParserPool() .parse(new ByteArrayInputStream(assertion.getBytes(StandardCharsets.UTF_8))); Element element = document.getDocumentElement(); - return (Assertion) assertionUnmarshaller.unmarshall(element); + return (Assertion) OpenSamlXmlUtils.getAssertionUnmarshaller().unmarshall(element); } catch (Exception ex) { throw OpenSaml4AuthenticationProvider.createAuthenticationException(Saml2ErrorCodes.INVALID_ASSERTION, "Unable to parse bearer assertion", ex); } @@ -312,10 +292,10 @@ private static Assertion parseAssertion(String assertion) throws Saml2Exception, protected static Response parseSamlResponse(String samlResponse) throws Saml2Exception, Saml2AuthenticationException { try { - Document document = parserPool + Document document = OpenSamlXmlUtils.getParserPool() .parse(new ByteArrayInputStream(samlResponse.getBytes(StandardCharsets.UTF_8))); Element element = document.getDocumentElement(); - return (Response) responseUnMarshaller.unmarshall(element); + return (Response) OpenSamlXmlUtils.getResponseUnmarshaller().unmarshall(element); } catch (Exception ex) { throw OpenSaml4AuthenticationProvider.createAuthenticationException(Saml2ErrorCodes.INVALID_RESPONSE, "Unable to parse saml response", ex); } diff --git a/server/src/main/java/org/cloudfoundry/identity/uaa/provider/saml/Saml2Utils.java b/server/src/main/java/org/cloudfoundry/identity/uaa/provider/saml/Saml2Utils.java index 076fd35fb73..089691dfeb7 100644 --- a/server/src/main/java/org/cloudfoundry/identity/uaa/provider/saml/Saml2Utils.java +++ b/server/src/main/java/org/cloudfoundry/identity/uaa/provider/saml/Saml2Utils.java @@ -39,6 +39,7 @@ */ public final class Saml2Utils { + private Saml2Utils() { throw new java.lang.UnsupportedOperationException("This is a utility class and cannot be instantiated"); }