Zimbra SOAP connection for AuthToken using WSDL

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

Zimbra SOAP connection for AuthToken using WSDL

Post by SteliosPh »

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
viewtopic.php?t=732
But unfortunately the code there is old, and not entirely clear what needs to be done.
User avatar
rcardozo1987
Posts: 23
Joined: Tue Sep 10, 2019 9:14 pm
ZCS/ZD Version: NETWORK edition, Patch 8.8.15_P11

Re: Zimbra SOAP connection for AuthToken using WSDL

Post by rcardozo1987 »

Hello @SteliosPh, maybe I can help you.

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

Regards
viduc
Posts: 1
Joined: Wed Jan 06, 2021 2:48 pm

Re: Zimbra SOAP connection for AuthToken using WSDL

Post by viduc »

Hi!

did someone find solution? i have the same probleme with soapclient in php. I try few solution but i always have message:

Code: Select all

SoapFault : no valid authtoken present
panimozhi
Posts: 2
Joined: Mon Dec 14, 2020 1:17 pm

Re: Zimbra SOAP connection for AuthToken using WSDL

Post by panimozhi »

Anybody found solution for no valid Auth token problem
User avatar
barrydegraaff
Zimbra Employee
Zimbra Employee
Posts: 242
Joined: Tue Jun 17, 2014 3:31 am
Contact:

Re: Zimbra SOAP connection for AuthToken using WSDL

Post by barrydegraaff »

This one works, used it a couple months back:

https://github.com/zimbra-api/zimbra-api

Also to debug you should send us all the headers you are sending in the requests does does not work. Most likely you are not sending the correct authentication. Try and debug using curl.
--
Barry de Graaff
Email: barry.degraaff [at] synacor [dot] com
Admin of Zimbra-Community Github: https://github.com/orgs/Zimbra-Community/ and the
Zimlet Gallery https://gallery.zetalliance.org/extend/
rafaelppaulucci
Posts: 1
Joined: Fri Sep 30, 2022 10:24 pm

Re: Zimbra SOAP connection for AuthToken using WSDL

Post by rafaelppaulucci »

barrydegraaff wrote:This one works, used it a couple months back:

https://github.com/zimbra-api/zimbra-api

Also to debug you should send us all the headers you are sending in the requests does does not work. Most likely you are not sending the correct authentication. Try and debug using curl.
Hi Barry,

can you provide some example like setting up a COS?
Getting info of COS by name?

With this library i can create the cos but cannot parse attrs correctly, all settings became nulled.

I loosed 2 days trying to figure out this problem but im really tired.
Hope you can help.

Regards.
Post Reply