auth: handle unauthorized response
authorWim Taymans <wim.taymans@collabora.co.uk>
Fri, 12 Jul 2013 13:19:29 +0000 (15:19 +0200)
committerWim Taymans <wim.taymans@collabora.co.uk>
Fri, 12 Jul 2013 13:19:29 +0000 (15:19 +0200)
Move handling of the unauthorized response to the auth module, it can add
the appropriate headers to request authorization for the required method
much better than the client.

gst/rtsp-server/rtsp-auth.c
gst/rtsp-server/rtsp-auth.h
gst/rtsp-server/rtsp-client.c

index f5afb97..f7386a7 100644 (file)
@@ -56,7 +56,6 @@ 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_setup (GstRTSPAuth * auth, GstRTSPClientState * state);
 static gboolean default_authenticate (GstRTSPAuth * auth,
     GstRTSPClientState * state);
 static gboolean default_check (GstRTSPAuth * auth, GstRTSPClientState * state,
@@ -77,7 +76,6 @@ gst_rtsp_auth_class_init (GstRTSPAuthClass * klass)
   gobject_class->set_property = gst_rtsp_auth_set_property;
   gobject_class->finalize = gst_rtsp_auth_finalize;
 
-  klass->setup = default_setup;
   klass->authenticate = default_authenticate;
   klass->check = default_check;
 
@@ -267,47 +265,6 @@ gst_rtsp_auth_remove_basic (GstRTSPAuth * auth, const gchar * basic)
 }
 
 static gboolean
-default_setup (GstRTSPAuth * auth, GstRTSPClientState * state)
-{
-  if (state->response == NULL)
-    return FALSE;
-
-  /* we only have Basic for now */
-  gst_rtsp_message_add_header (state->response, GST_RTSP_HDR_WWW_AUTHENTICATE,
-      "Basic realm=\"GStreamer RTSP Server\"");
-
-  return TRUE;
-}
-
-/**
- * gst_rtsp_auth_setup:
- * @auth: a #GstRTSPAuth
- * @state: the client state
- *
- * Add authentication tokens to @response in @state.
- *
- * Returns: FALSE if something is wrong.
- */
-gboolean
-gst_rtsp_auth_setup (GstRTSPAuth * auth, GstRTSPClientState * state)
-{
-  gboolean result = FALSE;
-  GstRTSPAuthClass *klass;
-
-  g_return_val_if_fail (GST_IS_RTSP_AUTH (auth), FALSE);
-  g_return_val_if_fail (state != NULL, FALSE);
-
-  klass = GST_RTSP_AUTH_GET_CLASS (auth);
-
-  GST_DEBUG_OBJECT (auth, "setup auth");
-
-  if (klass->setup)
-    result = klass->setup (auth, state);
-
-  return result;
-}
-
-static gboolean
 default_authenticate (GstRTSPAuth * auth, GstRTSPClientState * state)
 {
   GstRTSPAuthPrivate *priv = auth->priv;
@@ -378,51 +335,124 @@ no_auth:
   }
 }
 
+static void
+send_response (GstRTSPAuth * auth, GstRTSPStatusCode code,
+    GstRTSPClientState * state)
+{
+  gst_rtsp_message_init_response (state->response, code,
+      gst_rtsp_status_as_text (code), state->request);
+
+  if (code == GST_RTSP_STS_UNAUTHORIZED) {
+    /* we only have Basic for now */
+    gst_rtsp_message_add_header (state->response, GST_RTSP_HDR_WWW_AUTHENTICATE,
+        "Basic realm=\"GStreamer RTSP Server\"");
+  }
+  gst_rtsp_client_send_message (state->client, state->session, state->response);
+}
+
+/* new connection */
 static gboolean
-default_check (GstRTSPAuth * auth, GstRTSPClientState * state,
+check_connect (GstRTSPAuth * auth, GstRTSPClientState * state,
     const gchar * check)
 {
   GstRTSPAuthPrivate *priv = auth->priv;
+
+  if (priv->certificate) {
+    GTlsConnection *tls;
+
+    /* configure the connection */
+    tls = gst_rtsp_connection_get_tls (state->conn, NULL);
+    g_tls_connection_set_certificate (tls, priv->certificate);
+  }
+  return TRUE;
+}
+
+/* check url and methods */
+static gboolean
+check_url (GstRTSPAuth * auth, GstRTSPClientState * state, const gchar * check)
+{
+  GstRTSPAuthPrivate *priv = auth->priv;
+
+  if ((state->method & priv->methods) != 0)
+    if (!ensure_authenticated (auth, state))
+      goto not_authenticated;
+
+  return TRUE;
+
+  /* ERRORS */
+not_authenticated:
+  {
+    send_response (auth, GST_RTSP_STS_UNAUTHORIZED, state);
+    return FALSE;
+  }
+}
+
+/* check access to media factory */
+static gboolean
+check_factory (GstRTSPAuth * auth, GstRTSPClientState * state,
+    const gchar * check)
+{
+  const gchar *role;
+  GstRTSPPermissions *perms;
+
+  if (!(role = gst_rtsp_token_get_string (state->token,
+              GST_RTSP_MEDIA_FACTORY_ROLE)))
+    goto no_media_role;
+  if (!(perms = gst_rtsp_media_factory_get_permissions (state->factory)))
+    goto no_permissions;
+
+  if (g_str_equal (check, "auth.check.media.factory.access")) {
+    if (!gst_rtsp_permissions_is_allowed (perms, role,
+            GST_RTSP_MEDIA_FACTORY_PERM_ACCESS))
+      goto no_access;
+  } else if (g_str_equal (check, "auth.check.media.factory.construct")) {
+    if (gst_rtsp_permissions_is_allowed (perms, role,
+            GST_RTSP_MEDIA_FACTORY_PERM_CONSTRUCT))
+      goto no_construct;
+  }
+  return TRUE;
+
+  /* ERRORS */
+no_media_role:
+  {
+    GST_DEBUG_OBJECT (auth, "no media factory role found");
+    send_response (auth, GST_RTSP_STS_UNAUTHORIZED, state);
+    return FALSE;
+  }
+no_permissions:
+  {
+    GST_DEBUG_OBJECT (auth, "no permissions on media factory found");
+    send_response (auth, GST_RTSP_STS_UNAUTHORIZED, state);
+    return FALSE;
+  }
+no_access:
+  {
+    GST_DEBUG_OBJECT (auth, "no permissions to access media factory");
+    send_response (auth, GST_RTSP_STS_NOT_FOUND, state);
+    return FALSE;
+  }
+no_construct:
+  {
+    GST_DEBUG_OBJECT (auth, "no permissions to construct media factory");
+    send_response (auth, GST_RTSP_STS_UNAUTHORIZED, state);
+    return FALSE;
+  }
+}
+
+static gboolean
+default_check (GstRTSPAuth * auth, GstRTSPClientState * state,
+    const gchar * check)
+{
   gboolean res = FALSE;
 
+  /* FIXME, use hastable or so */
   if (g_str_equal (check, GST_RTSP_AUTH_CHECK_CONNECT)) {
-    /* new connection */
-    if (priv->certificate) {
-      GTlsConnection *tls;
-
-      /* configure the connection */
-      tls = gst_rtsp_connection_get_tls (state->conn, NULL);
-      g_tls_connection_set_certificate (tls, priv->certificate);
-    }
-    res = TRUE;
+    res = check_connect (auth, state, check);
   } else if (g_str_equal (check, GST_RTSP_AUTH_CHECK_URL)) {
-    /* check url and methods */
-    if ((state->method & priv->methods) != 0)
-      res = ensure_authenticated (auth, state);
-    else
-      res = TRUE;
+    res = check_url (auth, state, check);
   } else if (g_str_has_prefix (check, "auth.check.media.factory.")) {
-    /* check access to media factory */
-    const gchar *role;
-    GstRTSPPermissions *perms;
-
-    if (!(role =
-            gst_rtsp_token_get_string (state->token,
-                GST_RTSP_MEDIA_FACTORY_ROLE)))
-      goto done;
-    if (!(perms = gst_rtsp_media_factory_get_permissions (state->factory)))
-      goto done;
-
-    if (g_str_equal (check, "auth.check.media.factory.access"))
-      res =
-          gst_rtsp_permissions_is_allowed (perms, role,
-          GST_RTSP_MEDIA_FACTORY_PERM_ACCESS);
-    else if (g_str_equal (check, "auth.check.media.factory.construct"))
-      res =
-          gst_rtsp_permissions_is_allowed (perms, role,
-          GST_RTSP_MEDIA_FACTORY_PERM_CONSTRUCT);
+    res = check_factory (auth, state, check);
   }
-done:
   return res;
 }
 
index 29044de..b38d8d2 100644 (file)
@@ -53,24 +53,20 @@ struct _GstRTSPAuth {
 
 /**
  * GstRTSPAuthClass:
- * @setup: called when an unauthorized resource has been accessed and
- *         authentication needs to be requested to the client. The default
- *         implementation adds basic authentication to the response.
  * @authenticate: check the authentication of a client. The default implementation
  *         checks if the authentication in the header matches one of the basic
  *         authentication tokens. This function should set the authgroup field
  *         in the state.
  * @check: check if a resource can be accessed. this function should
- *         call validate to authenticate the client when needed. The default
- *         implementation disallows unauthenticated access to all methods
- *         except OPTIONS.
+ *         call authenticate to authenticate the client when needed. The method
+ *         should also construct and send an appropriate response message on
+ *         error.
  *
  * The authentication class.
  */
 struct _GstRTSPAuthClass {
   GObjectClass  parent_class;
 
-  gboolean           (*setup)        (GstRTSPAuth *auth, GstRTSPClientState *state);
   gboolean           (*authenticate) (GstRTSPAuth *auth, GstRTSPClientState *state);
   gboolean           (*check)        (GstRTSPAuth *auth, GstRTSPClientState *state,
                                       const gchar *check);
@@ -87,8 +83,6 @@ void                gst_rtsp_auth_add_basic         (GstRTSPAuth *auth, const gc
                                                      GstRTSPToken *token);
 void                gst_rtsp_auth_remove_basic      (GstRTSPAuth *auth, const gchar * basic);
 
-gboolean            gst_rtsp_auth_setup             (GstRTSPAuth *auth, GstRTSPClientState *state);
-
 gboolean            gst_rtsp_auth_check             (const gchar *check);
 
 
index 529d7cc..1424032 100644 (file)
@@ -470,22 +470,6 @@ send_generic_response (GstRTSPClient * client, GstRTSPStatusCode code,
   send_message (client, NULL, state->response, FALSE);
 }
 
-static void
-handle_unauthorized_request (GstRTSPClient * client, GstRTSPAuth * auth,
-    GstRTSPClientState * state)
-{
-  gst_rtsp_message_init_response (state->response, GST_RTSP_STS_UNAUTHORIZED,
-      gst_rtsp_status_as_text (GST_RTSP_STS_UNAUTHORIZED), state->request);
-
-  if (auth) {
-    /* and let the authentication manager setup the auth tokens */
-    gst_rtsp_auth_setup (auth, state);
-  }
-
-  send_message (client, state->session, state->response, FALSE);
-}
-
-
 static gboolean
 paths_are_equal (const gchar * path1, const gchar * path2, gint len2)
 {
@@ -599,13 +583,11 @@ no_factory:
 no_factory_access:
   {
     GST_ERROR ("client %p: not authorized to see factory uri %s", client, path);
-    send_generic_response (client, GST_RTSP_STS_NOT_FOUND, state);
     return NULL;
   }
 not_authorized:
   {
     GST_ERROR ("client %p: not authorized for factory uri %s", client, path);
-    handle_unauthorized_request (client, priv->auth, state);
     return NULL;
   }
 no_media:
@@ -2030,7 +2012,6 @@ session_not_found:
 not_authorized:
   {
     GST_ERROR ("client %p: not allowed", client);
-    handle_unauthorized_request (client, priv->auth, &state);
     goto done;
   }
 not_implemented: