Commit fed77d04 authored by Carlos Garcia Campos's avatar Carlos Garcia Campos Committed by Carlos Garcia Campos
Browse files

message: add API to handle password protected client certificates

Implement GTlsInteraction::ask_password to expose another signal in
SoupMessage to ask the user for ther password.
parent d72d9eab
......@@ -32,6 +32,7 @@ soup_message_get_remote_address
soup_message_get_tls_peer_certificate
soup_message_get_tls_peer_certificate_errors
soup_message_set_tls_client_certificate
soup_message_tls_client_certificate_password_request_complete
<SUBSECTION>
soup_message_set_first_party
soup_message_get_first_party
......
......@@ -51,6 +51,35 @@ soup_tls_interaction_request_certificate_finish (GTlsInteraction *tls_interactio
return task_result != -1 ? task_result : G_TLS_INTERACTION_FAILED;
}
static void
soup_tls_interaction_ask_password_async (GTlsInteraction *tls_interaction,
GTlsPassword *password,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data)
{
SoupTlsInteractionPrivate *priv = soup_tls_interaction_get_instance_private (SOUP_TLS_INTERACTION (tls_interaction));
GTask *task;
task = g_task_new (tls_interaction, cancellable, callback, user_data);
if (priv->conn)
soup_connection_request_tls_certificate_password (priv->conn, password, task);
else
g_task_return_int (task, G_TLS_INTERACTION_FAILED);
g_object_unref (task);
}
static GTlsInteractionResult
soup_tls_interaction_ask_password_finish (GTlsInteraction *tls_interaction,
GAsyncResult *result,
GError **error)
{
int task_result;
task_result = g_task_propagate_int (G_TASK (result), error);
return task_result != -1 ? task_result : G_TLS_INTERACTION_FAILED;
}
static void
soup_tls_interaction_finalize (GObject *object)
{
......@@ -79,6 +108,8 @@ soup_tls_interaction_class_init (SoupTlsInteractionClass *klass)
interaction_class->request_certificate_async = soup_tls_interaction_request_certificate_async;
interaction_class->request_certificate_finish = soup_tls_interaction_request_certificate_finish;
interaction_class->ask_password_async = soup_tls_interaction_ask_password_async;
interaction_class->ask_password_finish = soup_tls_interaction_ask_password_finish;
}
GTlsInteraction *
......
......@@ -55,6 +55,7 @@ enum {
EVENT,
ACCEPT_CERTIFICATE,
REQUEST_CERTIFICATE,
REQUEST_CERTIFICATE_PASSWORD,
DISCONNECTED,
LAST_SIGNAL
};
......@@ -244,6 +245,16 @@ soup_connection_class_init (SoupConnectionClass *connection_class)
G_TYPE_BOOLEAN, 2,
G_TYPE_TLS_CLIENT_CONNECTION,
G_TYPE_TASK);
signals[REQUEST_CERTIFICATE_PASSWORD] =
g_signal_new ("request-certificate-password",
G_OBJECT_CLASS_TYPE (object_class),
G_SIGNAL_RUN_LAST,
0,
g_signal_accumulator_true_handled, NULL,
NULL,
G_TYPE_BOOLEAN, 2,
G_TYPE_TLS_PASSWORD,
G_TYPE_TASK);
signals[DISCONNECTED] =
g_signal_new ("disconnected",
G_OBJECT_CLASS_TYPE (object_class),
......@@ -1200,6 +1211,37 @@ soup_connection_complete_tls_certificate_request (SoupConnection *conn,
g_object_unref (task);
}
void
soup_connection_request_tls_certificate_password (SoupConnection *conn,
GTlsPassword *password,
GTask *task)
{
SoupConnectionPrivate *priv = soup_connection_get_instance_private (conn);
gboolean handled = FALSE;
if (!G_IS_TLS_CONNECTION (priv->connection)) {
g_task_return_int (task, G_TLS_INTERACTION_FAILED);
return;
}
g_signal_emit (conn, signals[REQUEST_CERTIFICATE_PASSWORD], 0, password, task, &handled);
if (!handled)
g_task_return_int (task, G_TLS_INTERACTION_FAILED);
}
void
soup_connection_complete_tls_certificate_password_request (SoupConnection *conn,
GTask *task)
{
SoupConnectionPrivate *priv = soup_connection_get_instance_private (conn);
if (G_IS_TLS_CONNECTION (priv->connection))
g_task_return_int (task, G_TLS_INTERACTION_HANDLED);
else
g_task_return_int (task, G_TLS_INTERACTION_FAILED);
g_object_unref (task);
}
guint64
soup_connection_get_id (SoupConnection *conn)
{
......
......@@ -63,16 +63,21 @@ gboolean soup_connection_is_idle_open (SoupConnection *conn);
SoupClientMessageIO *soup_connection_setup_message_io (SoupConnection *conn,
SoupMessage *msg);
GTlsCertificate *soup_connection_get_tls_certificate (SoupConnection *conn);
GTlsCertificateFlags soup_connection_get_tls_certificate_errors (SoupConnection *conn);
void soup_connection_request_tls_certificate (SoupConnection *conn,
GTlsConnection *connection,
GTask *task);
void soup_connection_complete_tls_certificate_request (SoupConnection *conn,
GTlsCertificate *certificate,
GTask *task);
void soup_connection_set_tls_client_certificate (SoupConnection *conn,
GTlsCertificate *certificate);
GTlsCertificate *soup_connection_get_tls_certificate (SoupConnection *conn);
GTlsCertificateFlags soup_connection_get_tls_certificate_errors (SoupConnection *conn);
void soup_connection_request_tls_certificate (SoupConnection *conn,
GTlsConnection *connection,
GTask *task);
void soup_connection_complete_tls_certificate_request (SoupConnection *conn,
GTlsCertificate *certificate,
GTask *task);
void soup_connection_set_tls_client_certificate (SoupConnection *conn,
GTlsCertificate *certificate);
void soup_connection_request_tls_certificate_password (SoupConnection *conn,
GTlsPassword *password,
GTask *task);
void soup_connection_complete_tls_certificate_password_request (SoupConnection *conn,
GTask *task);
guint64 soup_connection_get_id (SoupConnection *conn);
GSocketAddress *soup_connection_get_remote_address (SoupConnection *conn);
......
......@@ -91,6 +91,7 @@ typedef struct {
GTlsCertificate *tls_client_certificate;
GTask *pending_tls_cert_request;
GTask *pending_tls_cert_pass_request;
SoupMessagePriority priority;
......@@ -123,6 +124,7 @@ enum {
NETWORK_EVENT,
ACCEPT_CERTIFICATE,
REQUEST_CERTIFICATE,
REQUEST_CERTIFICATE_PASSWORD,
HSTS_ENFORCED,
LAST_SIGNAL
......@@ -178,6 +180,11 @@ soup_message_finalize (GObject *object)
g_object_unref (priv->pending_tls_cert_request);
}
if (priv->pending_tls_cert_pass_request) {
g_task_return_int (priv->pending_tls_cert_pass_request, G_TLS_INTERACTION_FAILED);
g_object_unref (priv->pending_tls_cert_pass_request);
}
soup_message_set_connection (msg, NULL);
g_clear_pointer (&priv->uri, g_uri_unref);
......@@ -633,6 +640,36 @@ soup_message_class_init (SoupMessageClass *message_class)
G_TYPE_BOOLEAN, 1,
G_TYPE_TLS_CLIENT_CONNECTION);
/**
* SoupMessage::request-certificate-password:
* @msg: the message
* @tls_password: the #GTlsPassword
*
* Emitted during the @msg's connection TLS handshake when
* @tls_connection requests a certificate password from the client.
* You can set the certificate password on @password, then call
* soup_message_tls_client_certificate_password_request_complete() and return %TRUE
* to handle the signal synchronously.
* It's possible to handle the request asynchornously by calling g_object_ref()
* on @password, then returning %TRUE and call
* soup_message_tls_client_certificate_password_request_complete() later after
* setting the password on @password.
* Note that this signal is not emitted if #SoupSession::tls-interaction
* was set.
*
* Returns: %TRUE to handle the request, or %FALSE to make the connection
* fail with %G_TLS_ERROR_CERTIFICATE_REQUIRED.
*/
signals[REQUEST_CERTIFICATE_PASSWORD] =
g_signal_new ("request-certificate-password",
G_OBJECT_CLASS_TYPE (object_class),
G_SIGNAL_RUN_LAST,
0,
g_signal_accumulator_true_handled, NULL,
NULL,
G_TYPE_BOOLEAN, 1,
G_TYPE_TLS_PASSWORD);
/**
* SoupMessage::hsts-enforced:
* @msg: the message
......@@ -1447,6 +1484,23 @@ re_emit_request_certificate (SoupMessage *msg,
return handled;
}
static gboolean
re_emit_request_certificate_password (SoupMessage *msg,
GTlsPassword *password,
GTask *task)
{
SoupMessagePrivate *priv = soup_message_get_instance_private (msg);
gboolean handled = FALSE;
priv->pending_tls_cert_pass_request = g_object_ref (task);
g_signal_emit (msg, signals[REQUEST_CERTIFICATE_PASSWORD], 0, password, &handled);
if (!handled)
g_clear_object (&priv->pending_tls_cert_pass_request);
return handled;
}
static void
re_emit_tls_certificate_changed (SoupMessage *msg,
GParamSpec *pspec,
......@@ -1516,6 +1570,9 @@ soup_message_set_connection (SoupMessage *msg,
g_signal_connect_object (priv->connection, "request-certificate",
G_CALLBACK (re_emit_request_certificate),
msg, G_CONNECT_SWAPPED);
g_signal_connect_object (priv->connection, "request-certificate-password",
G_CALLBACK (re_emit_request_certificate_password),
msg, G_CONNECT_SWAPPED);
g_signal_connect_object (priv->connection, "notify::tls-certificate",
G_CALLBACK (re_emit_tls_certificate_changed),
msg, G_CONNECT_SWAPPED);
......@@ -2215,6 +2272,33 @@ soup_message_set_tls_client_certificate (SoupMessage *msg,
priv->tls_client_certificate = g_object_ref (certificate);
}
/**
* soup_message_tls_client_certificate_password_request_complete:
* @msg: a #SoupMessage
*
* Completes a certificate password request.
*
* You must call this as a response to #SoupMessage::request-certificate-password
* signal, to notify @msg that the #GTlsPassword has already been updated.
*/
void
soup_message_tls_client_certificate_password_request_complete (SoupMessage *msg)
{
SoupMessagePrivate *priv;
g_return_if_fail (SOUP_IS_MESSAGE (msg));
priv = soup_message_get_instance_private (msg);
if (!priv->pending_tls_cert_pass_request) {
g_warning ("soup_message_tls_client_certificate_password_request_complete should only be called as a response to SoupMessage::request-certificate-password signal");
return;
}
g_assert (SOUP_IS_CONNECTION (priv->connection));
soup_connection_complete_tls_certificate_password_request (priv->connection,
g_steal_pointer (&priv->pending_tls_cert_pass_request));
}
/**
* SoupMessagePriority:
* @SOUP_MESSAGE_PRIORITY_VERY_LOW: The lowest priority, the messages
......
......@@ -101,14 +101,17 @@ gboolean soup_message_query_flags (SoupMessage *msg,
SoupMessageFlags flags);
SOUP_AVAILABLE_IN_ALL
GTlsCertificate *soup_message_get_tls_peer_certificate (SoupMessage *msg);
GTlsCertificate *soup_message_get_tls_peer_certificate (SoupMessage *msg);
SOUP_AVAILABLE_IN_ALL
GTlsCertificateFlags soup_message_get_tls_peer_certificate_errors (SoupMessage *msg);
GTlsCertificateFlags soup_message_get_tls_peer_certificate_errors (SoupMessage *msg);
SOUP_AVAILABLE_IN_ALL
void soup_message_set_tls_client_certificate (SoupMessage *msg,
GTlsCertificate *certificate);
void soup_message_set_tls_client_certificate (SoupMessage *msg,
GTlsCertificate *certificate);
SOUP_AVAILABLE_IN_ALL
void soup_message_tls_client_certificate_password_request_complete (SoupMessage *msg);
/* Specialized signal handlers */
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment