# The http_da plugin for clients and stand-alone services

Additional build steps required:

- Compile all sources with -DWITH_OPENSSL
- Link libgsoapssl (libgsoapssl++), or use the lib's stdsoap2.c/.cpp source
- Compile and link with plugin/httpda.c, plugin/md5evp.c, and plugin/threads.c

## Client-Side Usage

HTTP Basic Authentication is the default authentication supported by gSOAP. The credentials for client-side use age set with:

    soap.userid = "<userid>";
    soap.passed = "<passwd>";
    if (soap_call_ns__method(&soap, ...))
      ... // error

HTTP Basic Authentication should never be used over plain HTTP, because the user ID and password are sent in the clear. It is safe(r) to use over HTTPS, because the HTTP headers and body are encrypted.

The better alternative is to use HTTP Digest Authentication, which uses the digest (hash value) of the credentials and avoids a plain-text password exchange.

To use HTTP Disgest Authentication with gSOAP, register the http_da plugin:

    #include "httpda.h"
    soap_register_plugin(&soap, http_da);

To make a client-side service call:

    struct http_da_info info;
    http_da_save(&soap, &info, "<authrealm>", "<userid>", "<passwd>");
    if (soap_call_ns__method(&soap, ...))
      ... // error

The "<authrealm>" is a string that is associated with the server's realm. It can be obtained after an unsuccesful non-authenticated call:

    if (soap_call_ns__method(&soap, ...))
    {
      if (soap.error == 401) // HTTP authentication is required
      {
        const char *realm = soap.authrealm;
        ...
      }
      else
        ... // error
    }

Before a second call is made to the same endpoint that requires authentication, you must restore the authentication state and then finally release it:

    struct http_da_info info;

    http_da_save(&soap, &info, "<authrealm>", "<userid>", "<passwd>");
    if (soap_call_ns__method(&soap, ...))
      ... // error

    http_da_restore(&soap, &info);
    if (soap_call_ns__method(&soap, ...))
      ... // error

    soap_destroy(&soap); // okay to dealloc data
    soap_end(&soap);     // okay to dealloc data

    http_da_restore(&soap, &info);
    if (soap_call_ns__method(&soap, ...))
      ... // error

    http_da_release(&soap, &info);
    soap_destroy(&soap);
    soap_end(&soap);
    soap_done(&soap);

## Client Eample

    soap_register_plugin(&soap, http_da);
    // try calling without authenticating
    if (soap_call_ns__method(&soap, ...))
    {
      if (soap.error == 401) // HTTP authentication is required
      {
        if (!strcmp(soap.authrealm, authrealm)) // check authentication realm
        {
          struct http_da_info info; // to store userid and passwd
          http_da_save(&soap, &info, authrealm, userid, passwd);
          // call again, now with credentials
          if (soap_call_ns__method(&soap, ...) == SOAP_OK)
          {
            ... // process response data
            soap_end(&soap);
            ... // userid and passwd were deallocated (!)
            http_da_restore(&soap, &info); // get userid and passwd after soap_end()
            if (!soap_call_ns__method(&soap, ...) == SOAP_OK)
              ... // error
            http_da_release(&soap, &info); // free data and remove userid and passwd

## Server-Side Usage

Server-side HTTP Basic Authentication can be enforced by simply checking the soap.userid and soap.passwd values in a service method that requires client authentication:

    soap_register_plugin(&soap, http_da);
    ...
    soap_serve(&soap);
    ...
    int ns__method(struct soap *soap, ...)
    {
      if (!soap->userid || !soap->passwd || strcmp(soap->userid, "<userid>") || strmp(soap->passwd, "<passwd>"))
        return 401; // HTTP authentication required
      ...
    }

HTTP Digest Authentication is verified differently:

    soap_register_plugin(&soap, http_da);
    ...
    soap_serve(&soap);
    ...
    int ns__method(struct soap *soap, ...)
    {
      if (soap->authrealm && soap->userid)
      {
        passwd = ... // database lookup on userid and authrealm to find passwd
        if (!strcmp(soap->authrealm, authrealm) && !strcmp(soap->userid, userid))
        {
          if (!http_da_verify_post(soap, passwd)) // HTTP POST DA verification
          {
            ... // process request and produce response
            return SOAP_OK;
          }
        }
      }
      soap->authrealm = authrealm; // realm to send to client
      return 401; // Not authorized, challenge with digest authentication

The http_da_verify_post() function checks the HTTP POST credentials. To verify an HTTP GET operation, use http_da_verify_get().

## Server Example

    soap_register_plugin(&soap, http_da);
    ...
    soap_serve(&soap);
    ...
    int ns__method(struct soap *soap, ...)
    {
      if (soap->userid && soap->passwd) // Basic authentication
      {
        if (!strcmp(soap->userid, userid) && !strcmp(soap->passwd, passwd))
        {
          ... // can also check soap->authrealm
          ... // process request and produce response
          return SOAP_OK;
        }
      }
      else if (soap->authrealm && soap->userid) // Digest authentication
      {
        passwd = ... // database lookup on userid and authrealm to find passwd
        if (!strcmp(soap->authrealm, authrealm) && !strcmp(soap->userid, userid))
        {
          if (!http_da_verify_post(soap, passwd)) // HTTP POST DA verification
          {
            ... // process request and produce response
            return SOAP_OK;
          }
        }
      }
      soap->authrealm = authrealm; // realm to send to client
      return 401; // Not authorized, challenge with digest authentication
    }

## HTTP Digest Authentication Limitations

HTTP Digest Authentication cannot be used with streaming MTOM/MIME/DIME attachments. Streaming is turned off by the plugin and attachment data is buffered. Non-streaming MTOM/MIME/DIME attachments are handled.