From: Wim Taymans Date: Tue, 11 Jan 2011 23:17:54 +0000 (+0100) Subject: auth: add authentication object X-Git-Tag: 1.19.3~495^2~1387^2~88 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=5fb5f750208c7f35422a7fc3405fdb9b35b86fdc;p=platform%2Fupstream%2Fgstreamer.git auth: add authentication object Add an object that can check the authorization of requests. Implement basic authentication. Add example authentication to test-video --- diff --git a/examples/test-video.c b/examples/test-video.c index c4eed53..988c162 100644 --- a/examples/test-video.c +++ b/examples/test-video.c @@ -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 diff --git a/gst/rtsp-server/Makefile.am b/gst/rtsp-server/Makefile.am index 50e2718..ca400c0 100644 --- a/gst/rtsp-server/Makefile.am +++ b/gst/rtsp-server/Makefile.am @@ -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 index 0000000..ff83c1b --- /dev/null +++ b/gst/rtsp-server/rtsp-auth.c @@ -0,0 +1,220 @@ +/* GStreamer + * Copyright (C) 2010 Wim Taymans + * + * 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 + +#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 index 0000000..85ac733 --- /dev/null +++ b/gst/rtsp-server/rtsp-auth.h @@ -0,0 +1,79 @@ +/* GStreamer + * Copyright (C) 2010 Wim Taymans + * + * 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 + +#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__ */ diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index be193de..8465a97 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -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) diff --git a/gst/rtsp-server/rtsp-client.h b/gst/rtsp-server/rtsp-client.h index 59996d5..e678105 100644 --- a/gst/rtsp-server/rtsp-client.h +++ b/gst/rtsp-server/rtsp-client.h @@ -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); diff --git a/gst/rtsp-server/rtsp-server.c b/gst/rtsp-server/rtsp-server.c index 36c6b52..d7a0d1c 100644 --- a/gst/rtsp-server/rtsp-server.c +++ b/gst/rtsp-server/rtsp-server.c @@ -17,6 +17,8 @@ * Boston, MA 02111-1307, USA. */ +#include + #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 diff --git a/gst/rtsp-server/rtsp-server.h b/gst/rtsp-server/rtsp-server.h index 296e19a..3354f8c 100644 --- a/gst/rtsp-server/rtsp-server.h +++ b/gst/rtsp-server/rtsp-server.h @@ -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);