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



我正在为 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)

这是我在这里的环境:

  • Intellij IDEA IDE
  • 阿帕奇轴
  • Apache WSS4J 1.5.1
  • Apache XML Security 1.4.0
  • JDK 1.6
  • 最大操作系统 X

尽管在互联网上搜索提供了许多如何通过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!");
            }
        }
    }
}

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

这是我第一次收到回调时的 print 语句的输出:

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

以下是设置密码后的输出:

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

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

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

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

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)

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

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

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

现在WSConstants.PASSWORD_TEXT实际上等同于"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText".我真正使用的一定是WSConstants.PW_TEXT,这相当于"PasswordText"这正是我在代码中所需要的。一旦我做出了改变,一切都很好。

与流行的看法相反,您可以完全以编程方式完成所有这些操作。您不需要配置 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;
}

进行这些修改后,您的客户将工作。请记住,上面的一些设置特定于我正在集成的服务。您可能需要调整这些以适应您的集成,这可能需要一些试验和错误。

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

最新更新