I recently undertook a project that involved the consumption of Exchange Web Services through PHP on Redhat Linux. After a few tests, I knew this wasn’t going to be easy as I kept getting a 401 error. After trying out a few libraries, I decided to start off with a simple test so I could get to the root of the problem.
<?php $host = 'foo.ews-host.com'; $username = 'username'; // just need the name, no domain, nothing else $password = 'password'; $ch = curl_init('https://'.$host.'/ews/services.wsdl'); curl_setopt($ch, CURLOPT_VERBOSE, true); curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_HEADER, 0); curl_setopt($ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1); curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_NTLM); curl_setopt($ch, CURLOPT_USERPWD, $username.':'.$password); $response = curl_exec($ch); $info = curl_getinfo( $ch ); $error = curl_error ($ch); print_r(array($response,$info,$error));
I ran the simple test script on my window’s vm and received the contents of the wsdl, so I know the test script works. However, running the test script on Linux (I tried Redhat and Ubuntu) resulted in a 401 status code.
Exchange Web Services (EWS) relies on NTLMv2 for all service requests, even for just obtaining the wsdl. The 401 unauthorized status code was coming from NTLM, and after some brief research it appeared as if Linux didn’t support NTLMv2… but why? I tried circumventing the problem by installing the Cntlm proxy, but I had no luck in using it through Exchange Web Services. I’m not saying Cntlm is bad, I’m just saying it didn’t work for me… and at this point I was just feeling like I was trying to band-aid the problem instead of fixing it.
I noticed there have been many references to NTLM in the libcurl changelog, so I decided to compile the latest stable version (7.25 right now).
The installation went smoothly:
1. mkdir curlbuild && cd curlbuild
2. Pull the latest copy from http://curl.haxx.se/dlwiz/?type=source&os=-
3. tar -zxvf curl-7.25.0.tar.gz
4. cd curl-7.25.0
5. Install OpenSSL dev
– Redhat yum install openssl-devel
– Ubuntu apt-get install libcurl4-openssl-dev
6. ./configure -with-ssl
8. make install
9. Remove old link
– Redhat rm /usr/lib/libcurl.so.4
– Ubuntu rm /usr/lib/i386-linux-gnu/libcurl.so.4 OR rm /usr/lib/libcurl.so.4
10. Create new link
– Redhat ln -s /usr/local/lib/libcurl.so.4.2.0 /usr/lib/libcurl.so.4
– Ubuntu ln -s /usr/local/lib/libcurl.so.4.2.0 /usr/lib/i386-linux-gnu/libcurl.so.4 OR ln -s /usr/local/lib/libcurl.so.4.2.0 /usr/lib/libcurl.so.4
11. Check version, should be the newly installed version
– PHP $version = curl_version();
– Curl curl -V
12. Remove/delete curlbuild install directory
I ran my test script again, and SUCCESS! The updated libcurl allowed me to authenticate with NTLMv2 on Linux!
Before and after of version:
curl 7.25.0 (x86_64-unknown-linux-gnu) libcurl/7.21.3 OpenSSL/0.9.8o zlib/18.104.22.168 libidn/1.18 Protocols: dict file ftp ftps gopher http https imap imaps ldap ldaps pop3 pop3s rtsp smtp smtps telnet tftp Features: GSS-Negotiate IDN IPv6 Largefile NTLM SSL libz
curl 7.25.0 (x86_64-unknown-linux-gnu) libcurl/7.25.0 OpenSSL/0.9.8o zlib/22.214.171.124 libidn/1.18 Protocols: dict file ftp ftps gopher http https imap imaps ldap ldaps pop3 pop3s rtsp smtp smtps telnet tftp Features: IDN IPv6 Largefile NTLM NTLM_WB SSL libz