static gchar* _make_base_string(
                                GSignondSessionData *session_data, 
                                SoupURI* uri, gchar* nonce, gchar* timestamp)
{
    GString* base_string = g_string_new("POST&");
    
    gchar* base_uri;
    if (soup_uri_uses_default_port(uri))
        base_uri = g_strdup_printf("https://%s%s", soup_uri_get_host(uri),
                                                    soup_uri_get_path(uri));
    else
        base_uri = g_strdup_printf("https://%s:%u%s", soup_uri_get_host(uri),
                                                       soup_uri_get_port(uri),
                                                       soup_uri_get_path(uri));
    gchar* base_uri_e = _percent_encode(base_uri);
    g_string_append(base_string, base_uri_e);
    g_string_append(base_string, "&");
    g_free(base_uri);
    g_free(base_uri_e);
    
    GTree* parameters = g_tree_new((GCompareFunc)g_strcmp0);
    
    const gchar* query_s = soup_uri_get_query(uri);
    GHashTable* query;
    if (query_s != NULL)
        query = soup_form_decode(query_s);
    else    
        query = soup_form_decode("");
   
    g_hash_table_foreach(query, _insert_into_tree, parameters);
    
    const gchar* callback_uri = gsignond_dictionary_get_string(session_data, "Callback");
    if (callback_uri != NULL)
        g_tree_insert(parameters, "oauth_callback", (gchar*)callback_uri);
    const gchar* oauth_verifier = gsignond_dictionary_get_string(session_data, "_OauthVerifier");
    if (oauth_verifier != NULL)
        g_tree_insert(parameters, "oauth_verifier", (gchar*)oauth_verifier);
    g_tree_insert(parameters, "oauth_consumer_key", (gchar*)gsignond_dictionary_get_string(session_data, "ConsumerKey"));
    const gchar* oauth_temp_token = gsignond_dictionary_get_string(session_data, "_OauthTemporaryToken");
    if (oauth_temp_token != NULL)
        g_tree_insert(parameters, "oauth_token", (gchar*)oauth_temp_token);
    g_tree_insert(parameters, "oauth_signature_method", (gchar*)gsignond_dictionary_get_string(session_data, "SignatureMethod"));
    g_tree_insert(parameters, "oauth_nonce", nonce);
    g_tree_insert(parameters, "oauth_timestamp", timestamp);
    g_tree_insert(parameters, "oauth_version", "1.0");
    
    GString* parameters_string = g_string_new(NULL);
    g_tree_foreach(parameters, _make_parameters_string, parameters_string);
    gchar* parameters_s = g_string_free(parameters_string, FALSE);
    parameters_s[strlen(parameters_s)-1] = '\0'; //remove trailing '&'
    gchar* parameters_encoded = _percent_encode(parameters_s);
    g_string_append(base_string, parameters_encoded);
    
    g_free(parameters_encoded);
    g_free(parameters_s);
    g_tree_destroy(parameters);
    g_hash_table_destroy(query);
    
    return g_string_free(base_string, FALSE);
}
예제 #2
0
static void
_oauth_service_get_request_token_ready_cb (SoupSession *session,
					   SoupMessage *msg,
					   gpointer     user_data)
{
	OAuthService       *self = user_data;
	GSimpleAsyncResult *result;
	SoupBuffer         *body;
	GHashTable         *values;
	char               *token;
	char               *token_secret;

	result = _web_service_get_result (WEB_SERVICE (self));

	if (msg->status_code != 200) {
		g_simple_async_result_set_error (result,
						 SOUP_HTTP_ERROR,
						 msg->status_code,
						 "%s",
						 soup_status_get_phrase (msg->status_code));
		g_simple_async_result_complete_in_idle (result);
		return;
	}

	body = soup_message_body_flatten (msg->response_body);
	values = soup_form_decode (body->data);
	token = g_hash_table_lookup (values, "oauth_token");
	token_secret = g_hash_table_lookup (values, "oauth_token_secret");
	if ((token != NULL) && (token_secret != NULL)) {
		oauth_service_set_token (self, token);
		oauth_service_set_token_secret (self, token_secret);
		g_simple_async_result_set_op_res_gboolean (result, TRUE);
	}
	else {
		GError *error;

		error = g_error_new_literal (WEB_SERVICE_ERROR, WEB_SERVICE_ERROR_GENERIC, _("Unknown error"));
		g_simple_async_result_set_from_error (result, error);
	}

	g_simple_async_result_complete_in_idle (result);

	g_hash_table_destroy (values);
	soup_buffer_free (body);
}
예제 #3
0
static void
flickr_access_token_response (OAuthService       *self,
			      SoupMessage        *msg,
			      SoupBuffer         *body,
			      GSimpleAsyncResult *result)
{
	GHashTable *values;
	char       *username;
	char       *token;
	char       *token_secret;

	values = soup_form_decode (body->data);

	username = g_hash_table_lookup (values, "username");
	token = g_hash_table_lookup (values, "oauth_token");
	token_secret = g_hash_table_lookup (values, "oauth_token_secret");
	if ((username != NULL) && (token != NULL) && (token_secret != NULL)) {
		FlickrAccount *account;

		oauth_service_set_token (OAUTH_SERVICE (self), token);
		oauth_service_set_token_secret (OAUTH_SERVICE (self), token_secret);

		account = g_object_new (FLICKR_TYPE_ACCOUNT,
					"id", g_hash_table_lookup (values, "user_nsid"),
					"name", username,
					"token", token,
					"token-secret", token_secret,
					NULL);
		g_simple_async_result_set_op_res_gpointer (result, account, g_object_unref);
	}
	else {
		GError *error;

		error = g_error_new_literal (WEB_SERVICE_ERROR, WEB_SERVICE_ERROR_GENERIC, _("Unknown error"));
		g_simple_async_result_set_from_error (result, error);
	}

	g_hash_table_destroy (values);
}
예제 #4
0
static void
ask_authorization_dialog_load_request_cb (OAuthAskAuthorizationDialog *dialog,
					  gpointer                     user_data)
{
	OAuthService *self = user_data;
	const char   *uri;

	uri = oauth_ask_authorization_dialog_get_uri (dialog);
	if (uri == NULL)
		return;

	if (g_str_has_prefix (uri, OAUTH_CALLBACK)) {
		const char *uri_data;
		GHashTable *data;
		gboolean    success = FALSE;

		uri_data = uri + strlen (OAUTH_CALLBACK "?");

		data = soup_form_decode (uri_data);
		_g_strset (&self->priv->token, g_hash_table_lookup (data, "oauth_token"));

		if (self->priv->token != NULL) {
			gtk_widget_hide (GTK_WIDGET (dialog));
			gth_task_dialog (GTH_TASK (self), FALSE, NULL);

			success = TRUE;
			_oauth_service_get_access_token (self,
							 g_hash_table_lookup (data, "oauth_verifier"),
							 gth_task_get_cancellable (GTH_TASK (self)),
							 get_access_token_ready_cb,
							 self);
		}

		if (! success)
			gtk_dialog_response (GTK_DIALOG (dialog), GTK_RESPONSE_CANCEL);

		g_hash_table_destroy (data);
	}
}
예제 #5
0
파일: main.c 프로젝트: lcp/bisho
static void
handle_uri (BishoWindow *window, const char *s)
{
  SoupURI *uri = NULL;
  GHashTable *params = NULL;

  uri = soup_uri_new (s);
  if (strcmp (uri->scheme, "x-bisho") != 0) {
    soup_uri_free (uri);
    return;
  }

  if (uri->query)
    params = soup_form_decode (uri->query);
  else
    params = g_hash_table_new (NULL, NULL);

  bisho_window_callback (window, uri->path, params);

  g_hash_table_destroy (params);
  soup_uri_free (uri);
}
예제 #6
0
void
oauth_proxy_call_parse_token_reponse (OAuthProxyCall *call)
{
  OAuthProxyPrivate *priv;
  GHashTable *form;

  /* TODO: sanity checks, error handling, probably return gboolean */

  g_return_if_fail (OAUTH_IS_PROXY_CALL (call));

  priv = PROXY_GET_PRIVATE (REST_PROXY_CALL (call)->priv->proxy);
  g_assert (priv);

  form = soup_form_decode (rest_proxy_call_get_payload (REST_PROXY_CALL (call)));

  priv->token = g_strdup (g_hash_table_lookup (form, "oauth_token"));
  priv->token_secret = g_strdup (g_hash_table_lookup (form, "oauth_token_secret"));
  /* This header should only exist for request_token replies, but its easier just to always check it */
  priv->oauth_10a = g_hash_table_lookup (form, "oauth_callback_confirmed") != NULL;

  g_hash_table_destroy (form);
}
예제 #7
0
GHashTable *
gss_config_get_post_hash (GssTransaction * t)
{
  GHashTable *hash;
  const char *content_type;

  content_type = soup_message_headers_get_one (t->msg->request_headers,
      "Content-Type");

  hash = NULL;
  if (g_str_equal (content_type, "application/x-www-form-urlencoded")) {
    hash = soup_form_decode (t->msg->request_body->data);
  } else if (g_str_has_prefix (content_type, "multipart/form-data")) {
    SoupBuffer *buffer;

    hash = soup_form_decode_multipart (t->msg, "none", NULL, NULL, &buffer);

    if (buffer && buffer->length > 0) {
      soup_buffer_free (buffer);
    }
  }

  return hash;
}
예제 #8
0
static void
on_login_content_read (GObject      *obj,
                       GAsyncResult *res,
                       gpointer      user_data)
{
    LoginData *data = user_data;

    LiaWebview *self;
    EvdHttpConnection *conn;
    gchar *content;
    gssize size;
    GError *error = NULL;
    GHashTable *params;
    GCancellable *cancellable;
    SoupURI *uri;
    GDBusConnection *bus_conn;
    const gchar *core_service_name;

    const gchar *user;
    const gchar *passw;
    gchar *domain;

    self = data->self;
    conn = data->conn;

    content = evd_http_connection_read_all_content_finish (conn,
              res,
              &size,
              &error);
    if (content == NULL)
    {
        /* @TODO: Failed reading login data */
        g_debug ("Error reading login daa: %s", error->message);
        g_error_free (error);
        return;
    }

    params = soup_form_decode (content);
    g_free (content);

    /* call authenticate method of AuthService interface */

    user = (const gchar *) g_hash_table_lookup (params, "user");
    passw = (const gchar *) g_hash_table_lookup (params, "passw");

    cancellable = g_cancellable_new ();
    g_signal_connect (conn,
                      "close",
                      G_CALLBACK (on_login_conn_closed),
                      cancellable);

    uri = evd_http_request_get_uri (data->request);
    domain = g_strdup_printf ("%s:%d", uri->host, uri->port);

    bus_conn = lia_application_get_bus (LIA_APPLICATION (self), LIA_BUS_PRIVATE);
    core_service_name =
        lia_application_get_core_service_name (LIA_APPLICATION (self));

    g_dbus_connection_call (bus_conn,
                            core_service_name,
                            LIA_AUTH_SERVICE_OBJ_PATH,
                            LIA_AUTH_SERVICE_IFACE_NAME,
                            "Authenticate",
                            g_variant_new ("(sss)",
                                           user,
                                           passw,
                                           domain),
                            NULL,
                            G_DBUS_CALL_FLAGS_NONE,
                            30000,
                            cancellable,
                            on_auth_response,
                            data);

    g_free (domain);
    g_hash_table_unref (params);
}
static void _request_new_token(GSignondOauthPlugin *self, 
                        GSignondSessionData *session_data,
                        GError** error)
{
    const gchar* response_type = gsignond_dictionary_get_string(session_data, "ResponseType");
    const gchar* grant_type = gsignond_dictionary_get_string(session_data, "GrantType");
    
    if (response_type != NULL &&
            (g_strcmp0(response_type, "code") == 0 || 
            g_strcmp0(response_type, "token") == 0)) {
        const gchar* host = gsignond_dictionary_get_string(session_data, "AuthHost");
        if (host == NULL) {
            *error = g_error_new(GSIGNOND_ERROR,
                                 GSIGNOND_ERROR_MISSING_DATA,
                                 "AuthHost not set");
            return;
        }

        gsignond_oauth_plugin_check_host(host, gsignond_session_data_get_allowed_realms (session_data), error);
        if (*error != NULL)
            return;
        
        const gchar* auth_path = gsignond_dictionary_get_string(session_data, "AuthPath");
        if (auth_path == NULL) {
            *error = g_error_new(GSIGNOND_ERROR,
                                 GSIGNOND_ERROR_MISSING_DATA,
                                 "AuthPath not set");
            return;
        }
        const gchar* client_id = gsignond_dictionary_get_string(session_data, "ClientId");
        if (client_id == NULL) {
            *error = g_error_new(GSIGNOND_ERROR,
                                 GSIGNOND_ERROR_MISSING_DATA,
                                 "ClientId not set");
            return;
        }

        SoupURI* open_url = soup_uri_new(NULL);
        soup_uri_set_scheme(open_url, SOUP_URI_SCHEME_HTTPS);
        soup_uri_set_host(open_url, host);
        soup_uri_set_path(open_url, auth_path);

        guint port;
        if (gsignond_dictionary_get_uint32(session_data, "AuthPort", &port) != FALSE)
            soup_uri_set_port(open_url, port);

        GHashTable* query = g_hash_table_new((GHashFunc)g_str_hash,
                                             (GEqualFunc)g_str_equal);
        const gchar* auth_query_str = gsignond_dictionary_get_string(session_data, "AuthQuery");
        GHashTable *auth_query = NULL;
        if (auth_query_str != NULL) {
            auth_query = soup_form_decode(auth_query_str);
            if (auth_query)
                // insert all key/values in AuthQuery into final query
                // according to RFC6749 section 3.1
                g_hash_table_foreach(auth_query, _insert_key_value, query);
        }

        g_hash_table_insert(query, "response_type", (gchar*)response_type);
        g_hash_table_insert(query, "client_id", (gchar*)client_id);
        
        const gchar* redirect_uri = gsignond_dictionary_get_string(session_data, "RedirectUri");
        if (redirect_uri != NULL) {
            g_hash_table_insert(query, "redirect_uri", (gchar*)redirect_uri);
        }

        const gchar* scope_str = gsignond_dictionary_get_string(session_data, "Scope");
        if (scope_str != NULL) {
            g_hash_table_insert(query, "scope", (gchar*)scope_str);
        }
        
        gchar* state = gsignond_oauth_plugin_generate_random_data(20);
        g_hash_table_insert(query, "state", state);
        gsignond_dictionary_set_string(self->oauth2_request, "_Oauth2State", state);

        const gchar* username = gsignond_session_data_get_username(session_data);
        const gchar* secret = gsignond_session_data_get_secret(session_data);

        // login_hint is a google extension specified here:
        // https://developers.google.com/accounts/docs/OAuth2InstalledApp#formingtheurl
        gboolean use_login_hint = FALSE;
        if (gsignond_dictionary_get_boolean(session_data, 
            "UseLoginHint", &use_login_hint) && 
            use_login_hint && username != NULL)
            g_hash_table_insert(query, "login_hint", (gchar*)username);
        
        // display is a facebook extension specified here:
        // https://developers.facebook.com/docs/reference/dialogs/oauth/
        const gchar* display = gsignond_dictionary_get_string(session_data, "UseDisplay");
        if (display != NULL) {
            g_hash_table_insert(query, "display", (gchar*)display);
        }
        
        soup_uri_set_query_from_form(open_url, query);
        g_free(state);
        g_hash_table_unref(query);
        if (auth_query)
            g_hash_table_unref(auth_query);

        char* open_url_str = soup_uri_to_string(open_url, FALSE);
        soup_uri_free(open_url);
        
        GSignondSignonuiData* ui_request = gsignond_dictionary_new();
        gsignond_signonui_data_set_open_url(ui_request, open_url_str);
        free(open_url_str);
        
        if (redirect_uri != NULL)
            gsignond_signonui_data_set_final_url(ui_request, redirect_uri);
        
        /* add username and password, for fields initialization (the
         * decision on whether to actually use them is up to the signon UI */
        if (username != NULL)
            gsignond_signonui_data_set_username(ui_request, username);
        if (secret != NULL)
            gsignond_signonui_data_set_password(ui_request, secret);
        
        gsignond_plugin_user_action_required(GSIGNOND_PLUGIN(self), ui_request);
        gsignond_dictionary_unref(ui_request);
        
    } else if (grant_type != NULL &&
            (g_strcmp0(grant_type, "password") == 0)) {
        const gchar* username = gsignond_session_data_get_username(session_data);
        const gchar* secret = gsignond_session_data_get_secret(session_data);
        if (username == NULL || secret == NULL) {
            *error = g_error_new(GSIGNOND_ERROR,
                                 GSIGNOND_ERROR_MISSING_DATA,
                                 "username or password not set");
            return;
        }
        GHashTable* params = g_hash_table_new((GHashFunc)g_str_hash,
                                             (GEqualFunc)g_str_equal);
        g_hash_table_insert(params, "grant_type", "password");
        g_hash_table_insert(params, "username", (gchar*)username);
        g_hash_table_insert(params, "password", (gchar*)secret);
        _set_scope(params, session_data);
    
        _do_token_query(self, session_data, params, error);
        g_hash_table_unref(params);
    } else if (grant_type != NULL &&
            (g_strcmp0(grant_type, "client_credentials") == 0)) {
        GHashTable* params = g_hash_table_new((GHashFunc)g_str_hash,
                                             (GEqualFunc)g_str_equal);
        g_hash_table_insert(params, "grant_type", "client_credentials");
        _set_scope(params, session_data);
    
        _do_token_query(self, session_data, params, error);
        g_hash_table_unref(params);
    } else {
        *error = g_error_new(GSIGNOND_ERROR,
                             GSIGNOND_ERROR_MISSING_DATA,
                             "Unknown ResponseType or GrantType");
    }
}
예제 #10
0
static void
control_callback (G_GNUC_UNUSED SoupServer * soup, SoupMessage * msg,
    const char *path, GHashTable * query,
    G_GNUC_UNUSED SoupClientContext * client, SnraManager * manager)
{
  gchar **parts = g_strsplit (path, "/", 3);
  guint n_parts = g_strv_length (parts);
  SnraControlEvent event_type;
  GHashTable *post_params = NULL;
  const gchar *content_type;

  if (n_parts < 3 || !g_str_equal ("control", parts[1]))
    goto done;                  /* Invalid request */

  event_type = str_to_control_event_type (parts[2]);
  content_type =
      soup_message_headers_get_content_type (msg->request_headers, NULL);
  if (g_str_equal (msg->method, "POST") &&
      content_type &&
      g_str_equal (content_type, SOUP_FORM_MIME_TYPE_URLENCODED))
    post_params = soup_form_decode (msg->request_body->data);

  switch (event_type) {
    case SNRA_CONTROL_NEXT:{
      gchar *id_str = find_param_str ("id", query, post_params);
      guint resource_id;

      if (id_str == NULL || !sscanf (id_str, "%d", &resource_id)) {
        /* No or invalid resource id: skip to another random track */
        resource_id =
            (guint) g_random_int_range (0, get_playlist_len (manager)) + 1;
      } else {
        resource_id = CLAMP (resource_id, 1, get_playlist_len (manager));
      }
      if (resource_id != 0) {
        manager->paused = FALSE;
        snra_manager_play_resource (manager, resource_id);
      }
      break;
    }
    case SNRA_CONTROL_PAUSE:{
      if (!manager->paused)
        snra_manager_send_pause (manager, NULL);
      manager->paused = TRUE;
      break;
    }
    case SNRA_CONTROL_PLAY:{
      if (manager->paused) {
        if (manager->current_resource == 0) {
          guint resource_id =
              g_random_int_range (0, get_playlist_len (manager) + 1);
          if (resource_id != 0) {
            manager->paused = FALSE;
            snra_manager_play_resource (manager, resource_id);
          }
        } else {
          manager->paused = FALSE;
          snra_manager_send_play (manager, NULL);
        }
      }
      break;
    }
    case SNRA_CONTROL_VOLUME:{
      gchar *vol_str = find_param_str ("level", query, post_params);
      gchar *id_str = find_param_str ("client_id", query, post_params);
      guint client_id = 0;
      gdouble new_vol;

      if (id_str != NULL)
        sscanf (id_str, "%u", &client_id);

      if (vol_str && sscanf (vol_str, "%lf", &new_vol)) {
        new_vol = CLAMP (new_vol, 0.0, 10.0);
        if (client_id == 0)
          snra_manager_adjust_volume (manager, new_vol);
        else
          snra_manager_adjust_client_volume (manager, client_id, new_vol);
      }

      break;
    }
    case SNRA_CONTROL_CLIENT_SETTING:{
      gchar *set_str = find_param_str ("enable", query, post_params);
      gchar *id_str = find_param_str ("client_id", query, post_params);
      guint client_id = 0;
      gint enable = 1;

      if (id_str != NULL)
        sscanf (id_str, "%u", &client_id);

      if (set_str && sscanf (set_str, "%d", &enable)) {
        if (client_id > 0)
          snra_manager_adjust_client_setting (manager, client_id, enable != 0);
      }

      break;
    }
    default:
      g_message ("Ignoring unknown/unimplemented control %s\n", parts[2]);
      soup_message_set_status (msg, SOUP_STATUS_NOT_FOUND);
      goto done;
  }

  soup_message_set_response (msg, "text/plain", SOUP_MEMORY_STATIC, " ", 1);
  soup_message_set_status (msg, SOUP_STATUS_OK);
done:
  if (post_params)
    g_hash_table_destroy (post_params);
  g_strfreev (parts);
}
void _process_oauth1_user_action_finished(GSignondOauthPlugin *self, 
                                         GSignondSignonuiData *ui_data)
{
    GError* error = NULL;
    GSignondSignonuiError query_error;
    gboolean res = gsignond_signonui_data_get_query_error(ui_data,
                                                          &query_error);
    if (res == FALSE) {
        error = g_error_new(GSIGNOND_ERROR,
                                GSIGNOND_ERROR_USER_INTERACTION,
                                "userActionFinished did not return an error value");
        goto out;
    }
    if (query_error == SIGNONUI_ERROR_CANCELED) {
        error = g_error_new(GSIGNOND_ERROR,
                                GSIGNOND_ERROR_SESSION_CANCELED,
                                "Session canceled");
        goto out;
    } else if (query_error != SIGNONUI_ERROR_NONE) {
        error = g_error_new(GSIGNOND_ERROR,
                                GSIGNOND_ERROR_USER_INTERACTION,
                                "userActionFinished error: %d",
                                query_error);
        goto out;
    }

    const gchar* response_url = gsignond_signonui_data_get_url_response(ui_data);
    const gchar* callback_uri = gsignond_dictionary_get_string(
        self->oauth1_request, "Callback");
    if (response_url == NULL || callback_uri == NULL ||
        g_str_has_prefix(response_url, callback_uri) == FALSE) {
        error = g_error_new(GSIGNOND_ERROR,
                                GSIGNOND_ERROR_NOT_AUTHORIZED,
                                "Callback URI and URI supplied by UI don't match");
        goto out;
    }
    
    SoupURI* response = soup_uri_new(response_url);
    const gchar* query = soup_uri_get_query(response);
    if (query == NULL) {
        soup_uri_free(response);
        error = g_error_new(GSIGNOND_ERROR,
                                GSIGNOND_ERROR_NOT_AUTHORIZED,
                                "No query in returned redirect URI");
        goto out;
    }
    GHashTable* params = soup_form_decode(query);
    soup_uri_free(response);

    const gchar* oauth_token_response = g_hash_table_lookup(params, "oauth_token");
    if (g_strcmp0(oauth_token_response, 
                  gsignond_dictionary_get_string(self->oauth1_request,
                                                 "_OauthTemporaryToken")) != 0) {
        g_hash_table_destroy(params);
        error = g_error_new(GSIGNOND_ERROR,
                                GSIGNOND_ERROR_NOT_AUTHORIZED,
                                "Token returned by callback URI and temporary token don't match");
        goto out;
    }
    
    const gchar* oauth_verifier = g_hash_table_lookup(params, "oauth_verifier");
    if (oauth_verifier == NULL) {
        g_hash_table_destroy(params);
        error = g_error_new(GSIGNOND_ERROR,
                                GSIGNOND_ERROR_NOT_AUTHORIZED,
                                "No oauth_verifier in callback URI");
        goto out;
    }
    
    gsignond_dictionary_set_string(self->oauth1_request, "_OauthVerifier", oauth_verifier);
    gsignond_dictionary_remove(self->oauth1_request, "Callback");
    g_hash_table_destroy(params);
    
    _request_access_token(self, self->oauth1_request, &error);
out:
   if (error != NULL) {
        _do_reset_oauth1(self);
        gsignond_plugin_error (GSIGNOND_PLUGIN(self), error);
        g_error_free(error);
   }

}
static void
_access_token_callback (SoupSession *session, SoupMessage *msg, gpointer user_data)
{
    GError* error = NULL;
    GSignondOauthPlugin *self = GSIGNOND_OAUTH_PLUGIN(user_data);

    if (msg->status_code != SOUP_STATUS_OK) {
        error = g_error_new(GSIGNOND_ERROR,
                                GSIGNOND_ERROR_NOT_AUTHORIZED,
                                "Access token endpoint returned an error: %d %s",
                                msg->status_code, msg->reason_phrase);
        goto out;
    }

    SoupBuffer* response_s = soup_message_body_flatten(msg->response_body);
    GHashTable* response = soup_form_decode(response_s->data);
    soup_buffer_free(response_s);

    const gchar* token = g_hash_table_lookup(response, "oauth_token");
    const gchar* token_secret = g_hash_table_lookup(response, "oauth_token_secret");        

    if (token == NULL || token_secret == NULL) {
        g_hash_table_destroy(response);
        error = g_error_new(GSIGNOND_ERROR,
                                GSIGNOND_ERROR_NOT_AUTHORIZED,
                                "Access token endpoint returned an invalid response");
        goto out;
    }
    
    GSignondDictionary* token_dict = gsignond_dictionary_new();
    gsignond_dictionary_set_string(token_dict, "AccessToken", token);
    gsignond_dictionary_set_string(token_dict, "TokenSecret", token_secret);

    const gchar* realm = gsignond_dictionary_get_string(self->oauth1_request,
                                                        "Realm");
    if (realm != NULL)
        gsignond_dictionary_set_string(token_dict, "Realm", realm);

    GSignondDictionary* parameters_dict = gsignond_dictionary_new();
    g_hash_table_foreach(response, _insert_token_parameters, parameters_dict);
    g_hash_table_destroy(response);
    gsignond_dictionary_set(token_dict, "TokenParameters",
                            gsignond_dictionary_to_variant(parameters_dict));
    gsignond_dictionary_unref(parameters_dict);
    
    const gchar* client_id = gsignond_dictionary_get_string(self->oauth1_request, "ConsumerKey");
    gsignond_dictionary_set(self->token_cache, client_id, 
                            gsignond_dictionary_to_variant(token_dict));
    
    gsignond_plugin_store(GSIGNOND_PLUGIN(self), self->token_cache);
    
    _do_reset_oauth1(self);
    gsignond_plugin_response_final(GSIGNOND_PLUGIN(self), token_dict);
    gsignond_dictionary_unref(token_dict);

out:
   if (error != NULL) {
        _do_reset_oauth1(self);
        gsignond_plugin_error (GSIGNOND_PLUGIN(self), error);
        g_error_free(error);
   }

}
static void
_temporary_token_callback (SoupSession *session, SoupMessage *msg, gpointer user_data)
{
    GError* error = NULL;
    GSignondOauthPlugin *self = GSIGNOND_OAUTH_PLUGIN(user_data);

    if (msg->status_code != SOUP_STATUS_OK) {
        error = g_error_new(GSIGNOND_ERROR,
                                GSIGNOND_ERROR_NOT_AUTHORIZED,
                                "Temporary token endpoint returned an error: %d %s",
                                msg->status_code, msg->reason_phrase);
        goto out;
    }

    SoupBuffer* response_s = soup_message_body_flatten(msg->response_body);
    GHashTable* response = soup_form_decode(response_s->data);
    soup_buffer_free(response_s);

    const gchar* callback_confirmed = g_hash_table_lookup(response, "oauth_callback_confirmed");
    const gchar* token = g_hash_table_lookup(response, "oauth_token");
    const gchar* token_secret = g_hash_table_lookup(response, "oauth_token_secret");        

    if (token == NULL || token_secret == NULL || g_strcmp0(callback_confirmed, "true") != 0) {
        g_hash_table_destroy(response);
        error = g_error_new(GSIGNOND_ERROR,
                                GSIGNOND_ERROR_NOT_AUTHORIZED,
                                "Temporary token endpoint returned an invalid response");
        goto out;
    }

    const gchar* callback_url = gsignond_dictionary_get_string(self->oauth1_request, 
                                                               "Callback");
    if (callback_url == NULL) {                                                                    
        g_hash_table_destroy(response);
        error = g_error_new(GSIGNOND_ERROR,
                                GSIGNOND_ERROR_NOT_AUTHORIZED,
                                "Client did not supply Callback");
        goto out;
    }

    const gchar* authorization_url_s = gsignond_dictionary_get_string(self->oauth1_request, 
                                                                    "AuthorizationEndpoint");
    if (authorization_url_s == NULL) {                                                                    
        g_hash_table_destroy(response);
        error = g_error_new(GSIGNOND_ERROR,
                                GSIGNOND_ERROR_NOT_AUTHORIZED,
                                "Client did not supply AuthorizationEndpoint");
        goto out;
    }
    
    SoupURI* authorization_url = soup_uri_new(authorization_url_s);
    if (authorization_url == NULL) {
        g_hash_table_destroy(response);
        error = g_error_new(GSIGNOND_ERROR,
                                GSIGNOND_ERROR_NOT_AUTHORIZED,
                                "Client did not supply a valid AuthorizationEndpoint");
        goto out;
    }
    gsignond_oauth_plugin_check_host(soup_uri_get_host(authorization_url),
        gsignond_session_data_get_allowed_realms (self->oauth1_request), &error);
    if (error != NULL) {
        soup_uri_free(authorization_url);
        g_hash_table_destroy(response);
        return;
    }
    
    GHashTable* query = g_hash_table_new((GHashFunc)g_str_hash,
                                             (GEqualFunc)g_str_equal);
    const gchar* authorization_query_s = soup_uri_get_query(authorization_url);
    GHashTable *auth_query = NULL;
    if (authorization_query_s != NULL) {
        auth_query = soup_form_decode(authorization_query_s);
        g_hash_table_foreach(auth_query, _insert_key_value, query);
    }
    g_hash_table_insert(query, "oauth_token", (gchar*)token);
    soup_uri_set_query_from_form(authorization_url, query);
    if (auth_query)
        g_hash_table_destroy(auth_query);
    g_hash_table_destroy(query);
    
    gchar* open_url = soup_uri_to_string(authorization_url, FALSE);
    soup_uri_free(authorization_url);
    
    gsignond_dictionary_set_string(self->oauth1_request, "_OauthTemporaryToken", token);
    gsignond_dictionary_set_string(self->oauth1_request, "_OauthTemporaryTokenSecret", token_secret);
    
    GSignondSignonuiData* ui_request = gsignond_dictionary_new();
    gsignond_signonui_data_set_open_url(ui_request, open_url);
    g_free(open_url);
        
    if (g_strcmp0(callback_url, "oob") != 0)
        gsignond_signonui_data_set_final_url(ui_request, callback_url);
        
    /* add username and password, for fields initialization (the
     * decision on whether to actually use them is up to the signon UI */
    const gchar* username = gsignond_session_data_get_username(self->oauth1_request);
    if (username != NULL)
        gsignond_signonui_data_set_username(ui_request, username);
    const gchar* secret = gsignond_session_data_get_secret(self->oauth1_request);
    if (secret != NULL)
        gsignond_signonui_data_set_password(ui_request, secret);


     gsignond_plugin_user_action_required(GSIGNOND_PLUGIN(self), ui_request);
     gsignond_dictionary_unref(ui_request);    

    g_hash_table_destroy(response);

out:
   if (error != NULL) {
        _do_reset_oauth1(self);
        gsignond_plugin_error (GSIGNOND_PLUGIN(self), error);
        g_error_free(error);
   }
}