Zimbra SOAP connection for AuthToken using WSDL

Have a great idea for extending Zimbra? Share ideas, ask questions, contribute, and get feedback.
SteliosPh
Posts: 1
Joined: Tue Apr 16, 2019 9:19 am

Zimbra SOAP connection for AuthToken using WSDL

Postby SteliosPh » Tue Apr 16, 2019 9:43 am

Hello,

I am currently trying to get the SOAP code to work.

I have downloaded the ZimbraUserService.wsdl and all the related xsd files.
From there i have automatically generated the java code using the apache-cxf-3.3.1 wsdl2java.

After stumbling a bit i wrote a custom AuthRequest to make sure that everything is working correcty

Code: Select all

package com.somewhere.swing.calendar;

import java.net.URL;

import javax.xml.soap.MessageFactory;
import javax.xml.soap.MimeHeaders;
import javax.xml.soap.Name;
import javax.xml.soap.SOAPBody;
import javax.xml.soap.SOAPBodyElement;
import javax.xml.soap.SOAPConnection;
import javax.xml.soap.SOAPConnectionFactory;
import javax.xml.soap.SOAPEnvelope;
import javax.xml.soap.SOAPException;
import javax.xml.soap.SOAPHeader;
import javax.xml.soap.SOAPMessage;
import javax.xml.soap.SOAPPart;

public class soap {

   private static String zimbra_user = "user";
   private static String zimbra_password = "passsssword;

   public static void main(String args[]) {
      connectWithRawSoap();
   }

   private static void connectWithRawSoap() {
      String soapEndpointUrl = "http://my-urlservice/soap";
      String soapAction = "http://my-url:443/service/soap/AuthRequest";

      callSoapWebService(soapEndpointUrl, soapAction);
   }

   private static void callSoapWebService(String soapEndpointUrl, String soapAction) {
      try {
         // Create SOAP Connection
         SOAPConnectionFactory soapConnectionFactory = SOAPConnectionFactory.newInstance();
         SOAPConnection soapConnection = soapConnectionFactory.createConnection();

         // Send SOAP Message to SOAP Server
         URL url = new URL(soapEndpointUrl);

         SOAPMessage soapResponse = soapConnection.call(createSOAPRequest(soapAction), url);

         // Print the SOAP Response
         System.out.println("Response SOAP Message:");
         soapResponse.writeTo(System.out);
         System.out.println();

         soapConnection.close();
      } catch (Exception e) {
         System.err.println(
               "\nError occurred while sending SOAP Request to Server!\nMake sure you have the correct endpoint URL and SOAPAction!\n");
         e.printStackTrace();
      }
   }

   private static SOAPMessage createSOAPRequest(String soapAction) throws Exception {
      MessageFactory messageFactory = MessageFactory.newInstance();
      SOAPMessage soapMessage = messageFactory.createMessage();

      createSoapEnvelope(soapMessage);

      MimeHeaders headers = soapMessage.getMimeHeaders();
      headers.addHeader("SOAPAction", soapAction);

      soapMessage.saveChanges();

      /* Print the request message, just for debugging purposes */
      System.out.println("Request SOAP Message:");
      soapMessage.writeTo(System.out);
      System.out.println("\n");

      return soapMessage;
   }

   private static void createSoapEnvelope(SOAPMessage soapMessage) throws SOAPException {
      SOAPPart soapPart = soapMessage.getSOAPPart();

      // SOAP Envelope
      SOAPEnvelope envelope = soapPart.getEnvelope();
      Name context = envelope.createName("context", null, "urn:zimbra");
      Name xml = envelope.createName("format", "type", "xml");
      //context.

      Name authRequest = envelope.createName("AuthRequest", null, "urn:zimbraAccount");
      Name account = envelope.createName("account");
      Name password = envelope.createName("password");

      // SOAP Body
      SOAPHeader header = envelope.getHeader();
      //      header.addChildElement(context).addChildElement(xml);

      SOAPBody soapBody = envelope.getBody();
      SOAPBodyElement auth_body = soapBody.addBodyElement(authRequest);
      auth_body.addChildElement(account).addAttribute(envelope.createName("by"), "name").addTextNode(zimbra_user);
      auth_body.addChildElement(password).addTextNode(zimbra_password);
   }

}


This has validated that the connection works as expected.

Then i have started working on the wsdl code in order to get that to work.
After a few issues i.e Fixing the PKIX path in order to register the cacert, finding the correct code to send the SOAP command.

I have managed to come up with the following code correctly sends an authentication command and receives the AuthResp

Code: Select all

package com.something.calendar;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Set;

import javax.xml.bind.JAXBElement;
import javax.xml.namespace.QName;
import javax.xml.soap.SOAPException;
import javax.xml.soap.SOAPMessage;
import javax.xml.ws.handler.Handler;
import javax.xml.ws.handler.HandlerResolver;
import javax.xml.ws.handler.MessageContext;
import javax.xml.ws.handler.PortInfo;
import javax.xml.ws.handler.soap.SOAPHandler;
import javax.xml.ws.handler.soap.SOAPMessageContext;

import com.zimbra.wsdl.zimbraservice_wsdl.ZcsPortType;
import com.zimbra.wsdl.zimbraservice_wsdl.ZcsService;

import zimbra.AccountBy;
import zimbra.AccountSelector;
import zimbra.AuthTokenControl;
import zimbra.HeaderContext;
import zimbraaccount.AuthRequest;
import zimbraaccount.AuthResponse;
import zimbraaccount.AuthToken;
import zimbraaccount.GetAccountInfoRequest;
import zimbraaccount.GetAccountInfoResponse;
import zimbraaccount.ObjectFactory;

public class SoapTest {

   private static String zimbra_user = "user;
   private static String zimbra_password = "pass";

   static class HeaderHandlerResolver implements HandlerResolver {

      @Override
      public List<Handler> getHandlerChain(PortInfo portInfo) {
         List<Handler> handlerChain = new ArrayList<Handler>();
         HandlerHeader hh = new HandlerHeader();
         handlerChain.add(hh);
         return handlerChain;
      }
   }

   static class HandlerHeader implements SOAPHandler<SOAPMessageContext> {

      @Override
      public Set<QName> getHeaders() {
         return Collections.emptySet();
      }

      @Override
      public boolean handleMessage(SOAPMessageContext context) {
         Boolean outboundProperty = (Boolean) context.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY);
         if (outboundProperty.booleanValue()) {
            try {
               System.out.println("\nOutbound message:");
               System.out.println("******************");
               context.getMessage().writeTo(System.out);
               System.out.println("\n******************");
            } catch (SOAPException e) {
               e.printStackTrace();
            } catch (IOException e) {
               e.printStackTrace();
            }

         } else {
            try {
               System.out.println("\nInbound message:");
               SOAPMessage message = context.getMessage();
               System.out.println("\n******************");
               message.writeTo(System.out);
               System.out.println("\n******************");
            } catch (SOAPException e) {
               // TODO Auto-generated catch block
               e.printStackTrace();
            } catch (IOException e) {
               // TODO Auto-generated catch block
               e.printStackTrace();
            }
         }

         return true;
      }

      @Override
      public boolean handleFault(SOAPMessageContext context) {
         try {
            SOAPMessage message = context.getMessage();
            ByteArrayOutputStream out = new ByteArrayOutputStream();
            message.writeTo(out);
            String strMsg = new String(out.toByteArray());
            System.err.println("FAULT:");
            System.err.println(strMsg);
         } catch (SOAPException | IOException ex) {
            ex.printStackTrace();
         }
         return true;
      }

      @Override
      public void close(MessageContext context) {
      }

   }

   public static void main(String args[]) {
      connectAndAuthenticate();
   }

   private static void connectAndAuthenticate() {
      ObjectFactory zimbraAccountFactory = new ObjectFactory();
      AuthRequest authRequest = zimbraAccountFactory.createAuthRequest();

      AccountSelector accountSelector = new AccountSelector();
      accountSelector.setBy(AccountBy.NAME);
      accountSelector.setValue(zimbra_user);

      authRequest.setAccount(accountSelector);
      authRequest.setPassword(zimbra_password);

      ZcsService service = new ZcsService();
      HeaderHandlerResolver handlerResolver = new HeaderHandlerResolver();
      service.setHandlerResolver(handlerResolver);

      ZcsPortType port = service.getZcsServicePort();

      AuthResponse response = port.authRequest(authRequest);
      JAXBElement<AuthResponse> response2 = zimbraAccountFactory.createAuthResponse(response);

      AuthToken token = zimbraAccountFactory.createAuthToken();
      String resp = response2.getValue().getAuthToken();
      long lifeTime = response2.getValue().getLifetime();
      token.setValue(resp);
      token.setLifetime(lifeTime);
      authRequest.setAuthToken(token);

      zimbra.ObjectFactory zimbraFactory = new zimbra.ObjectFactory();

      HeaderContext c = zimbraFactory.createHeaderContext();
      c.setAuthToken(resp);
      AuthTokenControl tokenControl = zimbraFactory.createAuthTokenControl();
      tokenControl.setVoidOnExpired(true);
      c.setAuthTokenControl(tokenControl);

      GetAccountInfoRequest infoRequest = zimbraAccountFactory.createGetAccountInfoRequest();
      infoRequest.setAccount(accountSelector);
      GetAccountInfoResponse getAccountInfoRequest = port.getAccountInfoRequest(infoRequest);

      zimbraAccountFactory.createGetAccountInfoResponse();
   }
}



I have been trying for hours how to send the AuthRespond on to the next Request in order to get the response but what ever i have tried it did not work.
I cant seem to add the authtoken in my commands.

Exception in thread "main" com.sun.xml.internal.ws.fault.ServerSOAPFaultException: Client received SOAP Fault from server: no valid authtoken present Please see the server log to find more detail regarding exact cause of the failure.


Does anyone have any ideas how i can proceed from here and add the AuthResponse into the next commands ?
I have tried to use the following code
[url]https://forums.zimbra.org/viewtopic.php?t=732
[/url]
But unfortunately the code there is old, and not entirely clear what needs to be done.


User avatar
rcardozo1987
Posts: 8
Joined: Tue Sep 10, 2019 9:14 pm

Re: Zimbra SOAP connection for AuthToken using WSDL

Postby rcardozo1987 » Thu Sep 19, 2019 1:44 am

Hello @SteliosPh, maybe I can help you.

I did something similar, but using PHP SoapClient object. Is it usefull for you?

Regards

Return to “Developers”

Who is online

Users browsing this forum: No registered users and 2 guests