ZSI and Zimbra

Tony
2007-08-24
2013-05-02
  • Tony
    Tony
    2007-08-24

    First, I am new to wsdl and SOAP in general and ZSI in specific, so please be gentle.

    I am trying to get ZSI to interoperate with Zimbra.  Since Zimbra has no wsdl, I am attempting to write one by hand.  To do this, I have shamelessly stolen any wsdl ideas that I have been able to find along the way.

    The specific problem that I've run into is that Application requests to the administrative interface need a specific SOAP header.  Essentially you start by authenticating to the server which returns an authentication response that should then be passed back to each application call as a SOAP header.

    An example of such a message is:

    <soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope">
      <soap:Header>
        <context xmlns="urn:zimbra">
          <authToken>REALLY_LONG_RANDOM_STRING_HERE</authToken>
          <sessionId id="639">639</sessionId>
        </context>
      </soap:Header>
      <soap:Body>
        <GetAccountRequest xmlns="urn:zimbraAdmin">
          <account by="name">foo@mail.my.domain</account>
        </GetAccountRequest>
      </soap:Body>
    </soap:Envelope>

    The following is a portion of my wsdl that purports to perform this:

       <wsdl:types>
       <xsd:schema
          targetNamespace="urn:zimbraAdmin"
          xmlns:xsd="http://www.w3.org/2001/XMLSchema">

        <xsd:element name="context">
          <xsd:complexType>
            <xsd:sequence>
              <xsd:element name="authToken" type="xsd:string"/>
              <xsd:element name="sessionId" type="xsd:string">
                <xsd:complexType>
                  <xsd:attribute name="id" type="xsd:string"/>
                </xsd:complexType>
              </xsd:element>
            </xsd:sequence>
          </xsd:complexType>
        </xsd:element>

       </xsd:schema>
       </wsdl:types>

       <wsdl:message name="context">
          <wsdl:part name="context" element="tns:context"/>
       </wsdl:message>

       <wsdl:portType name="AppPort">
         <wsdl:operation name="GetAccountRequest">
           <wsdl:input message="tns:GetAccountRequest"/>
           <wsdl:output message="tns:GetAccountResponse"/>
         </wsdl:operation>
       </wsdl:portType>

       <wsdl:binding name="AppBinding" type="tns:AppPort">
         <soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/>

         <wsdl:operation name="GetAccountRequest">
            <soap:operation soapAction="/service/admin/soap/GetAccountRequest"/>
           <wsdl:input>
             <soap:header use="literal" message="tns:context"/>
             <soap:body use="literal"/>
           </wsdl:input>
           <wsdl:output>
             <soap:header use="literal" message="tns:context"/>
             <soap:body use="literal"/>
           </wsdl:output>
         </wsdl:operation>

       </wsdl:binding>

    wsdl2py does not complain about this and produces (what I can only assume is) appropriate stub code.  However I cannot figure out how to get the context into the serialized output.

    Currently, I am using the following test code.

    import os
    import sys
    import ZimbraAdmin_services as ZA
    import ZimbraAdmin_services_types as ZAT

    server_url = 'https://my.domain:7071/service/admin/soap/'

    AuthPort = ZA.ZimbraAdminLocator().getAuthPort(url=server_url, tracefile=sys.stdout)

    req = ZA.AuthRequest()
    req._name = 'admin-user'
    req._password = 'admin-password'

    auth_resp = AuthPort.AuthRequest(req)

    myContext = ZAT.ns0.context_Dec().pyclass
    myContext._authToken = auth_resp._authToken
    myContext._sessionId = auth_resp._sessionId

    AppPort = ZA.ZimbraAdminLocator().getAppPort(url=server_url, tracefile=sys.stdout)

    myGA_req = ZA.GetAccountRequest()
    myGA_req._account = 'foo@mail.my.domain'

    GA_resp = AppPort.GetAccountRequest(myGA_req)

    All of the authentication stuff seems to be working.  I get a 200 response with the appropriate attributes.

    What I cannot figure out, is how I provide the context to the App call.  I've tried adding it as:
         - a keyword argument to the AppPort definitition
         - a keyword argument to the GetAccountRequest() call
         - doing nothing at all

    All 3 produce no context SOAP header and the corresponding complaint from the server about un-authenticated messages.

    Any help would be greatly apreciated.

    --Tony

     
    • Tony
      Tony
      2007-08-24

      Some additional info...

      First, I apologize for the horrible formatting of my previous message.  I was unaware that sourceforge would eat all my leading spaces that way.  In the future, I shall endeavor to use HTML markup when formatting is necessary.

      Second, I am using version 2.0 of ZSI and version 2.4 of python if that has any bearing.

      Third, when I mentioned the things I had tried, I meant the AppPort *declaration* in the first item. i.e. AppPort = ...getAppPort(url=server_url, context=myContext, tracefile=sys.stdout)

      Lastly, upon reflection, I think that the first 2 things that I tried resulted in a python exception along the lines of "TypeError: GetAccountRequest() got an unexpected keyword argument 'context'".  (with the approriate function name for each placement)