Exchange Web Services (EWS), NTLMv2 and Linux
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
7. make
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:
Before:
curl 7.25.0 (x86_64-unknown-linux-gnu) libcurl/7.21.3 OpenSSL/0.9.8o zlib/1.2.3.4 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
After:
curl 7.25.0 (x86_64-unknown-linux-gnu) libcurl/7.25.0 OpenSSL/0.9.8o zlib/1.2.3.4 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
You are amazingly awesome for finding this information out. Using your notes here, I finally discovered how to fix my broken authentication script that was using PHP’s NuSOAP to communicate via EWS to Exchange 2010. It used to work, then all of a sudden stopped. Was wracking my brain for what seemed like nearly 2 years. I’m on shared hosting. I’m guessing a Windows security update may have modified default behavior since it’s (apparently) not just my (shared) server OS that’s causing issue but others are experiencing it too. However, I tested this on Debian running off a Linode account, and it started working again. Guess it’s time to move to a different host.
Thanks again!!!!!
Brendon Kozlowski said this on July 27, 2012 at 4:50 pm |
Thank you very much for this. I would not have known (nor thought) to update my cURL installation. I’m now at 7.28 and it’s working properly.
Kevin DeCapite said this on November 6, 2012 at 3:27 pm |
After following directions just had to restart apache and worked perfectly
doubter said this on November 22, 2012 at 7:29 am |
just a quick note, on Centos 6 the path is not /usr/lib but /usr/lib64, for those who need to do it there 🙂 thanks for this post, very usefull !
Radek Havelka said this on January 28, 2013 at 10:37 am |
another quick note for Centos 6 regarding SSL (OpenSSl)
./configure –with-ssl=/usr/bin/
this post was very usefull for my projetct and also for our ADMINISTRATOR/ DEVELOPERS relationship
We use curl-7.29.0.
Sabrina said this on March 12, 2013 at 10:22 am |