[gstreamer-bugs] [Bug 561775] New: souphttpsrc patch to support basic and digest authentication

GStreamer (bugzilla.gnome.org) bugzilla-daemon at bugzilla.gnome.org
Thu Nov 20 23:42:24 PST 2008


If you have any questions why you received this email, please see the text at
the end of this email. Replies to this email are NOT read, please see the text
at the end of this email. You can add comments to this bug at:
  http://bugzilla.gnome.org/show_bug.cgi?id=561775

  GStreamer | gst-plugins-good | Ver: 0.10.11
           Summary: souphttpsrc patch to support basic and digest
                    authentication
           Product: GStreamer
           Version: 0.10.11
          Platform: Other
        OS/Version: Linux
            Status: UNCONFIRMED
          Severity: enhancement
          Priority: Normal
         Component: gst-plugins-good
        AssignedTo: gstreamer-bugs at lists.sourceforge.net
        ReportedBy: rmcouat at smartt.com
         QAContact: gstreamer-bugs at lists.sourceforge.net
     GNOME version: Unspecified
   GNOME milestone: Unspecified


The souphttpsrc element is preferred for connecting to HTTP MJPEG cameras but
was missing authentication capabilities. This patch addresses that for both
basic and digest authentication. The unit tests were also added to verify
correct operation against the libsoup server built into the test program.
Although unlikely to be used there are also properties and methods for
authentication through a proxy server. I was not able to test that but the code
paths through the element are identical except for a 407 instead of a 401
status.

Thanks to Wouter Cloetens for encouraging me to get this done.

Please let me know if you would like this in a different form or need some
adjustment.

This patch is a context diff from cvs-head

diff -r -c cvs-head/ext/soup/gstsouphttpsrc.c work/ext/soup/gstsouphttpsrc.c
*** cvs-head/ext/soup/gstsouphttpsrc.c  2008-11-19 20:47:48.000000000 -0800
--- work/ext/soup/gstsouphttpsrc.c      2008-11-20 00:08:18.000000000 -0800
***************
*** 121,126 ****
--- 121,130 ----
    PROP_USER_AGENT,
    PROP_AUTOMATIC_REDIRECT,
    PROP_PROXY,
+   PROP_USER_ID,
+   PROP_USER_PW,
+   PROP_PROXY_ID,
+   PROP_PROXY_PW,
    PROP_COOKIES,
    PROP_IRADIO_MODE,
    PROP_IRADIO_NAME,
***************
*** 195,201 ****
      GstSoupHTTPSrc * src);
  static void gst_soup_http_src_finished_cb (SoupMessage * msg,
      GstSoupHTTPSrc * src);
! 

  static void
  _do_init (GType type)
--- 199,206 ----
      GstSoupHTTPSrc * src);
  static void gst_soup_http_src_finished_cb (SoupMessage * msg,
      GstSoupHTTPSrc * src);
! static void gst_soup_http_src_authenticate_cb (SoupSession *session,
SoupMessage *msg,
!     SoupAuth *auth, gboolean retrying, GstSoupHTTPSrc *src);

  static void
  _do_init (GType type)
***************
*** 262,267 ****
--- 267,288 ----
        g_param_spec_string ("proxy", "Proxy",
            "HTTP proxy server URI", "", G_PARAM_READWRITE));
    g_object_class_install_property (gobject_class,
+       PROP_USER_ID,
+       g_param_spec_string ("user-id", "user-id",
+           "HTTP location URI user id for authentication", "",
G_PARAM_READWRITE));
+   g_object_class_install_property (gobject_class,
+       PROP_USER_PW,
+       g_param_spec_string ("user-pw", "user-pw",
+           "HTTP location URI user password for authentication", "",
G_PARAM_READWRITE));
+   g_object_class_install_property (gobject_class,
+       PROP_PROXY_ID,
+       g_param_spec_string ("proxy-id", "proxy-id",
+           "HTTP proxy URI user id for authentication", "",
G_PARAM_READWRITE));
+   g_object_class_install_property (gobject_class,
+       PROP_PROXY_PW,
+       g_param_spec_string ("proxy-pw", "proxy-pw",
+           "HTTP proxy URI user password for authentication", "",
G_PARAM_READWRITE));
+   g_object_class_install_property (gobject_class,
        PROP_COOKIES, g_param_spec_boxed ("cookies", "Cookies",
            "HTTP request cookies", G_TYPE_STRV, G_PARAM_READWRITE));
    g_object_class_install_property (gobject_class,
***************
*** 319,324 ****
--- 340,349 ----
    src->location = NULL;
    src->automatic_redirect = TRUE;
    src->user_agent = g_strdup (DEFAULT_USER_AGENT);
+   src->user_id = NULL;
+   src->user_pw = NULL;
+   src->proxy_id = NULL;
+   src->proxy_pw = NULL;
    src->cookies = NULL;
    src->icy_caps = NULL;
    src->iradio_mode = FALSE;
***************
*** 358,363 ****
--- 383,396 ----
      soup_uri_free (src->proxy);
      src->proxy = NULL;
    }
+   g_free (src->user_id);
+   src->user_id = NULL;
+   g_free (src->user_pw);
+   src->user_pw = NULL;
+   g_free (src->proxy_id);
+   src->proxy_id = NULL;
+   g_free (src->proxy_pw);
+   src->proxy_pw = NULL;
    g_strfreev (src->cookies);
    g_free (src->iradio_name);
    src->iradio_name = NULL;
***************
*** 435,440 ****
--- 468,493 ----
      case PROP_IS_LIVE:
        gst_base_src_set_live (GST_BASE_SRC (src), g_value_get_boolean
(value));
        break;
+     case PROP_USER_ID:
+       if (src->user_id)
+         g_free (src->user_id);
+       src->user_id = g_value_dup_string (value);
+       break;
+     case PROP_USER_PW:
+       if (src->user_pw)
+         g_free (src->user_pw);
+       src->user_pw = g_value_dup_string (value);
+       break;
+     case PROP_PROXY_ID:
+       if (src->proxy_id)
+         g_free (src->proxy_id);
+       src->proxy_id = g_value_dup_string (value);
+       break;
+     case PROP_PROXY_PW:
+       if (src->proxy_pw)
+         g_free (src->proxy_pw);
+       src->proxy_pw = g_value_dup_string (value);
+       break;
    }
  done:
    return;
***************
*** 487,492 ****
--- 540,557 ----
      case PROP_IRADIO_TITLE:
        g_value_set_string (value, src->iradio_title);
        break;
+     case PROP_USER_ID:
+       g_value_set_string (value, src->user_id);
+       break;
+     case PROP_USER_PW:
+       g_value_set_string (value, src->user_pw);
+       break;
+     case PROP_PROXY_ID:
+       g_value_set_string (value, src->proxy_id);
+       break;
+     case PROP_PROXY_PW:
+       g_value_set_string (value, src->proxy_pw);
+       break;
      default:
        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
        break;
***************
*** 564,569 ****
--- 629,649 ----
  }

  static void
+ gst_soup_http_src_authenticate_cb (SoupSession *session, SoupMessage *msg,
+     SoupAuth *auth, gboolean retrying, GstSoupHTTPSrc *src)
+ {
+   if (! retrying) {
+     /* First time authentication only, if we fail and are called again with
retry true fall through */
+     if (msg->status_code == SOUP_STATUS_UNAUTHORIZED) {
+       soup_auth_authenticate (auth, src->user_id, src->user_pw);
+     }
+     else if (msg->status_code == SOUP_STATUS_PROXY_AUTHENTICATION_REQUIRED) {
+       soup_auth_authenticate (auth, src->proxy_id, src->proxy_pw);
+     }
+   }
+ }
+ 
+ static void
  gst_soup_http_src_got_headers_cb (SoupMessage * msg, GstSoupHTTPSrc * src)
  {
    const char *value;
***************
*** 1061,1066 ****
--- 1141,1148 ----
      return FALSE;
    }

+   g_signal_connect (src->session, "authenticate",
+       G_CALLBACK (gst_soup_http_src_authenticate_cb), src);
    return TRUE;
  }

diff -r -c cvs-head/ext/soup/gstsouphttpsrc.h work/ext/soup/gstsouphttpsrc.h
*** cvs-head/ext/soup/gstsouphttpsrc.h  2008-11-19 20:48:09.000000000 -0800
--- work/ext/soup/gstsouphttpsrc.h      2008-11-20 00:43:15.000000000 -0800
***************
*** 52,57 ****
--- 52,61 ----
    gchar *user_agent;           /* User-Agent HTTP header. */
    gboolean automatic_redirect; /* Follow redirects. */
    SoupURI *proxy;              /* HTTP proxy URI. */
+   gchar *user_id;              /* Authentication user id for location URI. */
+   gchar *user_pw;              /* Authentication user password for location
URI. */
+   gchar *proxy_id;             /* Authentication user id for proxy URI. */
+   gchar *proxy_pw;             /* Authentication user password for proxy URI.
*/
    gchar **cookies;             /* HTTP request cookies. */
    GMainContext *context;       /* I/O context. */
    GMainLoop *loop;             /* Event loop. */
diff -r -c cvs-head/tests/check/elements/souphttpsrc.c
work/tests/check/elements/souphttpsrc.c
*** cvs-head/tests/check/elements/souphttpsrc.c 2008-11-20 18:54:19.000000000
-0800
--- work/tests/check/elements/souphttpsrc.c     2008-11-20 22:51:08.000000000
-0800
***************
*** 28,33 ****
--- 28,36 ----
  #include <libsoup/soup-address.h>
  #include <libsoup/soup-message.h>
  #include <libsoup/soup-server.h>
+ #include <libsoup/soup-auth-domain.h>
+ #include <libsoup/soup-auth-domain-basic.h>
+ #include <libsoup/soup-auth-domain-digest.h>
  #include <gst/check/gstcheck.h>

  static int http_port = 0, https_port = 0;
***************
*** 36,41 ****
--- 39,55 ----

  static const char **cookies = NULL;

+ /* Variables for authentication tests */
+ static const char *user_id = NULL;
+ static const char *user_pw = NULL;
+ static const char *good_user = "good_user";
+ static const char *bad_user = "bad_user";
+ static const char *good_pw = "good_pw";
+ static const char *bad_pw = "bad_pw";
+ static const char *realm = "SOUPHTTPSRC_REALM";
+ static const char *basic_auth_path = "/basic_auth";
+ static const char *digest_auth_path = "/digest_auth";
+ 
  static int run_server (int *http_port, int *https_port);


***************
*** 48,53 ****
--- 62,87 ----
      *p_outbuf = gst_buffer_ref (buf);
  }

+ static gboolean
+ basic_auth_cb (SoupAuthDomain *domain, SoupMessage *msg,
+                const char *username, const char *password,
+                gpointer user_data)
+ {
+   /* There is only one good login for testing */
+   return (strcmp (username, good_user) == 0) && (strcmp (password, good_pw)
== 0);
+ }
+ 
+ 
+ static char*
+ digest_auth_cb (SoupAuthDomain *domain, SoupMessage *msg,
+                 const char *username, gpointer user_data)
+ {
+   /* There is only one good login for testing */
+   if (strcmp (username, good_user) == 0)
+     return soup_auth_domain_digest_encode_password (good_user, realm,
good_pw);
+   return NULL;
+ }
+ 
  int
  run_test (const char *format, ...)
  {
***************
*** 94,99 ****
--- 128,138 ----
    g_object_set (sink, "signal-handoffs", TRUE, NULL);
    g_signal_connect (sink, "preroll-handoff", G_CALLBACK (handoff_cb), &buf);

+   if (user_id != NULL)
+     g_object_set (src, "user-id", user_id, NULL);
+   if (user_pw != NULL)
+     g_object_set (src, "user-pw", user_pw, NULL);
+ 
    ret = gst_element_set_state (pipe, GST_STATE_PAUSED);
    if (ret != GST_STATE_CHANGE_ASYNC) {
      GST_DEBUG ("failed to start up soup http src, ret = %d", ret);
***************
*** 114,119 ****
--- 153,160 ----
        rc = 404;
      else if (g_str_has_suffix (err->message, "Forbidden"))
        rc = 403;
+     else if (g_str_has_suffix (err->message, "Unauthorized"))
+       rc = 401;
      else if (g_str_has_suffix (err->message, "Found"))
        rc = 302;
      GST_INFO ("debug: %s", debug);
***************
*** 210,215 ****
--- 251,340 ----

  GST_END_TEST;

+ GST_START_TEST (test_good_user_basic_auth)
+ {
+   int res;
+ 
+   user_id = good_user;
+   user_pw = good_pw;
+   res = run_test ("http://127.0.0.1:%d%s", http_port, basic_auth_path);
+   GST_DEBUG ("Basic Auth user %s password %s res = %d", user_id, user_pw,
res);
+   user_id = user_pw = NULL;
+   fail_unless (res == 0);
+ }
+ 
+ GST_END_TEST;
+ 
+ GST_START_TEST (test_bad_user_basic_auth)
+ {
+   int res;
+ 
+   user_id = bad_user;
+   user_pw = good_pw;
+   res = run_test ("http://127.0.0.1:%d%s", http_port, basic_auth_path);
+   GST_DEBUG ("Basic Auth user %s password %s res = %d", user_id, user_pw,
res);
+   user_id = user_pw = NULL;
+   fail_unless (res == 401);
+ }
+ 
+ GST_END_TEST;
+ 
+ GST_START_TEST (test_bad_password_basic_auth)
+ {
+   int res;
+ 
+   user_id = good_user;
+   user_pw = bad_pw;
+   res = run_test ("http://127.0.0.1:%d%s", http_port, basic_auth_path);
+   GST_DEBUG ("Basic Auth user %s password %s res = %d", user_id, user_pw,
res);
+   user_id = user_pw = NULL;
+   fail_unless (res == 401);
+ }
+ 
+ GST_END_TEST;
+ 
+ GST_START_TEST (test_good_user_digest_auth)
+ {
+   int res;
+ 
+   user_id = good_user;
+   user_pw = good_pw;
+   res = run_test ("http://127.0.0.1:%d%s", http_port, digest_auth_path);
+   GST_DEBUG ("Digest Auth user %s password %s res = %d", user_id, user_pw,
res);
+   user_id = user_pw = NULL;
+   fail_unless (res == 0);
+ }
+ 
+ GST_END_TEST;
+ 
+ GST_START_TEST (test_bad_user_digest_auth)
+ {
+   int res;
+ 
+   user_id = bad_user;
+   user_pw = good_pw;
+   res = run_test ("http://127.0.0.1:%d%s", http_port, digest_auth_path);
+   GST_DEBUG ("Digest Auth user %s password %s res = %d", user_id, user_pw,
res);
+   user_id = user_pw = NULL;
+   fail_unless (res == 401);
+ }
+ 
+ GST_END_TEST;
+ 
+ GST_START_TEST (test_bad_password_digest_auth)
+ {
+   int res;
+ 
+   user_id = good_user;
+   user_pw = bad_pw;
+   res = run_test ("http://127.0.0.1:%d%s", http_port, digest_auth_path);
+   GST_DEBUG ("Digest Auth user %s password %s res = %d", user_id, user_pw,
res);
+   user_id = user_pw = NULL;
+   fail_unless (res == 401);
+ }
+ 
+ GST_END_TEST;
+ 
  static gboolean icy_caps = FALSE;

  static void
***************
*** 331,336 ****
--- 456,467 ----
    tcase_add_test (tc_chain, test_not_found);
    tcase_add_test (tc_chain, test_forbidden);
    tcase_add_test (tc_chain, test_cookies);
+   tcase_add_test (tc_chain, test_good_user_basic_auth);
+   tcase_add_test (tc_chain, test_bad_user_basic_auth);
+   tcase_add_test (tc_chain, test_bad_password_basic_auth);
+   tcase_add_test (tc_chain, test_good_user_digest_auth);
+   tcase_add_test (tc_chain, test_bad_user_digest_auth);
+   tcase_add_test (tc_chain, test_bad_password_digest_auth);

    suite_add_tcase (s, tc_internet);
    tcase_set_timeout (tc_internet, 250);
***************
*** 440,445 ****
--- 571,578 ----

    static int server_running = 0;

+   SoupAuthDomain *domain = NULL;
+ 
    if (server_running)
      return 0;
    server_running = 1;
***************
*** 454,459 ****
--- 587,606 ----
    *http_port = soup_server_get_port (server);
    GST_INFO ("HTTP server listening on port %d", *http_port);
    soup_server_add_handler (server, NULL, server_callback, NULL, NULL);
+   domain = soup_auth_domain_basic_new (
+            SOUP_AUTH_DOMAIN_REALM, realm,
+            SOUP_AUTH_DOMAIN_BASIC_AUTH_CALLBACK, basic_auth_cb,
+            SOUP_AUTH_DOMAIN_ADD_PATH, basic_auth_path,
+            NULL);
+   soup_server_add_auth_domain (server, domain);
+   g_object_unref (domain);
+   domain = soup_auth_domain_digest_new (
+            SOUP_AUTH_DOMAIN_REALM, realm,
+            SOUP_AUTH_DOMAIN_DIGEST_AUTH_CALLBACK, digest_auth_cb,
+            SOUP_AUTH_DOMAIN_ADD_PATH, digest_auth_path,
+            NULL);
+   soup_server_add_auth_domain (server, domain);
+   g_object_unref (domain);
    soup_server_run_async (server);

    if (ssl_cert_file && ssl_key_file) {


-- 
See http://bugzilla.gnome.org/page.cgi?id=email.html for more info about why you received
this email, why you can't respond via email, how to stop receiving
emails (or reduce the number you receive), and how to contact someone
if you are having problems with the system.

You can add comments to this bug at http://bugzilla.gnome.org/show_bug.cgi?id=561775.




More information about the Gstreamer-bugs mailing list