You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.20 06:44:54