Spring Boot: добавьте указанный c заголовок HTTP в запросе SOAP на основе имени пользователя Web-Security Security (WS-Security, WSS) - PullRequest
0 голосов
/ 13 апреля 2020

Я предоставляю доступ к веб-сервису SOAP, используя Spring Boot. Этот веб-сервис защищен с помощью Web Service Security (WSS), который настроен с помощью security_policy. xml:

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

До этого момента приложение работало нормально. Он может успешно аутентифицироваться.

Теперь мне нужно добавить указанный c HTTP-заголовок на основе имени пользователя WSS. Добавляет заголовок HTTP "x-auth-type" со значениями:

  • "test-auth-type" , когда имя пользователя "test"
  • "production-auth-type" , если имя пользователя "production"
  • "undefined-auth-type" в противном случае

Я думал, что было легко добавить EndpointInterceptor, в котором я могу установить заголовок HTTP на основе пользователя, но это невозможно до сих пор.

Мой класс конфигурации веб-службы выглядит следующим образом:

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());
    }

}

Мой класс конечной точки веб-службы выглядит следующим образом:

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;
    }
}

Любой совет будет очень признателен!

1 Ответ

0 голосов
/ 16 апреля 2020

Это работает для меня:

Вставить элемент Безопасность , присутствующий в заголовке SOAP в Конечной точке :

@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;
}

POJO для элемента UsernameToken :

@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;
    }

}

Надеюсь, это поможет!

...