Initial release including wifi display based on gst-rtsp-server-1.4.1
[platform/upstream/gstreamer.git] / gst / rtsp-server / rtsp-auth.c
1 /* GStreamer
2  * Copyright (C) 2010 Wim Taymans <wim.taymans at gmail.com>
3  *
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.
8  *
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.
13  *
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.
18  */
19 /**
20  * SECTION:rtsp-auth
21  * @short_description: Authentication and authorization
22  * @see_also: #GstRTSPPermissions, #GstRTSPToken
23  *
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.
27  *
28  * A new auth object is made with gst_rtsp_auth_new(). It is usually configured
29  * on the #GstRTSPServer object.
30  *
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.
36  *
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
40  * authenticated.
41  *
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
44  * connection.
45  *
46  * Last reviewed on 2013-07-16 (1.0.0)
47  */
48
49 #include <string.h>
50
51 #include "rtsp-auth.h"
52
53 #define GST_RTSP_AUTH_GET_PRIVATE(obj)  \
54    (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GST_TYPE_RTSP_AUTH, GstRTSPAuthPrivate))
55
56 struct _GstRTSPAuthPrivate
57 {
58   GMutex lock;
59
60   /* the TLS certificate */
61   GTlsCertificate *certificate;
62   GHashTable *basic;            /* protected by lock */
63   GstRTSPToken *default_token;
64   GstRTSPMethod methods;
65 };
66
67 enum
68 {
69   PROP_0,
70   PROP_LAST
71 };
72
73 GST_DEBUG_CATEGORY_STATIC (rtsp_auth_debug);
74 #define GST_CAT_DEFAULT rtsp_auth_debug
75
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);
81
82 static gboolean default_authenticate (GstRTSPAuth * auth, GstRTSPContext * ctx);
83 static gboolean default_check (GstRTSPAuth * auth, GstRTSPContext * ctx,
84     const gchar * check);
85
86 G_DEFINE_TYPE (GstRTSPAuth, gst_rtsp_auth, G_TYPE_OBJECT);
87
88 static void
89 gst_rtsp_auth_class_init (GstRTSPAuthClass * klass)
90 {
91   GObjectClass *gobject_class;
92
93   g_type_class_add_private (klass, sizeof (GstRTSPAuthPrivate));
94
95   gobject_class = G_OBJECT_CLASS (klass);
96
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;
100
101   klass->authenticate = default_authenticate;
102   klass->check = default_check;
103
104   GST_DEBUG_CATEGORY_INIT (rtsp_auth_debug, "rtspauth", 0, "GstRTSPAuth");
105 }
106
107 static void
108 gst_rtsp_auth_init (GstRTSPAuth * auth)
109 {
110   GstRTSPAuthPrivate *priv;
111
112   auth->priv = priv = GST_RTSP_AUTH_GET_PRIVATE (auth);
113
114   g_mutex_init (&priv->lock);
115
116   priv->basic = g_hash_table_new_full (g_str_hash, g_str_equal, g_free,
117       (GDestroyNotify) gst_rtsp_token_unref);
118
119   /* bitwise or of all methods that need authentication */
120   priv->methods = 0;
121 }
122
123 static void
124 gst_rtsp_auth_finalize (GObject * obj)
125 {
126   GstRTSPAuth *auth = GST_RTSP_AUTH (obj);
127   GstRTSPAuthPrivate *priv = auth->priv;
128
129   GST_INFO ("finalize auth %p", auth);
130
131   if (priv->certificate)
132     g_object_unref (priv->certificate);
133   g_hash_table_unref (priv->basic);
134   g_mutex_clear (&priv->lock);
135
136   G_OBJECT_CLASS (gst_rtsp_auth_parent_class)->finalize (obj);
137 }
138
139 static void
140 gst_rtsp_auth_get_property (GObject * object, guint propid,
141     GValue * value, GParamSpec * pspec)
142 {
143   switch (propid) {
144     default:
145       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec);
146   }
147 }
148
149 static void
150 gst_rtsp_auth_set_property (GObject * object, guint propid,
151     const GValue * value, GParamSpec * pspec)
152 {
153   switch (propid) {
154     default:
155       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec);
156   }
157 }
158
159 /**
160  * gst_rtsp_auth_new:
161  *
162  * Create a new #GstRTSPAuth instance.
163  *
164  * Returns: (transfer full): a new #GstRTSPAuth
165  */
166 GstRTSPAuth *
167 gst_rtsp_auth_new (void)
168 {
169   GstRTSPAuth *result;
170
171   result = g_object_new (GST_TYPE_RTSP_AUTH, NULL);
172
173   return result;
174 }
175
176 /**
177  * gst_rtsp_auth_set_tls_certificate:
178  * @auth: a #GstRTSPAuth
179  * @cert: (transfer none) (allow-none): a #GTlsCertificate
180  *
181  * Set the TLS certificate for the auth. Client connections will only
182  * be accepted when TLS is negotiated.
183  */
184 void
185 gst_rtsp_auth_set_tls_certificate (GstRTSPAuth * auth, GTlsCertificate * cert)
186 {
187   GstRTSPAuthPrivate *priv;
188   GTlsCertificate *old;
189
190   g_return_if_fail (GST_IS_RTSP_AUTH (auth));
191
192   priv = auth->priv;
193
194   if (cert)
195     g_object_ref (cert);
196
197   g_mutex_lock (&priv->lock);
198   old = priv->certificate;
199   priv->certificate = cert;
200   g_mutex_unlock (&priv->lock);
201
202   if (old)
203     g_object_unref (old);
204 }
205
206 /**
207  * gst_rtsp_auth_get_tls_certificate:
208  * @auth: a #GstRTSPAuth
209  *
210  * Get the #GTlsCertificate used for negotiating TLS @auth.
211  *
212  * Returns: (transfer full): the #GTlsCertificate of @auth. g_object_unref() after
213  * usage.
214  */
215 GTlsCertificate *
216 gst_rtsp_auth_get_tls_certificate (GstRTSPAuth * auth)
217 {
218   GstRTSPAuthPrivate *priv;
219   GTlsCertificate *result;
220
221   g_return_val_if_fail (GST_IS_RTSP_AUTH (auth), NULL);
222
223   priv = auth->priv;
224
225   g_mutex_lock (&priv->lock);
226   if ((result = priv->certificate))
227     g_object_ref (result);
228   g_mutex_unlock (&priv->lock);
229
230   return result;
231 }
232
233 /**
234  * gst_rtsp_auth_set_default_token:
235  * @auth: a #GstRTSPAuth
236  * @token: (transfer none) (allow-none): a #GstRTSPToken
237  *
238  * Set the default #GstRTSPToken to @token in @auth. The default token will
239  * be used for unauthenticated users.
240  */
241 void
242 gst_rtsp_auth_set_default_token (GstRTSPAuth * auth, GstRTSPToken * token)
243 {
244   GstRTSPAuthPrivate *priv;
245   GstRTSPToken *old;
246
247   g_return_if_fail (GST_IS_RTSP_AUTH (auth));
248
249   priv = auth->priv;
250
251   if (token)
252     gst_rtsp_token_ref (token);
253
254   g_mutex_lock (&priv->lock);
255   old = priv->default_token;
256   priv->default_token = token;
257   g_mutex_unlock (&priv->lock);
258
259   if (old)
260     gst_rtsp_token_unref (old);
261 }
262
263 /**
264  * gst_rtsp_auth_get_default_token:
265  * @auth: a #GstRTSPAuth
266  *
267  * Get the default token for @auth. This token will be used for unauthenticated
268  * users.
269  *
270  * Returns: (transfer full): the #GstRTSPToken of @auth. gst_rtsp_token_unref() after
271  * usage.
272  */
273 GstRTSPToken *
274 gst_rtsp_auth_get_default_token (GstRTSPAuth * auth)
275 {
276   GstRTSPAuthPrivate *priv;
277   GstRTSPToken *result;
278
279   g_return_val_if_fail (GST_IS_RTSP_AUTH (auth), NULL);
280
281   priv = auth->priv;
282
283   g_mutex_lock (&priv->lock);
284   if ((result = priv->default_token))
285     gst_rtsp_token_ref (result);
286   g_mutex_unlock (&priv->lock);
287
288   return result;
289 }
290
291 /**
292  * gst_rtsp_auth_add_basic:
293  * @auth: a #GstRTSPAuth
294  * @basic: the basic token
295  * @token: (transfer none): authorisation token
296  *
297  * Add a basic token for the default authentication algorithm that
298  * enables the client with privileges listed in @token.
299  */
300 void
301 gst_rtsp_auth_add_basic (GstRTSPAuth * auth, const gchar * basic,
302     GstRTSPToken * token)
303 {
304   GstRTSPAuthPrivate *priv;
305
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));
309
310   priv = auth->priv;
311
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);
316 }
317
318 /**
319  * gst_rtsp_auth_remove_basic:
320  * @auth: a #GstRTSPAuth
321  * @basic: (transfer none): the basic token
322  *
323  * Add a basic token for the default authentication algorithm that
324  * enables the client with privileges from @authgroup.
325  */
326 void
327 gst_rtsp_auth_remove_basic (GstRTSPAuth * auth, const gchar * basic)
328 {
329   GstRTSPAuthPrivate *priv;
330
331   g_return_if_fail (GST_IS_RTSP_AUTH (auth));
332   g_return_if_fail (basic != NULL);
333
334   priv = auth->priv;
335
336   g_mutex_lock (&priv->lock);
337   g_hash_table_remove (priv->basic, basic);
338   g_mutex_unlock (&priv->lock);
339 }
340
341 static gboolean
342 default_authenticate (GstRTSPAuth * auth, GstRTSPContext * ctx)
343 {
344   GstRTSPAuthPrivate *priv = auth->priv;
345   GstRTSPResult res;
346   gchar *authorization;
347
348   GST_DEBUG_OBJECT (auth, "authenticate");
349
350   g_mutex_lock (&priv->lock);
351   /* FIXME, need to ref but we have no way to unref when the ctx is
352    * popped */
353   ctx->token = priv->default_token;
354   g_mutex_unlock (&priv->lock);
355
356   res =
357       gst_rtsp_message_get_header (ctx->request, GST_RTSP_HDR_AUTHORIZATION,
358       &authorization, 0);
359   if (res < 0)
360     goto no_auth;
361
362   /* parse type */
363   if (g_ascii_strncasecmp (authorization, "basic ", 6) == 0) {
364     GstRTSPToken *token;
365
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);
370       ctx->token = token;
371     }
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 */
376   }
377   return TRUE;
378
379 no_auth:
380   {
381     GST_DEBUG_OBJECT (auth, "no authorization header found");
382     return TRUE;
383   }
384 }
385
386 static void
387 send_response (GstRTSPAuth * auth, GstRTSPStatusCode code, GstRTSPContext * ctx)
388 {
389   gst_rtsp_message_init_response (ctx->response, code,
390       gst_rtsp_status_as_text (code), ctx->request);
391
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\"");
396   }
397   gst_rtsp_client_send_message (ctx->client, ctx->session, ctx->response);
398 }
399
400 static gboolean
401 ensure_authenticated (GstRTSPAuth * auth, GstRTSPContext * ctx)
402 {
403   GstRTSPAuthClass *klass;
404
405   klass = GST_RTSP_AUTH_GET_CLASS (auth);
406
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;
412     }
413   }
414   if (ctx->token == NULL)
415     goto no_auth;
416
417   return TRUE;
418
419 /* ERRORS */
420 authenticate_failed:
421   {
422     GST_DEBUG_OBJECT (auth, "authenticate failed");
423     send_response (auth, GST_RTSP_STS_UNAUTHORIZED, ctx);
424     return FALSE;
425   }
426 no_auth:
427   {
428     GST_DEBUG_OBJECT (auth, "no authorization token found");
429     send_response (auth, GST_RTSP_STS_UNAUTHORIZED, ctx);
430     return FALSE;
431   }
432 }
433
434 /* new connection */
435 static gboolean
436 check_connect (GstRTSPAuth * auth, GstRTSPContext * ctx, const gchar * check)
437 {
438   GstRTSPAuthPrivate *priv = auth->priv;
439
440   if (priv->certificate) {
441     GTlsConnection *tls;
442
443     /* configure the connection */
444     tls = gst_rtsp_connection_get_tls (ctx->conn, NULL);
445     g_tls_connection_set_certificate (tls, priv->certificate);
446   }
447   return TRUE;
448 }
449
450 /* check url and methods */
451 static gboolean
452 check_url (GstRTSPAuth * auth, GstRTSPContext * ctx, const gchar * check)
453 {
454   GstRTSPAuthPrivate *priv = auth->priv;
455
456   if ((ctx->method & priv->methods) != 0)
457     if (!ensure_authenticated (auth, ctx))
458       goto not_authenticated;
459
460   return TRUE;
461
462   /* ERRORS */
463 not_authenticated:
464   {
465     return FALSE;
466   }
467 }
468
469 /* check access to media factory */
470 static gboolean
471 check_factory (GstRTSPAuth * auth, GstRTSPContext * ctx, const gchar * check)
472 {
473   const gchar *role;
474   GstRTSPPermissions *perms;
475
476   if (!ensure_authenticated (auth, ctx))
477     return FALSE;
478
479   if (!(role = gst_rtsp_token_get_string (ctx->token,
480               GST_RTSP_TOKEN_MEDIA_FACTORY_ROLE)))
481     goto no_media_role;
482   if (!(perms = gst_rtsp_media_factory_get_permissions (ctx->factory)))
483     goto no_permissions;
484
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))
488       goto no_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))
492       goto no_construct;
493   }
494
495   gst_rtsp_permissions_unref (perms);
496
497   return TRUE;
498
499   /* ERRORS */
500 no_media_role:
501   {
502     GST_DEBUG_OBJECT (auth, "no media factory role found");
503     send_response (auth, GST_RTSP_STS_UNAUTHORIZED, ctx);
504     return FALSE;
505   }
506 no_permissions:
507   {
508     GST_DEBUG_OBJECT (auth, "no permissions on media factory found");
509     send_response (auth, GST_RTSP_STS_UNAUTHORIZED, ctx);
510     return FALSE;
511   }
512 no_access:
513   {
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);
517     return FALSE;
518   }
519 no_construct:
520   {
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);
524     return FALSE;
525   }
526 }
527
528 static gboolean
529 check_client_settings (GstRTSPAuth * auth, GstRTSPContext * ctx,
530     const gchar * check)
531 {
532   if (!ensure_authenticated (auth, ctx))
533     return FALSE;
534
535   return gst_rtsp_token_is_allowed (ctx->token,
536       GST_RTSP_TOKEN_TRANSPORT_CLIENT_SETTINGS);
537 }
538
539 static gboolean
540 default_check (GstRTSPAuth * auth, GstRTSPContext * ctx, const gchar * check)
541 {
542   gboolean res = FALSE;
543
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);
553   }
554   return res;
555 }
556
557 static gboolean
558 no_auth_check (const gchar * check)
559 {
560   gboolean res;
561
562   if (g_str_equal (check, GST_RTSP_AUTH_CHECK_TRANSPORT_CLIENT_SETTINGS))
563     res = FALSE;
564   else
565     res = TRUE;
566
567   return res;
568 }
569
570 /**
571  * gst_rtsp_auth_check:
572  * @check: the item to check
573  *
574  * Check if @check is allowed in the current context.
575  *
576  * Returns: FALSE if check failed.
577  */
578 gboolean
579 gst_rtsp_auth_check (const gchar * check)
580 {
581   gboolean result = FALSE;
582   GstRTSPAuthClass *klass;
583   GstRTSPContext *ctx;
584   GstRTSPAuth *auth;
585
586   g_return_val_if_fail (check != NULL, FALSE);
587
588   if (!(ctx = gst_rtsp_context_get_current ()))
589     goto no_context;
590
591   /* no auth, we don't need to check */
592   if (!(auth = ctx->auth))
593     return no_auth_check (check);
594
595   klass = GST_RTSP_AUTH_GET_CLASS (auth);
596
597   GST_DEBUG_OBJECT (auth, "check authorization '%s'", check);
598
599   if (klass->check)
600     result = klass->check (auth, ctx, check);
601
602   return result;
603
604   /* ERRORS */
605 no_context:
606   {
607     GST_ERROR ("no context found");
608     return FALSE;
609   }
610 }
611
612 /**
613  * gst_rtsp_auth_make_basic:
614  * @user: a userid
615  * @pass: a password
616  *
617  * Construct a Basic authorisation token from @user and @pass.
618  *
619  * Returns: (transfer full): the base64 encoding of the string @user:@pass.
620  * g_free() after usage.
621  */
622 gchar *
623 gst_rtsp_auth_make_basic (const gchar * user, const gchar * pass)
624 {
625   gchar *user_pass;
626   gchar *result;
627
628   g_return_val_if_fail (user != NULL, NULL);
629   g_return_val_if_fail (pass != NULL, NULL);
630
631   user_pass = g_strjoin (":", user, pass, NULL);
632   result = g_base64_encode ((guchar *) user_pass, strlen (user_pass));
633   g_free (user_pass);
634
635   return result;
636 }