auth: move TLS handling to auth module

Remove the TLS settings on the server and move it to the auth module because
that is where security related bits go.
This commit is contained in:
Wim Taymans 2013-07-12 12:41:52 +02:00
parent a1e96c2269
commit 4b2e6d88b3
5 changed files with 147 additions and 123 deletions

View file

@ -22,7 +22,7 @@
#include <gst/rtsp-server/rtsp-server.h>
/* define this if you want the resource to only be available when using
* user/admin as the password */
* user/password as the password */
#undef WITH_AUTH
/* define this if you want the server to use TLS */
@ -52,7 +52,10 @@ main (int argc, char *argv[])
GstRTSPMediaFactory *factory;
#ifdef WITH_AUTH
GstRTSPAuth *auth;
GstRTSPToken *token;
GstStructure *s;
gchar *basic;
GstRTSPPermissions *permissions;
#endif
#ifdef WITH_TLS
GTlsCertificate *cert;
@ -64,6 +67,11 @@ main (int argc, char *argv[])
/* create a server instance */
server = gst_rtsp_server_new ();
#ifdef WITH_AUTH
/* make a new authentication manager. it can be added to control access to all
* the factories on the server or on individual factories. */
auth = gst_rtsp_auth_new ();
#ifdef WITH_TLS
cert = g_tls_certificate_new_from_pem ("-----BEGIN CERTIFICATE-----"
"MIICJjCCAY+gAwIBAgIBBzANBgkqhkiG9w0BAQUFADCBhjETMBEGCgmSJomT8ixk"
@ -88,25 +96,27 @@ main (int argc, char *argv[])
"DwIga8PqH5Sf5sHedy2+CiK0V4MRfoU4c3zQ6kArI+bEgSkCIQCLA1vXBiE31B5s"
"bdHoYa1BXebfZVd+1Hd95IfEM5mbRwIgSkDuQwV55BBlvWph3U8wVIMIb4GStaH8"
"W535W8UBbEg=" "-----END PRIVATE KEY-----", -1, NULL);
gst_rtsp_server_set_tls_certificate (server, cert);
gst_rtsp_auth_set_tls_certificate (auth, cert);
g_object_unref (cert);
#endif
/* make user token */
token = gst_rtsp_token_new ();
s = gst_rtsp_token_writable_structure (token);
gst_structure_set (s, "media.factory.role", G_TYPE_STRING, "user", NULL);
basic = gst_rtsp_auth_make_basic ("user", "password");
gst_rtsp_auth_add_basic (auth, basic, token);
g_free (basic);
gst_rtsp_token_unref (token);
/* configure in the server */
gst_rtsp_server_set_auth (server, auth);
#endif
/* get the mount points for this server, every server has a default object
* that be used to map uri mount points to media factories */
mounts = gst_rtsp_server_get_mount_points (server);
#ifdef WITH_AUTH
/* make a new authentication manager. it can be added to control access to all
* the factories on the server or on individual factories. */
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);
#endif
/* 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
@ -117,6 +127,16 @@ main (int argc, char *argv[])
"x264enc ! rtph264pay name=pay0 pt=96 "
"audiotestsrc ! audio/x-raw,rate=8000 ! "
"alawenc ! rtppcmapay name=pay1 pt=97 " ")");
#ifdef WITH_AUTH
/* add permissions for the user media role */
permissions = gst_rtsp_permissions_new ();
gst_rtsp_permissions_add_role (permissions, "user",
gst_structure_new ("user",
"media.factory.access", G_TYPE_BOOLEAN, TRUE,
"media.factory.construct", G_TYPE_BOOLEAN, TRUE, NULL));
gst_rtsp_media_factory_set_permissions (factory, permissions);
gst_rtsp_permissions_unref (permissions);
#endif
/* attach the test factory to the /test url */
gst_rtsp_mount_points_add_factory (mounts, "/test", factory);

View file

@ -34,6 +34,9 @@
struct _GstRTSPAuthPrivate
{
GMutex lock;
/* the TLS certificate */
GTlsCertificate *certificate;
GHashTable *basic; /* protected by lock */
GstRTSPMethod methods;
};
@ -109,6 +112,9 @@ gst_rtsp_auth_finalize (GObject * obj)
GstRTSPAuthPrivate *priv = auth->priv;
GST_INFO ("finalize auth %p", auth);
if (priv->certificate)
g_object_unref (priv->certificate);
g_hash_table_unref (priv->basic);
g_mutex_clear (&priv->lock);
@ -152,6 +158,64 @@ gst_rtsp_auth_new (void)
return result;
}
/**
* gst_rtsp_auth_set_tls_certificate:
* @auth: a #GstRTSPAuth
* @cert: (allow none): a #GTlsCertificate
*
* Set the TLS certificate for the auth. Client connections will only
* be accepted when TLS is negotiated.
*/
void
gst_rtsp_auth_set_tls_certificate (GstRTSPAuth * auth, GTlsCertificate * cert)
{
GstRTSPAuthPrivate *priv;
GTlsCertificate *old;
g_return_if_fail (GST_IS_RTSP_AUTH (auth));
priv = auth->priv;
if (cert)
g_object_ref (cert);
g_mutex_lock (&priv->lock);
old = priv->certificate;
priv->certificate = cert;
g_mutex_unlock (&priv->lock);
if (old)
g_object_unref (old);
}
/**
* gst_rtsp_auth_get_tls_certificate:
* @auth: a #GstRTSPAuth
*
* Get the #GTlsCertificate used for negotiating TLS @auth.
*
* Returns: (transfer full): the #GTlsCertificate of @auth. g_object_unref() after
* usage.
*/
GTlsCertificate *
gst_rtsp_auth_get_tls_certificate (GstRTSPAuth * auth)
{
GstRTSPAuthPrivate *priv;
GTlsCertificate *result;
g_return_val_if_fail (GST_IS_RTSP_AUTH (auth), NULL);
priv = auth->priv;
g_mutex_lock (&priv->lock);
if ((result = priv->certificate))
g_object_ref (result);
g_mutex_unlock (&priv->lock);
return result;
}
/**
* gst_rtsp_auth_add_basic:
* @auth: a #GstRTSPAuth
@ -321,12 +385,24 @@ default_check (GstRTSPAuth * auth, GstRTSPClientState * state,
GstRTSPAuthPrivate *priv = auth->priv;
gboolean res = FALSE;
if (g_str_equal (check, GST_RTSP_AUTH_CHECK_URL)) {
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;
} 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;
} else if (g_str_has_prefix (check, "auth.check.media.factory.")) {
/* check access to media factory */
const gchar *role;
GstRTSPPermissions *perms;

View file

@ -80,6 +80,9 @@ GType gst_rtsp_auth_get_type (void);
GstRTSPAuth * gst_rtsp_auth_new (void);
void gst_rtsp_auth_set_tls_certificate (GstRTSPAuth *auth, GTlsCertificate *cert);
GTlsCertificate * gst_rtsp_auth_get_tls_certificate (GstRTSPAuth *auth);
void gst_rtsp_auth_add_basic (GstRTSPAuth *auth, const gchar * basic,
GstRTSPToken *token);
void gst_rtsp_auth_remove_basic (GstRTSPAuth *auth, const gchar * basic);
@ -93,6 +96,12 @@ gboolean gst_rtsp_auth_check (const gchar *check);
gchar * gst_rtsp_auth_make_basic (const gchar * user, const gchar * pass);
/* checks */
/**
* GST_RTSP_AUTH_CHECK_CONNECT:
*
* Check a new connection
*/
#define GST_RTSP_AUTH_CHECK_CONNECT "auth.check.connect"
/**
* GST_RTSP_AUTH_CHECK_URL:
*

View file

@ -31,7 +31,7 @@
* network (0.0.0.0) and port 8554.
*
* The server will require an SSL connection when a TLS certificate has been
* set with gst_rtsp_server_set_tls_certificate().
* set in the auth object with gst_rtsp_auth_set_tls_certificate().
*
* To start the server, use gst_rtsp_server_attach() to attach it to a
* #GMainContext. For more control, gst_rtsp_server_create_source() and
@ -89,9 +89,6 @@ struct _GstRTSPServerPrivate
/* resource manager */
GstRTSPThreadPool *thread_pool;
/* the TLS certificate */
GTlsCertificate *certificate;
/* the clients that are connected */
GList *clients;
};
@ -144,8 +141,6 @@ static void gst_rtsp_server_set_property (GObject * object, guint propid,
static void gst_rtsp_server_finalize (GObject * object);
static GstRTSPClient *default_create_client (GstRTSPServer * server);
static gboolean default_setup_connection (GstRTSPServer * server,
GstRTSPClient * client, GstRTSPConnection * conn);
static void
gst_rtsp_server_class_init (GstRTSPServerClass * klass)
@ -248,7 +243,6 @@ gst_rtsp_server_class_init (GstRTSPServerClass * klass)
gst_rtsp_client_get_type ());
klass->create_client = default_create_client;
klass->setup_connection = default_setup_connection;
GST_DEBUG_CATEGORY_INIT (rtsp_server_debug, "rtspserver", 0, "GstRTSPServer");
}
@ -295,9 +289,6 @@ gst_rtsp_server_finalize (GObject * object)
if (priv->auth)
g_object_unref (priv->auth);
if (priv->certificate)
g_object_unref (priv->certificate);
g_mutex_clear (&priv->lock);
G_OBJECT_CLASS (gst_rtsp_server_parent_class)->finalize (object);
@ -784,64 +775,6 @@ gst_rtsp_server_get_use_client_settings (GstRTSPServer * server)
return res;
}
/**
* gst_rtsp_server_set_tls_certificate:
* @server: a #GstRTSPServer
* @cert: (allow none): a #GTlsCertificate
*
* Set the TLS certificate for the server. Client connections will only
* be accepted when TLS is negotiated.
*/
void
gst_rtsp_server_set_tls_certificate (GstRTSPServer * server,
GTlsCertificate * cert)
{
GstRTSPServerPrivate *priv;
GTlsCertificate *old;
g_return_if_fail (GST_IS_RTSP_SERVER (server));
priv = server->priv;
if (cert)
g_object_ref (cert);
GST_RTSP_SERVER_LOCK (server);
old = priv->certificate;
priv->certificate = cert;
GST_RTSP_SERVER_UNLOCK (server);
if (old)
g_object_unref (old);
}
/**
* gst_rtsp_server_get_tls_certificate:
* @server: a #GstRTSPServer
*
* Get the #GTlsCertificate used for negotiating TLS @server.
*
* Returns: (transfer full): the #GTlsCertificate of @server. g_object_unref() after
* usage.
*/
GTlsCertificate *
gst_rtsp_server_get_tls_certificate (GstRTSPServer * server)
{
GstRTSPServerPrivate *priv;
GTlsCertificate *result;
g_return_val_if_fail (GST_IS_RTSP_SERVER (server), NULL);
priv = server->priv;
GST_RTSP_SERVER_LOCK (server);
if ((result = priv->certificate))
g_object_ref (result);
GST_RTSP_SERVER_UNLOCK (server);
return result;
}
static void
gst_rtsp_server_get_property (GObject * object, guint propid,
GValue * value, GParamSpec * pspec)
@ -1188,25 +1121,6 @@ default_create_client (GstRTSPServer * server)
return client;
}
static gboolean
default_setup_connection (GstRTSPServer * server, GstRTSPClient * client,
GstRTSPConnection * conn)
{
GstRTSPServerPrivate *priv = server->priv;
GST_RTSP_SERVER_LOCK (server);
if (priv->certificate) {
GTlsConnection *tls;
/* configure the connection */
tls = gst_rtsp_connection_get_tls (conn, NULL);
g_tls_connection_set_certificate (tls, priv->certificate);
}
GST_RTSP_SERVER_UNLOCK (server);
return TRUE;
}
/**
* gst_rtsp_server_transfer_connection:
* @server: a #GstRTSPServer
@ -1282,29 +1196,33 @@ gboolean
gst_rtsp_server_io_func (GSocket * socket, GIOCondition condition,
GstRTSPServer * server)
{
GstRTSPServerPrivate *priv = server->priv;
GstRTSPClient *client = NULL;
GstRTSPServerClass *klass;
GstRTSPResult res;
GstRTSPConnection *conn = NULL;
GstRTSPClientState state = { NULL };
if (condition & G_IO_IN) {
/* a new client connected. */
GST_RTSP_CHECK (gst_rtsp_connection_accept (socket, &conn, NULL),
accept_failed);
state.server = server;
state.conn = conn;
state.auth = priv->auth;
gst_rtsp_client_state_push_current (&state);
if (!gst_rtsp_auth_check (GST_RTSP_AUTH_CHECK_CONNECT))
goto connection_refused;
klass = GST_RTSP_SERVER_GET_CLASS (server);
/* a new client connected, create a client object to handle the client. */
if (klass->create_client)
client = klass->create_client (server);
if (client == NULL)
goto client_failed;
/* a new client connected. */
GST_RTSP_CHECK (gst_rtsp_connection_accept (socket, &conn, NULL),
accept_failed);
if (klass->setup_connection)
if (!klass->setup_connection (server, client, conn))
goto setup_failed;
/* set connection on the client now */
gst_rtsp_client_set_connection (client, conn);
@ -1316,29 +1234,31 @@ gst_rtsp_server_io_func (GSocket * socket, GIOCondition condition,
} else {
GST_WARNING_OBJECT (server, "received unknown event %08x", condition);
}
exit:
gst_rtsp_client_state_pop_current (&state);
return G_SOURCE_CONTINUE;
/* ERRORS */
client_failed:
{
GST_ERROR_OBJECT (server, "failed to create a client");
return G_SOURCE_CONTINUE;
}
accept_failed:
{
gchar *str = gst_rtsp_strresult (res);
GST_ERROR_OBJECT (server, "Could not accept client on socket %p: %s",
socket, str);
g_free (str);
g_object_unref (client);
return G_SOURCE_CONTINUE;
goto exit;
}
setup_failed:
connection_refused:
{
GST_ERROR_OBJECT (server, "failed to setup client connection");
GST_ERROR_OBJECT (server, "connection refused");
gst_rtsp_connection_free (conn);
g_object_unref (client);
return G_SOURCE_CONTINUE;
goto exit;
}
client_failed:
{
GST_ERROR_OBJECT (server, "failed to create a client");
gst_rtsp_connection_free (conn);
goto exit;
}
}

View file

@ -70,8 +70,7 @@ struct _GstRTSPServerClass {
GObjectClass parent_class;
GstRTSPClient * (*create_client) (GstRTSPServer *server);
gboolean (*setup_connection) (GstRTSPServer *server, GstRTSPClient *client,
GstRTSPConnection *conn);
/* signals */
void (*client_connected) (GstRTSPServer *server, GstRTSPClient *client);
};