JAX-WS 密码类型密码文本

2022-09-02 03:01:12

我有一个简单的命令行Java JAX-WS应用程序来测试SOAP请求,但是服务器期望密码类型是PasswordText,我对如何设置这个感到困惑...

代码如下所示:

@WebServiceRef
private static final HelloService helloService = new HelloService(url, new QName(
        URL, "HelloService"));

public static void main(final String... args) {

    try {
        final HelloPort helloPort = helloService.getHelloPort();
        final BindingProvider hB = ((BindingProvider) helloPort);
        hB.getRequestContext().put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY,
                                   END_POINT_ADDRESS);
        hB.getRequestContext().put(BindingProvider.USERNAME_PROPERTY,
                                   USERNAME);
        hB.getRequestContext().put(BindingProvider.PASSWORD_PROPERTY,
                                   PASSWORD);
        ...

我已经使用SOAP-UI测试了请求,所以我知道它正在工作。有关设置密码类型的任何帮助将不胜感激。

谢谢。


答案 1

这将设置基本 HTTP 身份验证的用户名和密码。如果您已经在SoapUI中对其进行了测试,我猜您所说的“PasswordText”值是请求详细信息窗格中的“WSS-Password Type”。这设置了 WSS 安全性,而不是 HTTP 安全性。

使用 Java6 中的 JAX-WS,您需要附加一个 SOAPHandler 以将 WSS-Usertoken 注入到 SOAP Header 中。关于这个网络有很多零碎的东西,但我找不到一个单一的链接来发布,所以这里有一些代码来让你继续前进......

要添加处理程序,您需要类似下面的内容:

final Binding binding = ((BindingProvider) servicePort).getBinding();
List<Handler> handlerList = binding.getHandlerChain();
if (handlerList == null)
    handlerList = new ArrayList<Handler>();

handlerList.add(new SecurityHandler());
binding.setHandlerChain(handlerList); // <- important!

然后,安全处理员类将做契约。处理程序是一般的东西,对于成功的消息和错误都被调用,但也许更重要的是,它们在两个消息方向上都被调用 - 对于传出请求,然后再次为传入响应。您只想处理传出邮件。因此,您需要类似以下内容的内容:

public final class SecurityHandler implements SOAPHandler<SOAPMessageContext> {

    ...

    @Override
    public boolean handleMessage(final SOAPMessageContext msgCtx) {

        // Indicator telling us which direction this message is going in
        final Boolean outInd = (Boolean) msgCtx.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY);

        // Handler must only add security headers to outbound messages
        if (outInd.booleanValue()) {
            try {
                // Get the SOAP Envelope
                final SOAPEnvelope envelope = msgCtx.getMessage().getSOAPPart().getEnvelope();

                // Header may or may not exist yet
                SOAPHeader header = envelope.getHeader();
                if (header == null)
                    header = envelope.addHeader();

                // Add WSS Usertoken Element Tree 
                final SOAPElement security = header.addChildElement("Security", "wsse",
                        "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd");
                final SOAPElement userToken = security.addChildElement("UsernameToken", "wsse");
                userToken.addChildElement("Username", "wsse").addTextNode("MyWSSUsername");
                userToken.addChildElement("Password", "wsse").addTextNode("MyWSSPassword");

            } catch (final Exception e) {
                LOG.error(e);
                return false;
            }
        }
        return true;
    }

    ...
    // Other required methods on interface need no guts
}

我在这里做了一些假设,但希望它能让你继续前进!

亲切问候。


答案 2

如果实现 SOAPHandler 接口,则方法 msgCtx.getMessage() 将呈现整个 XML,并且如果您正在处理大文件,则会出现内存不足错误。我在JAX-WS客户端上使用UsernameToken身份验证进行了测试,它的工作原理是:

String SECURITY_NS = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd";
String PASSWORD_TYPE = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText";
String AUTH_PREFIX = "wss";

MyService service = new MyService();
MyServicePort port = service.getMyServicePort();

try {
    SOAPFactory soapFactory = SOAPFactory.newInstance();
    SOAPElement security = soapFactory.createElement("Security", AUTH_PREFIX, SECURITY_NS);
    SOAPElement uToken = soapFactory.createElement("UsernameToken", AUTH_PREFIX, SECURITY_NS);
    SOAPElement username = soapFactory.createElement("Username", AUTH_PREFIX, SECURITY_NS);
    username.addTextNode("username");

    SOAPElement pass = soapFactory.createElement("Password", AUTH_PREFIX, SECURITY_NS);
    pass.addAttribute(new QName("Type"), PASSWORD_TYPE);
    pass.addTextNode("password");

    uToken.addChildElement(username);
    uToken.addChildElement(pass);
    security.addChildElement(uToken);

    Header header = Headers.create(security);
    ((WSBindingProvider) port).setOutboundHeaders(header);

    // now, call webservice

} catch (SOAPException ex) {
    ex.printStackTrace();
}

编辑:您应该将“rt.jar”从 jre 添加到类路径。


推荐