【问题标题】:Spring Boot: Add a specific HTTP header in a SOAP request based on Web Service Security (WS-Security, WSS) usernameSpring Boot:根据 Web Service Security(WS-Security,WSS)用户名在 SOAP 请求中添加特定的 HTTP 标头
【发布时间】:2020-04-13 20:44:01
【问题描述】:

我正在使用 Spring Boot 公开一个 SOAP Web 服务。此 Web 服务使用通过此 security_policy.xml 配置的 Web 服务安全性 (WSS) 进行保护:

<xwss:SecurityConfiguration
    xmlns:xwss="http://java.sun.com/xml/ns/xwss/config">
    <xwss:RequireUsernameToken
        passwordDigestRequired="true" nonceRequired="true" />
</xwss:SecurityConfiguration>

到目前为止,应用程序运行良好。能够认证成功。

现在,我需要根据 WSS 用户名添加特定的 HTTP 标头。即,添加 HTTP 标头 "x-auth-type" 和值:

  • "test-auth-type" 当用户名是 "test"
  • “production-auth-type” 当用户名是 “production”
  • "undefined-auth-type" 否则

我认为添加一个 EndpointInterceptor 很容易,我可以在其中根据用户设置 HTTP 标头,但直到现在我才可能。

我的 Web 服务配置类如下所示:

package com.godev.soapwebserviceswithspring;

import java.util.Collections;
import java.util.List;

import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
import org.springframework.ws.config.annotation.EnableWs;
import org.springframework.ws.config.annotation.WsConfigurerAdapter;
import org.springframework.ws.server.EndpointInterceptor;
import org.springframework.ws.server.endpoint.interceptor.PayloadLoggingInterceptor;
import org.springframework.ws.soap.security.xwss.XwsSecurityInterceptor;
import org.springframework.ws.soap.security.xwss.callback.SimplePasswordValidationCallbackHandler;
import org.springframework.ws.soap.server.endpoint.interceptor.PayloadValidatingInterceptor;
import org.springframework.ws.transport.http.MessageDispatcherServlet;
import org.springframework.ws.wsdl.wsdl11.DefaultWsdl11Definition;
import org.springframework.xml.xsd.SimpleXsdSchema;
import org.springframework.xml.xsd.XsdSchema;

@EnableWs
@Configuration
public class WebServiceConfig extends WsConfigurerAdapter {
    private static final String WS_SCHEMA_PATH = "godev_contract.xsd";
    private static final String NAMESPACE_URI = "http://godev.com/soap/webservices/demo";

    @Bean
    public ServletRegistrationBean<MessageDispatcherServlet> messageDispatcherServlet(
            ApplicationContext applicationContext) {
        MessageDispatcherServlet servlet = new MessageDispatcherServlet();
        servlet.setApplicationContext(applicationContext);
        servlet.setTransformWsdlLocations(true);
        return new ServletRegistrationBean<>(servlet, "/ws/*");
    }

    @Bean(name = "xml_message")
    public DefaultWsdl11Definition defaultWsdl11Definition(XsdSchema billsSchema) {
        DefaultWsdl11Definition wsdl11Definition = new DefaultWsdl11Definition();
        wsdl11Definition.setPortTypeName("XmlMessagePort");
        wsdl11Definition.setLocationUri("/ws");
        wsdl11Definition.setTargetNamespace(NAMESPACE_URI);
        wsdl11Definition.setSchema(billsSchema);
        return wsdl11Definition;
    }

    @Bean
    public XsdSchema countriesSchema() {
        return new SimpleXsdSchema(new ClassPathResource(WS_SCHEMA_PATH));
    }

    @Bean
    PayloadLoggingInterceptor payloadLoggingInterceptor() {
        return new PayloadLoggingInterceptor();
    }

    @Bean
    PayloadValidatingInterceptor payloadValidatingInterceptor() {
        final PayloadValidatingInterceptor payloadValidatingInterceptor = new PayloadValidatingInterceptor();
        payloadValidatingInterceptor.setSchema(new ClassPathResource(WS_SCHEMA_PATH));
        return payloadValidatingInterceptor;
    }

    @Bean
    XwsSecurityInterceptor securityInterceptor() {
        XwsSecurityInterceptor securityInterceptor = new XwsSecurityInterceptor();
        securityInterceptor.setCallbackHandler(callbackHandler());
        securityInterceptor.setPolicyConfiguration(new ClassPathResource("security_policy.xml"));
        return securityInterceptor;
    }

    @Bean
    SimplePasswordValidationCallbackHandler callbackHandler() {
        SimplePasswordValidationCallbackHandler callbackHandler = new SimplePasswordValidationCallbackHandler();
        callbackHandler.setUsersMap(Collections.singletonMap("admin", "pwd123"));
        return callbackHandler;
    }

    @Override
    public void addInterceptors(List<EndpointInterceptor> interceptors) {
        interceptors.add(payloadLoggingInterceptor());
        interceptors.add(payloadValidatingInterceptor());
        interceptors.add(securityInterceptor());
    }

}

我的 Web 服务端点类如下所示:

package com.godev.soapwebserviceswithspring;

import org.springframework.ws.server.endpoint.annotation.Endpoint;
import org.springframework.ws.server.endpoint.annotation.PayloadRoot;
import org.springframework.ws.server.endpoint.annotation.RequestPayload;
import org.springframework.ws.server.endpoint.annotation.ResponsePayload;

import com.godev.soap.webservices.demo.GetXmlMessageRequest;
import com.godev.soap.webservices.demo.GetXmlMessageResponse;

@Endpoint
public class XmlMessageEndpoint {
    private static final String NAMESPACE_URI = "http://godev.com/soap/webservices/demo";

    @PayloadRoot(namespace = NAMESPACE_URI, localPart = "getXmlMessageRequest")
    @ResponsePayload
    public GetXmlMessageResponse getXmlDocument(@RequestPayload GetXmlMessageRequest request) {
        GetXmlMessageResponse response = new GetXmlMessageResponse();
        response.setXmlMessage("<xml>empty document</xml>");

        return response;
    }
}

任何建议将不胜感激!

【问题讨论】:

    标签: spring-boot http soap spring-security spring-ws


    【解决方案1】:

    它对我有用:

    Endpoint 的 SOAP 标头中注入 Security 元素:

    @Endpoint
    public class XmlMessageEndpoint {
        private static final String NAMESPACE_URI = "http://godev.com/soap/webservices/demo";
    
        @PayloadRoot(namespace = NAMESPACE_URI, localPart = "getXmlMessageRequest")
        @ResponsePayload
        public GetXmlMessageResponse getXmlDocument(@RequestPayload GetXmlMessageRequest request, @SoapHeader("{" + Security.SECURITY_NAMESPACE + "}Security") SoapHeaderElement securityHeader) {
            GetXmlMessageResponse response = new GetXmlMessageResponse();
            response.setXmlMessage("<xml>empty document</xml>");
    
            return response;
     }
    

    为了将 securityHeader 解析为可用的内容,您需要定义几个 POJO。就我而言,我只需要 用户名

    安全元素的 POJO

    @XmlAccessorType(XmlAccessType.FIELD)
    @XmlRootElement(namespace = Security.SECURITY_NAMESPACE, name = "Security")
    @Getter
    @Setter
    public class Security {
    
        public static final String SECURITY_NAMESPACE = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd";
    
        @XmlElement(namespace = Security.SECURITY_NAMESPACE, name = "UsernameToken")
        private UsernameToken usernameToken;
    }
    

    用于 UsernameToken 元素的 POJO

    @XmlAccessorType(XmlAccessType.FIELD)
    @XmlRootElement(namespace = Security.SECURITY_NAMESPACE, name = "UsernameToken")
    @Getter
    @Setter
    public class UsernameToken {
    
        @XmlElement(namespace = Security.SECURITY_NAMESPACE, name = "Username")
        private String username;
    }
    

    最后,您可以使用以下方式解析 securityHeader

    public class SoapParser {
    
        public static Security parseSecurityElement(SoapHeaderElement soapHeaderElement) {
            Security securityElement = null;
            try {
    
                JAXBContext context = JAXBContext.newInstance(Security.class);
                Unmarshaller unmarshaller = context.createUnmarshaller();
                securityElement = (Security) unmarshaller.unmarshal(soapHeaderElement.getSource());
    
            } catch (JAXBException e) {
                e.printStackTrace();
            }
            return securityElement;
        }
    
    }
    

    希望对你有帮助!

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-09-02
      • 1970-01-01
      相关资源
      最近更新 更多