Заголовки SOAPFaultException MustUnderstand (oasis-200401-wss-wssecurity-secext-1.0.xsd) не распознаются

Я пытаюсь получить информацию от веб-службы, использующей тип PasswordText WSS. Во-первых, я тестировал его с помощью soapUI и успешно получил данные. Затем я реализовал аутентификацию на Java, написав SecurityHandler:

public final class SecurityHandler implements SOAPHandler<SOAPMessageContext> {

...

@Override
public boolean handleMessage(SOAPMessageContext messageContext) {
    boolean outInd = (Boolean) messageContext.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY);
    if (outInd) {
        try {
            WSSecUsernameToken builder = new WSSecUsernameToken();
            builder.setPasswordType(WSConstants.PASSWORD_TEXT);
            builder.setUserInfo(_username, _password);
            builder.addNonce();
            builder.addCreated();

            Document doc = messageContext.getMessage().getSOAPPart().getEnvelope().getOwnerDocument();
            WSSecHeader secHeader = new WSSecHeader();
            secHeader.insertSecurityHeader(doc);
            builder.build(doc, secHeader);
        } catch (Exception e) {
            LOGGER.error("Unable to handle SOAP message", e);
            return false;
        }
    }
    return true;
}

...
}

Я проверил объект doc с помощью XMLUtils.PrettyDocumentToString(doc) и увидел, что он похож на XML, отправленный soupUI - вся аутентификационная информация (логин, пароль, одноразовый номер и время создания) была на месте, атрибут mustUnderstand тега Security был истинным.

Тогда я столкнулся с ошибкой:

javax.xml.ws.soap.SOAPFaultException: заголовки MustUnderstand: [{http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd} Безопасность] не понял

Я нашел советы по удалению атрибута mustUnderstand из тега Security, но это не помогает. Есть ли у вас какие-либо идеи?

P.S.

Конечная точка веб-службы находится на HTTPS.

Часть политики из WSDL:

<wsp:Policy wsu:Id="BasicHttpBinding_RelateService_policy">
    <wsp:ExactlyOne>
        <wsp:All>
            <sp:TransportBinding>
                <wsp:Policy>
                    <sp:TransportToken>
                        <wsp:Policy>
                            <sp:HttpsToken RequireClientCertificate="false"/>
                        </wsp:Policy>
                    </sp:TransportToken>
                    <sp:AlgorithmSuite>
                        <wsp:Policy>
                            <sp:Basic256/>
                        </wsp:Policy>
                    </sp:AlgorithmSuite>
                    <sp:Layout>
                        <wsp:Policy>
                            <sp:Lax/>
                        </wsp:Policy>
                    </sp:Layout>
                    <sp:IncludeTimestamp/>
                </wsp:Policy>
            </sp:TransportBinding>
            <sp:SignedSupportingTokens>
                <wsp:Policy>
                    <sp:UsernameToken
                            sp:IncludeToken="http://schemas.xmlsoap.org/ws/2005/07/securitypolicy/IncludeToken/AlwaysToRecipient">
                        <wsp:Policy>
                            <sp:WssUsernameToken10/>
                        </wsp:Policy>
                    </sp:UsernameToken>
                </wsp:Policy>
            </sp:SignedSupportingTokens>
            <sp:Wss10>
                <wsp:Policy/>
            </sp:Wss10>
        </wsp:All>
    </wsp:ExactlyOne>
</wsp:Policy>

запрос soapUI:

<soapenv:Envelope xmlns:ns="http://api.example.com/RelateService/1.0"
                  xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
    <soapenv:Header>
        <wsse:Security soapenv:mustUnderstand="1"
                       xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
            <wsse:UsernameToken wsu:Id="UsernameToken-37"
                                xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
                <wsse:Username>username</wsse:Username>
                <wsse:Password
                        Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">
                    password
                </wsse:Password>
                <wsse:Nonce
                        EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary">
                    li/0YK2wxrmrHL7Cg+etdQ==
                </wsse:Nonce>
                <wsu:Created>2012-02-21T08:59:10.262Z</wsu:Created>
            </wsse:UsernameToken>
        </wsse:Security>
    </soapenv:Header>
    <soapenv:Body>
        <ns:RetrieveCustomerByEmail>
            <ns:email>[email protected]</ns:email>
            <ns:firstName/>
            <ns:lastName/>
        </ns:RetrieveCustomerByEmail>
    </soapenv:Body>
</soapenv:Envelope>

Мой запрос:

<?xml version="1.0" encoding="UTF-8"?>
<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
    <S:Header>
        <wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"
                       xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"
                       S:mustUnderstand="1">
            <wsse:UsernameToken wsu:Id="UsernameToken-1">
                <wsse:Username>username</wsse:Username>
                <wsse:Password
                        Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">
                    password
                </wsse:Password>
                <wsse:Nonce
                        EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary">
                    +jeleKO9zr0/wLjAIYcmSg==
                </wsse:Nonce>
                <wsu:Created>2012-02-21T09:42:03.760Z</wsu:Created>
            </wsse:UsernameToken>
        </wsse:Security>
    </S:Header>
    <S:Body>
        <ns5:RetrieveCustomerByEmail xmlns="http://schemas.microsoft.com/2003/10/Serialization/Arrays"
                                     xmlns:ns2="http://schemas.datacontract.org/2004/07/XXX.Service"
                                     xmlns:ns3="http://schemas.datacontract.org/2004/07/XXX.Service.Relate.Contract"
                                     xmlns:ns4="http://schemas.datacontract.org/2004/07/XXX.Service.Dto"
                                     xmlns:ns5="http://api.example.com/RelateService/1.0"
                                     xmlns:ns6="http://schemas.microsoft.com/2003/10/Serialization/">
            <ns5:email>[email protected]</ns5:email>
            <ns5:firstName/>
            <ns5:lastName/>
        </ns5:RetrieveCustomerByEmail>
    </S:Body>
</S:Envelope>

person Marboni    schedule 20.02.2012    source источник
comment
Не могли бы вы направить меня сюда: stackoverflow.com/questions/60260277/?   -  person Pra_A    schedule 19.02.2020


Ответы (4)


Вы можете получить эту ошибку, если служба не обрабатывает заголовки. Служба должна реализовать SOAPHandler с getHeaders (), который разрешал бы заголовки. Для вышеупомянутой ошибки правильная реализация будет следующей

 @Override 
    public Set<QName> getHeaders() { 
        QName securityHeader = new QName("http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd", 
                "Security"); 
        HashSet<QName> headers = new HashSet<QName>(); 
        headers.add(securityHeader);         
        return headers; 
    }

Также возможно получить это, когда служба на самом деле небезопасна, но клиент пытается использовать конфигурацию безопасности (возможно, используя конфигурацию безопасности XWSS). Для этого просто проверьте опубликованный wsdl из браузера и убедитесь, что он содержит ожидаемый политика безопасности (добавьте? wsdl к URL-адресу конечной точки)

person Joseph Rajeev Motha    schedule 12.02.2014
comment
Это определенно помогло! - person Tomasz Dzięcielewski; 22.03.2019
comment
Примечание: getHeaders () вызывается только один раз при запуске контейнера (Tomcat в моем случае). Но остальные методы обработчика (handleMessage и close ()) вызываются с каждым обработанным запросом / ответом (handleFault () вызывается при ошибке). - person yurin; 17.06.2019
comment
Не могли бы вы направить меня сюда: stackoverflow.com/questions/60260277/? - person Pra_A; 17.02.2020
comment
@Joseph - У меня это не работает. Вопрос размещен здесь: stackoverflow.com/questions/60260277/ - person Pra_A; 17.02.2020
comment
Где настроить этот класс при использовании проекта Spring Boot SOAP? - person Pra_A; 18.02.2020
comment
это было бы настоящим чудом, если бы кто-нибудь все еще мог построить что-нибудь на основе WS без SO. Спасибо, Джозеф, это спаситель !! - person 62mkv; 04.03.2020

Я нашел решение. Требуются следующие зависимости:

<dependency>
    <groupId>org.apache.cxf</groupId>
    <artifactId>cxf-rt-frontend-jaxws</artifactId>
    <version>2.2.3</version>
</dependency>
<dependency>
    <groupId>org.apache.cxf</groupId>
    <artifactId>cxf-rt-transports-http</artifactId>
    <version>2.2.3</version>
</dependency>

Хорошая статья по этой теме и некоторые подводные камни cxf: http://www.logicsector.com/java/how-to-create-a-wsdl-first-soap-client-in-java-with-cxf-and-maven/

person Marboni    schedule 21.02.2012
comment
Я попробовал это и получил следующее исключение: Servlet /test threw load() exception java.lang.ClassCastException: test.TestServiceListener cannot be cast to javax.servlet.Servlet - person Jono; 08.02.2014
comment
не понял ни причину, ни решение. копия вставлена ​​и все работает. любить это. ;) - person iTake; 26.05.2015

Вот что у меня сработало. По сути, это воплощение идеи, высказанной @Joseph Rajeev Motha (хотя я нашел ее в другом месте, здесь: https://dwuysan.wordpress.com/2012/04/02/jax-ws-wsimport-and-the-error-mustunderstand-headers-not-formed/#comment-215), но в его ответе нет шаблона, и без него ответ будет довольно загадочным.

Обратите внимание, что эта последовательность применяется к отдельному случаю (когда вы публикуете Endpoint самостоятельно).

Шаг 1

Создайте SOAPHandler, который будет «понимать» заголовок:

public class WSSESecurityUnderstandPretender implements SOAPHandler<SOAPMessageContext> {
    @Override
    public Set<QName> getHeaders() {
        final QName securityHeader = new QName(
            "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd",
            "Security",
            "wsse");

        final Set<QName> headers = new HashSet<>();
        headers.add(securityHeader);

        // notify the runtime that this is handled
        return headers;
    }

    @Override
    public boolean handleMessage(SOAPMessageContext context) {
        // we must return true, or else the runtime will return
        // wrong wrapper element name (like makeTransfer instead of
        // makeTransferResponse)
        return true;
    }

    @Override
    public boolean handleFault(SOAPMessageContext context) {
        // we must return true, or else the runtime will return
        // wrong wrapper element name (like makeTransfer instead of
        // makeTransferResponse)
        return true;
    }

    @Override
    public void close(MessageContext context) {
    }
}

Шаг 2

Создайте handler-chain.xml файл и поместите его в путь к классам:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<javaee:handler-chains
     xmlns:javaee="http://java.sun.com/xml/ns/javaee"
     xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <javaee:handler-chain>
    <javaee:handler>
      <javaee:handler-class>com.mypackage.WSSESecurityUnderstandPretender</javaee:handler-class>
    </javaee:handler>
  </javaee:handler-chain>
</javaee:handler-chains>

Шаг 3

Аннотируйте свой класс реализации (класс, помеченный знаком @WebService) ссылкой на файл цепочки обработчиков:

@HandlerChain(file = "handler-chain.xml")

Шаг 4

Опубликуйте свою конечную точку:

Endpoint endpoint = Endpoint.publish(url, impl);

Важное примечание

handleMessage() и handleFault(), определенные обработчиком, должны возвращать true. В противном случае вы получите странные ошибки, такие как «Неожиданный элемент оболочки», потому что будет использоваться другое имя элемента оболочки.

person Roman Puchkovskiy    schedule 28.09.2018
comment
Вы спасли меня, особенно код, который возвращает заголовки! Спасибо Роман :) - person Tomasz Dzięcielewski; 16.03.2019
comment
@Roman - Не могли бы вы направить меня сюда: stackoverflow.com/questions/60260277/? - person Pra_A; 17.02.2020
comment
@Roman - это решение не работает с проектом Spring Boot v2.2.2.RELEASE и SOAP. - person Pra_A; 17.02.2020

Если у вас есть эта проблема в проекте с Java 11, попробуйте использовать выпуск Apache CXF 3.3.x.
Ответ ниже от Часто задаваемые вопросы об Apache CXF:

Может ли CXF работать с JDK / Java 9+ (10, 11)?
Да. CXF будет поддерживать Java 9-11 в следующем выпуске 3.3.x.

person prianichnikov    schedule 17.06.2020
comment
Хотя эта ссылка может дать ответ на вопрос, лучше включить сюда основные части ответа и предоставить ссылку для справки. Ответы, содержащие только ссылки, могут стать недействительными, если ссылка на страницу изменится. - Из отзыва - person isma3l; 17.06.2020