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.
21 * @short_description: Authentication and authorization
22 * @see_also: #GstRTSPPermission, #GstRTSPtoken
24 * The #GstRTSPAuth object is responsible for checking if the current user is
25 * allowed to perform requested actions. The default implementation has some
26 * reasonable checks but subclasses can implement custom security policies.
28 * A new auth object is made with gst_rtsp_auth_new(). It is usually configured
29 * on the #GstRTSPServer object.
31 * The RTSP server will call gst_rtsp_auth_check() with a string describing the
32 * check to perform. The possible checks are prefixed with
33 * #GST_RTSP_AUTH_CHECK_*. Depending on the check, the default implementation
34 * will use the current #GstRTSPToken, #GstRTSPContext and
35 * #GstRTSPPermissions on the object to check if an operation is allowed.
37 * The default #GstRTSPAuth object has support for basic authentication. With
38 * gst_rtsp_auth_add_basic() you can add a basic authentication string together
39 * with the #GstRTSPToken that will become active when successfully
42 * When a TLS certificate has been set with gst_rtsp_auth_set_tls_certificate(),
43 * the default auth object will require the client to connect with a TLS
46 * Last reviewed on 2013-07-16 (1.0.0)
51 #include "rtsp-auth.h"
53 #define GST_RTSP_AUTH_GET_PRIVATE(obj) \
54 (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GST_TYPE_RTSP_AUTH, GstRTSPAuthPrivate))
56 struct _GstRTSPAuthPrivate
60 /* the TLS certificate */
61 GTlsCertificate *certificate;
62 GHashTable *basic; /* protected by lock */
63 GstRTSPToken *default_token;
64 GstRTSPMethod methods;
73 GST_DEBUG_CATEGORY_STATIC (rtsp_auth_debug);
74 #define GST_CAT_DEFAULT rtsp_auth_debug
76 static void gst_rtsp_auth_get_property (GObject * object, guint propid,
77 GValue * value, GParamSpec * pspec);
78 static void gst_rtsp_auth_set_property (GObject * object, guint propid,
79 const GValue * value, GParamSpec * pspec);
80 static void gst_rtsp_auth_finalize (GObject * obj);
82 static gboolean default_authenticate (GstRTSPAuth * auth, GstRTSPContext * ctx);
83 static gboolean default_check (GstRTSPAuth * auth, GstRTSPContext * ctx,
86 G_DEFINE_TYPE (GstRTSPAuth, gst_rtsp_auth, G_TYPE_OBJECT);
89 gst_rtsp_auth_class_init (GstRTSPAuthClass * klass)
91 GObjectClass *gobject_class;
93 g_type_class_add_private (klass, sizeof (GstRTSPAuthPrivate));
95 gobject_class = G_OBJECT_CLASS (klass);
97 gobject_class->get_property = gst_rtsp_auth_get_property;
98 gobject_class->set_property = gst_rtsp_auth_set_property;
99 gobject_class->finalize = gst_rtsp_auth_finalize;
101 klass->authenticate = default_authenticate;
102 klass->check = default_check;
104 GST_DEBUG_CATEGORY_INIT (rtsp_auth_debug, "rtspauth", 0, "GstRTSPAuth");
108 gst_rtsp_auth_init (GstRTSPAuth * auth)
110 GstRTSPAuthPrivate *priv;
112 auth->priv = priv = GST_RTSP_AUTH_GET_PRIVATE (auth);
114 g_mutex_init (&priv->lock);
116 priv->basic = g_hash_table_new_full (g_str_hash, g_str_equal, g_free,
117 (GDestroyNotify) gst_rtsp_token_unref);
119 /* bitwise or of all methods that need authentication */
124 gst_rtsp_auth_finalize (GObject * obj)
126 GstRTSPAuth *auth = GST_RTSP_AUTH (obj);
127 GstRTSPAuthPrivate *priv = auth->priv;
129 GST_INFO ("finalize auth %p", auth);
131 if (priv->certificate)
132 g_object_unref (priv->certificate);
133 g_hash_table_unref (priv->basic);
134 g_mutex_clear (&priv->lock);
136 G_OBJECT_CLASS (gst_rtsp_auth_parent_class)->finalize (obj);
140 gst_rtsp_auth_get_property (GObject * object, guint propid,
141 GValue * value, GParamSpec * pspec)
145 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec);
150 gst_rtsp_auth_set_property (GObject * object, guint propid,
151 const GValue * value, GParamSpec * pspec)
155 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec);
162 * Create a new #GstRTSPAuth instance.
164 * Returns: a new #GstRTSPAuth
167 gst_rtsp_auth_new (void)
171 result = g_object_new (GST_TYPE_RTSP_AUTH, NULL);
177 * gst_rtsp_auth_set_tls_certificate:
178 * @auth: a #GstRTSPAuth
179 * @cert: (allow none): a #GTlsCertificate
181 * Set the TLS certificate for the auth. Client connections will only
182 * be accepted when TLS is negotiated.
185 gst_rtsp_auth_set_tls_certificate (GstRTSPAuth * auth, GTlsCertificate * cert)
187 GstRTSPAuthPrivate *priv;
188 GTlsCertificate *old;
190 g_return_if_fail (GST_IS_RTSP_AUTH (auth));
197 g_mutex_lock (&priv->lock);
198 old = priv->certificate;
199 priv->certificate = cert;
200 g_mutex_unlock (&priv->lock);
203 g_object_unref (old);
207 * gst_rtsp_auth_get_tls_certificate:
208 * @auth: a #GstRTSPAuth
210 * Get the #GTlsCertificate used for negotiating TLS @auth.
212 * Returns: (transfer full): the #GTlsCertificate of @auth. g_object_unref() after
216 gst_rtsp_auth_get_tls_certificate (GstRTSPAuth * auth)
218 GstRTSPAuthPrivate *priv;
219 GTlsCertificate *result;
221 g_return_val_if_fail (GST_IS_RTSP_AUTH (auth), NULL);
225 g_mutex_lock (&priv->lock);
226 if ((result = priv->certificate))
227 g_object_ref (result);
228 g_mutex_unlock (&priv->lock);
234 * gst_rtsp_auth_set_default_token:
235 * @auth: a #GstRTSPAuth
236 * @token: (allow none): a #GstRTSPToken
238 * Set the default #GstRTSPToken to @token in @auth. The default token will
239 * be used for unauthenticated users.
242 gst_rtsp_auth_set_default_token (GstRTSPAuth * auth, GstRTSPToken * token)
244 GstRTSPAuthPrivate *priv;
247 g_return_if_fail (GST_IS_RTSP_AUTH (auth));
252 gst_rtsp_token_ref (token);
254 g_mutex_lock (&priv->lock);
255 old = priv->default_token;
256 priv->default_token = token;
257 g_mutex_unlock (&priv->lock);
260 gst_rtsp_token_unref (old);
264 * gst_rtsp_auth_get_default_token:
265 * @auth: a #GstRTSPAuth
267 * Get the default token for @auth. This token will be used for unauthorized
270 * Returns: (transfer full): the #GstRTSPToken of @auth. gst_rtsp_token_unref() after
274 gst_rtsp_auth_get_default_token (GstRTSPAuth * auth)
276 GstRTSPAuthPrivate *priv;
277 GstRTSPToken *result;
279 g_return_val_if_fail (GST_IS_RTSP_AUTH (auth), NULL);
283 g_mutex_lock (&priv->lock);
284 if ((result = priv->default_token))
285 gst_rtsp_token_ref (result);
286 g_mutex_unlock (&priv->lock);
292 * gst_rtsp_auth_add_basic:
293 * @auth: a #GstRTSPAuth
294 * @basic: the basic token
295 * @token: authorisation token
297 * Add a basic token for the default authentication algorithm that
298 * enables the client with privileges listed in @token.
301 gst_rtsp_auth_add_basic (GstRTSPAuth * auth, const gchar * basic,
302 GstRTSPToken * token)
304 GstRTSPAuthPrivate *priv;
306 g_return_if_fail (GST_IS_RTSP_AUTH (auth));
307 g_return_if_fail (basic != NULL);
308 g_return_if_fail (GST_IS_RTSP_TOKEN (token));
312 g_mutex_lock (&priv->lock);
313 g_hash_table_replace (priv->basic, g_strdup (basic),
314 gst_rtsp_token_ref (token));
315 g_mutex_unlock (&priv->lock);
319 * gst_rtsp_auth_remove_basic:
320 * @auth: a #GstRTSPAuth
321 * @basic: (transfer none): the basic token
323 * Add a basic token for the default authentication algorithm that
324 * enables the client qith privileges from @authgroup.
327 gst_rtsp_auth_remove_basic (GstRTSPAuth * auth, const gchar * basic)
329 GstRTSPAuthPrivate *priv;
331 g_return_if_fail (GST_IS_RTSP_AUTH (auth));
332 g_return_if_fail (basic != NULL);
336 g_mutex_lock (&priv->lock);
337 g_hash_table_remove (priv->basic, basic);
338 g_mutex_unlock (&priv->lock);
342 default_authenticate (GstRTSPAuth * auth, GstRTSPContext * ctx)
344 GstRTSPAuthPrivate *priv = auth->priv;
346 gchar *authorization;
348 GST_DEBUG_OBJECT (auth, "authenticate");
350 g_mutex_lock (&priv->lock);
351 /* FIXME, need to ref but we have no way to unref when the ctx is
353 ctx->token = priv->default_token;
354 g_mutex_unlock (&priv->lock);
357 gst_rtsp_message_get_header (ctx->request, GST_RTSP_HDR_AUTHORIZATION,
363 if (g_ascii_strncasecmp (authorization, "basic ", 6) == 0) {
366 GST_DEBUG_OBJECT (auth, "check Basic auth");
367 g_mutex_lock (&priv->lock);
368 if ((token = g_hash_table_lookup (priv->basic, &authorization[6]))) {
369 GST_DEBUG_OBJECT (auth, "setting token %p", token);
372 g_mutex_unlock (&priv->lock);
373 } else if (g_ascii_strncasecmp (authorization, "digest ", 7) == 0) {
374 GST_DEBUG_OBJECT (auth, "check Digest auth");
375 /* not implemented yet */
381 GST_DEBUG_OBJECT (auth, "no authorization header found");
387 send_response (GstRTSPAuth * auth, GstRTSPStatusCode code, GstRTSPContext * ctx)
389 gst_rtsp_message_init_response (ctx->response, code,
390 gst_rtsp_status_as_text (code), ctx->request);
392 if (code == GST_RTSP_STS_UNAUTHORIZED) {
393 /* we only have Basic for now */
394 gst_rtsp_message_add_header (ctx->response, GST_RTSP_HDR_WWW_AUTHENTICATE,
395 "Basic realm=\"GStreamer RTSP Server\"");
397 gst_rtsp_client_send_message (ctx->client, ctx->session, ctx->response);
401 ensure_authenticated (GstRTSPAuth * auth, GstRTSPContext * ctx)
403 GstRTSPAuthClass *klass;
405 klass = GST_RTSP_AUTH_GET_CLASS (auth);
407 /* we need a token to check */
408 if (ctx->token == NULL) {
409 if (klass->authenticate) {
410 if (!klass->authenticate (auth, ctx))
411 goto authenticate_failed;
414 if (ctx->token == NULL)
422 GST_DEBUG_OBJECT (auth, "authenticate failed");
423 send_response (auth, GST_RTSP_STS_UNAUTHORIZED, ctx);
428 GST_DEBUG_OBJECT (auth, "no authorization token found");
429 send_response (auth, GST_RTSP_STS_UNAUTHORIZED, ctx);
436 check_connect (GstRTSPAuth * auth, GstRTSPContext * ctx, const gchar * check)
438 GstRTSPAuthPrivate *priv = auth->priv;
440 if (priv->certificate) {
443 /* configure the connection */
444 tls = gst_rtsp_connection_get_tls (ctx->conn, NULL);
445 g_tls_connection_set_certificate (tls, priv->certificate);
450 /* check url and methods */
452 check_url (GstRTSPAuth * auth, GstRTSPContext * ctx, const gchar * check)
454 GstRTSPAuthPrivate *priv = auth->priv;
456 if ((ctx->method & priv->methods) != 0)
457 if (!ensure_authenticated (auth, ctx))
458 goto not_authenticated;
469 /* check access to media factory */
471 check_factory (GstRTSPAuth * auth, GstRTSPContext * ctx, const gchar * check)
474 GstRTSPPermissions *perms;
476 if (!ensure_authenticated (auth, ctx))
479 if (!(role = gst_rtsp_token_get_string (ctx->token,
480 GST_RTSP_TOKEN_MEDIA_FACTORY_ROLE)))
482 if (!(perms = gst_rtsp_media_factory_get_permissions (ctx->factory)))
485 if (g_str_equal (check, GST_RTSP_AUTH_CHECK_MEDIA_FACTORY_ACCESS)) {
486 if (!gst_rtsp_permissions_is_allowed (perms, role,
487 GST_RTSP_PERM_MEDIA_FACTORY_ACCESS))
489 } else if (g_str_equal (check, GST_RTSP_AUTH_CHECK_MEDIA_FACTORY_CONSTRUCT)) {
490 if (!gst_rtsp_permissions_is_allowed (perms, role,
491 GST_RTSP_PERM_MEDIA_FACTORY_CONSTRUCT))
495 gst_rtsp_permissions_unref (perms);
502 GST_DEBUG_OBJECT (auth, "no media factory role found");
503 send_response (auth, GST_RTSP_STS_UNAUTHORIZED, ctx);
508 GST_DEBUG_OBJECT (auth, "no permissions on media factory found");
509 send_response (auth, GST_RTSP_STS_UNAUTHORIZED, ctx);
514 GST_DEBUG_OBJECT (auth, "no permissions to access media factory");
515 gst_rtsp_permissions_unref (perms);
516 send_response (auth, GST_RTSP_STS_NOT_FOUND, ctx);
521 GST_DEBUG_OBJECT (auth, "no permissions to construct media factory");
522 gst_rtsp_permissions_unref (perms);
523 send_response (auth, GST_RTSP_STS_UNAUTHORIZED, ctx);
529 check_client_settings (GstRTSPAuth * auth, GstRTSPContext * ctx,
532 if (!ensure_authenticated (auth, ctx))
535 return gst_rtsp_token_is_allowed (ctx->token,
536 GST_RTSP_TOKEN_TRANSPORT_CLIENT_SETTINGS);
540 default_check (GstRTSPAuth * auth, GstRTSPContext * ctx, const gchar * check)
542 gboolean res = FALSE;
544 /* FIXME, use hastable or so */
545 if (g_str_equal (check, GST_RTSP_AUTH_CHECK_CONNECT)) {
546 res = check_connect (auth, ctx, check);
547 } else if (g_str_equal (check, GST_RTSP_AUTH_CHECK_URL)) {
548 res = check_url (auth, ctx, check);
549 } else if (g_str_has_prefix (check, "auth.check.media.factory.")) {
550 res = check_factory (auth, ctx, check);
551 } else if (g_str_equal (check, GST_RTSP_AUTH_CHECK_TRANSPORT_CLIENT_SETTINGS)) {
552 res = check_client_settings (auth, ctx, check);
558 no_auth_check (const gchar * check)
562 if (g_str_equal (check, GST_RTSP_AUTH_CHECK_TRANSPORT_CLIENT_SETTINGS))
571 * gst_rtsp_auth_check:
572 * @check: the item to check
574 * Check if @check is allowed in the current context.
576 * Returns: FALSE if check failed.
579 gst_rtsp_auth_check (const gchar * check)
581 gboolean result = FALSE;
582 GstRTSPAuthClass *klass;
586 g_return_val_if_fail (check != NULL, FALSE);
588 if (!(ctx = gst_rtsp_context_get_current ()))
591 /* no auth, we don't need to check */
592 if (!(auth = ctx->auth))
593 return no_auth_check (check);
595 klass = GST_RTSP_AUTH_GET_CLASS (auth);
597 GST_DEBUG_OBJECT (auth, "check authorization '%s'", check);
600 result = klass->check (auth, ctx, check);
607 GST_ERROR ("no context found");
613 * gst_rtsp_auth_make_basic:
617 * Construct a Basic authorisation token from @user and @pass.
619 * Returns: the base64 encoding of the string @user:@pass. g_free()
623 gst_rtsp_auth_make_basic (const gchar * user, const gchar * pass)
628 g_return_val_if_fail (user != NULL, NULL);
629 g_return_val_if_fail (pass != NULL, NULL);
631 user_pass = g_strjoin (":", user, pass, NULL);
632 result = g_base64_encode ((guchar *) user_pass, strlen (user_pass));