使用Spring Security SAML生成AuthnRequest时遇编组器不可用异常
SAML AuthnRequest编组异常:No marshaller available
在不使用Spring Boot、仅依赖spring-security-saml2-service-provider生成SAML AuthnRequest时,编组AuthnRequest阶段抛出如下异常:
Exception in thread "main" org.springframework.security.saml2.Saml2Exception: org.opensaml.core.xml.io.MarshallingException: No marshaller available for {urn:oasis:names:tc:SAML:2.0:assertion}Issuer, child of {urn:oasis:names:tc:SAML:2.0:protocol}AuthnRequest at org.opensamlExample.SecurityConfiguration.serialize(SecurityConfiguration.java:116) at org.opensamlExample.SecurityConfiguration.generateAuthRequest(SecurityConfiguration.java:91) at org.opensamlExample.SecurityConfiguration.main(SecurityConfiguration.java:81) Caused by: org.opensaml.core.xml.io.MarshallingException: No marshaller available for {urn:oasis:names:tc:SAML:2.0:assertion}Issuer, child of {urn:oasis:names:tc:SAML:2.0:protocol}AuthnRequest at org.opensaml.core.xml.io.AbstractXMLObjectMarshaller.marshallChildElements(AbstractXMLObjectMarshaller.java:270) at org.opensaml.core.xml.io.AbstractXMLObjectMarshaller.marshallInto(AbstractXMLObjectMarshaller.java:219) at org.opensaml.core.xml.io.AbstractXMLObjectMarshaller.marshall(AbstractXMLObjectMarshaller.java:121) at org.opensaml.saml.common.AbstractSAMLObjectMarshaller.marshall(AbstractSAMLObjectMarshaller.java:58) at org.opensaml.core.xml.io.AbstractXMLObjectMarshaller.marshall(AbstractXMLObjectMarshaller.java:76) at org.opensamlExample.SecurityConfiguration.serialize(SecurityConfiguration.java:110) ... 2 more
用于复现问题的代码如下:
public static AuthnRequest buildAuthRequest() { RandomIdentifierGenerationStrategy securerandomgenerator = new RandomIdentifierGenerationStrategy(); AuthnRequestBuilder builder = new AuthnRequestBuilder(); AuthnRequest request= builder.buildObject(); request.setAssertionConsumerServiceURL("http://localhost:8080/samlResponse"); request.setDestination("https://dev-omtekjsu50kzoy13.us.auth0.com/samlp/HuW59mrq3kiGZBmvP9ZdZLil8qIL4o0y"); request.setProtocolBinding(SAMLConstants.SAML2_POST_BINDING_URI); request.setID(securerandomgenerator.generateIdentifier()); // build issuer Issuer issuer = new IssuerBuilder().buildObject(); issuer.setValue("https://mySamlExampleSP.com:8080"); request.setIssuer(issuer); //build nameid policy NameIDPolicy nameIDPolicy = new NameIDPolicyBuilder().buildObject(); nameIDPolicy.setAllowCreate(false); nameIDPolicy.setFormat(NameIDType.TRANSIENT); request.setNameIDPolicy(nameIDPolicy); MessageContext context = new MessageContext(); context.setMessage(request); SAMLPeerEntityContext peerEntityContext = context.getSubcontext(SAMLPeerEntityContext.class, true); SAMLEndpointContext endpointContext = peerEntityContext.getSubcontext(SAMLEndpointContext.class, true); return request; //endpointContext.setEndpoint(); } public static AuthnRequest initializeOpensaml() { OpenSamlInitializationService.initialize(); AuthnRequest request = buildAuthRequest(); return request; } public static void main(String[] args) { AuthnRequest request=initializeOpensaml(); generateAuthRequest(request); } public static void generateAuthRequest(AuthnRequest authnRequest) { RelyingPartyRegistration registration = RelyingPartyRegistrations.fromMetadataLocation("classpath:asserting-party-metadata.xml") .registrationId("samlExample") .singleLogoutServiceResponseLocation("{baseUrl}/logout/saml2/slo") .nameIdFormat("urn:oasis:names:tc:SAML:2.0:nameid-format:transient") .build(); Saml2RedirectAuthenticationRequest authenticationRequest= Saml2RedirectAuthenticationRequest.withRelyingPartyRegistration(registration) .samlRequest(serialize(authnRequest)). id(authnRequest.getID()). build(); } private static String serialize(AuthnRequest authnRequest) { try { XMLObjectProviderRegistry xmlObjectProviderRegistry = new XMLObjectProviderRegistry(); ConfigurationService.register(XMLObjectProviderRegistry.class, xmlObjectProviderRegistry); xmlObjectProviderRegistry.setParserPool(getParserPool()); Marshaller marshallObj = xmlObjectProviderRegistry.getMarshallerFactory().getMarshaller(authnRequest); AuthnRequestMarshaller marshaller = new AuthnRequestMarshaller(); Element element =marshaller.marshall(authnRequest); // Getting null marshaller here... String xml =SerializeSupport.nodeToString(element); String encoded = Base64.getEncoder().encodeToString(xml.getBytes(StandardCharsets.UTF_8)); return encoded; } catch (MarshallingException ex) { throw new Saml2Exception(ex); } }
解决方案
问题根源在于serialize方法中重复创建并注册了XMLObjectProviderRegistry,覆盖了OpenSamlInitializationService.initialize()初始化好的注册表,导致缺少Issuer等元素对应的Marshaller。
移除以下代码后,异常消失:
XMLObjectProviderRegistry xmlObjectProviderRegistry = new XMLObjectProviderRegistry(); ConfigurationService.register(XMLObjectProviderRegistry.class, xmlObjectProviderRegistry); xmlObjectProviderRegistry.setParserPool(getParserPool()); Marshaller marshallObj = xmlObjectProviderRegistry.getMarshallerFactory().getMarshaller(authnRequest);
内容的提问来源于stack exchange,提问作者Sasirekha Kumaran
相关产品推荐
相关产品推荐

