Explorar o código

modify test for digest auth -- basics

Christian Grothoff hai 1 ano
pai
achega
5978da8ebc

+ 4 - 3
src/include/microhttpd2.h

@@ -6945,7 +6945,7 @@ MHD_upgraded_recv (struct MHD_UpgradedHandle *MHD_RESTRICT urh,
                    void *MHD_RESTRICT recv_buf,
                    size_t *MHD_RESTRICT received_size,
                    uint_fast64_t max_wait_millisec)
-MHD_FN_PAR_NONNULL_ALL_ MHD_FN_PAR_OUT_SIZE_(3,2)
+MHD_FN_PAR_NONNULL_ALL_ MHD_FN_PAR_OUT_SIZE_ (3,2)
 MHD_FN_PAR_OUT_ (4);
 
 
@@ -7000,7 +7000,7 @@ MHD_upgraded_send (struct MHD_UpgradedHandle *MHD_RESTRICT urh,
                    size_t *MHD_RESTRICT sent_size,
                    uint_fast64_t max_wait_millisec,
                    enum MHD_Bool more_data_to_come)
-MHD_FN_PAR_NONNULL_ALL_ MHD_FN_PAR_IN_SIZE_(3,2)
+MHD_FN_PAR_NONNULL_ALL_ MHD_FN_PAR_IN_SIZE_ (3,2)
 MHD_FN_PAR_OUT_ (4);
 
 
@@ -7882,6 +7882,7 @@ MHD_FN_PAR_OUT_SIZE_ (6,5);
  *                        hashing algorithm (see #MHD_MD5_DIGEST_SIZE,
  *                        #MHD_SHA256_DIGEST_SIZE, #MHD_SHA512_256_DIGEST_SIZE,
  *                        #MHD_digest_get_hash_size())
+ *   FIXME: why pass it if it must anyway match????
  * @param nonce_timeout the period of seconds since nonce generation, when
  *                      the nonce is recognised as valid and not stale;
  *                      if zero is specified then daemon default value is used.
@@ -8292,7 +8293,7 @@ MHD_response_add_auth_basic_challenge (
   struct MHD_Response *MHD_RESTRICT response,
   const char *MHD_RESTRICT realm,
   enum MHD_Bool prefer_utf8)
-MHD_FN_PAR_NONNULL_(2) MHD_FN_PAR_CSTR_ (2);
+MHD_FN_PAR_NONNULL_ (2) MHD_FN_PAR_CSTR_ (2);
 
 #ifndef MHD_NO_STATIC_INLINE
 

+ 57 - 0
src/tests/client_server/libtest.h

@@ -403,6 +403,34 @@ MHDT_client_fail_basic_auth (
   struct MHDT_PhaseContext *pc);
 
 
+/**
+ * Perform GET request and send some HTTP digest authentication header
+ * to authorize the request.
+ *
+ * @param cls a string with "$USERNAME:$PASSWORD"
+ * @param pc context for the client
+ * @return error message, NULL on success
+ */
+const char *
+MHDT_client_send_digest_auth (
+  const void *cls,
+  struct MHDT_PhaseContext *pc);
+
+
+/**
+ * Perform GET request and send some HTTP digest authentication header
+ * to authorize the request. Expect authentication to fail.
+ *
+ * @param cls a string with "$USERNAME:$PASSWORD"
+ * @param pc context for the client
+ * @return error message, NULL on success
+ */
+const char *
+MHDT_client_fail_digest_auth (
+  const void *cls,
+  struct MHDT_PhaseContext *pc);
+
+
 /**
  * Returns the text from @a cls as the response to any
  * request.
@@ -659,6 +687,35 @@ MHDT_server_reply_check_basic_auth (
   uint_fast64_t upload_size);
 
 
+/**
+ * Checks that the client request includes the given
+ * username and password in HTTP digest authetnication.
+ * If so, returns #MHD_HTTP_STATUS_NO_CONTENT, otherwise
+ * an #MHD_HTTP_STATUS_UNAUTHORIZED.
+ *
+ * @param cls expected upload data as a 0-terminated string.
+ * @param request the request object
+ * @param path the requested uri (without arguments after "?")
+ * @param method the HTTP method used (#MHD_HTTP_METHOD_GET,
+ *        #MHD_HTTP_METHOD_PUT, etc.)
+ * @param upload_size the size of the message upload content payload,
+ *                    #MHD_SIZE_UNKNOWN for chunked uploads (if the
+ *                    final chunk has not been processed yet)
+ * @return action how to proceed, NULL
+ *         if the request must be aborted due to a serious
+ *         error while handling the request (implies closure
+ *         of underling data stream, for HTTP/1.1 it means
+ *         socket closure).
+ */
+const struct MHD_Action *
+MHDT_server_reply_check_digest_auth (
+  void *cls,
+  struct MHD_Request *MHD_RESTRICT request,
+  const struct MHD_String *MHD_RESTRICT path,
+  enum MHD_HTTP_Method method,
+  uint_fast64_t upload_size);
+
+
 /**
  * Initialize options for an MHD daemon for a test.
  *

+ 111 - 0
src/tests/client_server/libtest_convenience_client_request.c

@@ -925,3 +925,114 @@ MHDT_client_fail_basic_auth (
     return "invalid HTTP response code";
   return NULL;
 }
+
+
+/**
+ * Send HTTP request with digest authentication.
+ *
+ * @param cred $USERNAME:$PASSWORD to use
+ * @param[in,out] phase context
+ * @param[out] http_status set to HTTP status
+ * @return error message, NULL on success
+ */
+static const char *
+send_digest_auth (const char *cred,
+                  struct MHDT_PhaseContext *pc,
+                  unsigned int *http_status)
+{
+  CURL *c;
+  const char *err;
+  long status;
+  char *pass = strchr (cred, ':');
+  char *user;
+
+  if (NULL == pass)
+    return "invalid credential given";
+  user = strndup (cred,
+                  pass - cred);
+  pass++;
+  c = curl_easy_init ();
+  if (NULL == c)
+  {
+    free (user);
+    return "Failed to initialize Curl handle";
+  }
+  err = set_url (c,
+                 pc->base_url,
+                 pc);
+  if (NULL != err)
+  {
+    free (user);
+    curl_easy_cleanup (c);
+    return err;
+  }
+  if ( (CURLE_OK !=
+        curl_easy_setopt (c,
+                          CURLOPT_HTTPAUTH,
+                          (long) CURLAUTH_DIGEST)) ||
+       (CURLE_OK !=
+        curl_easy_setopt (c,
+                          CURLOPT_USERNAME,
+                          user)) ||
+       (CURLE_OK !=
+        curl_easy_setopt (c,
+                          CURLOPT_PASSWORD,
+                          pass)) )
+  {
+    curl_easy_cleanup (c);
+    free (user);
+    return "Failed to set digest authentication header for curl request";
+  }
+  free (user);
+  PERFORM_REQUEST (c);
+  if (CURLE_OK !=
+      curl_easy_getinfo (c,
+                         CURLINFO_RESPONSE_CODE,
+                         &status))
+  {
+    return "Failed to get HTTP status";
+  }
+  *http_status = (unsigned int) status;
+  curl_easy_cleanup (c);
+  return NULL;
+}
+
+
+const char *
+MHDT_client_send_digest_auth (
+  const void *cls,
+  struct MHDT_PhaseContext *pc)
+{
+  const char *cred = cls;
+  const char *ret;
+  unsigned int status;
+
+  ret = send_digest_auth (cred,
+                          pc,
+                          &status);
+  if (NULL != ret)
+    return ret;
+  if (MHD_HTTP_STATUS_NO_CONTENT != status)
+    return "invalid HTTP response code";
+  return NULL;
+}
+
+
+const char *
+MHDT_client_fail_digest_auth (
+  const void *cls,
+  struct MHDT_PhaseContext *pc)
+{
+  const char *cred = cls;
+  const char *ret;
+  unsigned int status;
+
+  ret = send_digest_auth (cred,
+                          pc,
+                          &status);
+  if (NULL != ret)
+    return ret;
+  if (MHD_HTTP_STATUS_UNAUTHORIZED != status)
+    return "invalid HTTP response code";
+  return NULL;
+}

+ 73 - 12
src/tests/client_server/libtest_convenience_server_reply.c

@@ -33,7 +33,7 @@
 #include <unistd.h>
 #include <errno.h>
 #include <curl/curl.h>
-
+#include <assert.h>
 
 const struct MHD_Action *
 MHDT_server_reply_text (
@@ -757,17 +757,7 @@ MHDT_server_reply_check_basic_auth (
         MHD_HTTP_STATUS_UNAUTHORIZED));
   }
   ba = dd.v_auth_basic_creds;
-  if (NULL == ba)
-  {
-    fprintf (stderr,
-             "No credentials??\n");
-    return MHD_action_basic_auth_challenge_p (
-      request,
-      "test-realm",
-      MHD_YES,
-      MHD_response_from_empty (
-        MHD_HTTP_STATUS_UNAUTHORIZED));
-  }
+  assert (NULL != ba);
   if ( (0 != strncmp (ba->username.cstr,
                       cred,
                       ba->username.len)) ||
@@ -793,3 +783,74 @@ MHDT_server_reply_check_basic_auth (
     MHD_response_from_empty (
       MHD_HTTP_STATUS_NO_CONTENT));
 }
+
+
+const struct MHD_Action *
+MHDT_server_reply_check_digest_auth (
+  void *cls,
+  struct MHD_Request *MHD_RESTRICT request,
+  const struct MHD_String *MHD_RESTRICT path,
+  enum MHD_HTTP_Method method,
+  uint_fast64_t upload_size)
+{
+  const char *cred = cls;
+  const char *colon = strchr (cred, ':');
+  char *username;
+  const char *password;
+  enum MHD_DigestAuthResult dar;
+
+  assert (NULL != colon);
+  password = colon + 1;
+  username = strndup (cred,
+                      colon - cred);
+  assert (NULL != username);
+  dar = MHD_digest_auth_check_digest (request,
+                                      "test-realm",
+                                      username,
+                                      password,
+                                      MHD_SHA256_DIGEST_SIZE,
+                                      0, /* nonce timeout in seconds; 0: default */
+                                      0, /* maximum nonce counter; 0: default */
+                                      MHD_DIGEST_AUTH_MULT_QOP_AUTH,
+                                      MHD_DIGEST_AUTH_MULT_ALGO_SHA256);
+
+  free (username);
+  if (MHD_DAUTH_OK != dar)
+  {
+    struct MHD_Response *resp;
+    enum MHD_StatusCode sc;
+
+    resp = MHD_response_from_empty (
+      MHD_HTTP_STATUS_UNAUTHORIZED);
+    if (NULL == resp)
+    {
+      fprintf (stderr,
+               "Failed to create response body\n");
+      return NULL;
+    }
+    sc = MHD_response_add_auth_digest_challenge (
+      resp,
+      "test-realm",
+      "opaque",
+      NULL, /* domain */
+      MHD_YES,                        /* indicate stale */
+      MHD_DIGEST_AUTH_MULT_QOP_AUTH,
+      MHD_DIGEST_AUTH_MULT_ALGO_SHA256,
+      MHD_YES /* userhash_support */,
+      MHD_YES /* prefer UTF8 */);
+    if (MHD_SC_OK != sc)
+    {
+      fprintf (stderr,
+               "MHD_response_add_auth_digest_challenge failed: %d\n",
+               (int) sc);
+      return NULL;
+    }
+    return MHD_action_from_response (
+      request,
+      resp);
+  }
+  return MHD_action_from_response (
+    request,
+    MHD_response_from_empty (
+      MHD_HTTP_STATUS_NO_CONTENT));
+}

+ 18 - 1
src/tests/client_server/test_authentication.c

@@ -53,6 +53,7 @@ main (int argc, char *argv[])
     },
   };
   struct MHDT_Phase phases[] = {
+#if FIXME
     {
       .label = "simple basic authentication",
       .server_cb = &MHDT_server_reply_check_basic_auth,
@@ -69,7 +70,23 @@ main (int argc, char *argv[])
       .client_cb_cls = (void *) "username:word", /* incorrect on purpose */
       .timeout_ms = 200,
     },
-    // TODO: digest auth
+#endif
+    {
+      .label = "simple digest authentication",
+      .server_cb = &MHDT_server_reply_check_digest_auth,
+      .server_cb_cls = (void *) "username:password",
+      .client_cb = &MHDT_client_send_digest_auth,
+      .client_cb_cls = (void *) "username:password",
+      .timeout_ms = 200,
+    },
+    {
+      .label = "failing digest authentication",
+      .server_cb = &MHDT_server_reply_check_digest_auth,
+      .server_cb_cls = (void *) "username:password",
+      .client_cb = &MHDT_client_fail_digest_auth,
+      .client_cb_cls = (void *) "username:word", /* incorrect on purpose */
+      .timeout_ms = 200,
+    },
     {
       .label = NULL,
     },