media: enable per factory authorisations

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.
This commit is contained in:
Wim Taymans 2011-01-12 13:57:09 +01:00
parent 5773df1d52
commit 7797023fda
12 changed files with 227 additions and 26 deletions

1
examples/.gitignore vendored
View file

@ -5,3 +5,4 @@ test-readme
test-sdp
test-video
test-uri
test-auth

View 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)

115
examples/test-auth.c Normal file
View file

@ -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;
}
}

View 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.

View 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;
}

View 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);

View 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;
}
}

View 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);
}
}

View file

@ -522,6 +522,54 @@ gst_rtsp_media_is_eos_shutdown (GstRTSPMedia * media)
return media->eos_shutdown;
}
/**
* 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

View 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);

View file

@ -22,10 +22,14 @@
#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.

View 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