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

时间:2012-04-21 15:43:43

标签: java soap client axis ws-security

我正在为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 Axis
  • Apache WSS4J 1.5.1
  • Apache XML Security 1.4.0
  • JDK 1.6
  • Max OS 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)

1 个答案:

答案 0 :(得分:4)

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

所以这里没有进一步的问题是:

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上发布知识渊博文章的人,让像我这样的用户能够解决我们偶尔遇到的问题。