media: enable per factory authorisations
authorWim Taymans <wim.taymans@collabora.co.uk>
Wed, 12 Jan 2011 12:57:09 +0000 (13:57 +0100)
committerWim Taymans <wim.taymans@collabora.co.uk>
Wed, 12 Jan 2011 12:57:09 +0000 (13:57 +0100)
Allow for adding a GstRTSPAuth on the factory and media level and check
permissions when accessing the factory.
Add hints to the auth methods for future more fine grained authorisation.
Add example application for per factory authentication.

12 files changed:
examples/.gitignore
examples/Makefile.am
examples/test-auth.c [new file with mode: 0644]
examples/test-video.c
gst/rtsp-server/rtsp-auth.c
gst/rtsp-server/rtsp-auth.h
gst/rtsp-server/rtsp-client.c
gst/rtsp-server/rtsp-media-factory.c
gst/rtsp-server/rtsp-media.c
gst/rtsp-server/rtsp-media.h
gst/rtsp-server/rtsp-session-pool.h
gst/rtsp-server/rtsp-session.h

index b5dd6b2..6912d88 100644 (file)
@@ -5,3 +5,4 @@ test-readme
 test-sdp
 test-video
 test-uri
+test-auth
index 1886511..92f6cf4 100644 (file)
@@ -1,4 +1,4 @@
-noinst_PROGRAMS = test-video test-ogg test-mp4 test-readme test-launch test-sdp test-uri
+noinst_PROGRAMS = test-video test-ogg test-mp4 test-readme test-launch test-sdp test-uri test-auth
 
 INCLUDES = -I$(top_srcdir) -I$(srcdir)
 
diff --git a/examples/test-auth.c b/examples/test-auth.c
new file mode 100644 (file)
index 0000000..915173a
--- /dev/null
@@ -0,0 +1,115 @@
+/* GStreamer
+ * Copyright (C) 2008 Wim Taymans <wim.taymans at gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <gst/gst.h>
+
+#include <gst/rtsp-server/rtsp-server.h>
+
+
+static gboolean
+timeout (GstRTSPServer * server, gboolean ignored)
+{
+  GstRTSPSessionPool *pool;
+
+  pool = gst_rtsp_server_get_session_pool (server);
+  gst_rtsp_session_pool_cleanup (pool);
+  g_object_unref (pool);
+
+  return TRUE;
+}
+
+int
+main (int argc, char *argv[])
+{
+  GMainLoop *loop;
+  GstRTSPServer *server;
+  GstRTSPMediaMapping *mapping;
+  GstRTSPMediaFactory *factory;
+  GstRTSPAuth *auth;
+  gchar *basic;
+
+  gst_init (&argc, &argv);
+
+  loop = g_main_loop_new (NULL, FALSE);
+
+  /* create a server instance */
+  server = gst_rtsp_server_new ();
+
+  /* get the mapping for this server, every server has a default mapper object
+   * that be used to map uri mount points to media factories */
+  mapping = gst_rtsp_server_get_media_mapping (server);
+
+
+  /* make a media factory for a test stream. The default media factory can use
+   * gst-launch syntax to create pipelines. 
+   * any launch line works as long as it contains elements named pay%d. Each
+   * element with pay%d names will be a stream */
+  factory = gst_rtsp_media_factory_new ();
+  gst_rtsp_media_factory_set_launch (factory, "( "
+      "videotestsrc ! video/x-raw-yuv,width=352,height=288,framerate=15/1 ! "
+      "x264enc ! rtph264pay name=pay0 pt=96 "
+      "audiotestsrc ! audio/x-raw-int,rate=8000 ! "
+      "alawenc ! rtppcmapay name=pay1 pt=97 " ")");
+
+  /* make a new authentication manager */
+  auth = gst_rtsp_auth_new ();
+  basic = gst_rtsp_auth_make_basic ("user", "admin");
+  gst_rtsp_auth_set_basic (auth, basic);
+  g_free (basic);
+  gst_rtsp_media_factory_set_auth (factory, auth);
+  g_object_unref (auth);
+  /* attach the test factory to the /test url */
+  gst_rtsp_media_mapping_add_factory (mapping, "/test", factory);
+
+  /* make another factory */
+  factory = gst_rtsp_media_factory_new ();
+  gst_rtsp_media_factory_set_launch (factory, "( "
+      "videotestsrc ! video/x-raw-yuv,width=352,height=288,framerate=30/1 ! "
+      "x264enc ! rtph264pay name=pay0 pt=96 )");
+  /* make a new authentication manager */
+  auth = gst_rtsp_auth_new ();
+  basic = gst_rtsp_auth_make_basic ("user2", "admin2");
+  gst_rtsp_auth_set_basic (auth, basic);
+  g_free (basic);
+  gst_rtsp_media_factory_set_auth (factory, auth);
+  g_object_unref (auth);
+  /* attach the test factory to the /test url */
+  gst_rtsp_media_mapping_add_factory (mapping, "/test2", factory);
+
+  /* don't need the ref to the mapper anymore */
+  g_object_unref (mapping);
+
+  /* attach the server to the default maincontext */
+  if (gst_rtsp_server_attach (server, NULL) == 0)
+    goto failed;
+
+  g_timeout_add_seconds (2, (GSourceFunc) timeout, server);
+
+  /* start serving */
+  g_main_loop_run (loop);
+
+  return 0;
+
+  /* ERRORS */
+failed:
+  {
+    g_print ("failed to attach the server\n");
+    return -1;
+  }
+}
index 988c162..41194a0 100644 (file)
@@ -41,8 +41,10 @@ main (int argc, char *argv[])
   GstRTSPServer *server;
   GstRTSPMediaMapping *mapping;
   GstRTSPMediaFactory *factory;
+#if 0
   GstRTSPAuth *auth;
   gchar *basic;
+#endif
 
   gst_init (&argc, &argv);
 
@@ -55,6 +57,7 @@ main (int argc, char *argv[])
    * that be used to map uri mount points to media factories */
   mapping = gst_rtsp_server_get_media_mapping (server);
 
+#if 0
   /* make a new authentication manager */
   auth = gst_rtsp_auth_new ();
   basic = gst_rtsp_auth_make_basic ("user", "admin");
@@ -62,6 +65,7 @@ main (int argc, char *argv[])
   g_free (basic);
   /* configure in the server */
   gst_rtsp_server_set_auth (server, auth);
+#endif
 
   /* make a media factory for a test stream. The default media factory can use
    * gst-launch syntax to create pipelines. 
index 676537b..84d5c54 100644 (file)
@@ -37,9 +37,9 @@ static void gst_rtsp_auth_set_property (GObject * object, guint propid,
 static void gst_rtsp_auth_finalize (GObject * obj);
 
 static gboolean default_setup_auth (GstRTSPAuth * auth, GstRTSPClient * client,
-    GstRTSPClientState * state);
+    GQuark hint, GstRTSPClientState * state);
 static gboolean default_check_method (GstRTSPAuth * auth,
-    GstRTSPClient * client, GstRTSPClientState * state);
+    GstRTSPClient * client, GQuark hint, GstRTSPClientState * state);
 
 G_DEFINE_TYPE (GstRTSPAuth, gst_rtsp_auth, G_TYPE_OBJECT);
 
@@ -140,7 +140,7 @@ gst_rtsp_auth_set_basic (GstRTSPAuth * auth, const gchar * basic)
 
 static gboolean
 default_setup_auth (GstRTSPAuth * auth, GstRTSPClient * client,
-    GstRTSPClientState * state)
+    GQuark hint, GstRTSPClientState * state)
 {
   if (state->response == NULL)
     return FALSE;
@@ -167,7 +167,7 @@ default_setup_auth (GstRTSPAuth * auth, GstRTSPClient * client,
  */
 gboolean
 gst_rtsp_auth_setup_auth (GstRTSPAuth * auth, GstRTSPClient * client,
-    GstRTSPClientState * state)
+    GQuark hint, GstRTSPClientState * state)
 {
   gboolean result = FALSE;
   GstRTSPAuthClass *klass;
@@ -177,14 +177,14 @@ gst_rtsp_auth_setup_auth (GstRTSPAuth * auth, GstRTSPClient * client,
   GST_DEBUG_OBJECT (auth, "setup auth");
 
   if (klass->setup_auth)
-    result = klass->setup_auth (auth, client, state);
+    result = klass->setup_auth (auth, client, hint, state);
 
   return result;
 }
 
 static gboolean
 default_check_method (GstRTSPAuth * auth, GstRTSPClient * client,
-    GstRTSPClientState * state)
+    GQuark hint, GstRTSPClientState * state)
 {
   gboolean result = TRUE;
   GstRTSPResult res;
@@ -224,6 +224,7 @@ no_auth:
  * gst_rtsp_auth_check_method:
  * @auth: a #GstRTSPAuth
  * @client: the client
+ * @hint: a hint
  * @state: client state
  *
  * Check if @client is allowed to perform the actions of @state.
@@ -232,7 +233,7 @@ no_auth:
  */
 gboolean
 gst_rtsp_auth_check (GstRTSPAuth * auth, GstRTSPClient * client,
-    GstRTSPClientState * state)
+    GQuark hint, GstRTSPClientState * state)
 {
   gboolean result = FALSE;
   GstRTSPAuthClass *klass;
@@ -242,7 +243,7 @@ gst_rtsp_auth_check (GstRTSPAuth * auth, GstRTSPClient * client,
   GST_DEBUG_OBJECT (auth, "check state");
 
   if (klass->check_method)
-    result = klass->check_method (auth, client, state);
+    result = klass->check_method (auth, client, hint, state);
 
   return result;
 }
index 4699dea..3aadeff 100644 (file)
@@ -56,8 +56,10 @@ struct _GstRTSPAuth {
 struct _GstRTSPAuthClass {
   GObjectClass  parent_class;
 
-  gboolean (*setup_auth)   (GstRTSPAuth *auth, GstRTSPClient * client, GstRTSPClientState *state);
-  gboolean (*check_method) (GstRTSPAuth *auth, GstRTSPClient * client, GstRTSPClientState *state);
+  gboolean (*setup_auth)   (GstRTSPAuth *auth, GstRTSPClient * client,
+                            GQuark hint, GstRTSPClientState *state);
+  gboolean (*check_method) (GstRTSPAuth *auth, GstRTSPClient * client,
+                            GQuark hint, GstRTSPClientState *state);
 };
 
 GType               gst_rtsp_auth_get_type          (void);
@@ -67,9 +69,9 @@ GstRTSPAuth *       gst_rtsp_auth_new               (void);
 void                gst_rtsp_auth_set_basic         (GstRTSPAuth *auth, const gchar * basic);
 
 gboolean            gst_rtsp_auth_setup_auth        (GstRTSPAuth *auth, GstRTSPClient * client,
-                                                     GstRTSPClientState *state);
+                                                     GQuark hint, GstRTSPClientState *state);
 gboolean            gst_rtsp_auth_check_method      (GstRTSPAuth *auth, GstRTSPClient * client,
-                                                     GstRTSPClientState *state);
+                                                     GQuark hint, GstRTSPClientState *state);
 /* helpers */
 gchar *             gst_rtsp_auth_make_basic        (const gchar * user, const gchar * pass);
 
index d73bb49..b829ffa 100644 (file)
@@ -255,7 +255,8 @@ send_generic_response (GstRTSPClient * client, GstRTSPStatusCode code,
 }
 
 static void
-handle_unauthorized_request (GstRTSPClient * client, GstRTSPClientState * state)
+handle_unauthorized_request (GstRTSPClient * client, GstRTSPAuth * auth,
+    GstRTSPClientState * state)
 {
   GstRTSPMessage response = { 0 };
 
@@ -264,9 +265,9 @@ handle_unauthorized_request (GstRTSPClient * client, GstRTSPClientState * state)
 
   state->response = &response;
 
-  if (client->auth) {
+  if (auth) {
     /* and let the authentication manager setup the auth tokens */
-    gst_rtsp_auth_setup_auth (client->auth, client, state);
+    gst_rtsp_auth_setup_auth (auth, client, 0, state);
   }
 
   send_response (client, state->session, &response);
@@ -293,6 +294,7 @@ find_media (GstRTSPClient * client, GstRTSPClientState * state)
 {
   GstRTSPMediaFactory *factory;
   GstRTSPMedia *media;
+  GstRTSPAuth *auth;
 
   if (!compare_uri (client->uri, state->uri)) {
     /* remove any previously cached values before we try to construct a new
@@ -315,10 +317,20 @@ find_media (GstRTSPClient * client, GstRTSPClientState * state)
 
     state->factory = factory;
 
+    /* check if we have access to the factory */
+    if ((auth = gst_rtsp_media_factory_get_auth (factory))) {
+      if (!gst_rtsp_auth_check (auth, client, 0, state))
+        goto not_allowed;
+
+      g_object_unref (auth);
+    }
+
     /* prepare the media and add it to the pipeline */
     if (!(media = gst_rtsp_media_factory_construct (factory, state->uri)))
       goto no_media;
 
+    g_object_unref (factory);
+
     /* set ipv6 on the media before preparing */
     media->is_ipv6 = client->is_ipv6;
     state->media = media;
@@ -353,6 +365,13 @@ no_factory:
     send_generic_response (client, GST_RTSP_STS_NOT_FOUND, state);
     return NULL;
   }
+not_allowed:
+  {
+    handle_unauthorized_request (client, auth, state);
+    g_object_unref (factory);
+    g_object_unref (auth);
+    return NULL;
+  }
 no_media:
   {
     send_generic_response (client, GST_RTSP_STS_SERVICE_UNAVAILABLE, state);
@@ -1389,7 +1408,7 @@ session_not_found:
   }
 not_authorized:
   {
-    handle_unauthorized_request (client, &state);
+    handle_unauthorized_request (client, client->auth, &state);
     return;
   }
 }
index dd0ef79..2fe309d 100644 (file)
@@ -354,7 +354,6 @@ gst_rtsp_media_factory_set_auth (GstRTSPMediaFactory * factory,
   }
 }
 
-
 /**
  * gst_rtsp_media_factory_get_auth:
  * @factory: a #GstRTSPMediaFactory
@@ -365,7 +364,7 @@ gst_rtsp_media_factory_set_auth (GstRTSPMediaFactory * factory,
  * usage.
  */
 GstRTSPAuth *
-gst_rtsp_factory_get_auth (GstRTSPMediaFactory * factory)
+gst_rtsp_media_factory_get_auth (GstRTSPMediaFactory * factory)
 {
   GstRTSPAuth *result;
 
@@ -377,7 +376,6 @@ gst_rtsp_factory_get_auth (GstRTSPMediaFactory * factory)
   return result;
 }
 
-
 static gboolean
 compare_media (gpointer key, GstRTSPMedia * media1, GstRTSPMedia * media2)
 {
@@ -660,6 +658,7 @@ static void
 default_configure (GstRTSPMediaFactory * factory, GstRTSPMedia * media)
 {
   gboolean shared, eos_shutdown;
+  GstRTSPAuth *auth;
 
   /* configure the sharedness */
   GST_RTSP_MEDIA_FACTORY_LOCK (factory);
@@ -669,4 +668,9 @@ default_configure (GstRTSPMediaFactory * factory, GstRTSPMedia * media)
 
   gst_rtsp_media_set_shared (media, shared);
   gst_rtsp_media_set_eos_shutdown (media, eos_shutdown);
+
+  if ((auth = gst_rtsp_media_factory_get_auth (factory))) {
+    gst_rtsp_media_set_auth (media, auth);
+    g_object_unref (auth);
+  }
 }
index 61d9352..cd1e42a 100644 (file)
@@ -523,6 +523,54 @@ gst_rtsp_media_is_eos_shutdown (GstRTSPMedia * media)
 }
 
 /**
+ * gst_rtsp_media_set_auth:
+ * @media: a #GstRTSPMedia
+ * @auth: a #GstRTSPAuth
+ *
+ * configure @auth to be used as the authentication manager of @media.
+ */
+void
+gst_rtsp_media_set_auth (GstRTSPMedia * media, GstRTSPAuth * auth)
+{
+  GstRTSPAuth *old;
+
+  g_return_if_fail (GST_IS_RTSP_MEDIA (media));
+
+  old = media->auth;
+
+  if (old != auth) {
+    if (auth)
+      g_object_ref (auth);
+    media->auth = auth;
+    if (old)
+      g_object_unref (old);
+  }
+}
+
+/**
+ * gst_rtsp_media_get_auth:
+ * @media: a #GstRTSPMedia
+ *
+ * Get the #GstRTSPAuth used as the authentication manager of @media.
+ *
+ * Returns: the #GstRTSPAuth of @media. g_object_unref() after
+ * usage.
+ */
+GstRTSPAuth *
+gst_rtsp_media_get_auth (GstRTSPMedia * media)
+{
+  GstRTSPAuth *result;
+
+  g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), NULL);
+
+  if ((result = media->auth))
+    g_object_ref (result);
+
+  return result;
+}
+
+
+/**
  * gst_rtsp_media_n_streams:
  * @media: a #GstRTSPMedia
  *
index 33db2f9..a62390a 100644 (file)
@@ -85,6 +85,8 @@ struct _GstRTSPMediaTrans {
   GObject             *rtpsource;
 };
 
+#include "rtsp-auth.h"
+
 /**
  * GstRTSPMediaStream:
  * @srcpad: the srcpad of the stream
@@ -204,6 +206,7 @@ struct _GstRTSPMedia {
   gboolean           reused;
   gboolean           is_ipv6;
   gboolean           eos_shutdown;
+  GstRTSPAuth       *auth;
 
   GstElement        *element;
   GArray            *streams;
@@ -277,6 +280,9 @@ GstRTSPLowerTrans     gst_rtsp_media_get_protocols    (GstRTSPMedia *media);
 void                  gst_rtsp_media_set_eos_shutdown (GstRTSPMedia *media, gboolean eos_shutdown);
 gboolean              gst_rtsp_media_is_eos_shutdown  (GstRTSPMedia *media);
 
+void                  gst_rtsp_media_set_auth         (GstRTSPMedia *media, GstRTSPAuth *auth);
+GstRTSPAuth *         gst_rtsp_media_get_auth         (GstRTSPMedia *media);
+
 /* prepare the media for playback */
 gboolean              gst_rtsp_media_prepare          (GstRTSPMedia *media);
 gboolean              gst_rtsp_media_is_prepared      (GstRTSPMedia *media);
index 865b16b..3cd56d4 100644 (file)
 #ifndef __GST_RTSP_SESSION_POOL_H__
 #define __GST_RTSP_SESSION_POOL_H__
 
-#include "rtsp-session.h"
 
 G_BEGIN_DECLS
 
+typedef struct _GstRTSPSessionPool GstRTSPSessionPool;
+typedef struct _GstRTSPSessionPoolClass GstRTSPSessionPoolClass;
+
+#include "rtsp-session.h"
+
 #define GST_TYPE_RTSP_SESSION_POOL              (gst_rtsp_session_pool_get_type ())
 #define GST_IS_RTSP_SESSION_POOL(obj)           (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_RTSP_SESSION_POOL))
 #define GST_IS_RTSP_SESSION_POOL_CLASS(klass)   (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_RTSP_SESSION_POOL))
@@ -35,9 +39,6 @@ G_BEGIN_DECLS
 #define GST_RTSP_SESSION_POOL_CAST(obj)         ((GstRTSPSessionPool*)(obj))
 #define GST_RTSP_SESSION_POOL_CLASS_CAST(klass) ((GstRTSPSessionPoolClass*)(klass))
 
-typedef struct _GstRTSPSessionPool GstRTSPSessionPool;
-typedef struct _GstRTSPSessionPoolClass GstRTSPSessionPoolClass;
-
 /**
  * GstRTSPSessionPool:
  * @max_sessions: the maximum number of sessions.
index 00bc3f3..07efb19 100644 (file)
@@ -21,8 +21,6 @@
 
 #include <gst/rtsp/gstrtsptransport.h>
 
-#include "rtsp-media.h"
-
 #ifndef __GST_RTSP_SESSION_H__
 #define __GST_RTSP_SESSION_H__
 
@@ -43,6 +41,8 @@ typedef struct _GstRTSPSessionClass GstRTSPSessionClass;
 typedef struct _GstRTSPSessionStream GstRTSPSessionStream;
 typedef struct _GstRTSPSessionMedia GstRTSPSessionMedia;
 
+#include "rtsp-media.h"
+
 /**
  * GstRTSPSessionStream:
  * @trans: the media transport