简体   繁体   中英

Java Paypal Integration SOAP JAX-WS - SSL Handshakeexception

This question is related to the integration of PayPal API with Java using SOAP request/response model.

The following method consist in establish the request parameters and return the response string, in this case the token. I watch several examples of how suppose to do the request call, but those methods were created for less versions (this version is "109.0", the other examples I saw were 80, 60 even 40).

Anyway, I downloaded the .wsdl file from PayPal, created the client java classes with SOAPUI and JAX-WS web services style, saved the project and opened with MyEclipse. I imported the PayPal certificate on my Java TomCat Server aswell, using keytool import on cacerts file of java.

The following method suppose to be the request method to return the String value:

public String setExpressCheckout(String returnURL, String cancelURL) throws ErrorGeneral {

    PayPalAPIInterfaceService pp = new PayPalAPIInterfaceService();
    UserIdPasswordType login = new UserIdPasswordType();
    login.setUsername("carlos.martinez_api1.netijam.com");
    login.setPassword("1389974315");
    login.setSignature("AFcWxV21C7fd0v3bYYYRCpSSRl31AI-ujedgZR8zf1CorgeJpph2tssY");
    String token = "";
    String ackString;   
    // following class is generated by wsdl2java utility Service class

    final PayPalAPIAAInterface expressCheckoutPort = pp.getPayPalAPIAA();
    final Binding binding = ((BindingProvider) expressCheckoutPort).getBinding();
    List<Handler> handlersList = new ArrayList<Handler>();

    // now, adding instance of Handler to handlersList which should do our job:
    // creating header instance
    CustomSecurityHeaderType headerObj = new CustomSecurityHeaderType();
    UserIdPasswordType credentials = new UserIdPasswordType();
    credentials.setUsername("carlos.martinez_api1.netijam.com");
    credentials.setPassword("1389974315");
    credentials.setSignature("AFcWxV21C7fd0v3bYYYRCpSSRl31AI-ujedgZR8zf1CorgeJpph2tssY");
    headerObj.setCredentials(credentials);


    ObjectFactory objectFactory = new ObjectFactory();
    // creating JAXBElement from headerObj
    final JAXBElement<CustomSecurityHeaderType> requesterCredentials = objectFactory.createRequesterCredentials(headerObj);

    handlersList.add(new SOAPHandler<SOAPMessageContext>() {
        @Override
        public boolean handleMessage(final SOAPMessageContext context) {        
            try {
                // checking whether handled message is outbound one as per Martin Strauss answer
                final Boolean outbound = (Boolean) context.get("javax.xml.ws.handler.message.outbound");
                if (outbound != null && outbound) {
                    // obtaining marshaller which should marshal instance to xml
                    final Marshaller marshaller = JAXBContext.newInstance(CustomSecurityHeaderType.class).createMarshaller();
                    // adding header because otherwise it's null
                    final SOAPHeader soapHeader = context.getMessage().getSOAPPart().getEnvelope().addHeader();
                    // marshalling instance (appending) to SOAP header's xml node
                    marshaller.marshal(requesterCredentials, soapHeader);
                }
            } catch (final Exception e) {
                throw new RuntimeException(e);
            }
            return true;
        }

        @Override
        public boolean handleFault(SOAPMessageContext context) {
            // TODO Auto-generated method stub
            return false;
        }

        @Override
        public void close(MessageContext context) {
            // TODO Auto-generated method stub

        }

        @Override
        public Set<QName> getHeaders() {
            // TODO Auto-generated method stub
            return null;
        }

        // ... default implementations of other methods go here

    });
    // as per Jean-Bernard Pellerin's comment setting handlerChain list here, after all handlers were added to list

    binding.setHandlerChain(handlersList);


    try {

        SetExpressCheckoutReq sECR = new SetExpressCheckoutReq();
        SetExpressCheckoutRequestType sECRDT = new SetExpressCheckoutRequestType();
        sECRDT.setVersion("109.0");
        SetExpressCheckoutRequestDetailsType details = new SetExpressCheckoutRequestDetailsType();
        PaymentDetailsType paymentDetails = new PaymentDetailsType();
        paymentDetails.setOrderDescription("Integrating Stuff Test Order");
        paymentDetails.setInvoiceID("INVOICE-" + Math.random());
        BasicAmountType orderTotal = new BasicAmountType();
        orderTotal.setCurrencyID(CurrencyCodeType.EUR);
        orderTotal.setValue("120.00");
        paymentDetails.setOrderTotal(orderTotal);
        paymentDetails.setPaymentAction(PaymentActionCodeType.SALE);
        List<PaymentDetailsType> listaDetallesPago = new ArrayList<PaymentDetailsType>();
        listaDetallesPago.add(paymentDetails);
        details.setPaymentDetails(listaDetallesPago);
        details.setReturnURL(returnURL);
        details.setCancelURL(cancelURL);

        sECRDT.setSetExpressCheckoutRequestDetails(details);


        sECR.setSetExpressCheckoutRequest(sECRDT);


        SetExpressCheckoutResponseType response = expressCheckoutPort.setExpressCheckout(sECR);

        ackString = response.getAck().value();
        System.out.println(ackString);
        token = response.getToken();

        for (ErrorType msg : response.getErrors()) {
            System.out.println(msg.getLongMessage());
        }
    } catch (Exception ex) {
        System.out.println(ex.getMessage());
    }

    // get the token from the response
    return token;
}

And this is the error that I receive:

javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure
at sun.security.ssl.Alerts.getSSLException(Alerts.java:192)
at sun.security.ssl.Alerts.getSSLException(Alerts.java:154)
at sun.security.ssl.SSLSocketImpl.recvAlert(SSLSocketImpl.java:1959)
at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:1077)
at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1312)
at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1339)
at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1323)
at sun.net.www.protocol.https.HttpsClient.afterConnect(HttpsClient.java:563)
at sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect(AbstractDelegateHttpsURLConnection.java:185)
at sun.net.www.protocol.http.HttpURLConnection.getOutputStream(HttpURLConnection.java:1091)
at sun.net.www.protocol.https.HttpsURLConnectionImpl.getOutputStream(HttpsURLConnectionImpl.java:250)
at com.sun.xml.ws.transport.http.client.HttpClientTransport.getOutput(HttpClientTransport.java:92)
at com.sun.xml.ws.transport.http.client.HttpTransportPipe.process(HttpTransportPipe.java:110)
at com.sun.xml.ws.protocol.soap.ClientMUPipe.process(ClientMUPipe.java:72)
at com.sun.xml.ws.handler.HandlerPipe.process(HandlerPipe.java:134)
at com.sun.xml.ws.handler.HandlerPipe.process(HandlerPipe.java:134)
at com.sun.xml.ws.client.Stub.process(Stub.java:125)
at com.sun.xml.ws.client.sei.SEIStub.doProcess(SEIStub.java:127)
at com.sun.xml.ws.client.sei.SyncMethodHandler.invoke(SyncMethodHandler.java:238)
at com.sun.xml.ws.client.sei.SyncMethodHandler.invoke(SyncMethodHandler.java:212)
at com.sun.xml.ws.client.sei.SEIStub.invoke(SEIStub.java:110)
at com.sun.proxy.$Proxy39.setExpressCheckout(Unknown Source)
at capsula.SetExpressCheckoutService.setExpressCheckout(SetExpressCheckoutService.java:168)
at capsula.SetExpressCheckoutService.main(SetExpressCheckoutService.java:56)

I tried to search on every part of the web to find a solution but I cannot. I read a lot of examples from PayPal but It doesn't tell anything about new versions, because in old version there is an easy way to make the request including the credentials on the request and not doing that shitty part of:

ObjectFactory objectFactory = new ObjectFactory();
// creating JAXBElement from headerObj
final JAXBElement<CustomSecurityHeaderType> requesterCredentials = objectFactory.createRequesterCredentials(headerObj);

handlersList.add(new SOAPHandler<SOAPMessageContext>() {
    @Override
    public boolean handleMessage(final SOAPMessageContext context) {        
        try {
            // checking whether handled message is outbound one as per Martin Strauss answer
            final Boolean outbound = (Boolean) context.get("javax.xml.ws.handler.message.outbound");
            if (outbound != null && outbound) {
                // obtaining marshaller which should marshal instance to xml
                final Marshaller marshaller = JAXBContext.newInstance(CustomSecurityHeaderType.class).createMarshaller();
                // adding header because otherwise it's null
                final SOAPHeader soapHeader = context.getMessage().getSOAPPart().getEnvelope().addHeader();
                // marshalling instance (appending) to SOAP header's xml node
                marshaller.marshal(requesterCredentials, soapHeader);
            }
        } catch (final Exception e) {
            throw new RuntimeException(e);
        }
        return true;
    }

    @Override
    public boolean handleFault(SOAPMessageContext context) {
        // TODO Auto-generated method stub
        return false;
    }

    @Override
    public void close(MessageContext context) {
        // TODO Auto-generated method stub

    }

    @Override
    public Set<QName> getHeaders() {
        // TODO Auto-generated method stub
        return null;
    }

    // ... default implementations of other methods go here

});
// as per Jean-Bernard Pellerin's commententer code here setting handlerChain list here, after all handlers were added to list

binding.setHandlerChain(handlersList);

Because I'm not sure if this is settle correctly.

All help will be appreciated. Thanks! =)

The problem was in my own generated classes when I tried to call the webservice, I couldnt pass the CustomSecurityHeader and was because the class APIService wasn't generated correctly. For this case, and after an investigation I figured out what happened.

At first I was using soapUI program to autogenerate the classes sending the .wsdl file that Paypal gives to developers. But, the important thing that I didnt do it's stablishing a custom argument necessary to do a correct generated code:

-XadditionalHeaders -Xnocompile

This was extracted for an other tutorial who use “wsimport” command (for Jax-WS library generated code) and the guy who uses this command added those arguments aswell. The complete line is. I could either use a Terminal Console command like this:

wsimport -keep -XadditionalHeaders -Xnocompile -p paypal.test Desktop/PayPalSvc.wsdl/

To generate the correct classes and pass the CustomSecurityHeader.

My present code to do a correct request is:

String usuario = "carlos.martinez_api1.netijam.com";
String password = "XEDdsafXSCE4";
String firma = "A6aFJz-KhDsdf7f-668iCsdfweFplAcbDlof-vWP5wsdfsdEAy9T-d.";
//Make encapsulated object of my own class cabeceraPeticiones
CabeceraPeticiones cabeceraPeticiones = CabeceraPeticiones.getInstanceCabecera(usuario, password, firma);
//Call the method that takes the header in the format that webservice needs
Holder<CustomSecurityHeaderType> cabeceraSeguridad = cabeceraPeticiones.getCabecera();      

//Set the connection params to work properly and the webservice method that I want to execute
PayPalAPIInterfaceService pp = new PayPalAPIInterfaceService();
GetExpressCheckoutDetailsReq gECR = new GetExpressCheckoutDetailsReq();
GetExpressCheckoutDetailsRequestType gECDRT = new GetExpressCheckoutDetailsRequestType();
PayPalAPIAAInterface expressCheckoutPort = pp.getPayPalAPIAA(); 
((BindingProvider) expressCheckoutPort).getRequestContext().put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY,  "https://api-aa-3t.sandbox.paypal.com/2.0/");

//I take the response from the webservice operation that I execute, passing the header and the webservice request param
GetExpressCheckoutDetailsResponseType response = expressCheckoutPort.getExpressCheckoutDetails(gECR, cabeceraSeguridad);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM