java WSSecurityEngine 表示在回调期间未提供密码,即使提供了密码

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/10260463/
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-10-31 00:16:31  来源:igfitidea点击:

WSSecurityEngine says password was not supplied during callback even though it is provided

javasoapclientaxisws-security

提问by Karthic Raghupathi

I'm in the process of creating a client for a web service. I keep getting the following error:

我正在为 Web 服务创建客户端。我不断收到以下错误:

AxisFault
    faultCode: {http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd}InvalidSecurity
    faultSubcode:
    faultString:
        Security Data : General security error (WSSecurityEngine: Callback supplied no password for: TestMerchant)
    faultActor: 
    faultNode: 
    faultDetail: {http://xml.apache.org/axis/}
    stackTrace:
        Security Data : General security error (WSSecurityEngine: Callback supplied no password for: TestMerchant)

This is my environment here:

这是我这里的环境:

  • Intellij IDEA IDE
  • Apache Axis
  • Apache WSS4J 1.5.1
  • Apache XML Security 1.4.0
  • JDK 1.6
  • Max OS X
  • Intellij IDEA IDE
  • 阿帕奇轴
  • Apache WSS4J 1.5.1
  • Apache XML 安全 1.4.0
  • JDK 1.6
  • 最大 OS X

Although searching on the internet provides a lot of examples of how the security header can be added to the request via XML configuration, my requirement is to do this dynamically via the program. So here is my code:

尽管在 Internet 上搜索提供了很多示例,说明如何通过 XML 配置将安全标头添加到请求中,但我的要求是通过程序动态执行此操作。所以这是我的代码:

public class AxisClient implements CallbackHandler {

    ServerEnvironment environment;

    AxisClient(ServerEnvironment environment) {
        this.environment = environment;
    }

    public enum ServerEnvironment {
        LIVE("https://ics2ws.ic3.com/commerce/1.x/transactionProcessor"),
        TEST("https://ics2wstest.ic3.com/commerce/1.x/transactionProcessor");

        String url;

        ServerEnvironment (String url) {
            this.url = url;
        }

        public String getUrl() {
            return url;
        }
    }

    public enum Merchant {
        TestMerchant ("testpassword");

        private String transactionKey;

        Merchant(String transactionKey) {
            this.transactionKey = transactionKey;
        }

        public String getTransactionKey() {
            return transactionKey;
        }
    }

    public static void main(String[] argv) {
        String ani = "7162502800";
        String zipCode = "14221";
        String ccNum ="5555555555554444";
        String expMonth = "01";
        String expYear = "15";
        String cvv = "123";
        String unitPrice = "9.99";
        String qty = "2";

        try {
            new AxisClient(ServerEnvironment.TEST).doAuth(Merchant.TestMerchant, ani, zipCode, ccNum, expMonth, expYear, cvv, String.valueOf(new Date().getTime()), unitPrice, qty);
        }
        catch (Exception e) {
            e.printStackTrace();
        }
    }

    public Boolean doAuth(Merchant merchant, String ani, String zipCode, String ccNum, String expMonth, String expYear, String cvv, String id, String unitPrice, String qty) throws Exception {
        Boolean result = false;

        RequestMessage request;
        BillTo billTo;
        Card card;
        PurchaseTotals purchaseTotals;
        Item item;
        Item[] items;
        ReplyMessage reply;

        try {
            // billing info
            billTo = new BillTo();
            billTo.setPhoneNumber(ani);
            billTo.setPostalCode(zipCode);

            // card info
            card = new Card();
            card.setAccountNumber(ccNum);
            card.setExpirationMonth(new BigInteger(expMonth));
            card.setExpirationYear(new BigInteger(expYear));
            card.setCvNumber(cvv);

            // currency info
            purchaseTotals = new PurchaseTotals();
            purchaseTotals.setCurrency("USD");

            // item
            item = new Item();
            item.setId(new BigInteger(id));
            item.setUnitPrice(unitPrice);
            item.setQuantity(new BigInteger(qty));

            // add item to items array
            items = new Item[1];
            items[0] = item;

            // create our request
            request = new RequestMessage();
            request.setMerchantID(merchant.toString());
            request.setCcAuthService(new CCAuthService());
            request.getCcAuthService().setRun("true");

            // add request specific params
            request.setBillTo(billTo);
            request.setCard(card);
            request.setPurchaseTotals(purchaseTotals);
            request.setItem(items);

            reply = post(merchant, request);

            if (reply != null) {
                System.out.println(ReflectionToStringBuilder.toString(reply, ToStringStyle.MULTI_LINE_STYLE));
            }
        }
        catch (Exception e) {
            throw e;
        }

        return result;
    }

    public EngineConfiguration createConfigurationWithSecurityHeaders(Merchant merchant) throws Exception {
        SimpleProvider result;

        Handler securityHandler;
        SimpleChain requestHandler;
        SimpleChain responseHandler;
        Handler pivot;
        Handler transport;

        try {
            result = new SimpleProvider();

            securityHandler = new WSDoAllSender();
            securityHandler.setOption(WSHandlerConstants.ACTION, WSHandlerConstants.USERNAME_TOKEN);
            securityHandler.setOption(WSHandlerConstants.PASSWORD_TYPE, WSConstants.PASSWORD_TEXT);
            securityHandler.setOption(WSHandlerConstants.PW_CALLBACK_REF, this);
            securityHandler.setOption(WSHandlerConstants.USER, merchant.toString());
            securityHandler.setOption(WSHandlerConstants.MUST_UNDERSTAND, "false");

            requestHandler = new SimpleChain();
            requestHandler.addHandler(securityHandler);

            responseHandler = new SimpleChain();
            responseHandler.addHandler(securityHandler);

            pivot = new HTTPSender();

            transport = new SimpleTargetedChain(requestHandler, pivot, responseHandler);

            result.deployTransport(HTTPTransport.DEFAULT_TRANSPORT_NAME, transport);
        }
        catch (Exception e) {
            throw e;
        }

        return result;
    }

    public ReplyMessage post (Merchant merchant, RequestMessage request) throws Exception {
        ReplyMessage result;

        TransactionProcessorLocator locator;
        URL endPoint;
        ITransactionProcessorStub stub;
        EngineConfiguration configuration;

        try {
            locator = new TransactionProcessorLocator();

            // use client config
            configuration = createConfigurationWithSecurityHeaders(merchant);
            locator.setEngineConfiguration(configuration);
            locator.setEngine(new org.apache.axis.client.AxisClient(configuration));

            endPoint = new URL(environment.getUrl());

            stub = (ITransactionProcessorStub) locator.getportXML(endPoint);
            stub._setProperty(WSHandlerConstants.USER, request.getMerchantID());
            stub._setProperty(WSHandlerConstants.ACTION, WSHandlerConstants.USERNAME_TOKEN);
            stub._setProperty(WSHandlerConstants.PASSWORD_TYPE, WSConstants.PASSWORD_TEXT);
            stub._setProperty(WSHandlerConstants.PW_CALLBACK_REF, this);
            stub._setProperty(WSHandlerConstants.MUST_UNDERSTAND, "false");

            result = stub.runTransaction(request);
        }
        catch (Exception e) {
            throw e;
        }

        return result;
    }

    @Override
    public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {

        for (Callback callback : callbacks) {

            System.out.println(ReflectionToStringBuilder.toString(callback, ToStringStyle.MULTI_LINE_STYLE));

            if (callback instanceof WSPasswordCallback) {

                WSPasswordCallback passwordCallback = (WSPasswordCallback) callback;

                switch (Merchant.valueOf(passwordCallback.getIdentifer())) {

                    case TestMerchant:
                        passwordCallback.setPassword(Merchant.TestMerchant.getTransactionKey());
                        System.out.println(ReflectionToStringBuilder.toString(passwordCallback, ToStringStyle.MULTI_LINE_STYLE));
                        break;

                    default:
                        throw new UnsupportedCallbackException(callback, "Unrecognized prompt!");
                }
            }
            else {
                throw new UnsupportedCallbackException(callback, "Unrecognized callback!");
            }
        }
    }
}

As you can see from the above, my class implements CallbackHandler and I'm overriding handle() which provides the password for WSPasswordCallback.

从上面可以看出,我的类实现了 CallbackHandler 并且我正在覆盖为 WSPasswordCallback 提供密码的 handle()。

Here is the output of the print statement for when I get the callback first:

这是我首先获得回调时打印语句的输出:

org.apache.ws.security.WSPasswordCallback@50c713d2[
  identifier=TestMerchant
  password=<null>
  key=<null>
  usage=2
  passwordType=<null>
]

Here is the output for after setting the password:

这是设置密码后的输出:

org.apache.ws.security.WSPasswordCallback@50c713d2[
  identifier=TestMerchant
  password=testpassword
  key=<null>
  usage=2
  passwordType=<null>
]

So I'm not really sure why I keep getting that error message. Any help in solving this issue will be greatly appreciated.

所以我不确定为什么我不断收到该错误消息。任何解决此问题的帮助将不胜感激。

Also recommendations for a different approach (axis2, cxf) are welcome.

还欢迎对不同方法(axis2,cxf)的建议。

Here is my full stack trace if it is of any help:

如果有帮助,这是我的完整堆栈跟踪:

AxisFault
 faultCode: {http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd}InvalidSecurity
 faultSubcode: 
 faultString: 
Security Data : General security error (WSSecurityEngine: Callback supplied no password for: TestMerchant)
General security error (WSSecurityEngine: Callback supplied no password for: TestMerchant)

 faultActor: 
 faultNode: 
 faultDetail: 
    {http://xml.apache.org/axis/}stackTrace:
Security Data : General security error (WSSecurityEngine: Callback supplied no password for: TestMerchant)
General security error (WSSecurityEngine: Callback supplied no password for: TestMerchant)

    at org.apache.axis.message.SOAPFaultBuilder.createFault(SOAPFaultBuilder.java:222)
    at org.apache.axis.message.SOAPFaultBuilder.endElement(SOAPFaultBuilder.java:129)
    at org.apache.axis.encoding.DeserializationContext.endElement(DeserializationContext.java:1087)
    at com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser.endElement(AbstractSAXParser.java:601)
    at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl.scanEndElement(XMLDocumentFragmentScannerImpl.java:1782)
    at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl$FragmentContentDriver.next(XMLDocumentFragmentScannerImpl.java:2939)
    at com.sun.org.apache.xerces.internal.impl.XMLDocumentScannerImpl.next(XMLDocumentScannerImpl.java:648)
    at com.sun.org.apache.xerces.internal.impl.XMLNSDocumentScannerImpl.next(XMLNSDocumentScannerImpl.java:140)
    at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl.scanDocument(XMLDocumentFragmentScannerImpl.java:511)
    at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:808)
    at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:737)
    at com.sun.org.apache.xerces.internal.parsers.XMLParser.parse(XMLParser.java:119)
    at com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser.parse(AbstractSAXParser.java:1205)
    at com.sun.org.apache.xerces.internal.jaxp.SAXParserImpl$JAXPSAXParser.parse(SAXParserImpl.java:522)
    at javax.xml.parsers.SAXParser.parse(SAXParser.java:395)
    at org.apache.axis.encoding.DeserializationContext.parse(DeserializationContext.java:227)
    at org.apache.axis.SOAPPart.getAsSOAPEnvelope(SOAPPart.java:696)
    at org.apache.axis.Message.getSOAPEnvelope(Message.java:435)
    at org.apache.axis.handlers.soap.MustUnderstandChecker.invoke(MustUnderstandChecker.java:62)
    at org.apache.axis.client.AxisClient.invoke(AxisClient.java:206)
    at org.apache.axis.client.Call.invokeEngine(Call.java:2784)
    at org.apache.axis.client.Call.invoke(Call.java:2767)
    at org.apache.axis.client.Call.invoke(Call.java:2443)
    at org.apache.axis.client.Call.invoke(Call.java:2366)
    at org.apache.axis.client.Call.invoke(Call.java:1812)
    at itg.cybersource.axis.ITransactionProcessorStub.runTransaction(ITransactionProcessorStub.java:1284)
    at itg.AxisClient.post(AxisClient.java:208)
    at itg.AxisClient.doAuth(AxisClient.java:132)
    at itg.AxisClient.main(AxisClient.java:75)

    {http://xml.apache.org/axis/}hostname:C02GD302DRJL.local


Security Data : General security error (WSSecurityEngine: Callback supplied no password for: TestMerchant)
General security error (WSSecurityEngine: Callback supplied no password for: TestMerchant)

    at org.apache.axis.message.SOAPFaultBuilder.createFault(SOAPFaultBuilder.java:222)
    at org.apache.axis.message.SOAPFaultBuilder.endElement(SOAPFaultBuilder.java:129)
    at org.apache.axis.encoding.DeserializationContext.endElement(DeserializationContext.java:1087)
    at com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser.endElement(AbstractSAXParser.java:601)
    at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl.scanEndElement(XMLDocumentFragmentScannerImpl.java:1782)
    at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl$FragmentContentDriver.next(XMLDocumentFragmentScannerImpl.java:2939)
    at com.sun.org.apache.xerces.internal.impl.XMLDocumentScannerImpl.next(XMLDocumentScannerImpl.java:648)
    at com.sun.org.apache.xerces.internal.impl.XMLNSDocumentScannerImpl.next(XMLNSDocumentScannerImpl.java:140)
    at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl.scanDocument(XMLDocumentFragmentScannerImpl.java:511)
    at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:808)
    at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:737)
    at com.sun.org.apache.xerces.internal.parsers.XMLParser.parse(XMLParser.java:119)
    at com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser.parse(AbstractSAXParser.java:1205)
    at com.sun.org.apache.xerces.internal.jaxp.SAXParserImpl$JAXPSAXParser.parse(SAXParserImpl.java:522)
    at javax.xml.parsers.SAXParser.parse(SAXParser.java:395)
    at org.apache.axis.encoding.DeserializationContext.parse(DeserializationContext.java:227)
    at org.apache.axis.SOAPPart.getAsSOAPEnvelope(SOAPPart.java:696)
    at org.apache.axis.Message.getSOAPEnvelope(Message.java:435)
    at org.apache.axis.handlers.soap.MustUnderstandChecker.invoke(MustUnderstandChecker.java:62)
    at org.apache.axis.client.AxisClient.invoke(AxisClient.java:206)
    at org.apache.axis.client.Call.invokeEngine(Call.java:2784)
    at org.apache.axis.client.Call.invoke(Call.java:2767)
    at org.apache.axis.client.Call.invoke(Call.java:2443)
    at org.apache.axis.client.Call.invoke(Call.java:2366)
    at org.apache.axis.client.Call.invoke(Call.java:1812)
    at itg.cybersource.axis.ITransactionProcessorStub.runTransaction(ITransactionProcessorStub.java:1284)
    at itg.AxisClient.post(AxisClient.java:208)
    at itg.AxisClient.doAuth(AxisClient.java:132)
    at itg.AxisClient.main(AxisClient.java:75)

回答by Karthic Raghupathi

After many days of trying very many different things, I finally figured out the answer to my problem. Talk about the problem being in between the keyboard and the chair!!!!!

在尝试了很多不同的事情很多天之后,我终于找到了我的问题的答案。谈谈键盘和椅子之间的问题!!!!

So without further ado here is what the issue was:

因此,事不宜迟,这里是问题所在:

securityHandler.setOption(WSHandlerConstants.PASSWORD_TYPE, WSConstants.PASSWORD_TEXT);

Now WSConstants.PASSWORD_TEXTactually equates to "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText". What I must have really been using is WSConstants.PW_TEXTwhich equates to "PasswordText"which is exactly what I needed in my code. Once I made the change, everything works beautifully.

现在WSConstants.PASSWORD_TEXT实际上等于"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText"。我必须真正使用的是WSConstants.PW_TEXT这等同于"PasswordText"我在代码中所需要的。一旦我进行了更改,一切都运行良好。

Contrary to popular belief, you can do all this entirely in a programmatic manner. You DO NOT need to configure the WSDD xml for you to intercept a message and handle WS-Security in the SOAP header. To tidy up loose ends, here is what the modified methods look like:

与流行的看法相反,您可以完全以程序化的方式完成所有这些工作。您不需要配置 WSDD xml 来拦截消息并处理 SOAP 标头中的 WS-Security。为了整理松散的部分,这里是修改后的方法的样子:

public EngineConfiguration createConfigurationWithSecurityHeaders(Merchant merchant) throws Exception {
    SimpleProvider result;

    Handler securityHandler;
    SimpleChain requestHandler;
    SimpleChain responseHandler;
    Handler pivot;
    Handler transport;

    try {
        result = new SimpleProvider();

        securityHandler = new WSDoAllSender();
        securityHandler.setOption(WSHandlerConstants.ACTION, WSHandlerConstants.USERNAME_TOKEN);
        securityHandler.setOption(WSHandlerConstants.PASSWORD_TYPE, WSConstants.PW_TEXT);
        securityHandler.setOption(WSHandlerConstants.USER, merchant.toString());
        securityHandler.setOption(WSHandlerConstants.MUST_UNDERSTAND, "false");

        requestHandler = new SimpleChain();
        requestHandler.addHandler(securityHandler);

        responseHandler = new SimpleChain();
        responseHandler.addHandler(securityHandler);

        pivot = new HTTPSender();

        transport = new SimpleTargetedChain(requestHandler, pivot, responseHandler);

        result.deployTransport(HTTPTransport.DEFAULT_TRANSPORT_NAME, transport);
    }
    catch (Exception e) {
        throw e;
    }

    return result;
}

public ReplyMessage post (Merchant merchant, RequestMessage request) throws Exception {
    ReplyMessage result;

    TransactionProcessorLocator locator;
    URL endPoint;
    ITransactionProcessorStub stub;
    EngineConfiguration configuration;

    try {
        locator = new TransactionProcessorLocator();

        // use client config
        configuration = createConfigurationWithSecurityHeaders(merchant);
        locator.setEngineConfiguration(configuration);
        locator.setEngine(new org.apache.axis.client.AxisClient(configuration));

        endPoint = new URL(environment.getUrl());

        stub = (ITransactionProcessorStub) locator.getportXML(endPoint);
        stub._setProperty(WSHandlerConstants.PW_CALLBACK_REF, this);

        result = stub.runTransaction(request);
    }
    catch (Exception e) {
        throw e;
    }

    return result;
}

Once these modifications are made, your client will work. Please keep in mind that a few of the settings above are specific to the service I'm integrating with. You might have to tweak these to suit your integration which might require a little trial and error.

完成这些修改后,您的客户端就可以工作了。请记住,上面的一些设置特定于我正在集成的服务。您可能需要调整这些以适应您的集成,这可能需要一些反复试验。

Thanks again to all the people who post incredibly knowledgeable articles in SO enabling users like me solve problems we come across every now and then.

再次感谢所有在 SO 中发布知识丰富的文章的人,使像我这样的用户能够解决我们时不时遇到的问题。