使用安全标头中的随机数从 java 调用soap webservice

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/28501207/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-11-02 13:42:21  来源:igfitidea点击:

Calling a soap webservice from java with nonce in security headers

javasoapws-securitynonce

提问by ErikL

I am trying to call a webservice from java. This is basically not that difficult, except that the webservice expects some security in the form of a username and password and a nonce. When I try to call the webservice from SoapUi, I see that the raw message looks like this:

我正在尝试从 Java 调用 Web 服务。这基本上没有那么难,只是 web 服务期望以用户名和密码以及随机数的形式提供一些安全性。当我尝试从 SoapUi 调用 Web 服务时,我看到原始消息如下所示:

<soapenv:Envelope xmlns:sch="http://somedomain.com/pe/ws/schema"
    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"
            xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
            <wsse:UsernameToken wsu:Id="UsernameToken-E70691ACBDEFEC750814238295617871">
                <wsse:Username>usr</wsse:Username>
                <wsse:Password
                    Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText"
                    >pw</wsse:Password>
                <wsse:Nonce
                    EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary"
                    >4smQZF5KMSktEXrQc0v5yw==</wsse:Nonce>
                <wsu:Created>2015-02-13T12:12:41.784Z</wsu:Created>
            </wsse:UsernameToken>
        </wsse:Security>
    </soapenv:Header>
    <soapenv:Body>
        <sch:EventSubmitRequest>
            <sch:Event>
                <sch:EventId>392</sch:EventId>
                <sch:Recoverable>false</sch:Recoverable>
            </sch:Event>
        </sch:EventSubmitRequest>
    </soapenv:Body>
</soapenv:Envelope>

The obvious elements in the message are the Username, Password and Created, but what puzzles me is the nonce. In the example this field has the value 4smQZF5KMSktEXrQc0v5yw==, but this value difference upon each request (which makes sense, since according to wikipedia, a nonce is an arbitrary number used only once). When searching around, I can't find any usable examples of how to generate the nonce in java (Although I did find some php examples here on stack overflow, but I can't easily verify weather they work) . While I don't mind construction this nonce myself, I'm wondering if this is really necessary, I kind of would expect this to be standard functionality in java.

消息中明显的元素是用户名、密码和创建者,但让我感到困惑的是随机数。在示例中,该字段的值是 4smQZF5KMSktEXrQc0v5yw==,但是每个请求的值都不同(这是有道理的,因为根据维基百科,随机数是只使用一次的任意数字)。在四处搜索时,我找不到任何关于如何在 java 中生成随机数的可用示例(虽然我确实在堆栈溢出时在这里找到了一些 php 示例,但我无法轻松验证它们是否工作)。虽然我不介意自己构造这个 nonce,但我想知道这是否真的有必要,我有点希望这是 Java 中的标准功能。

Below is the code I'm using:

下面是我正在使用的代码:

import java.text.SimpleDateFormat;
import java.util.Calendar;
import javax.xml.namespace.QName;
import javax.xml.soap.*;
import javax.xml.transform.*;
import javax.xml.transform.stream.*;

public class soaptest {

    public static void main(String args[]) {
        try {
            // Create SOAP Connection
            SOAPConnectionFactory soapConnectionFactory = SOAPConnectionFactory.newInstance();
            SOAPConnection soapConnection = soapConnectionFactory.createConnection();

            // Send SOAP Message to SOAP Server
            String url = "http://142.10.10.52:8080/pe/ws/pe/";
            SOAPMessage soapResponse = soapConnection.call(createSOAPRequest(), url);

            // Process the SOAP Response
            printSOAPResponse(soapResponse);

            soapConnection.close();
        } catch (Exception e) {
            System.err.println("Error occurred while sending SOAP Request to Server");
            e.printStackTrace();
        }
    }

    private static SOAPMessage createSOAPRequest() throws Exception {
        MessageFactory messageFactory = MessageFactory.newInstance();
        SOAPMessage soapMessage = messageFactory.createMessage();
        SOAPPart soapPart = soapMessage.getSOAPPart();

        SOAPEnvelope envelope = soapPart.getEnvelope();
        SOAPHeader header = soapMessage.getSOAPHeader();

        SOAPElement security = header.addChildElement("Security", "wsse", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd");

        SOAPElement usernameToken = security.addChildElement("UsernameToken", "wsse");
        usernameToken.addAttribute(new QName("xmlns:wsu"), "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd");

        SOAPElement username = usernameToken.addChildElement("Username", "wsse");
        username.addTextNode("usr");

        SOAPElement password = usernameToken.addChildElement("Password", "wsse");
        password.setAttribute("Type", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText");
        password.addTextNode("pw");

        SOAPElement nonce = usernameToken.addChildElement("Nonce", "wsse");
        nonce.setAttribute("EncodingType", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary");
        nonce.addTextNode("???");

        SOAPElement created = usernameToken.addChildElement("Created", "wsse");
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
        Calendar c1 = Calendar.getInstance();
        created.addTextNode(sdf.format(c1.getTime()));

        String serverURI = "http://somedomain.com/pe/ws/schema";

        envelope.addNamespaceDeclaration("sch", serverURI);

        // SOAP Body
        SOAPBody soapBody = envelope.getBody();
        SOAPElement soapBodyElem = soapBody.addChildElement("EventSubmitRequest", "sch");
        SOAPElement soapBodyElem1 = soapBody.addChildElement("Event", "sch");
        soapBodyElem.addChildElement(soapBodyElem1);

        SOAPElement soapBodyElem2 = soapBodyElem1.addChildElement("EventId", "sch");
        soapBodyElem2.addTextNode("392");
        SOAPElement soapBodyElem3 = soapBodyElem1.addChildElement("Recoverable", "sch");
        soapBodyElem3.addTextNode("false");

        MimeHeaders headers = soapMessage.getMimeHeaders();
        headers.addHeader("SOAPAction", serverURI  + "EventSubmitRequest");

        soapMessage.saveChanges();

        /* Print the request message */
        System.out.print("Request SOAP Message = ");
        soapMessage.writeTo(System.out);
        System.out.println();

        return soapMessage;
    }

    /**
     * Method used to print the SOAP Response
     */
    private static void printSOAPResponse(SOAPMessage soapResponse) throws Exception {
        TransformerFactory transformerFactory = TransformerFactory.newInstance();
        Transformer transformer = transformerFactory.newTransformer();
        Source sourceContent = soapResponse.getSOAPPart().getContent();
        System.out.print("\nResponse SOAP Message = ");
        StreamResult result = new StreamResult(System.out);
        transformer.transform(sourceContent, result);
    }

}

采纳答案by muttonUp

The Oasis referencefor the UsernameToken helped me fill in some of the blanks. Pages 7,8,9 are most appropriate in this case. In particular these sections

UsernameToken的Oasis 参考帮助我填补了一些空白。在这种情况下,第 7、8、9 页最合适。特别是这些部分

/wsse:UsernameToken/wsse:Nonce

This optional element specifies a cryptographically random nonce. Each message including a element MUST use a new nonce value in order for web service producers to detect replay attacks.

/wsse:UsernameToken/wsse:Nonce

此可选元素指定加密随机随机数。每条包含元素的消息必须使用新的 nonce 值,以便 Web 服务生产者检测重放攻击。

and

/wsse:UsernameToken/wsse:Nonce/@EncodingType

This optional attribute URI specifies the encoding type of the nonce (see the definition of <wsse:BinarySecurityToken> for valid values). If this attribute isn't specified then the default of Base64 encoding is used.

/wsse:UsernameToken/wsse:Nonce/@EncodingType

此可选属性 URI 指定了 nonce 的编码类型(有关有效值,请参阅 <wsse:BinarySecurityToken> 的定义)。如果未指定此属性,则使用默认的 Base64 编码。

In regards to generating the 'cryptographically random' nonce, can suggest you use this answerand then create an encoded string from it. Base64 encoding in your case, as that is the encodingType you are using in your XML request above.

关于生成“加密随机”随机数,可以建议您使用此答案,然后从中创建一个编码字符串。在您的情况下使用 Base64 编码,因为这是您在上面的 XML 请求中使用的 encodingType。