auth: add authentication object
authorWim Taymans <wim.taymans@collabora.co.uk>
Tue, 11 Jan 2011 23:17:54 +0000 (00:17 +0100)
committerWim Taymans <wim.taymans@gmail.com>
Tue, 11 Jan 2011 23:22:27 +0000 (00:22 +0100)
Add an object that can check the authorization of requests.
Implement basic authentication.
Add example authentication to test-video

examples/test-video.c
gst/rtsp-server/Makefile.am
gst/rtsp-server/rtsp-auth.c [new file with mode: 0644]
gst/rtsp-server/rtsp-auth.h [new file with mode: 0644]
gst/rtsp-server/rtsp-client.c
gst/rtsp-server/rtsp-client.h
gst/rtsp-server/rtsp-server.c
gst/rtsp-server/rtsp-server.h

index c4eed53..988c162 100644 (file)
@@ -41,6 +41,8 @@ main (int argc, char *argv[])
   GstRTSPServer *server;
   GstRTSPMediaMapping *mapping;
   GstRTSPMediaFactory *factory;
+  GstRTSPAuth *auth;
+  gchar *basic;
 
   gst_init (&argc, &argv);
 
@@ -53,6 +55,14 @@ main (int argc, char *argv[])
    * that be used to map uri mount points to media factories */
   mapping = gst_rtsp_server_get_media_mapping (server);
 
+  /* 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);
+  /* configure in the server */
+  gst_rtsp_server_set_auth (server, auth);
+
   /* 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
index 50e2718..ca400c0 100644 (file)
@@ -1,5 +1,6 @@
 public_headers = \
                rtsp-funnel.h \
+               rtsp-auth.h \
                rtsp-params.h \
                rtsp-sdp.h \
                rtsp-media.h \
@@ -13,6 +14,7 @@ public_headers = \
 
 c_sources = \
        rtsp-funnel.c \
+       rtsp-auth.c \
        rtsp-params.c \
        rtsp-sdp.c \
        rtsp-media.c \
diff --git a/gst/rtsp-server/rtsp-auth.c b/gst/rtsp-server/rtsp-auth.c
new file mode 100644 (file)
index 0000000..ff83c1b
--- /dev/null
@@ -0,0 +1,220 @@
+/* GStreamer
+ * Copyright (C) 2010 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 <string.h>
+
+#include "rtsp-auth.h"
+
+enum
+{
+  PROP_0,
+  PROP_LAST
+};
+
+GST_DEBUG_CATEGORY_STATIC (rtsp_auth_debug);
+#define GST_CAT_DEFAULT rtsp_auth_debug
+
+static void gst_rtsp_auth_get_property (GObject * object, guint propid,
+    GValue * value, GParamSpec * pspec);
+static void gst_rtsp_auth_set_property (GObject * object, guint propid,
+    const GValue * value, GParamSpec * pspec);
+static void gst_rtsp_auth_finalize (GObject * obj);
+
+static gboolean default_check_method (GstRTSPAuth * auth, GstRTSPMethod method,
+    GstRTSPClient * client, GstRTSPUrl * uri, GstRTSPSession * session,
+    GstRTSPMessage * request);
+
+G_DEFINE_TYPE (GstRTSPAuth, gst_rtsp_auth, G_TYPE_OBJECT);
+
+static void
+gst_rtsp_auth_class_init (GstRTSPAuthClass * klass)
+{
+  GObjectClass *gobject_class;
+
+  gobject_class = G_OBJECT_CLASS (klass);
+
+  gobject_class->get_property = gst_rtsp_auth_get_property;
+  gobject_class->set_property = gst_rtsp_auth_set_property;
+  gobject_class->finalize = gst_rtsp_auth_finalize;
+
+  klass->check_method = default_check_method;
+
+  GST_DEBUG_CATEGORY_INIT (rtsp_auth_debug, "rtspauth", 0, "GstRTSPAuth");
+}
+
+static void
+gst_rtsp_auth_init (GstRTSPAuth * auth)
+{
+  /* bitwise or of all methods that need authentication */
+  auth->methods = GST_RTSP_DESCRIBE |
+      GST_RTSP_ANNOUNCE |
+      GST_RTSP_GET_PARAMETER |
+      GST_RTSP_SET_PARAMETER |
+      GST_RTSP_PAUSE |
+      GST_RTSP_PLAY | GST_RTSP_RECORD | GST_RTSP_SETUP | GST_RTSP_TEARDOWN;
+}
+
+static void
+gst_rtsp_auth_finalize (GObject * obj)
+{
+  GstRTSPAuth *auth = GST_RTSP_AUTH (obj);
+
+  GST_INFO ("finalize auth %p", auth);
+
+  G_OBJECT_CLASS (gst_rtsp_auth_parent_class)->finalize (obj);
+}
+
+static void
+gst_rtsp_auth_get_property (GObject * object, guint propid,
+    GValue * value, GParamSpec * pspec)
+{
+  GstRTSPAuth *auth = GST_RTSP_AUTH (object);
+
+  switch (propid) {
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec);
+  }
+}
+
+static void
+gst_rtsp_auth_set_property (GObject * object, guint propid,
+    const GValue * value, GParamSpec * pspec)
+{
+  GstRTSPAuth *auth = GST_RTSP_AUTH (object);
+
+  switch (propid) {
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec);
+  }
+}
+
+/**
+ * gst_rtsp_auth_new:
+ *
+ * Create a new #GstRTSPAuth instance.
+ *
+ * Returns: a new #GstRTSPAuth
+ */
+GstRTSPAuth *
+gst_rtsp_auth_new (void)
+{
+  GstRTSPAuth *result;
+
+  result = g_object_new (GST_TYPE_RTSP_AUTH, NULL);
+
+  return result;
+}
+
+/**
+ * gst_rtsp_auth_set_basic:
+ * @auth: a #GstRTSPAuth
+ * @basic: the basic token
+ *
+ * Set the basic token for the default authentication algorithm.
+ */
+void
+gst_rtsp_auth_set_basic (GstRTSPAuth * auth, const gchar * basic)
+{
+  g_free (auth->basic);
+  auth->basic = g_strdup (basic);
+}
+
+static gboolean
+default_check_method (GstRTSPAuth * auth, GstRTSPMethod method,
+    GstRTSPClient * client, GstRTSPUrl * uri, GstRTSPSession * session,
+    GstRTSPMessage * request)
+{
+  gboolean result = TRUE;
+  GstRTSPResult res;
+
+  if (method & auth->methods != 0) {
+    gchar *authorization;
+
+    result = FALSE;
+
+    res =
+        gst_rtsp_message_get_header (request, GST_RTSP_HDR_AUTHORIZATION,
+        &authorization, 0);
+    if (res < 0)
+      goto no_auth;
+
+    /* parse type */
+    if (g_ascii_strncasecmp (authorization, "basic ", 6) == 0) {
+      GST_DEBUG_OBJECT (auth, "check Basic auth");
+      if (auth->basic && strcmp (&authorization[6], auth->basic) == 0)
+        result = TRUE;
+    } else if (g_ascii_strncasecmp (authorization, "digest ", 7) == 0) {
+      GST_DEBUG_OBJECT (auth, "check Digest auth");
+      /* not implemented yet */
+      result = FALSE;
+    }
+  }
+  return result;
+
+no_auth:
+  {
+    GST_DEBUG_OBJECT (auth, "no authorization header found");
+    return FALSE;
+  }
+}
+
+/**
+ * gst_rtsp_auth_check_method:
+ * @auth: a #GstRTSPAuth
+ * @method: method to check
+ * @client: the client
+ * @uri: the requested uri
+ * @session: the session
+ * @request: the request
+ *
+ * Check if @client is allowed to perform @method for the @uri in
+ * @session and with @request.
+ *
+ * Returns: FALSE if the method is not allowed.
+ */
+gboolean
+gst_rtsp_auth_check_method (GstRTSPAuth * auth, GstRTSPMethod method,
+    GstRTSPClient * client, GstRTSPUrl * uri, GstRTSPSession * session,
+    GstRTSPMessage * request)
+{
+  gboolean result = FALSE;
+  GstRTSPAuthClass *klass;
+
+  klass = GST_RTSP_AUTH_GET_CLASS (auth);
+
+  GST_DEBUG_OBJECT (auth, "check method %d", method);
+
+  if (klass->check_method)
+    result = klass->check_method (auth, method, client, uri, session, request);
+
+  return result;
+}
+
+gchar *
+gst_rtsp_auth_make_basic (const gchar * user, const gchar * pass)
+{
+  gchar *user_pass;
+  gchar *result;
+
+  user_pass = g_strjoin (":", user, pass, NULL);
+  result = g_base64_encode ((guchar *) user_pass, strlen (user_pass));
+  g_free (user_pass);
+
+  return result;
+}
diff --git a/gst/rtsp-server/rtsp-auth.h b/gst/rtsp-server/rtsp-auth.h
new file mode 100644 (file)
index 0000000..85ac733
--- /dev/null
@@ -0,0 +1,79 @@
+/* GStreamer
+ * Copyright (C) 2010 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>
+
+#ifndef __GST_RTSP_AUTH_H__
+#define __GST_RTSP_AUTH_H__
+
+typedef struct _GstRTSPAuth GstRTSPAuth;
+typedef struct _GstRTSPAuthClass GstRTSPAuthClass;
+
+#include "rtsp-client.h"
+#include "rtsp-media-mapping.h"
+#include "rtsp-session-pool.h"
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_RTSP_AUTH              (gst_rtsp_auth_get_type ())
+#define GST_IS_RTSP_AUTH(obj)           (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_RTSP_AUTH))
+#define GST_IS_RTSP_AUTH_CLASS(klass)   (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_RTSP_AUTH))
+#define GST_RTSP_AUTH_GET_CLASS(obj)    (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_RTSP_AUTH, GstRTSPAuthClass))
+#define GST_RTSP_AUTH(obj)              (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_RTSP_AUTH, GstRTSPAuth))
+#define GST_RTSP_AUTH_CLASS(klass)      (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_RTSP_AUTH, GstRTSPAuthClass))
+#define GST_RTSP_AUTH_CAST(obj)         ((GstRTSPAuth*)(obj))
+#define GST_RTSP_AUTH_CLASS_CAST(klass) ((GstRTSPAuthClass*)(klass))
+
+/**
+ * GstRTSPAuth:
+ *
+ * The authentication structure.
+ */
+struct _GstRTSPAuth {
+  GObject       parent;
+
+  /*< private >*/
+  gchar        *basic;
+  GstRTSPMethod methods;
+};
+
+struct _GstRTSPAuthClass {
+  GObjectClass  parent_class;
+
+  gboolean (*check_method) (GstRTSPAuth *auth, GstRTSPMethod method,
+          GstRTSPClient * client, GstRTSPUrl * uri,
+          GstRTSPSession * session, GstRTSPMessage * request);
+};
+
+GType               gst_rtsp_auth_get_type          (void);
+
+GstRTSPAuth *       gst_rtsp_auth_new               (void);
+
+void                gst_rtsp_auth_set_basic         (GstRTSPAuth *auth, const gchar * basic);
+
+gboolean            gst_rtsp_auth_check_method      (GstRTSPAuth *auth, GstRTSPMethod method,
+                                                     GstRTSPClient * client, GstRTSPUrl * uri,
+                                                     GstRTSPSession * session, GstRTSPMessage * request);
+
+/* helpers */
+gchar *             gst_rtsp_auth_make_basic        (const gchar * user, const gchar * pass);
+
+G_END_DECLS
+
+#endif /* __GST_RTSP_AUTH_H__ */
index be193de..8465a97 100644 (file)
@@ -253,6 +253,22 @@ send_generic_response (GstRTSPClient * client, GstRTSPStatusCode code,
 }
 
 static gboolean
+handle_unauthorized_request (GstRTSPClient * client, GstRTSPUrl * uri,
+    GstRTSPSession * session, GstRTSPMessage * request)
+{
+  GstRTSPMessage response = { 0 };
+
+  gst_rtsp_message_init_response (&response, GST_RTSP_STS_UNAUTHORIZED,
+      gst_rtsp_status_as_text (GST_RTSP_STS_UNAUTHORIZED), request);
+  gst_rtsp_message_add_header (&response, GST_RTSP_HDR_WWW_AUTHENTICATE,
+      "Basic ");
+
+  send_response (client, session, &response);
+  return;
+}
+
+
+static gboolean
 compare_uri (const GstRTSPUrl * uri1, const GstRTSPUrl * uri2)
 {
   if (uri1 == NULL || uri2 == NULL)
@@ -1277,6 +1293,12 @@ handle_request (GstRTSPClient * client, GstRTSPMessage * request)
   } else
     session = NULL;
 
+  if (client->auth) {
+    if (!gst_rtsp_auth_check_method (client->auth, method, client, uri, session,
+            request))
+      goto not_authorized;
+  }
+
   /* now see what is asked and dispatch to a dedicated handler */
   switch (method) {
     case GST_RTSP_OPTIONS:
@@ -1330,6 +1352,11 @@ session_not_found:
     send_generic_response (client, GST_RTSP_STS_SESSION_NOT_FOUND, request);
     return;
   }
+not_authorized:
+  {
+    handle_unauthorized_request (client, uri, session, request);
+    return;
+  }
 }
 
 static void
@@ -1476,6 +1503,54 @@ gst_rtsp_client_get_media_mapping (GstRTSPClient * client)
   return result;
 }
 
+/**
+ * gst_rtsp_client_set_auth:
+ * @client: a #GstRTSPClient
+ * @auth: a #GstRTSPAuth
+ *
+ * configure @auth to be used as the authentication manager of @client.
+ */
+void
+gst_rtsp_client_set_auth (GstRTSPClient * client, GstRTSPAuth * auth)
+{
+  GstRTSPAuth *old;
+
+  g_return_if_fail (GST_IS_RTSP_CLIENT (client));
+
+  old = client->auth;
+
+  if (old != auth) {
+    if (auth)
+      g_object_ref (auth);
+    client->auth = auth;
+    if (old)
+      g_object_unref (old);
+  }
+}
+
+
+/**
+ * gst_rtsp_client_get_auth:
+ * @client: a #GstRTSPClient
+ *
+ * Get the #GstRTSPAuth used as the authentication manager of @client.
+ *
+ * Returns: the #GstRTSPAuth of @client. g_object_unref() after
+ * usage.
+ */
+GstRTSPAuth *
+gst_rtsp_client_get_auth (GstRTSPClient * client)
+{
+  GstRTSPAuth *result;
+
+  g_return_val_if_fail (GST_IS_RTSP_CLIENT (client), NULL);
+
+  if ((result = client->auth))
+    g_object_ref (result);
+
+  return result;
+}
+
 static GstRTSPResult
 message_received (GstRTSPWatch * watch, GstRTSPMessage * message,
     gpointer user_data)
index 59996d5..e678105 100644 (file)
@@ -41,6 +41,8 @@ G_BEGIN_DECLS
 typedef struct _GstRTSPClient GstRTSPClient;
 typedef struct _GstRTSPClientClass GstRTSPClientClass;
 
+#include "rtsp-auth.h"
+
 /**
  * GstRTSPClient:
  *
@@ -68,6 +70,7 @@ struct _GstRTSPClient {
 
   GstRTSPSessionPool   *session_pool;
   GstRTSPMediaMapping  *media_mapping;
+  GstRTSPAuth          *auth;
 
   GstRTSPUrl     *uri;
   GstRTSPMedia   *media;
@@ -92,6 +95,10 @@ void                  gst_rtsp_client_set_media_mapping (GstRTSPClient *client,
                                                          GstRTSPMediaMapping *mapping);
 GstRTSPMediaMapping * gst_rtsp_client_get_media_mapping (GstRTSPClient *client);
 
+void                  gst_rtsp_client_set_auth          (GstRTSPClient *client, GstRTSPAuth *auth);
+GstRTSPAuth *         gst_rtsp_client_get_auth          (GstRTSPClient *client);
+
+
 gboolean              gst_rtsp_client_accept            (GstRTSPClient *client,
                                                          GIOChannel *channel);
 
index 36c6b52..d7a0d1c 100644 (file)
@@ -17,6 +17,8 @@
  * Boston, MA 02111-1307, USA.
  */
 
+#include <sys/ioctl.h>
+
 #include "rtsp-server.h"
 #include "rtsp-client.h"
 
@@ -370,6 +372,54 @@ gst_rtsp_server_get_media_mapping (GstRTSPServer * server)
   return result;
 }
 
+/**
+ * gst_rtsp_server_set_auth:
+ * @server: a #GstRTSPServer
+ * @auth: a #GstRTSPAuth
+ *
+ * configure @auth to be used as the authentication manager of @server.
+ */
+void
+gst_rtsp_server_set_auth (GstRTSPServer * server, GstRTSPAuth * auth)
+{
+  GstRTSPAuth *old;
+
+  g_return_if_fail (GST_IS_RTSP_SERVER (server));
+
+  old = server->auth;
+
+  if (old != auth) {
+    if (auth)
+      g_object_ref (auth);
+    server->auth = auth;
+    if (old)
+      g_object_unref (old);
+  }
+}
+
+
+/**
+ * gst_rtsp_server_get_auth:
+ * @server: a #GstRTSPServer
+ *
+ * Get the #GstRTSPAuth used as the authentication manager of @server.
+ *
+ * Returns: the #GstRTSPAuth of @server. g_object_unref() after
+ * usage.
+ */
+GstRTSPAuth *
+gst_rtsp_server_get_auth (GstRTSPServer * server)
+{
+  GstRTSPAuth *result;
+
+  g_return_val_if_fail (GST_IS_RTSP_SERVER (server), NULL);
+
+  if ((result = server->auth))
+    g_object_ref (result);
+
+  return result;
+}
+
 static void
 gst_rtsp_server_get_property (GObject * object, guint propid,
     GValue * value, GParamSpec * pspec)
@@ -580,6 +630,8 @@ default_accept_client (GstRTSPServer * server, GIOChannel * channel)
   gst_rtsp_client_set_session_pool (client, server->session_pool);
   /* set the media mapping that this client should use */
   gst_rtsp_client_set_media_mapping (client, server->media_mapping);
+  /* set authentication manager */
+  gst_rtsp_client_set_auth (client, server->auth);
 
   /* accept connections for that client, this function returns after accepting
    * the connection and will run the remainder of the communication with the
index 296e19a..3354f8c 100644 (file)
@@ -37,6 +37,7 @@
 #include "rtsp-media-mapping.h"
 #include "rtsp-media-factory-uri.h"
 #include "rtsp-client.h"
+#include "rtsp-auth.h"
 
 #ifndef __GST_RTSP_SERVER_H__
 #define __GST_RTSP_SERVER_H__
@@ -75,6 +76,9 @@ struct _GstRTSPServer {
 
   /* media mapper for this server */
   GstRTSPMediaMapping *media_mapping;
+
+  /* authentication manager */
+  GstRTSPAuth *auth;
 };
 
 /**
@@ -110,6 +114,9 @@ GstRTSPSessionPool *  gst_rtsp_server_get_session_pool     (GstRTSPServer *serve
 void                  gst_rtsp_server_set_media_mapping    (GstRTSPServer *server, GstRTSPMediaMapping *mapping);
 GstRTSPMediaMapping * gst_rtsp_server_get_media_mapping    (GstRTSPServer *server);
 
+void                  gst_rtsp_server_set_auth             (GstRTSPServer *server, GstRTSPAuth *auth);
+GstRTSPAuth *         gst_rtsp_server_get_auth             (GstRTSPServer *server);
+
 gboolean              gst_rtsp_server_io_func              (GIOChannel *channel, GIOCondition condition,
                                                             GstRTSPServer *server);