Accessing a WSDL with NTLM over SSL on IIS

BrendonKoz
2010-10-19
2013-06-06
  • BrendonKoz
    BrendonKoz
    2010-10-19

    I'm having problems with the ability to access a WSDL file on an IIS server (Exchange 2010 EWS API) that uses NTLM authentication over an SSL connection.

    When I strictly used cURL by itself to access the WSDL file, the handshake process alone took approximately 1.031 seconds. When trying to use NuSOAP to access the WSDL file *and* call a method, it is returning an error within 0.06 seconds. The other issue I'm having is that the debug string seems to be cleared when I run the call() method, and since no information is found, the debug string is empty (prior to the call it has data). Is this expected behavior?

    A pastebin to the WSDL file can be found here: http://pastebin.org/214070
    The example cURL code is shown below:

    <?php
        $c = curl_init();
        curl_setopt($c, CURLOPT_URL, 'https://owa.sals.edu/EWS/Services.wsdl');
        curl_setopt($c, CURLOPT_FAILONERROR, true); 
        curl_setopt($c, CURLOPT_SSL_VERIFYPEER, 0);
        curl_setopt($c, CURLOPT_RETURNTRANSFER, 1);
        curl_setopt($c, CURLOPT_USERPWD, "user@example.com:password");
        curl_setopt($c, CURLOPT_HTTPAUTH, CURLAUTH_NTLM);
        $page = curl_exec($c);
        curl_close($c);
        echo '<pre>'.htmlspecialchars($page).'</pre>';
    ?>
    

    My NuSOAP code, which is attempting to mimic the cURL script is below (with various commented out code and attempts made - all with the same results):

    <?php
        include_once('./lib/nusoap.php');
        $username = 'user@example.com';
        $password = 'password';
        $ews_url  = 'https://owa.example.com/ews/Services.wsdl';
        $soapclient = new nusoap_client($service, true);
        $err = $soapclient->getError();
        if($err){
            die('Error: '.$err);
        }
        $soapclient->setCredentials($username, $password, 'ntlm');
    #    $soapclient->setCredentials('', '', 'ntlm');
    #    $soapclient->setUseCurl(true);
    #    $soapclient->useHTTPPersistentConnection();
    #    $soapclient->setCurlOption(CURLOPT_HTTPAUTH, CURLAUTH_NTLM);
    #    $soapclient->setCurlOption(CURLOPT_SSL_VERIFYPEER, 0);
    #    $soapclient->setCurlOption(CURLOPT_RETURNTRANSFER, 1);
    #    $soapclient->setCurlOption(CURLOPT_USERPWD, $username.':'.$password);
        $soapclient->soap_defencoding = 'UTF-8';
        $proxy = $soapclient->getProxy();
        echo '<pre>'; echo htmlspecialchars($soapclient->debug_str, ENT_QUOTES); echo '</pre>';
        if($err){
            die('Error: '.$err);
        }
        
        $xml  = '<FindItem xmlns="http://schemas.microsoft.com/exchange/services/2006/messages" xmlns:t="http://schemas.microsoft.com/exchange/services/2006/types" Traversal="Shallow"><ItemShape><t:BaseShape>IdOnly</t:BaseShape><t:AdditionalProperties><t:FieldURI FieldURI="message:From"/><t:FieldURI FieldURI="item:Subject"/><t:FieldURI FieldURI="message:IsRead"/><t:FieldURI FieldURI="item:DateTimeReceived"/><t:FieldURI FieldURI="calendar:Start"/><t:FieldURI FieldURI="calendar:End"/><t:FieldURI FieldURI="calendar:Location"/><t:FieldURI FieldURI="task:Status"/><t:FieldURI FieldURI="task:DueDate"/></t:AdditionalProperties></ItemShape><IndexedPageItemView Offset="0" MaxEntriesReturned="5" BasePoint="Beginning"/><ParentFolderIds><t:DistinguishedFolderId Id="inbox"/></ParentFolderIds></FindItem>';
        $operation = 'FindItem';
        $result = $soapclient->call($operation, $xml);
        echo '<pre>'; print_r($result); echo '</pre>';
        if($soapclient->fault){
            echo 'FAULT: ';
            echo '<pre>'; print_r($result); echo '</pre>';
        }else{
            $err = $soapclient->getError();
            if ($err) {
                echo '<p><b><u>Error</u>:</b><br />' . $err . '</p>';
            }else{
                echo 'Connection succeeded.';
            }
        }
    ?>
    

    The error message given is: "operation FindItem not present in WSDL."
    Prior to that error message, I was receiving the message of "no operations defined in the WSDL document!".
    …I believe this to be NTLM/SSL related.

    The debug string contains the following information:

    2010-10-19 16:09:06.799285 nusoap_client: ctor wsdl=1 timeout=0 response_timeout=30
    endpoint=NULL
    2010-10-19 16:09:06.799404 nusoap_client: will use lazy evaluation of wsdl from
    2010-10-19 16:09:06.799464 nusoap_client: setCredentials username=user@example.com authtype=ntlm certRequest=
    array(0) {
    }
    2010-10-19 16:09:06.799531 nusoap_client: in getProxy endpointType=wsdl
    wsdl=NULL
    2010-10-19 16:09:06.799592 nusoap_client: instantiating wsdl class with doc:
    2010-10-19 16:09:06.799677 wsdl: ctor wsdl= timeout=0 response_timeout=30
    2010-10-19 16:09:06.799735 wsdl: parse and process WSDL path=
    2010-10-19 16:09:06.799802 wsdl: setCredentials username=user@example.com authtype=ntlm certRequest=
    array(0) {
    }
    2010-10-19 16:09:06.799865 wsdl: parse and process WSDL path=
    2010-10-19 16:09:06.799929 nusoap_client: checkWSDL
    2010-10-19 16:09:06.799985 wsdl: getOperations for port '' bindingType http://schemas.xmlsoap.org/wsdl/soap/
    2010-10-19 16:09:06.800037 wsdl: getOperations found no operations for port '' bindingType http://schemas.xmlsoap.org/wsdl/soap/
    2010-10-19 16:09:06.800091 wsdl: getOperations for port '' bindingType http://schemas.xmlsoap.org/wsdl/soap12/
    2010-10-19 16:09:06.800142 wsdl: getOperations found no operations for port '' bindingType http://schemas.xmlsoap.org/wsdl/soap12/
    2010-10-19 16:09:06.800197 nusoap_client: getOperations returned false
    2010-10-19 16:09:06.800254 nusoap_client: Error from _getProxyClassCode, so return NULL

    From what I can tell, no where in the debug does it establish a connection with the WSDL file. Does anyone have any ideas as to what I could try next? The location of the WSDL file is correct with 0 redirects (cURL helped me to verify this).

    Thank you.

     
  • BrendonKoz
    BrendonKoz
    2010-10-22

    I've solved this problem. It seems to be a problem with the Services.wsdl file's formatting…among stupid, overlooked mistakes in my own code. My solution has been posted at StackOverflow, but I'll post the example working code here as well.

    <?php
        include_once('./lib/nusoap.php');
        $username = 'username@example.com';
        $password = 'password';
        $endpoint = 'http://your.local.version/of/Services.wsdl';
        $wsdl = true;
        $soapclient = new nusoap_client($endpoint, $wsdl);
        $soapclient->setCredentials($username, $password, 'ntlm');
        $xml  = '<FindItem xmlns="http://schemas.microsoft.com/exchange/services/2006/messages"';
        $xml .= ' xmlns:t="http://schemas.microsoft.com/exchange/services/2006/types" Traversal="Shallow">';
        $xml .= '   <ItemShape>';
        $xml .= '       <t:BaseShape>IdOnly</t:BaseShape>';
        $xml .= '       <t:AdditionalProperties>';
        $xml .= '           <t:FieldURI FieldURI="message:From"/>';
        $xml .= '           <t:FieldURI FieldURI="item:Subject"/>';
        $xml .= '           <t:FieldURI FieldURI="message:IsRead"/>';
        $xml .= '           <t:FieldURI FieldURI="item:DateTimeReceived"/>';
        $xml .= '           <t:FieldURI FieldURI="calendar:Start"/>';
        $xml .= '           <t:FieldURI FieldURI="calendar:End"/>';
        $xml .= '           <t:FieldURI FieldURI="calendar:Location"/>';
        $xml .= '           <t:FieldURI FieldURI="task:Status"/>';
        $xml .= '           <t:FieldURI FieldURI="task:DueDate"/>';
        $xml .= '       </t:AdditionalProperties>';
        $xml .= '   </ItemShape>';
        $xml .= '   <IndexedPageItemView Offset="0" MaxEntriesReturned="5" BasePoint="Beginning"/>';
        $xml .= '   <ParentFolderIds>';
        $xml .= '       <t:DistinguishedFolderId Id="inbox"/>';
        $xml .= '   </ParentFolderIds>';
        $xml .= '</FindItem>';
        $operation = 'FindItem';
        $result = $soapclient->call($operation, $xml);
        echo '<pre>'; print_r($result); echo '</pre>';
    ?>
    

    The solution was missed while reading/skimming over other solutions. An additional section needed to be added to the WSDL file to let languages other than .NET know where to look for further information. (In this instance, changing the types.xsd was not necessary and actually broke the script.) Solution from a Java (bedework) Wiki: http://www.bedework.org/trac/bedework/wiki/ExchangeWS

     
  • Scott Nichol
    Scott Nichol
    2011-01-13

    Thank you for posting your solution here.