Partager via


Comment programmer en code natif (API) pour Exchange Web Service en C/C++ (fr-FR)

 


Avant de commencer 

  • Je vais beaucoups utiliser l'acronyme EWS dans l'article pour garder le texte lisible. (pour dire Exchange Web Service) 

Pourquoi programmer en language natif pour EWS

  •  Le code est beaucoups plus portable entre les systemes d'exploitation; quelque examples plus-bas
    • Permet de faire un CGI simple qui peut rouler sur un IIS ou un serveur web apache pour parler au serveur Exchange. (Pour faire par exemple un CGI qui lit le "free/busy" d'une boite aux lettres d'un centre d'assistance et qui peut envoyer les demandes là par vos usagés)
    • Permet au code de parler a votre serveur Exchange directment d'un appareil mobil
  • Permet d'apprendre la base en matière d'I/O pour le HTTP/HTTPS
  • Le résultat est généralement plus petit et plus rapide

Pourquoi ne pas programmer en language natif pour EWS

  • L'apprentissage est plus dur
  • Programmer en .NET par exemple est plus facile et plus rapide
  • Les IDE de .NET ont habituellement des assistants pour aider a faire des tâches 

La configuration utilisé

J'ai utilisé Visual Studio 2010 SP1 sous Windows


Qu'est-ce que vous avez de besoin

Beaucoups d'autre options existe pour la librairie NTLM et pour l'OpenSSL (comme libcurl ou WinHTTP)

Exchange répond en XML, alors vous pouvez utiliser xmllite, minixml ou juste gérer l'XML à la main, c'est votre chois


Quoi faire

  • Décompresser les librairies et faire un projet vide.
  • De la librairie libntlm, exporter le fichier .def du fichier libntlm-0.dll et faire le .lib.
  • Dans votre projet lier le .lib de libntlm, OpenSSL et de Winsock.

  • Inclure les fichiers de la librairie d'OpenSSL et libntlm

#include <openssl/ssl.h>
#include <openssl/err.h>
#include <openssl/bio.h>
#include "ntlm.h" 

  •  Utiliser l'API de Winsock pour ce connecter a votre serveur Exchange, un peu comme cela; (pas de contrôle d'erreures!)

struct hostent *hp;
struct sockaddr_in addr;
WORD wVersionRequested = MAKEWORD(2,2);
int sock;
WSADATA wsaData;
           
WSAStartup(wVersionRequested, &wsaData);
if(!(hp=gethostbyname("server_host")))
    return 0;
memset(&addr,0,
sizeof(addr));
addr.sin_addr=*(struct in_addr*)
hp->h_addr_list[0];
addr.sin_family=AF_INET;
addr.sin_port=htons(443);
if((sock=socket(AF_INET,SOCK_STREAM, IPPROTO_TCP))<0)
   return 0;
if(connect(sock,(struct sockaddr *)&addr, sizeof(addr))<0)
   return 0;
return 1;

  • Utiliser l'API d'OpenSSLpour vos connecté en SSL avec le "socket" reçu de Winsock, un peu comme cela; (pas de contrôle d'erreures! et je ne valide pas le certificat du tout!)

    const SSL_METHOD *meth;
    SSL *ssl;
    BIO *sbio;
    BIO *rbio;
    BIO *wbio;
    SSL_CTX *ctx;

    SSL_library_init();
    SSL_load_error_strings();
    meth=SSLv23_method();
    ctx=SSL_CTX_new(meth);

    ssl=SSL_new(ctx);
    sbio=BIO_new_socket(sock,BIO_NOCLOSE);

SSL_set_bio(ssl,sbio,sbio);
SSL_connect(ssl);

  •  Envoyer une demande vide a votre serveur Exchange pour générer un code d'erreur 401. L'erreur 401 veut dire que votre serveur Exchange doit vous authentifier et cela en  mode NTLM

SSL_write(ssl,"GET /EWS/Services.wsdl HTTP/1.1\r\nUser-Agent: test\r\nHost: serverhost:443\r\n\r\n",strlen("GET /EWS/Services.wsdl HTTP/1.1\r\nUser-Agent: test\r\nHost: serverhost:443\r\n\r\n"));

Regarder dans la réponde pour "WWW-Authenticate: NTLM". Si cela n'est pas là, alors soyez sure d'avoir activé ce mode dans votre IIS du serveur Exchange avec le rôle de CAS.

 

  • Utiliser la librairie libntlm pour vous authentifier (J'utilise deux fonctions base64, enc.Base64enc & enc.Base64dec. Je ne les ai pas montrées pour garder le tout facile a lire, mais ce sont des fonctions faciles a trouver sur internet (comme ici ou ici)

string encoded, encodedpass, decoded, sBuffer;

char cRequest[1024];
char cBuffer[1024];
tSmbNtlmAuthRequest request;
tSmbNtlmAuthResponse response;

ZeroMemory(cRequest, 1024);
buildSmbNtlmAuthRequest (&request, "username", "domain");
if (SmbLength(&request) > 1024)
    return 0;
encoded = enc.Base64enc((unsigned char *) &request, SmbLength(&request));
_snprintf(cRequest, 1024, "GET /EWS/Services.wsdl HTTP/1.1\r\nHost: serverhost\r\nConnection: Keep-Alive\r\nAuthorization: NTLM %s\r\n\r\n", encoded.c_str());
SSL_write(ssl, cRequest);

// lire la réponse, sBuffer = réponse NTLM

decoded = enc.Base64dec(sBuffer);
buildSmbNtlmAuthResponse((tSmbNtlmAuthChallenge *)decoded.c_str(), &response, "username", "password");
encodedpass = enc.Base64enc((unsigned char *) &response, SmbLength(&response));
_snprintf(cRequest, 1024, "GET /EWS/Services.wsdl HTTP/1.1\r\nHost: servername\r\nConnection: Keep-Alive\r\nAuthorization: NTLM %s\r\n\r\n", encodedpass.c_str());
SSL_write(ssl, cRequest);

// Si IIS répond avec 200 tout est ok !

  • Maintenant vous ete prêt a envoyer des commandes a otre serveur Exchange !

*En exemple recevoir une liste de distribution:
*
char cRequest[1024];
char request[1024] =
"<?xml version=\1.0\ encoding=\utf-8\?>"
"<soap:Envelope xmlns:soap=\http://schemas.xmlsoap.org/soap/envelope//
" xmlns:t=\http://schemas.microsoft.com/exchange/services/2006/types\>"
" <soap:Body>"
" <ExpandDL xmlns=\http://schemas.microsoft.com/exchange/services/2006/messages/
" xmlns:t=\http://schemas.microsoft.com/exchange/services/2006/types\>"
" <Mailbox xmlns=\http://schemas.microsoft.com/exchange/services/2006/messages\>"
" <EmailAddress xmlns=\http://schemas.microsoft.com/exchange/services/2006/types\>test@constoco.com</EmailAddress>"
" </Mailbox>"
" </ExpandDL>"
" </soap:Body>"
"</soap:Envelope>";

ZeroMemory(cRequest, 1024);
_snprintf(cRequest, 1024, "POST /ews/Exchange.asmx HTTP/1.1\r\n"
"Host: servername\r\n"
"Content-Length: %d\r\n"
"Content-Type: text/xml\r\n\r\n%s", strlen(request), request);

 // envoyé et lire la réponse...

  •  A partir de ce point vous avez le feu vert avec l'EWS pour toute transaction(s)

 


Référence

Quick and Dirty UNIX Shell Scripting with EWS - L'idée de départ est là.
EWSEditor - Pour générer des messages SOAP.
Exchange Web Services (EWS) - Référence d'MSDN avec un tas d'exemples.
theForger's Win32 API Programming Tutorial - Un site très bien pour apprendre le language natif.

Autres langues

Cet article est également disponible les langues suivantes :