static char *
challenge (SoupAuthDomain *domain, SoupMessage *msg)
{
	GString *str;

	str = g_string_new ("Digest ");
	soup_header_g_string_append_param_quoted (str, "realm", soup_auth_domain_get_realm (domain));
	g_string_append_printf (str, ", nonce=\"%lu%lu\"", 
				(unsigned long) msg,
				(unsigned long) time (0));
	g_string_append_printf (str, ", qop=\"auth\"");
	g_string_append_printf (str, ", algorithm=MD5");

	return g_string_free (str, FALSE);
}
static char *
soup_auth_digest_get_authorization (SoupAuth *auth, SoupMessage *msg)
{
	SoupAuthDigestPrivate *priv = SOUP_AUTH_DIGEST_GET_PRIVATE (auth);
	char response[33], *token;
	char *url, *algorithm;
	GString *out;
	SoupURI *uri;

	uri = soup_message_get_uri (msg);
	g_return_val_if_fail (uri != NULL, NULL);
	url = soup_uri_to_string (uri, TRUE);

	soup_auth_digest_compute_response (msg->method, url, priv->hex_a1,
					   priv->qop, priv->nonce,
					   priv->cnonce, priv->nc,
					   response);

	out = g_string_new ("Digest ");

	soup_header_g_string_append_param_quoted (out, "username", priv->user);
	g_string_append (out, ", ");
	soup_header_g_string_append_param_quoted (out, "realm", auth->realm);
	g_string_append (out, ", ");
	soup_header_g_string_append_param_quoted (out, "nonce", priv->nonce);
	g_string_append (out, ", ");
	soup_header_g_string_append_param_quoted (out, "uri", url);
	g_string_append (out, ", ");
	algorithm = soup_auth_digest_get_algorithm (priv->algorithm);
	g_string_append_printf (out, "algorithm=%s", algorithm);
	g_free (algorithm);
	g_string_append (out, ", ");
	soup_header_g_string_append_param_quoted (out, "response", response);

	if (priv->opaque) {
		g_string_append (out, ", ");
		soup_header_g_string_append_param_quoted (out, "opaque", priv->opaque);
	}

	if (priv->qop) {
		char *qop = soup_auth_digest_get_qop (priv->qop);

		g_string_append (out, ", ");
		soup_header_g_string_append_param_quoted (out, "cnonce", priv->cnonce);
		g_string_append_printf (out, ", nc=%.8x, qop=%s",
					priv->nc, qop);
		g_free (qop);
	}

	g_free (url);

	priv->nc++;

	token = g_string_free (out, FALSE);

	soup_message_add_header_handler (msg,
					 "got_headers",
					 soup_auth_is_for_proxy (auth) ?
					 "Proxy-Authentication-Info" :
					 "Authentication-Info",
					 G_CALLBACK (authentication_info_cb),
					 auth);
	return token;
}
static gchar* _make_authorization_header(
                                       GSignondSessionData *session_data,
                                       SoupURI* uri,
                                       GError** error
                                        )
{
    GString* header = g_string_new("OAuth ");
    
    const gchar* realm = gsignond_dictionary_get_string(session_data, "Realm");
    if (realm != NULL) {
        gchar* realm_e = _percent_encode(realm);
        soup_header_g_string_append_param_quoted (header, "realm", realm_e);
        g_free(realm_e);
        g_string_append (header, ", ");
    }
    
    const gchar* callback_uri = gsignond_dictionary_get_string(session_data, "Callback");
    if (callback_uri != NULL) {
        gchar* callback_uri_e = _percent_encode(callback_uri);
        soup_header_g_string_append_param_quoted (header, "oauth_callback", callback_uri_e);
        g_free(callback_uri_e);
        g_string_append (header, ", ");
    }

    const gchar* oauth_verifier = gsignond_dictionary_get_string(session_data, "_OauthVerifier");
    if (oauth_verifier != NULL) {
        gchar* oauth_verifier_e = _percent_encode(oauth_verifier);
        soup_header_g_string_append_param_quoted (header, "oauth_verifier", oauth_verifier_e);
        g_free(oauth_verifier_e);
        g_string_append (header, ", ");
    }
    
    const gchar* oauth_consumer_key = gsignond_dictionary_get_string(session_data, "ConsumerKey");
    if (oauth_consumer_key == NULL) {
        *error = g_error_new(GSIGNOND_ERROR,
                             GSIGNOND_ERROR_MISSING_DATA,
                             "Client did not supply ConsumerKey");
        g_string_free(header, TRUE);
        return NULL;
    }
    gchar* oauth_consumer_key_e = _percent_encode(oauth_consumer_key);
    soup_header_g_string_append_param_quoted (header, "oauth_consumer_key", oauth_consumer_key_e);
    g_free(oauth_consumer_key_e);
    g_string_append (header, ", ");
    
    const gchar* oauth_temp_token = gsignond_dictionary_get_string(session_data, "_OauthTemporaryToken");
    if (oauth_temp_token != NULL) {
        gchar* oauth_temp_token_e = _percent_encode(oauth_temp_token);
        soup_header_g_string_append_param_quoted (header, "oauth_token", oauth_temp_token_e);
        g_free(oauth_temp_token_e);
        g_string_append (header, ", ");
    }
    
    const gchar* oauth_signature_method = gsignond_dictionary_get_string(session_data, 
                                                                   "SignatureMethod");
    if (g_strcmp0(oauth_signature_method, "PLAINTEXT") == 0) {
        gchar* secret_key = _make_secret_key(session_data);
        gchar* secret_key_e = _percent_encode(secret_key);
        g_free(secret_key);
        soup_header_g_string_append_param_quoted(header, "oauth_signature",
                                                 secret_key_e);
        g_free(secret_key_e);
        g_string_append (header, ", ");
    } else if (g_strcmp0(oauth_signature_method, "HMAC-SHA1") == 0) {
        gchar* nonce = gsignond_oauth_plugin_generate_random_data(20);
        gchar* nonce_e = _percent_encode(nonce);
        gchar* timestamp = _get_timestamp();
        gchar* base_string = _make_base_string(session_data, uri, nonce, timestamp);
        gchar* key = _make_secret_key(session_data);
        gchar* signature = _make_hmacsha1_base64_signature(base_string, key);
        gchar* signature_e = _percent_encode(signature);
        soup_header_g_string_append_param_quoted(header, "oauth_nonce",
                                                 nonce_e);
        g_string_append (header, ", ");        
        soup_header_g_string_append_param_quoted(header, "oauth_timestamp",
                                                 timestamp);
        g_string_append (header, ", ");
        soup_header_g_string_append_param_quoted(header, "oauth_signature",
                                                 signature_e);
        g_string_append (header, ", ");
        
        g_free(signature_e);
        g_free(signature);
        g_free(key);
        g_free(base_string);
        g_free(timestamp);
        g_free(nonce_e);
        g_free(nonce);
        
    } else if (g_strcmp0(oauth_signature_method, "RSA-SHA1") == 0) {
        const gchar* key = gsignond_dictionary_get_string(session_data, "RSAPrivateKey");
        if (key == NULL) {
            *error = g_error_new(GSIGNOND_ERROR,
                                 GSIGNOND_ERROR_MISSING_DATA,
                                 "Client did not supply RSAPrivateKey");
            g_string_free(header, TRUE);
            return NULL;
        }
        gchar* nonce = gsignond_oauth_plugin_generate_random_data(160);
        gchar* nonce_e = _percent_encode(nonce);
        gchar* timestamp = _get_timestamp();
        gchar* base_string = _make_base_string(session_data, uri, nonce, timestamp);
        gchar* signature = _make_rsasha1_base64_signature(base_string, key);
        if (signature == NULL) {
            *error = g_error_new(GSIGNOND_ERROR,
                                 GSIGNOND_ERROR_MISSING_DATA,
                                 "Invalid RSA private key");
            g_string_free(header, TRUE);
            g_free(base_string);
            g_free(timestamp);
            g_free(nonce_e);
            g_free(nonce);
            return NULL;
        }
        gchar* signature_e = _percent_encode(signature);
        soup_header_g_string_append_param_quoted(header, "oauth_nonce",
                                                 nonce_e);
        g_string_append (header, ", ");        
        soup_header_g_string_append_param_quoted(header, "oauth_timestamp",
                                                 timestamp);
        g_string_append (header, ", ");
        soup_header_g_string_append_param_quoted(header, "oauth_signature",
                                                 signature_e);
        g_string_append (header, ", ");
        
        g_free(signature_e);
        g_free(signature);
        g_free(base_string);
        g_free(timestamp);
        g_free(nonce_e);
        g_free(nonce);
    } else {
        *error = g_error_new(GSIGNOND_ERROR,
                             GSIGNOND_ERROR_MISSING_DATA,
                             "Unknown oauth1 signature method");
        g_string_free(header, TRUE);
        return NULL;
    }
    
    soup_header_g_string_append_param_quoted(header, "oauth_signature_method",
                                             oauth_signature_method);
    g_string_append (header, ", ");
    soup_header_g_string_append_param_quoted(header, "oauth_version", "1.0");
    
    return g_string_free(header, FALSE);
}