static char * authenticated_user_to_id (CockpitAuth *self, const char *user, const char *password) { CockpitCredentials *credentials; guint64 seed; char *id; g_mutex_lock (&self->mutex); credentials = g_new0 (CockpitCredentials, 1); credentials->user = g_strdup (user); credentials->password = g_strdup (password); seed = self->nonce_seed++; id = g_compute_hmac_for_data (G_CHECKSUM_SHA256, self->key->data, self->key->len, (guchar *)&seed, sizeof (seed)); g_hash_table_insert (self->authenticated, g_strdup (id), credentials); g_mutex_unlock (&self->mutex); g_debug ("sending credential id '%s' for user '%s'", id, user); return id; }
gchar * cockpit_auth_nonce (CockpitAuth *self) { const guchar *key; gsize len; guint64 seed; seed = self->nonce_seed++; key = g_bytes_get_data (self->key, &len); return g_compute_hmac_for_data (G_CHECKSUM_SHA256, key, len, (guchar *)&seed, sizeof (seed)); }
/** * g_compute_hmac_for_string: * @digest_type: a #GChecksumType to use for the HMAC * @key: (array length=key_len): the key to use in the HMAC * @key_len: the length of the key * @str: the string to compute the HMAC for * @length: the length of the string, or -1 if the string is nul-terminated * * Computes the HMAC for a string. * * The hexadecimal string returned will be in lower case. * * Returns: the HMAC as a hexadecimal string. * The returned string should be freed with g_free() * when done using it. * * Since: 2.30 */ gchar * g_compute_hmac_for_string (GChecksumType digest_type, const guchar *key, gsize key_len, const gchar *str, gssize length) { g_return_val_if_fail (length == 0 || str != NULL, NULL); if (length < 0) length = strlen (str); return g_compute_hmac_for_data (digest_type, key, key_len, (const guchar *) str, length); }
/** * g_compute_hmac_for_bytes: * @digest_type: a #GChecksumType to use for the HMAC * @key: the key to use in the HMAC * @data: binary blob to compute the HMAC of * * Computes the HMAC for a binary @data. This is a * convenience wrapper for g_hmac_new(), g_hmac_get_string() * and g_hmac_unref(). * * The hexadecimal string returned will be in lower case. * * Returns: the HMAC of the binary data as a string in hexadecimal. * The returned string should be freed with g_free() when done using it. * * Since: 2.50 */ gchar * g_compute_hmac_for_bytes (GChecksumType digest_type, GBytes *key, GBytes *data) { gconstpointer byte_data; gsize length; gconstpointer key_data; gsize key_len; g_return_val_if_fail (data != NULL, NULL); g_return_val_if_fail (key != NULL, NULL); byte_data = g_bytes_get_data (data, &length); key_data = g_bytes_get_data (key, &key_len); return g_compute_hmac_for_data (digest_type, key_data, key_len, byte_data, length); }
static char * creds_to_cookie (CockpitAuth *self, CockpitCreds *creds) { guint64 seed; gchar *cookie; char *id; seed = self->nonce_seed++; id = g_compute_hmac_for_data (G_CHECKSUM_SHA256, self->key->data, self->key->len, (guchar *)&seed, sizeof (seed)); cookie = g_strdup_printf ("v=2;k=%s", id); g_hash_table_insert (self->authenticated, id, cockpit_creds_ref (creds)); g_debug ("sending credential id '%s' for user '%s'", id, cockpit_creds_get_user (creds)); return cookie; }
CockpitWebService * cockpit_auth_login_finish (CockpitAuth *self, GAsyncResult *result, CockpitAuthFlags flags, GHashTable *out_headers, GError **error) { CockpitAuthClass *klass = COCKPIT_AUTH_GET_CLASS (self); CockpitAuthenticated *authenticated; CockpitTransport *transport = NULL; CockpitCreds *creds; gchar *cookie_b64 = NULL; gchar *header; guint64 seed; gchar *id; g_return_val_if_fail (klass->login_finish != NULL, FALSE); creds = klass->login_finish (self, result, out_headers, &transport, error); if (creds == NULL) return NULL; seed = self->nonce_seed++; id = g_compute_hmac_for_data (G_CHECKSUM_SHA256, self->key->data, self->key->len, (guchar *)&seed, sizeof (seed)); authenticated = g_new0 (CockpitAuthenticated, 1); authenticated->cookie = g_strdup_printf ("v=2;k=%s", id); authenticated->creds = creds; authenticated->service = cockpit_web_service_new (creds, transport); authenticated->auth = self; authenticated->idling_sig = g_signal_connect (authenticated->service, "idling", G_CALLBACK (on_web_service_idling), authenticated); authenticated->destroy_sig = g_signal_connect (authenticated->service, "destroy", G_CALLBACK (on_web_service_destroy), authenticated); if (transport) g_object_unref (transport); g_object_weak_ref (G_OBJECT (authenticated->service), on_web_service_gone, authenticated); /* Start off in the idling state, and begin a timeout during which caller must do something else */ on_web_service_idling (authenticated->service, authenticated); g_hash_table_insert (self->authenticated, authenticated->cookie, authenticated); g_debug ("sending credential id '%s' for user '%s'", id, cockpit_creds_get_user (creds)); g_free (id); if (out_headers) { gboolean force_secure = !(flags & COCKPIT_AUTH_COOKIE_INSECURE); cookie_b64 = g_base64_encode ((guint8 *)authenticated->cookie, strlen (authenticated->cookie)); header = g_strdup_printf ("cockpit=%s; Path=/; %s HttpOnly", cookie_b64, force_secure ? " Secure;" : ""); g_free (cookie_b64); g_hash_table_insert (out_headers, g_strdup ("Set-Cookie"), header); } g_info ("logged in user: %s", cockpit_creds_get_user (authenticated->creds)); return g_object_ref (authenticated->service); }