diff options
author | Philip Withnall <philip@tecnocode.co.uk> | 2011-05-29 22:38:39 +0100 |
---|---|---|
committer | Philip Withnall <philip@tecnocode.co.uk> | 2011-06-05 16:50:02 +0100 |
commit | 47d20c21e8986cdbab21098428dd57bca203f6ad (patch) | |
tree | 0ac82cca33c670826bb02336158e210a2df6d655 /gdata/tests/oauth1-authorizer.c | |
parent | 65d3e0c373edcaf199b4d3dc3499b237bb620fc1 (diff) | |
download | libgdata-47d20c21e8986cdbab21098428dd57bca203f6ad.tar.gz |
core: Add an OAuth 1.0 authoriser
This adds a GDataAuthorizer implementation for OAuth 1.0, the current
favourite authentication/authorization protocol in Google-land.
This includes full documentation and a test suite.
This makes the following API changes:
• Add GDataOAuth1Authorizer and all its properties and methods.
It also adds a dependency on liboauth ≥ 0.9.4.
Helps: bgo#646285
Diffstat (limited to 'gdata/tests/oauth1-authorizer.c')
-rw-r--r-- | gdata/tests/oauth1-authorizer.c | 1048 |
1 files changed, 1048 insertions, 0 deletions
diff --git a/gdata/tests/oauth1-authorizer.c b/gdata/tests/oauth1-authorizer.c new file mode 100644 index 00000000..0cc4efc5 --- /dev/null +++ b/gdata/tests/oauth1-authorizer.c @@ -0,0 +1,1048 @@ +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ +/* + * GData Client + * Copyright (C) Philip Withnall 2011 <philip@tecnocode.co.uk> + * + * GData Client is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * GData Client is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with GData Client. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <glib.h> +#include <gdata/gdata.h> + +#include "common.h" + +static GThread *main_thread = NULL; + +static void +test_oauth1_authorizer_constructor (void) +{ + GDataOAuth1Authorizer *authorizer; + + authorizer = gdata_oauth1_authorizer_new ("Application name", GDATA_TYPE_CONTACTS_SERVICE); + + g_assert (authorizer != NULL); + g_assert (GDATA_IS_OAUTH1_AUTHORIZER (authorizer)); + g_assert (GDATA_IS_AUTHORIZER (authorizer)); + + g_object_unref (authorizer); +} + +static void +test_oauth1_authorizer_constructor_for_domains (void) +{ + GDataOAuth1Authorizer *authorizer; + GDataAuthorizationDomain *domain; + GList *domains; + + /* Try with standard domains first */ + domains = gdata_service_get_authorization_domains (GDATA_TYPE_CONTACTS_SERVICE); + authorizer = gdata_oauth1_authorizer_new_for_authorization_domains ("Application name", domains); + g_list_free (domains); + + g_assert (authorizer != NULL); + g_assert (GDATA_IS_OAUTH1_AUTHORIZER (authorizer)); + g_assert (GDATA_IS_AUTHORIZER (authorizer)); + + g_object_unref (authorizer); + + /* Try again with a custom domain. Note that, as in test_authorization_domain_properties() this should not normally happen in client code. */ + domain = GDATA_AUTHORIZATION_DOMAIN (g_object_new (GDATA_TYPE_AUTHORIZATION_DOMAIN, + "service-name", "test", + "scope", "test", + NULL)); + + domains = g_list_prepend (NULL, domain); + authorizer = gdata_oauth1_authorizer_new_for_authorization_domains ("Application name", domains); + g_list_free (domains); + + g_assert (authorizer != NULL); + g_assert (GDATA_IS_OAUTH1_AUTHORIZER (authorizer)); + g_assert (GDATA_IS_AUTHORIZER (authorizer)); + + g_object_unref (authorizer); + g_object_unref (domain); +} + +typedef struct { + GDataOAuth1Authorizer *authorizer; + + guint locale_notification_count; + gulong locale_signal_handler; + guint proxy_uri_notification_count; + gulong proxy_uri_signal_handler; + guint timeout_notification_count; + gulong timeout_signal_handler; +} OAuth1AuthorizerData; + +/* Used to count that exactly the right number of notify signals are emitted when setting properties */ +static void +notify_cb (GObject *object, GParamSpec *pspec, guint *notification_count) +{ + /* Check we're running in the main thread */ + g_assert (g_thread_self () == main_thread); + + /* Increment the notification count */ + *notification_count = *notification_count + 1; +} + +static void +connect_to_oauth1_authorizer (OAuth1AuthorizerData *data) +{ + /* Connect to notifications from the object to verify they're only emitted the correct number of times */ + data->locale_signal_handler = g_signal_connect (data->authorizer, "notify::locale", (GCallback) notify_cb, + &(data->locale_notification_count)); + data->proxy_uri_signal_handler = g_signal_connect (data->authorizer, "notify::proxy-uri", (GCallback) notify_cb, + &(data->proxy_uri_notification_count)); + data->timeout_signal_handler = g_signal_connect (data->authorizer, "notify::timeout", (GCallback) notify_cb, + &(data->timeout_notification_count)); +} + +static void +set_up_oauth1_authorizer_data (OAuth1AuthorizerData *data, gconstpointer user_data) +{ + data->authorizer = gdata_oauth1_authorizer_new ("Application name", GDATA_TYPE_CONTACTS_SERVICE); + connect_to_oauth1_authorizer (data); +} + +static void +set_up_oauth1_authorizer_data_fallback_application_name (OAuth1AuthorizerData *data, gconstpointer user_data) +{ + g_set_application_name ("Fallback name"); + data->authorizer = gdata_oauth1_authorizer_new (NULL, GDATA_TYPE_CONTACTS_SERVICE); + connect_to_oauth1_authorizer (data); +} + +static void +set_up_oauth1_authorizer_data_multiple_domains (OAuth1AuthorizerData *data, gconstpointer user_data) +{ + GList *authorization_domains = NULL; + + authorization_domains = g_list_prepend (authorization_domains, gdata_contacts_service_get_primary_authorization_domain ()); + authorization_domains = g_list_prepend (authorization_domains, gdata_picasaweb_service_get_primary_authorization_domain ()); + data->authorizer = gdata_oauth1_authorizer_new_for_authorization_domains ("Application name", authorization_domains); + g_list_free (authorization_domains); + + connect_to_oauth1_authorizer (data); +} + +static void +set_up_oauth1_authorizer_data_locale (OAuth1AuthorizerData *data, gconstpointer user_data) +{ + data->authorizer = gdata_oauth1_authorizer_new ("Application name", GDATA_TYPE_CONTACTS_SERVICE); + gdata_oauth1_authorizer_set_locale (data->authorizer, "en_GB"); + connect_to_oauth1_authorizer (data); +} + +/* Given an authentication URI, prompt the user to go to that URI, grant access to the test application and enter the resulting verifier */ +static gchar * +query_user_for_verifier (const gchar *authentication_uri) +{ + char verifier[100]; + + /* Wait for the user to retrieve and enter the verifier */ + g_print ("Please navigate to the following URI and grant access: %s\n", authentication_uri); + g_print ("Enter verifier (EOF to skip test): "); + if (scanf ("%100s", verifier) != 1) { + /* Skip the test */ + g_test_message ("Skipping test on user request."); + return NULL; + } + + g_test_message ("Proceeding with user-provided verifier “%s”.", verifier); + + return g_strdup (verifier); +} + +static void +set_up_oauth1_authorizer_data_authenticated (OAuth1AuthorizerData *data, gconstpointer user_data) +{ + gboolean *skip_test = (gboolean*) user_data; + gchar *authentication_uri, *token, *token_secret, *verifier; + + /* Chain up */ + set_up_oauth1_authorizer_data (data, NULL); + + /* Get an authentication URI */ + authentication_uri = gdata_oauth1_authorizer_request_authentication_uri (data->authorizer, &token, &token_secret, NULL, NULL); + g_assert (authentication_uri != NULL); + + /* Get the verifier off the user */ + verifier = query_user_for_verifier (authentication_uri); + + g_free (authentication_uri); + + if (verifier == NULL) { + *skip_test = TRUE; + goto skip_test; + } + + /* Authorise the token */ + g_assert (gdata_oauth1_authorizer_request_authorization (data->authorizer, token, token_secret, verifier, NULL, NULL) == TRUE); + +skip_test: + g_free (token); + g_free (token_secret); + g_free (verifier); +} + +static void +tear_down_oauth1_authorizer_data (OAuth1AuthorizerData *data, gconstpointer user_data) +{ + /* Clean up signal handlers */ + g_signal_handler_disconnect (data->authorizer, data->timeout_signal_handler); + g_signal_handler_disconnect (data->authorizer, data->proxy_uri_signal_handler); + g_signal_handler_disconnect (data->authorizer, data->locale_signal_handler); + + g_object_unref (data->authorizer); +} + +/* Test getting and setting the application-name property */ +static void +test_oauth1_authorizer_properties_application_name (OAuth1AuthorizerData *data, gconstpointer user_data) +{ + gchar *application_name; + + /* Verifying the normal state of the property in a newly-constructed instance of GDataOAuth1Authorizer */ + g_assert_cmpstr (gdata_oauth1_authorizer_get_application_name (data->authorizer), ==, "Application name"); + + g_object_get (data->authorizer, "application-name", &application_name, NULL); + g_assert_cmpstr (application_name, ==, "Application name"); + g_free (application_name); +} + +/* Test the fallback for the application-name property */ +static void +test_oauth1_authorizer_properties_application_name_fallback (OAuth1AuthorizerData *data, gconstpointer user_data) +{ + gchar *application_name; + + /* Verifying the normal state of the property in a newly-constructed instance of GDataOAuth1Authorizer */ + g_assert_cmpstr (gdata_oauth1_authorizer_get_application_name (data->authorizer), ==, "Fallback name"); + + g_object_get (data->authorizer, "application-name", &application_name, NULL); + g_assert_cmpstr (application_name, ==, "Fallback name"); + g_free (application_name); +} + +/* Test getting and setting the locale property */ +static void +test_oauth1_authorizer_properties_locale (OAuth1AuthorizerData *data, gconstpointer user_data) +{ + gchar *locale; + + /* Verifying the normal state of the property in a newly-constructed instance of GDataOAuth1Authorizer */ + g_assert_cmpstr (gdata_oauth1_authorizer_get_locale (data->authorizer), ==, NULL); + + g_object_get (data->authorizer, "locale", &locale, NULL); + g_assert_cmpstr (locale, ==, NULL); + g_free (locale); + + g_assert_cmpuint (data->locale_notification_count, ==, 0); + + /* Check setting it works and emits a notification */ + gdata_oauth1_authorizer_set_locale (data->authorizer, "en"); + + g_assert_cmpuint (data->locale_notification_count, ==, 1); + + g_assert_cmpstr (gdata_oauth1_authorizer_get_locale (data->authorizer), ==, "en"); + + g_object_get (data->authorizer, "locale", &locale, NULL); + g_assert_cmpstr (locale, ==, "en"); + g_free (locale); + + /* Check setting it to the same value is a no-op */ + gdata_oauth1_authorizer_set_locale (data->authorizer, "en"); + g_assert_cmpuint (data->locale_notification_count, ==, 1); + + /* Check setting it back to NULL works */ + gdata_oauth1_authorizer_set_locale (data->authorizer, NULL); + + g_assert_cmpuint (data->locale_notification_count, ==, 2); + + g_assert_cmpstr (gdata_oauth1_authorizer_get_locale (data->authorizer), ==, NULL); + + g_object_get (data->authorizer, "locale", &locale, NULL); + g_assert_cmpstr (locale, ==, NULL); + g_free (locale); + + /* Test that setting it using g_object_set() works */ + g_object_set (data->authorizer, "locale", "de", NULL); + g_assert_cmpstr (gdata_oauth1_authorizer_get_locale (data->authorizer), ==, "de"); +} + +/* Test getting and setting the proxy-uri property */ +static void +test_oauth1_authorizer_properties_proxy_uri (OAuth1AuthorizerData *data, gconstpointer user_data) +{ + SoupURI *proxy_uri, *new_proxy_uri; + + /* Verifying the normal state of the property in a newly-constructed instance of GDataOAuth1Authorizer */ + g_assert (gdata_oauth1_authorizer_get_proxy_uri (data->authorizer) == NULL); + + g_object_get (data->authorizer, "proxy-uri", &proxy_uri, NULL); + g_assert (proxy_uri == NULL); + + g_assert_cmpuint (data->proxy_uri_notification_count, ==, 0); + + /* Check setting it works and emits a notification */ + new_proxy_uri = soup_uri_new ("http://example.com/"); + gdata_oauth1_authorizer_set_proxy_uri (data->authorizer, new_proxy_uri); + + g_assert_cmpuint (data->proxy_uri_notification_count, ==, 1); + + g_assert (gdata_oauth1_authorizer_get_proxy_uri (data->authorizer) != NULL); + g_assert (soup_uri_equal (gdata_oauth1_authorizer_get_proxy_uri (data->authorizer), new_proxy_uri) == TRUE); + + g_object_get (data->authorizer, "proxy-uri", &proxy_uri, NULL); + g_assert (proxy_uri != NULL); + g_assert (soup_uri_equal (gdata_oauth1_authorizer_get_proxy_uri (data->authorizer), new_proxy_uri) == TRUE); + soup_uri_free (proxy_uri); + + soup_uri_free (new_proxy_uri); + + /* Check setting it back to NULL works */ + gdata_oauth1_authorizer_set_proxy_uri (data->authorizer, NULL); + + g_assert_cmpuint (data->proxy_uri_notification_count, ==, 2); + + g_assert (gdata_oauth1_authorizer_get_proxy_uri (data->authorizer) == NULL); + + g_object_get (data->authorizer, "proxy-uri", &proxy_uri, NULL); + g_assert (proxy_uri == NULL); + + /* Test that setting it using g_object_set() works */ + new_proxy_uri = soup_uri_new ("http://example.com/"); + g_object_set (data->authorizer, "proxy-uri", new_proxy_uri, NULL); + soup_uri_free (new_proxy_uri); + + g_assert (gdata_oauth1_authorizer_get_proxy_uri (data->authorizer) != NULL); +} + +/* Test getting and setting the timeout property */ +static void +test_oauth1_authorizer_properties_timeout (OAuth1AuthorizerData *data, gconstpointer user_data) +{ + guint timeout; + + /* Verifying the normal state of the property in a newly-constructed instance of GDataOAuth1Authorizer */ + g_assert_cmpuint (gdata_oauth1_authorizer_get_timeout (data->authorizer), ==, 0); + + g_object_get (data->authorizer, "timeout", &timeout, NULL); + g_assert_cmpuint (timeout, ==, 0); + + g_assert_cmpuint (data->timeout_notification_count, ==, 0); + + /* Check setting it works and emits a notification */ + gdata_oauth1_authorizer_set_timeout (data->authorizer, 30); + + g_assert_cmpuint (data->timeout_notification_count, ==, 1); + + g_assert_cmpuint (gdata_oauth1_authorizer_get_timeout (data->authorizer), ==, 30); + + g_object_get (data->authorizer, "timeout", &timeout, NULL); + g_assert_cmpuint (timeout, ==, 30); + + /* Check setting it to the same value is a no-op */ + gdata_oauth1_authorizer_set_timeout (data->authorizer, 30); + g_assert_cmpuint (data->timeout_notification_count, ==, 1); + + /* Check setting it back to 0 works */ + gdata_oauth1_authorizer_set_timeout (data->authorizer, 0); + + g_assert_cmpuint (data->timeout_notification_count, ==, 2); + + g_assert_cmpuint (gdata_oauth1_authorizer_get_timeout (data->authorizer), ==, 0); + + g_object_get (data->authorizer, "timeout", &timeout, NULL); + g_assert_cmpuint (timeout, ==, 0); + + /* Test that setting it using g_object_set() works */ + g_object_set (data->authorizer, "timeout", 15, NULL); + g_assert_cmpuint (gdata_oauth1_authorizer_get_timeout (data->authorizer), ==, 15); +} + +/* Test that gdata_authorizer_refresh_authorization() is a no-op (whether authorised or not) */ +static void +test_oauth1_authorizer_refresh_authorization (OAuth1AuthorizerData *data, gconstpointer user_data) +{ + gboolean *skip_test = (gboolean*) user_data; + GError *error = NULL; + + /* Skip the test if the user's requested */ + if (skip_test != NULL && *skip_test == TRUE) { + return; + } + + g_assert (gdata_authorizer_refresh_authorization (GDATA_AUTHORIZER (data->authorizer), NULL, &error) == FALSE); + g_assert_no_error (error); + g_clear_error (&error); +} + +/* Test that processing a request with a NULL domain will not change the request. */ +static void +test_oauth1_authorizer_process_request_null (OAuth1AuthorizerData *data, gconstpointer user_data) +{ + SoupMessage *message; + SoupMessageHeadersIter iter; + guint header_count = 0; + const gchar *name, *value; + + /* Create a new message with an empty set of request headers */ + message = soup_message_new (SOUP_METHOD_GET, "https://example.com/"); + + /* Process the message */ + gdata_authorizer_process_request (GDATA_AUTHORIZER (data->authorizer), NULL, message); + + /* Check that the set of request headers is still empty */ + soup_message_headers_iter_init (&iter, message->request_headers); + + while (soup_message_headers_iter_next (&iter, &name, &value) == TRUE) { + header_count++; + } + + g_assert_cmpuint (header_count, ==, 0); + + g_object_unref (message); +} + +/* Test that processing a request with an authorizer which hasn't been authenticated yet will not change the request. */ +static void +test_oauth1_authorizer_process_request_unauthenticated (OAuth1AuthorizerData *data, gconstpointer user_data) +{ + SoupMessage *message; + SoupMessageHeadersIter iter; + guint header_count = 0; + const gchar *name, *value; + + /* Create a new message with an empty set of request headers */ + message = soup_message_new (SOUP_METHOD_GET, "https://example.com/"); + + /* Process the message */ + gdata_authorizer_process_request (GDATA_AUTHORIZER (data->authorizer), gdata_contacts_service_get_primary_authorization_domain (), message); + + /* Check that the set of request headers is still empty */ + soup_message_headers_iter_init (&iter, message->request_headers); + + while (soup_message_headers_iter_next (&iter, &name, &value) == TRUE) { + header_count++; + } + + g_assert_cmpuint (header_count, ==, 0); + + g_object_unref (message); +} + +/* Test that processing a request with an authorizer which has been authenticated will change the request. */ +static void +test_oauth1_authorizer_process_request_authenticated (OAuth1AuthorizerData *data, gconstpointer user_data) +{ + gboolean *skip_test = (gboolean*) user_data; + SoupMessage *message; + SoupMessageHeadersIter iter; + guint header_count = 0; + const gchar *name, *value; + + /* Skip the test if the user's requested */ + if (skip_test != NULL && *skip_test == TRUE) { + return; + } + + /* Create a new message with an empty set of request headers */ + message = soup_message_new (SOUP_METHOD_GET, "http://example.com/"); + + /* Process the message */ + gdata_authorizer_process_request (GDATA_AUTHORIZER (data->authorizer), gdata_contacts_service_get_primary_authorization_domain (), message); + + /* Check that at least one new header has been set */ + soup_message_headers_iter_init (&iter, message->request_headers); + + while (soup_message_headers_iter_next (&iter, &name, &value) == TRUE) { + header_count++; + } + + g_assert_cmpuint (header_count, >, 0); + + g_object_unref (message); +} + +/* Test that requesting an authentication URI synchronously works correctly */ +static void +test_oauth1_authorizer_request_authentication_uri_sync (OAuth1AuthorizerData *data, gconstpointer user_data) +{ + gchar *authentication_uri, *token, *token_secret; + GError *error = NULL; + + authentication_uri = gdata_oauth1_authorizer_request_authentication_uri (data->authorizer, &token, &token_secret, NULL, &error); + g_assert_no_error (error); + g_assert (authentication_uri != NULL && *authentication_uri != '\0'); + g_assert (token != NULL && *token != '\0'); + g_assert (token_secret != NULL && *token != '\0'); + g_clear_error (&error); + + g_test_message ("Requesting an authentication URI gave “%s” with request token “%s” and request token secret “%s”.", + authentication_uri, token, token_secret); + + g_free (authentication_uri); + g_free (token); + g_free (token_secret); +} + +/* Test that requesting an authentication URI synchronously can be cancelled */ +static void +test_oauth1_authorizer_request_authentication_uri_sync_cancellation (OAuth1AuthorizerData *data, gconstpointer user_data) +{ + /* Initialise token and token_secret so we check that gdata_oauth1_authorizer_request_authentication_uri() NULLifies them on error */ + gchar *authentication_uri, *token = (gchar*) "error", *token_secret = (gchar*) "error"; + GCancellable *cancellable; + GError *error = NULL; + + /* Set up the cancellable */ + cancellable = g_cancellable_new (); + + /* Get a request token. This should return immediately as the cancellable was cancelled beforehand. */ + g_cancellable_cancel (cancellable); + authentication_uri = gdata_oauth1_authorizer_request_authentication_uri (data->authorizer, &token, &token_secret, cancellable, &error); + g_assert_error (error, G_IO_ERROR, G_IO_ERROR_CANCELLED); + g_assert (authentication_uri == NULL); + g_assert (token == NULL); + g_assert (token_secret == NULL); + g_clear_error (&error); + + g_free (authentication_uri); + g_free (token); + g_free (token_secret); + + g_object_unref (cancellable); +} + +typedef struct { + OAuth1AuthorizerData parent; + GMainLoop *main_loop; +} OAuth1AuthorizerAsyncData; + +static void +set_up_oauth1_authorizer_async_data (OAuth1AuthorizerAsyncData *data, gconstpointer user_data) +{ + /* Chain up */ + set_up_oauth1_authorizer_data ((OAuth1AuthorizerData*) data, user_data); + + /* Set up the main loop */ + data->main_loop = g_main_loop_new (NULL, FALSE); +} + +static void +set_up_oauth1_authorizer_async_data_multiple_domains (OAuth1AuthorizerAsyncData *data, gconstpointer user_data) +{ + /* Chain up */ + set_up_oauth1_authorizer_data_multiple_domains ((OAuth1AuthorizerData*) data, user_data); + + /* Set up the main loop */ + data->main_loop = g_main_loop_new (NULL, FALSE); +} + +static void +tear_down_oauth1_authorizer_async_data (OAuth1AuthorizerAsyncData *data, gconstpointer user_data) +{ + g_main_loop_unref (data->main_loop); + + /* Chain up */ + tear_down_oauth1_authorizer_data ((OAuth1AuthorizerData*) data, user_data); +} + +static void +test_oauth1_authorizer_request_authentication_uri_async_cb (GDataOAuth1Authorizer *authorizer, GAsyncResult *async_result, + OAuth1AuthorizerAsyncData *data) +{ + gchar *authentication_uri, *token, *token_secret; + GError *error = NULL; + + authentication_uri = gdata_oauth1_authorizer_request_authentication_uri_finish (authorizer, async_result, &token, &token_secret, &error); + g_assert_no_error (error); + g_assert (authentication_uri != NULL && *authentication_uri != '\0'); + g_assert (token != NULL && *token != '\0'); + g_assert (token_secret != NULL && *token != '\0'); + g_clear_error (&error); + + g_test_message ("Requesting an authentication URI asynchronously gave “%s” with request token “%s” and request token secret “%s”.", + authentication_uri, token, token_secret); + + g_free (authentication_uri); + g_free (token); + g_free (token_secret); + + g_main_loop_quit (data->main_loop); +} + +/* Test that asynchronously requesting an authentication URI for a single authorization domain works */ +static void +test_oauth1_authorizer_request_authentication_uri_async (OAuth1AuthorizerAsyncData *data, gconstpointer user_data) +{ + /* Create a main loop and request an authentication URI */ + gdata_oauth1_authorizer_request_authentication_uri_async (data->parent.authorizer, NULL, + (GAsyncReadyCallback) test_oauth1_authorizer_request_authentication_uri_async_cb, + data); + + g_main_loop_run (data->main_loop); +} + +static void +test_oauth1_authorizer_request_authentication_uri_async_cancellation_cb (GDataOAuth1Authorizer *authorizer, GAsyncResult *async_result, + OAuth1AuthorizerAsyncData *data) +{ + /* Initialise token and token_secret so we check that gdata_oauth1_authorizer_request_authentication_uri_finish() NULLifies them on error */ + gchar *authentication_uri, *token = (gchar*) "error", *token_secret = (gchar*) "error"; + GError *error = NULL; + + authentication_uri = gdata_oauth1_authorizer_request_authentication_uri_finish (authorizer, async_result, &token, &token_secret, &error); + g_assert_error (error, G_IO_ERROR, G_IO_ERROR_CANCELLED); + g_assert (authentication_uri == NULL); + g_assert (token == NULL); + g_assert (token_secret == NULL); + g_clear_error (&error); + + g_free (authentication_uri); + g_free (token); + g_free (token_secret); + + g_main_loop_quit (data->main_loop); +} + +/* Test that cancellation of asynchronous authentication URI requests work */ +static void +test_oauth1_authorizer_request_authentication_uri_async_cancellation (OAuth1AuthorizerAsyncData *data, gconstpointer user_data) +{ + GCancellable *cancellable; + + /* Set up the cancellable */ + cancellable = g_cancellable_new (); + + /* Create a main loop and request an authentication URI */ + gdata_oauth1_authorizer_request_authentication_uri_async (data->parent.authorizer, cancellable, + (GAsyncReadyCallback) + test_oauth1_authorizer_request_authentication_uri_async_cancellation_cb, + data); + g_cancellable_cancel (cancellable); + + g_main_loop_run (data->main_loop); + + g_object_unref (cancellable); +} + +typedef struct { + OAuth1AuthorizerData parent; + gchar *token; + gchar *token_secret; + gchar *verifier; +} OAuth1AuthorizerInteractiveData; + +/* NOTE: Any consumer of this data has to check for (data->verifier == NULL) and skip the test in that case */ +static void +set_up_oauth1_authorizer_interactive_data (OAuth1AuthorizerInteractiveData *data, gconstpointer user_data) +{ + gchar *authentication_uri; + + /* Chain up */ + set_up_oauth1_authorizer_data ((OAuth1AuthorizerData*) data, user_data); + + /* Get an authentication URI */ + authentication_uri = gdata_oauth1_authorizer_request_authentication_uri (data->parent.authorizer, &(data->token), &(data->token_secret), + NULL, NULL); + g_assert (authentication_uri != NULL); + + /* Wait for the user to retrieve and enter the verifier */ + data->verifier = query_user_for_verifier (authentication_uri); + + g_free (authentication_uri); +} + +static void +set_up_oauth1_authorizer_interactive_data_bad_credentials (OAuth1AuthorizerInteractiveData *data, gconstpointer user_data) +{ + gchar *authentication_uri; + + /* Chain up */ + set_up_oauth1_authorizer_data ((OAuth1AuthorizerData*) data, user_data); + + /* Get an authentication URI */ + authentication_uri = gdata_oauth1_authorizer_request_authentication_uri (data->parent.authorizer, &(data->token), &(data->token_secret), + NULL, NULL); + g_assert (authentication_uri != NULL); + + /* Give a bogus verifier */ + data->verifier = g_strdup ("test"); + + g_free (authentication_uri); +} + +static void +tear_down_oauth1_authorizer_interactive_data (OAuth1AuthorizerInteractiveData *data, gconstpointer user_data) +{ + g_free (data->token); + g_free (data->token_secret); + g_free (data->verifier); + + /* Chain up */ + tear_down_oauth1_authorizer_data ((OAuth1AuthorizerData*) data, user_data); +} + +/* Test that synchronously authorizing a request token is successful. Note that this test has to be interactive, as the user has to visit the + * authentication URI to retrieve a verifier for the request token. */ +static void +test_oauth1_authorizer_request_authorization_sync (OAuth1AuthorizerInteractiveData *data, gconstpointer user_data) +{ + gboolean success; + GError *error = NULL; + + /* Skip the test if the user's requested */ + if (data->verifier == NULL) { + return; + } + + /* Check we're not authorised beforehand */ + g_assert (gdata_authorizer_is_authorized_for_domain (GDATA_AUTHORIZER (data->parent.authorizer), + gdata_contacts_service_get_primary_authorization_domain ()) == FALSE); + + /* Test that authorising the token retrieved previously is successful */ + success = gdata_oauth1_authorizer_request_authorization (data->parent.authorizer, data->token, data->token_secret, data->verifier, NULL, + &error); + g_assert_no_error (error); + g_assert (success == TRUE); + g_clear_error (&error); + + /* Are we authorised now? */ + g_assert (gdata_authorizer_is_authorized_for_domain (GDATA_AUTHORIZER (data->parent.authorizer), + gdata_contacts_service_get_primary_authorization_domain ()) == TRUE); +} + +/* Test that synchronously authorizing a request token fails if an invalid verifier is provided. */ +static void +test_oauth1_authorizer_request_authorization_sync_bad_credentials (OAuth1AuthorizerInteractiveData *data, gconstpointer user_data) +{ + gboolean success; + GError *error = NULL; + + /* Check we're not authorised beforehand */ + g_assert (gdata_authorizer_is_authorized_for_domain (GDATA_AUTHORIZER (data->parent.authorizer), + gdata_contacts_service_get_primary_authorization_domain ()) == FALSE); + + /* Test that authorising the token retrieved above fails */ + success = gdata_oauth1_authorizer_request_authorization (data->parent.authorizer, data->token, data->token_secret, data->verifier, NULL, + &error); + g_assert_error (error, GDATA_SERVICE_ERROR, GDATA_SERVICE_ERROR_FORBIDDEN); + g_assert (success == FALSE); + g_clear_error (&error); + + /* Are we authorised now? */ + g_assert (gdata_authorizer_is_authorized_for_domain (GDATA_AUTHORIZER (data->parent.authorizer), + gdata_contacts_service_get_primary_authorization_domain ()) == FALSE); +} + +/* Test that cancellation of synchronously authorizing a request token works. Note that this test has to be interactive, as the user has to visit the + * authentication URI to retrieve a verifier for the request token. */ +static void +test_oauth1_authorizer_request_authorization_sync_cancellation (OAuth1AuthorizerInteractiveData *data, gconstpointer user_data) +{ + gboolean success; + GCancellable *cancellable; + GError *error = NULL; + + /* Skip the test if the user's requested */ + if (data->verifier == NULL) { + return; + } + + /* Check we're not authorised beforehand */ + g_assert (gdata_authorizer_is_authorized_for_domain (GDATA_AUTHORIZER (data->parent.authorizer), + gdata_contacts_service_get_primary_authorization_domain ()) == FALSE); + + /* Create the cancellable */ + cancellable = g_cancellable_new (); + + /* Test that authorising the token retrieved above is successful */ + g_cancellable_cancel (cancellable); + success = gdata_oauth1_authorizer_request_authorization (data->parent.authorizer, data->token, data->token_secret, data->verifier, + cancellable, &error); + g_assert_error (error, G_IO_ERROR, G_IO_ERROR_CANCELLED); + g_assert (success == FALSE); + g_clear_error (&error); + + /* Are we authorised now? */ + g_assert (gdata_authorizer_is_authorized_for_domain (GDATA_AUTHORIZER (data->parent.authorizer), + gdata_contacts_service_get_primary_authorization_domain ()) == FALSE); + + g_object_unref (cancellable); +} + +typedef struct { + OAuth1AuthorizerInteractiveData parent; + GMainLoop *main_loop; +} OAuth1AuthorizerInteractiveAsyncData; + +/* NOTE: Any consumer of this data has to check for (data->verifier == NULL) and skip the test in that case */ +static void +set_up_oauth1_authorizer_interactive_async_data (OAuth1AuthorizerInteractiveAsyncData *data, gconstpointer user_data) +{ + /* Chain up */ + set_up_oauth1_authorizer_interactive_data ((OAuth1AuthorizerInteractiveData*) data, user_data); + + /* Set up the main loop */ + data->main_loop = g_main_loop_new (NULL, FALSE); +} + +static void +set_up_oauth1_authorizer_interactive_async_data_bad_credentials (OAuth1AuthorizerInteractiveAsyncData *data, gconstpointer user_data) +{ + /* Chain up */ + set_up_oauth1_authorizer_interactive_data_bad_credentials ((OAuth1AuthorizerInteractiveData*) data, user_data); + + /* Set up the main loop */ + data->main_loop = g_main_loop_new (NULL, FALSE); +} + +static void +tear_down_oauth1_authorizer_interactive_async_data (OAuth1AuthorizerInteractiveAsyncData *data, gconstpointer user_data) +{ + g_main_loop_unref (data->main_loop); + + /* Chain up */ + tear_down_oauth1_authorizer_interactive_data ((OAuth1AuthorizerInteractiveData*) data, user_data); +} + +static void +test_oauth1_authorizer_request_authorization_async_cb (GDataOAuth1Authorizer *authorizer, GAsyncResult *async_result, + OAuth1AuthorizerInteractiveAsyncData *data) +{ + gboolean success; + GError *error = NULL; + + success = gdata_oauth1_authorizer_request_authorization_finish (authorizer, async_result, &error); + g_assert_no_error (error); + g_assert (success == TRUE); + g_clear_error (&error); + + /* Are we authorised now? */ + g_assert (gdata_authorizer_is_authorized_for_domain (GDATA_AUTHORIZER (authorizer), + gdata_contacts_service_get_primary_authorization_domain ()) == TRUE); + + g_main_loop_quit (data->main_loop); +} + +/* Test that asynchronously authorizing a request token works. Note that this test has to be interactive, as the user has to visit the + * authentication URI to retrieve a verifier for the request token. */ +static void +test_oauth1_authorizer_request_authorization_async (OAuth1AuthorizerInteractiveAsyncData *data, gconstpointer user_data) +{ + /* Skip the test if the user's requested */ + if (data->parent.verifier == NULL) { + return; + } + + /* Check we're not authorised beforehand */ + g_assert (gdata_authorizer_is_authorized_for_domain (GDATA_AUTHORIZER (data->parent.parent.authorizer), + gdata_contacts_service_get_primary_authorization_domain ()) == FALSE); + + /* Create a main loop and request authorization */ + gdata_oauth1_authorizer_request_authorization_async (data->parent.parent.authorizer, data->parent.token, data->parent.token_secret, + data->parent.verifier, NULL, + (GAsyncReadyCallback) test_oauth1_authorizer_request_authorization_async_cb, data); + + g_main_loop_run (data->main_loop); +} + +static void +test_oauth1_authorizer_request_authorization_async_bad_credentials_cb (GDataOAuth1Authorizer *authorizer, GAsyncResult *async_result, + OAuth1AuthorizerInteractiveAsyncData *data) +{ + gboolean success; + GError *error = NULL; + + success = gdata_oauth1_authorizer_request_authorization_finish (authorizer, async_result, &error); + g_assert_error (error, GDATA_SERVICE_ERROR, GDATA_SERVICE_ERROR_FORBIDDEN); + g_assert (success == FALSE); + g_clear_error (&error); + + /* Are we authorised now? */ + g_assert (gdata_authorizer_is_authorized_for_domain (GDATA_AUTHORIZER (authorizer), + gdata_contacts_service_get_primary_authorization_domain ()) == FALSE); + + g_main_loop_quit (data->main_loop); +} + +/* Test that asynchronously authorizing a request token fails if an invalid verifier is provided. */ +static void +test_oauth1_authorizer_request_authorization_async_bad_credentials (OAuth1AuthorizerInteractiveAsyncData *data, gconstpointer user_data) +{ + /* Check we're not authorised beforehand */ + g_assert (gdata_authorizer_is_authorized_for_domain (GDATA_AUTHORIZER (data->parent.parent.authorizer), + gdata_contacts_service_get_primary_authorization_domain ()) == FALSE); + + /* Create a main loop and request authorization */ + gdata_oauth1_authorizer_request_authorization_async (data->parent.parent.authorizer, data->parent.token, data->parent.token_secret, + data->parent.verifier, NULL, + (GAsyncReadyCallback) + test_oauth1_authorizer_request_authorization_async_bad_credentials_cb, + data); + + g_main_loop_run (data->main_loop); +} + +static void +test_oauth1_authorizer_request_authorization_async_cancellation_cb (GDataOAuth1Authorizer *authorizer, GAsyncResult *async_result, + OAuth1AuthorizerInteractiveAsyncData *data) +{ + gboolean success; + GError *error = NULL; + + success = gdata_oauth1_authorizer_request_authorization_finish (authorizer, async_result, &error); + g_assert_error (error, G_IO_ERROR, G_IO_ERROR_CANCELLED); + g_assert (success == FALSE); + g_clear_error (&error); + + /* Are we authorised now? */ + g_assert (gdata_authorizer_is_authorized_for_domain (GDATA_AUTHORIZER (authorizer), + gdata_contacts_service_get_primary_authorization_domain ()) == FALSE); + + g_main_loop_quit (data->main_loop); +} + +/* Test that cancelling asynchronously authorizing a request token works. Note that this test has to be interactive, as the user has to visit the + * authentication URI to retrieve a verifier for the request token. */ +static void +test_oauth1_authorizer_request_authorization_async_cancellation (OAuth1AuthorizerInteractiveAsyncData *data, gconstpointer user_data) +{ + GCancellable *cancellable; + + /* Skip the test if the user's requested */ + if (data->parent.verifier == NULL) { + return; + } + + /* Check we're not authorised beforehand */ + g_assert (gdata_authorizer_is_authorized_for_domain (GDATA_AUTHORIZER (data->parent.parent.authorizer), + gdata_contacts_service_get_primary_authorization_domain ()) == FALSE); + + /* Create the cancellable */ + cancellable = g_cancellable_new (); + + /* Create a main loop and request authorization */ + gdata_oauth1_authorizer_request_authorization_async (data->parent.parent.authorizer, data->parent.token, data->parent.token_secret, + data->parent.verifier, cancellable, + (GAsyncReadyCallback) test_oauth1_authorizer_request_authorization_async_cancellation_cb, + data); + g_cancellable_cancel (cancellable); + + g_main_loop_run (data->main_loop); + + g_object_unref (cancellable); +} + +int +main (int argc, char *argv[]) +{ + gdata_test_init (argc, argv); + + main_thread = g_thread_self (); + + g_test_add_func ("/oauth1-authorizer/constructor", test_oauth1_authorizer_constructor); + g_test_add_func ("/oauth1-authorizer/constructor/for-domains", test_oauth1_authorizer_constructor_for_domains); + + g_test_add ("/oauth1-authorizer/properties/application-name", OAuth1AuthorizerData, NULL, set_up_oauth1_authorizer_data, + test_oauth1_authorizer_properties_application_name, tear_down_oauth1_authorizer_data); + g_test_add ("/oauth1-authorizer/properties/application-name/fallback", OAuth1AuthorizerData, NULL, + set_up_oauth1_authorizer_data_fallback_application_name, test_oauth1_authorizer_properties_application_name_fallback, + tear_down_oauth1_authorizer_data); + g_test_add ("/oauth1-authorizer/properties/locale", OAuth1AuthorizerData, NULL, set_up_oauth1_authorizer_data, + test_oauth1_authorizer_properties_locale, tear_down_oauth1_authorizer_data); + g_test_add ("/oauth1-authorizer/properties/proxy-uri", OAuth1AuthorizerData, NULL, set_up_oauth1_authorizer_data, + test_oauth1_authorizer_properties_proxy_uri, tear_down_oauth1_authorizer_data); + g_test_add ("/oauth1-authorizer/properties/timeout", OAuth1AuthorizerData, NULL, set_up_oauth1_authorizer_data, + test_oauth1_authorizer_properties_timeout, tear_down_oauth1_authorizer_data); + + g_test_add ("/oauth1-authorizer/refresh-authorization/unauthenticated", OAuth1AuthorizerData, NULL, + set_up_oauth1_authorizer_data, test_oauth1_authorizer_refresh_authorization, tear_down_oauth1_authorizer_data); + + g_test_add ("/oauth1-authorizer/process-request/null", OAuth1AuthorizerData, NULL, + set_up_oauth1_authorizer_data, test_oauth1_authorizer_process_request_null, tear_down_oauth1_authorizer_data); + g_test_add ("/oauth1-authorizer/process-request/unauthenticated", OAuth1AuthorizerData, NULL, + set_up_oauth1_authorizer_data, test_oauth1_authorizer_process_request_unauthenticated, tear_down_oauth1_authorizer_data); + + if (gdata_test_internet () == TRUE) { + /* Sync request-authentication-uri tests */ + g_test_add ("/oauth1-authorizer/request-authentication-uri/sync", OAuth1AuthorizerData, NULL, set_up_oauth1_authorizer_data, + test_oauth1_authorizer_request_authentication_uri_sync, tear_down_oauth1_authorizer_data); + g_test_add ("/oauth1-authorizer/request-authentication-uri/sync/multiple-domains", OAuth1AuthorizerData, NULL, + set_up_oauth1_authorizer_data_multiple_domains, test_oauth1_authorizer_request_authentication_uri_sync, + tear_down_oauth1_authorizer_data); + g_test_add ("/oauth1-authorizer/request-authentication-uri/sync/multiple-domains", OAuth1AuthorizerData, NULL, + set_up_oauth1_authorizer_data_locale, test_oauth1_authorizer_request_authentication_uri_sync, + tear_down_oauth1_authorizer_data); + g_test_add ("/oauth1-authorizer/request-authentication-uri/sync/cancellation", OAuth1AuthorizerData, NULL, + set_up_oauth1_authorizer_data, test_oauth1_authorizer_request_authentication_uri_sync_cancellation, + tear_down_oauth1_authorizer_data); + + /* Async request-authentication-uri tests */ + g_test_add ("/oauth1-authorizer/request-authentication-uri/async", OAuth1AuthorizerAsyncData, NULL, + set_up_oauth1_authorizer_async_data, test_oauth1_authorizer_request_authentication_uri_async, + tear_down_oauth1_authorizer_async_data); + g_test_add ("/oauth1-authorizer/request-authentication-uri/async/multiple-domains", OAuth1AuthorizerAsyncData, NULL, + set_up_oauth1_authorizer_async_data_multiple_domains, test_oauth1_authorizer_request_authentication_uri_async, + tear_down_oauth1_authorizer_async_data); + g_test_add ("/oauth1-authorizer/request-authentication-uri/async/cancellation", OAuth1AuthorizerAsyncData, NULL, + set_up_oauth1_authorizer_async_data, test_oauth1_authorizer_request_authentication_uri_async_cancellation, + tear_down_oauth1_authorizer_async_data); + + /* Sync request-authorization tests */ + if (gdata_test_interactive () == TRUE) { + g_test_add ("/oauth1-authorizer/request-authorization/sync", OAuth1AuthorizerInteractiveData, NULL, + set_up_oauth1_authorizer_interactive_data, test_oauth1_authorizer_request_authorization_sync, + tear_down_oauth1_authorizer_interactive_data); + g_test_add ("/oauth1-authorizer/request-authorization/sync/cancellation", OAuth1AuthorizerInteractiveData, NULL, + set_up_oauth1_authorizer_interactive_data, test_oauth1_authorizer_request_authorization_sync_cancellation, + tear_down_oauth1_authorizer_interactive_data); + } + + g_test_add ("/oauth1-authorizer/request-authorization/sync/bad-credentials", OAuth1AuthorizerInteractiveData, NULL, + set_up_oauth1_authorizer_interactive_data_bad_credentials, + test_oauth1_authorizer_request_authorization_sync_bad_credentials, tear_down_oauth1_authorizer_interactive_data); + + /* Async request-authorization tests */ + if (gdata_test_interactive () == TRUE) { + g_test_add ("/oauth1-authorizer/request-authorization/async", OAuth1AuthorizerInteractiveAsyncData, NULL, + set_up_oauth1_authorizer_interactive_async_data, test_oauth1_authorizer_request_authorization_async, + tear_down_oauth1_authorizer_interactive_async_data); + g_test_add ("/oauth1-authorizer/request-authorization/async/cancellation", OAuth1AuthorizerInteractiveAsyncData, NULL, + set_up_oauth1_authorizer_interactive_async_data, test_oauth1_authorizer_request_authorization_async_cancellation, + tear_down_oauth1_authorizer_interactive_async_data); + } + + g_test_add ("/oauth1-authorizer/request-authorization/async/bad-credentials", OAuth1AuthorizerInteractiveAsyncData, NULL, + set_up_oauth1_authorizer_interactive_async_data_bad_credentials, + test_oauth1_authorizer_request_authorization_async_bad_credentials, tear_down_oauth1_authorizer_interactive_async_data); + + /* Miscellaneous tests */ + if (gdata_test_interactive () == TRUE) { + gboolean skip_test = FALSE; + + g_test_add ("/oauth1-authorizer/refresh-authorization/authenticated", OAuth1AuthorizerData, &skip_test, + set_up_oauth1_authorizer_data_authenticated, test_oauth1_authorizer_refresh_authorization, + tear_down_oauth1_authorizer_data); + + g_test_add ("/oauth1-authorizer/process-request/authenticated", OAuth1AuthorizerData, &skip_test, + set_up_oauth1_authorizer_data_authenticated, test_oauth1_authorizer_process_request_authenticated, + tear_down_oauth1_authorizer_data); + } + } + + return g_test_run (); +} |