2 * Copyright (C) 2010 Wim Taymans <wim.taymans at gmail.com>
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
17 * Boston, MA 02110-1301, USA.
22 #include "rtsp-auth.h"
24 #define GST_RTSP_AUTH_GET_PRIVATE(obj) \
25 (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GST_TYPE_RTSP_AUTH, GstRTSPAuthPrivate))
27 struct _GstRTSPAuthPrivate
30 GHashTable *basic; /* protected by lock */
31 GstRTSPMethod methods;
40 GST_DEBUG_CATEGORY_STATIC (rtsp_auth_debug);
41 #define GST_CAT_DEFAULT rtsp_auth_debug
43 static void gst_rtsp_auth_get_property (GObject * object, guint propid,
44 GValue * value, GParamSpec * pspec);
45 static void gst_rtsp_auth_set_property (GObject * object, guint propid,
46 const GValue * value, GParamSpec * pspec);
47 static void gst_rtsp_auth_finalize (GObject * obj);
49 static gboolean default_setup (GstRTSPAuth * auth, GstRTSPClientState * state);
50 static gboolean default_authenticate (GstRTSPAuth * auth,
51 GstRTSPClientState * state);
52 static gboolean default_check (GstRTSPAuth * auth, GstRTSPClientState * state,
55 G_DEFINE_TYPE (GstRTSPAuth, gst_rtsp_auth, G_TYPE_OBJECT);
58 gst_rtsp_auth_class_init (GstRTSPAuthClass * klass)
60 GObjectClass *gobject_class;
62 g_type_class_add_private (klass, sizeof (GstRTSPAuthPrivate));
64 gobject_class = G_OBJECT_CLASS (klass);
66 gobject_class->get_property = gst_rtsp_auth_get_property;
67 gobject_class->set_property = gst_rtsp_auth_set_property;
68 gobject_class->finalize = gst_rtsp_auth_finalize;
70 klass->setup = default_setup;
71 klass->authenticate = default_authenticate;
72 klass->check = default_check;
74 GST_DEBUG_CATEGORY_INIT (rtsp_auth_debug, "rtspauth", 0, "GstRTSPAuth");
78 gst_rtsp_auth_init (GstRTSPAuth * auth)
80 GstRTSPAuthPrivate *priv;
82 auth->priv = priv = GST_RTSP_AUTH_GET_PRIVATE (auth);
84 g_mutex_init (&priv->lock);
86 priv->basic = g_hash_table_new_full (g_str_hash, g_str_equal, g_free,
87 (GDestroyNotify) gst_rtsp_token_unref);
89 /* bitwise or of all methods that need authentication */
90 priv->methods = GST_RTSP_DESCRIBE |
92 GST_RTSP_GET_PARAMETER |
93 GST_RTSP_SET_PARAMETER |
95 GST_RTSP_PLAY | GST_RTSP_RECORD | GST_RTSP_SETUP | GST_RTSP_TEARDOWN;
99 gst_rtsp_auth_finalize (GObject * obj)
101 GstRTSPAuth *auth = GST_RTSP_AUTH (obj);
102 GstRTSPAuthPrivate *priv = auth->priv;
104 GST_INFO ("finalize auth %p", auth);
105 g_hash_table_unref (priv->basic);
106 g_mutex_clear (&priv->lock);
108 G_OBJECT_CLASS (gst_rtsp_auth_parent_class)->finalize (obj);
112 gst_rtsp_auth_get_property (GObject * object, guint propid,
113 GValue * value, GParamSpec * pspec)
117 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec);
122 gst_rtsp_auth_set_property (GObject * object, guint propid,
123 const GValue * value, GParamSpec * pspec)
127 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec);
134 * Create a new #GstRTSPAuth instance.
136 * Returns: a new #GstRTSPAuth
139 gst_rtsp_auth_new (void)
143 result = g_object_new (GST_TYPE_RTSP_AUTH, NULL);
149 * gst_rtsp_auth_add_basic:
150 * @auth: a #GstRTSPAuth
151 * @basic: the basic token
152 * @token: authorisation token
154 * Add a basic token for the default authentication algorithm that
155 * enables the client with privileges listed in @token.
158 gst_rtsp_auth_add_basic (GstRTSPAuth * auth, const gchar * basic,
159 GstRTSPToken * token)
161 GstRTSPAuthPrivate *priv;
163 g_return_if_fail (GST_IS_RTSP_AUTH (auth));
164 g_return_if_fail (basic != NULL);
165 g_return_if_fail (GST_IS_RTSP_TOKEN (token));
169 g_mutex_lock (&priv->lock);
170 g_hash_table_replace (priv->basic, g_strdup (basic),
171 gst_rtsp_token_ref (token));
172 g_mutex_unlock (&priv->lock);
176 * gst_rtsp_auth_remove_basic:
177 * @auth: a #GstRTSPAuth
178 * @basic: (transfer none): the basic token
180 * Add a basic token for the default authentication algorithm that
181 * enables the client qith privileges from @authgroup.
184 gst_rtsp_auth_remove_basic (GstRTSPAuth * auth, const gchar * basic)
186 GstRTSPAuthPrivate *priv;
188 g_return_if_fail (GST_IS_RTSP_AUTH (auth));
189 g_return_if_fail (basic != NULL);
193 g_mutex_lock (&priv->lock);
194 g_hash_table_remove (priv->basic, basic);
195 g_mutex_unlock (&priv->lock);
199 default_setup (GstRTSPAuth * auth, GstRTSPClientState * state)
201 if (state->response == NULL)
204 /* we only have Basic for now */
205 gst_rtsp_message_add_header (state->response, GST_RTSP_HDR_WWW_AUTHENTICATE,
206 "Basic realm=\"GStreamer RTSP Server\"");
212 * gst_rtsp_auth_setup:
213 * @auth: a #GstRTSPAuth
214 * @client: the client
217 * Add authentication tokens to @response.
219 * Returns: FALSE if something is wrong.
222 gst_rtsp_auth_setup (GstRTSPAuth * auth, GstRTSPClientState * state)
224 gboolean result = FALSE;
225 GstRTSPAuthClass *klass;
227 g_return_val_if_fail (GST_IS_RTSP_AUTH (auth), FALSE);
228 g_return_val_if_fail (state != NULL, FALSE);
230 klass = GST_RTSP_AUTH_GET_CLASS (auth);
232 GST_DEBUG_OBJECT (auth, "setup auth");
235 result = klass->setup (auth, state);
241 default_authenticate (GstRTSPAuth * auth, GstRTSPClientState * state)
243 GstRTSPAuthPrivate *priv = auth->priv;
245 gchar *authorization;
247 GST_DEBUG_OBJECT (auth, "authenticate");
250 gst_rtsp_message_get_header (state->request, GST_RTSP_HDR_AUTHORIZATION,
256 if (g_ascii_strncasecmp (authorization, "basic ", 6) == 0) {
259 GST_DEBUG_OBJECT (auth, "check Basic auth");
260 g_mutex_lock (&priv->lock);
261 if ((token = g_hash_table_lookup (priv->basic, &authorization[6]))) {
262 GST_DEBUG_OBJECT (auth, "setting token %p", token);
263 state->token = token;
265 g_mutex_unlock (&priv->lock);
266 } else if (g_ascii_strncasecmp (authorization, "digest ", 7) == 0) {
267 GST_DEBUG_OBJECT (auth, "check Digest auth");
268 /* not implemented yet */
274 GST_DEBUG_OBJECT (auth, "no authorization header found");
280 ensure_authenticated (GstRTSPAuth * auth, GstRTSPClientState * state)
282 GstRTSPAuthClass *klass;
284 klass = GST_RTSP_AUTH_GET_CLASS (auth);
286 /* we need a token to check */
287 if (state->token == NULL) {
288 if (klass->authenticate) {
289 if (!klass->authenticate (auth, state))
290 goto authenticate_failed;
293 if (state->token == NULL)
301 GST_DEBUG_OBJECT (auth, "authenticate failed");
306 GST_DEBUG_OBJECT (auth, "no authorization token found");
312 default_check (GstRTSPAuth * auth, GstRTSPClientState * state,
315 GstRTSPAuthPrivate *priv = auth->priv;
316 gboolean res = FALSE;
318 if (g_str_equal (check, GST_RTSP_AUTH_CHECK_URL)) {
319 if ((state->method & priv->methods) != 0)
320 res = ensure_authenticated (auth, state);
323 } else if (g_str_has_prefix (check, "auth.check.media.factory.")) {
325 GstRTSPPermissions *perms;
328 gst_rtsp_token_get_string (state->token,
329 GST_RTSP_MEDIA_FACTORY_ROLE)))
331 if (!(perms = gst_rtsp_media_factory_get_permissions (state->factory)))
334 if (g_str_equal (check, "auth.check.media.factory.access"))
336 gst_rtsp_permissions_is_allowed (perms, role,
337 GST_RTSP_MEDIA_FACTORY_PERM_ACCESS);
338 else if (g_str_equal (check, "auth.check.media.factory.construct"))
340 gst_rtsp_permissions_is_allowed (perms, role,
341 GST_RTSP_MEDIA_FACTORY_PERM_CONSTRUCT);
348 * gst_rtsp_auth_check:
349 * @check: the item to check
351 * Check if @check is allowed in the current context.
353 * Returns: FALSE if check failed.
356 gst_rtsp_auth_check (const gchar * check)
358 gboolean result = FALSE;
359 GstRTSPAuthClass *klass;
360 GstRTSPClientState *state;
363 g_return_val_if_fail (check != NULL, FALSE);
365 if (!(state = gst_rtsp_client_state_get_current ()))
368 /* no auth, we don't need to check */
369 if (!(auth = state->auth))
372 klass = GST_RTSP_AUTH_GET_CLASS (auth);
374 GST_DEBUG_OBJECT (auth, "check authorization '%s'", check);
377 result = klass->check (auth, state, check);
384 GST_ERROR ("no clientstate found");
390 * gst_rtsp_auth_make_basic:
394 * Construct a Basic authorisation token from @user and @pass.
396 * Returns: the base64 encoding of the string @user:@pass. g_free()
400 gst_rtsp_auth_make_basic (const gchar * user, const gchar * pass)
405 g_return_val_if_fail (user != NULL, NULL);
406 g_return_val_if_fail (pass != NULL, NULL);
408 user_pass = g_strjoin (":", user, pass, NULL);
409 result = g_base64_encode ((guchar *) user_pass, strlen (user_pass));