summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJonathon Jongsma <jonathon@quotidian.org>2010-05-07 17:15:20 -0500
committerRob Bradford <rob@linux.intel.com>2010-06-17 17:35:02 +0100
commit1305915bb6a6af6ef661d6076f3f11c25bf5b5cc (patch)
treedb008e9a6f5c8a893c0fdcac15b2de6949234942
parent09b651e4da616a83476a6b9f853940fa91938ad1 (diff)
Add a oauth2 proxylibrest-0.6.4
This new class provides a proxy class for oauth2-based web services, such as the new facebook graph API. The basic idea is as follows: - Construct a OAuth2Proxy object - Build a login url with _build_login_url(_full)() - Display said url in a browser widget (e.g. webkit) and listen for redirects to the specified 'redirect_uri' - Extract the access token from the uri that you are redirected to - Set the access token for the proxy with _set_access_token() http://bugs.meego.com/show_bug.cgi?id=2265
-rw-r--r--.gitignore1
-rw-r--r--rest/Makefile.am5
-rw-r--r--rest/oauth2-proxy-call.c69
-rw-r--r--rest/oauth2-proxy-call.h68
-rw-r--r--rest/oauth2-proxy-private.h34
-rw-r--r--rest/oauth2-proxy.c399
-rw-r--r--rest/oauth2-proxy.h95
-rw-r--r--tests/Makefile.am6
-rw-r--r--tests/oauth2.c56
9 files changed, 729 insertions, 4 deletions
diff --git a/.gitignore b/.gitignore
index fc48217..ffd8046 100644
--- a/.gitignore
+++ b/.gitignore
@@ -52,6 +52,7 @@ rest-extras/RestExtras-0.6.typelib
rest-extras/test-runner
tests/oauth
tests/oauth-async
+tests/oauth2
tests/proxy
tests/flickr
tests/threaded
diff --git a/rest/Makefile.am b/rest/Makefile.am
index c7bfc27..a5bbf0e 100644
--- a/rest/Makefile.am
+++ b/rest/Makefile.am
@@ -12,12 +12,17 @@ lib_sources = \
oauth-proxy.c \
oauth-proxy-call.c \
oauth-proxy-private.h \
+ oauth2-proxy.c \
+ oauth2-proxy-call.c \
+ oauth2-proxy-private.h \
sha1.c \
sha1.h
lib_headers = rest-proxy.h \
rest-proxy-call.h \
oauth-proxy.h \
oauth-proxy-call.h \
+ oauth2-proxy.h \
+ oauth2-proxy-call.h \
rest-xml-parser.h
lib_LTLIBRARIES = librest-@API_VERSION@.la
diff --git a/rest/oauth2-proxy-call.c b/rest/oauth2-proxy-call.c
new file mode 100644
index 0000000..f0d441c
--- /dev/null
+++ b/rest/oauth2-proxy-call.c
@@ -0,0 +1,69 @@
+/*
+ * librest - RESTful web services access
+ * Copyright (c) 2008, 2009, Intel Corporation.
+ *
+ * Authors: Rob Bradford <rob@linux.intel.com>
+ * Ross Burton <ross@linux.intel.com>
+ * Jonathon Jongsma <jonathon.jongsma@collabora.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU Lesser General Public License,
+ * version 2.1, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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 this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#include <string.h>
+#include <libsoup/soup.h>
+#include <rest/rest-proxy-call.h>
+#include "oauth2-proxy-call.h"
+#include "oauth2-proxy-private.h"
+#include "rest-proxy-call-private.h"
+#include "sha1.h"
+
+G_DEFINE_TYPE (OAuth2ProxyCall, oauth2_proxy_call, REST_TYPE_PROXY_CALL)
+
+static gboolean
+_prepare (RestProxyCall *call, GError **error)
+{
+ OAuth2Proxy *proxy = NULL;
+ gboolean result = TRUE;
+
+ g_object_get (call, "proxy", &proxy, NULL);
+
+ if (!proxy->priv->access_token) {
+ g_set_error (error,
+ REST_PROXY_CALL_ERROR,
+ REST_PROXY_CALL_FAILED,
+ "Missing access token, web service not properly authenticated");
+ result = FALSE;
+ } else {
+ rest_proxy_call_add_param (call, "access_token", proxy->priv->access_token);
+ }
+
+ g_object_unref (proxy);
+
+ return result;
+}
+
+static void
+oauth2_proxy_call_class_init (OAuth2ProxyCallClass *klass)
+{
+ RestProxyCallClass *call_class = REST_PROXY_CALL_CLASS (klass);
+
+ call_class->prepare = _prepare;
+}
+
+static void
+oauth2_proxy_call_init (OAuth2ProxyCall *self)
+{
+}
+
diff --git a/rest/oauth2-proxy-call.h b/rest/oauth2-proxy-call.h
new file mode 100644
index 0000000..ebe78a1
--- /dev/null
+++ b/rest/oauth2-proxy-call.h
@@ -0,0 +1,68 @@
+/*
+ * librest - RESTful web services access
+ * Copyright (c) 2008, 2009, Intel Corporation.
+ *
+ * Authors: Rob Bradford <rob@linux.intel.com>
+ * Ross Burton <ross@linux.intel.com>
+ * Jonathon Jongsma <jonathon.jongsma@collabora.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU Lesser General Public License,
+ * version 2.1, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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 this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#ifndef _OAUTH2_PROXY_CALL
+#define _OAUTH2_PROXY_CALL
+
+#include <rest/rest-proxy-call.h>
+
+G_BEGIN_DECLS
+
+#define OAUTH2_TYPE_PROXY_CALL oauth2_proxy_call_get_type()
+
+#define OAUTH2_PROXY_CALL(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST ((obj), OAUTH2_TYPE_PROXY_CALL, OAuth2ProxyCall))
+
+#define OAUTH2_PROXY_CALL_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST ((klass), OAUTH2_TYPE_PROXY_CALL, OAuth2ProxyCallClass))
+
+#define OAUTH2_IS_PROXY_CALL(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE ((obj), OAUTH2_TYPE_PROXY_CALL))
+
+#define OAUTH2_IS_PROXY_CALL_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE ((klass), OAUTH2_TYPE_PROXY_CALL))
+
+#define OAUTH2_PROXY_CALL_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS ((obj), OAUTH2_TYPE_PROXY_CALL, OAuth2ProxyCallClass))
+
+/**
+ * OAuth2ProxyCall:
+ *
+ * #OAuth2ProxyCall has no publicly available members.
+ */
+typedef struct {
+ RestProxyCall parent;
+} OAuth2ProxyCall;
+
+typedef struct {
+ RestProxyCallClass parent_class;
+ /*< private >*/
+ /* padding for future expansion */
+ gpointer _padding_dummy[8];
+} OAuth2ProxyCallClass;
+
+GType oauth2_proxy_call_get_type (void);
+
+G_END_DECLS
+
+#endif /* _OAUTH2_PROXY_CALL */
diff --git a/rest/oauth2-proxy-private.h b/rest/oauth2-proxy-private.h
new file mode 100644
index 0000000..565c1c3
--- /dev/null
+++ b/rest/oauth2-proxy-private.h
@@ -0,0 +1,34 @@
+/*
+ * librest - RESTful web services access
+ * Copyright (c) 2008, 2009, 2010 Intel Corporation.
+ *
+ * Authors: Rob Bradford <rob@linux.intel.com>
+ * Ross Burton <ross@linux.intel.com>
+ * Jonathon Jongsma <jonathon.jongsma@collabora.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU Lesser General Public License,
+ * version 2.1, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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 this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+#ifndef _OAUTH2_PROXY_PRIVATE
+#define _OAUTH2_PROXY_PRIVATE
+
+#include "oauth2-proxy.h"
+
+struct _OAuth2ProxyPrivate {
+ char *client_id;
+ char *auth_endpoint;
+ char *access_token;
+};
+
+#endif /* _OAUTH2_PROXY_PRIVATE */
diff --git a/rest/oauth2-proxy.c b/rest/oauth2-proxy.c
new file mode 100644
index 0000000..1a15bb6
--- /dev/null
+++ b/rest/oauth2-proxy.c
@@ -0,0 +1,399 @@
+/*
+ * librest - RESTful web services access
+ * Copyright (c) 2008, 2009, 2010 Intel Corporation.
+ *
+ * Authors: Rob Bradford <rob@linux.intel.com>
+ * Ross Burton <ross@linux.intel.com>
+ * Jonathon Jongsma <jonathon.jongsma@collabora.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU Lesser General Public License,
+ * version 2.1, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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 this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#include <rest/rest-proxy.h>
+#include <libsoup/soup.h>
+#include "oauth2-proxy.h"
+#include "oauth2-proxy-private.h"
+#include "oauth2-proxy-call.h"
+
+G_DEFINE_TYPE (OAuth2Proxy, oauth2_proxy, REST_TYPE_PROXY)
+
+#define OAUTH2_PROXY_GET_PRIVATE(o) \
+ (G_TYPE_INSTANCE_GET_PRIVATE ((o), OAUTH2_TYPE_PROXY, OAuth2ProxyPrivate))
+
+GQuark
+oauth2_proxy_error_quark (void)
+{
+ return g_quark_from_static_string ("rest-oauth2-proxy");
+}
+
+#define EXTRA_CHARS_ENCODE "!$&'()*+,;=@"
+
+enum {
+ PROP_0,
+ PROP_CLIENT_ID,
+ PROP_AUTH_ENDPOINT,
+ PROP_ACCESS_TOKEN
+};
+
+static RestProxyCall *
+_new_call (RestProxy *proxy)
+{
+ RestProxyCall *call;
+
+ call = g_object_new (OAUTH2_TYPE_PROXY_CALL,
+ "proxy", proxy,
+ NULL);
+
+ return call;
+}
+
+static void
+oauth2_proxy_get_property (GObject *object, guint property_id,
+ GValue *value, GParamSpec *pspec)
+{
+ OAuth2ProxyPrivate *priv = ((OAuth2Proxy*)object)->priv;
+
+ switch (property_id) {
+ case PROP_CLIENT_ID:
+ g_value_set_string (value, priv->client_id);
+ break;
+ case PROP_AUTH_ENDPOINT:
+ g_value_set_string (value, priv->auth_endpoint);
+ break;
+ case PROP_ACCESS_TOKEN:
+ g_value_set_string (value, priv->access_token);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ }
+}
+
+static void
+oauth2_proxy_set_property (GObject *object, guint property_id,
+ const GValue *value, GParamSpec *pspec)
+{
+ OAuth2ProxyPrivate *priv = ((OAuth2Proxy*)object)->priv;
+
+ switch (property_id) {
+ case PROP_CLIENT_ID:
+ if (priv->client_id)
+ g_free (priv->client_id);
+ priv->client_id = g_value_dup_string (value);
+ break;
+ case PROP_AUTH_ENDPOINT:
+ if (priv->auth_endpoint)
+ g_free (priv->auth_endpoint);
+ priv->auth_endpoint = g_value_dup_string (value);
+ break;
+ case PROP_ACCESS_TOKEN:
+ if (priv->access_token)
+ g_free (priv->access_token);
+ priv->access_token = g_value_dup_string (value);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ }
+}
+
+static void
+oauth2_proxy_finalize (GObject *object)
+{
+ OAuth2ProxyPrivate *priv = ((OAuth2Proxy*)object)->priv;
+
+ g_free (priv->client_id);
+ g_free (priv->auth_endpoint);
+ g_free (priv->access_token);
+
+ G_OBJECT_CLASS (oauth2_proxy_parent_class)->finalize (object);
+}
+
+static void
+oauth2_proxy_class_init (OAuth2ProxyClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ RestProxyClass *proxy_class = REST_PROXY_CLASS (klass);
+ GParamSpec *pspec;
+
+ g_type_class_add_private (klass, sizeof (OAuth2ProxyPrivate));
+
+ object_class->get_property = oauth2_proxy_get_property;
+ object_class->set_property = oauth2_proxy_set_property;
+ object_class->finalize = oauth2_proxy_finalize;
+
+ proxy_class->new_call = _new_call;
+
+ pspec = g_param_spec_string ("client-id", "client-id",
+ "The client (application) id", NULL,
+ G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY|G_PARAM_STATIC_STRINGS);
+ g_object_class_install_property (object_class,
+ PROP_CLIENT_ID,
+ pspec);
+
+ pspec = g_param_spec_string ("auth-endpoint", "auth-endpoint",
+ "The authentication endpoint url", NULL,
+ G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY|G_PARAM_STATIC_STRINGS);
+ g_object_class_install_property (object_class,
+ PROP_AUTH_ENDPOINT,
+ pspec);
+
+ pspec = g_param_spec_string ("access-token", "access-token",
+ "The request or access token", NULL,
+ G_PARAM_READWRITE|G_PARAM_STATIC_STRINGS);
+ g_object_class_install_property (object_class,
+ PROP_ACCESS_TOKEN,
+ pspec);
+}
+
+static void
+oauth2_proxy_init (OAuth2Proxy *proxy)
+{
+ proxy->priv = OAUTH2_PROXY_GET_PRIVATE (proxy);
+}
+
+/**
+ * oauth2_proxy_new:
+ * @client_id: the client (application) id
+ * @auth_endpoint: the authentication endpoint URL
+ * @url_format: the endpoint URL
+ * @binding_required: whether the URL needs to be bound before calling
+ *
+ * Create a new #OAuth2Proxy for the specified endpoint @url_format, using the
+ * specified API key and secret.
+ *
+ * This proxy won't have the Token set so will be unauthorised. If the token is
+ * unknown then the following steps should be taken to acquire an access token:
+ * - Get the authentication url with oauth2_proxy_build_login_url()
+ * - Display this url in an embedded browser widget
+ * - wait for the browser widget to be redirected to the specified redirect_uri
+ * - extract the token from the fragment of the redirected uri (using
+ * convenience function oauth2_proxy_extract_access_token())
+ * - set the token with oauth2_proxy_set_access_token()
+ *
+ * Set @binding_required to %TRUE if the URL contains string formatting
+ * operations (for example "http://foo.com/%<!-- -->s". These must be expanded
+ * using rest_proxy_bind() before invoking the proxy.
+ *
+ * Returns: A new #OAuth2Proxy.
+ */
+RestProxy *
+oauth2_proxy_new (const char *client_id,
+ const char *auth_endpoint,
+ const gchar *url_format,
+ gboolean binding_required)
+{
+ return g_object_new (OAUTH2_TYPE_PROXY,
+ "client-id", client_id,
+ "auth-endpoint", auth_endpoint,
+ "url-format", url_format,
+ "binding-required", binding_required,
+ NULL);
+}
+
+/**
+ * oauth2_proxy_new_with_token:
+ * @client_id: the client (application) id
+ * @access_token: the Access Token
+ * @auth_endpoint: the authentication endpoint URL
+ * @url_format: the endpoint URL
+ * @binding_required: whether the URL needs to be bound before calling
+ *
+ * Create a new #OAuth2Proxy for the specified endpoint @url_format, using the
+ * specified client id
+ *
+ * @access_token is used for the Access Token, so if they are still valid then
+ * this proxy is authorised.
+ *
+ * Set @binding_required to %TRUE if the URL contains string formatting
+ * operations (for example "http://foo.com/%<!-- -->s". These must be expanded
+ * using rest_proxy_bind() before invoking the proxy.
+ *
+ * Returns: A new #OAuth2Proxy.
+ */
+RestProxy *
+oauth2_proxy_new_with_token (const char *client_id,
+ const char *access_token,
+ const char *auth_endpoint,
+ const gchar *url_format,
+ gboolean binding_required)
+{
+ return g_object_new (OAUTH2_TYPE_PROXY,
+ "client-id", client_id,
+ "access-token", access_token,
+ "auth-endpoint", auth_endpoint,
+ "url-format", url_format,
+ "binding-required", binding_required,
+ NULL);
+}
+
+/* allocates a new string of the form "key=value" */
+static void
+append_query_param (gpointer key, gpointer value, gpointer user_data)
+{
+ GString *params = (GString*) user_data;
+ char *encoded_val, *encoded_key;
+ char *param;
+
+ encoded_val = soup_uri_encode (value, EXTRA_CHARS_ENCODE);
+ encoded_key = soup_uri_encode (key, EXTRA_CHARS_ENCODE);
+
+ param = g_strdup_printf ("%s=%s", encoded_key, encoded_val);
+ g_free (encoded_key);
+ g_free (encoded_val);
+
+ // if there's already a parameter in the string, we need to add a '&'
+ // separator before adding the new param
+ if (params->len)
+ g_string_append_c (params, '&');
+ g_string_append (params, param);
+}
+
+/**
+ * oauth2_proxy_build_login_url_full:
+ * @proxy: a OAuth2Proxy object
+ * @redirect_uri: the uri to redirect to after the user authenticates
+ * @extra_params: any extra parameters to add to the login url (e.g. facebook
+ * uses 'scope=foo,bar' to request extended permissions).
+ *
+ * Builds a url at which the user can log in to the specified OAuth2-based web
+ * service. In general, this url should be displayed in an embedded browser
+ * widget, and you should then intercept the browser's redirect to @redirect_uri
+ * and extract the access token from the url fragment. After the access token
+ * has been retrieved, call oauth2_proxy_set_access_token(). This must be done
+ * before making any API calls to the service.
+ *
+ * See the oauth2 spec for more details about the "user-agent" authentication
+ * flow.
+ *
+ * The @extra_params and @redirect_uri should not be uri-encoded, that will be
+ * done automatically
+ *
+ * Returns: a newly allocated uri string
+ */
+char *
+oauth2_proxy_build_login_url_full (OAuth2Proxy *proxy,
+ const char* redirect_uri,
+ GHashTable* extra_params)
+{
+ char *url;
+ GString *params = 0;
+ char *encoded_uri, *encoded_id;
+
+ g_return_val_if_fail (proxy, NULL);
+ g_return_val_if_fail (redirect_uri, NULL);
+
+ if (extra_params && g_hash_table_size (extra_params) > 0) {
+ params = g_string_new (NULL);
+ g_hash_table_foreach (extra_params, append_query_param, params);
+ }
+
+ encoded_uri = soup_uri_encode (redirect_uri, EXTRA_CHARS_ENCODE);
+ encoded_id = soup_uri_encode (proxy->priv->client_id, EXTRA_CHARS_ENCODE);
+
+ url = g_strdup_printf ("%s?client_id=%s&redirect_uri=%s&type=user_agent",
+ proxy->priv->auth_endpoint, encoded_id,
+ encoded_uri);
+
+ g_free (encoded_uri);
+ g_free (encoded_id);
+
+ if (params) {
+ char * full_url = g_strdup_printf ("%s&%s", url, params->str);
+ g_free (url);
+ url = full_url;
+ g_string_free (params, TRUE);
+ }
+
+ return url;
+}
+
+/**
+ * oauth2_proxy_build_login_url:
+ * @proxy: an OAuth2Proxy object
+ * @redirect_uri: the uri to redirect to after the user authenticates
+ *
+ * Builds a url at which the user can log in to the specified OAuth2-based web
+ * service. See the documentation for oauth2_proxy_build_login_url_full() for
+ * detailed information.
+ *
+ * Returns: a newly allocated uri string
+ */
+char *
+oauth2_proxy_build_login_url (OAuth2Proxy *proxy,
+ const char* redirect_uri)
+{
+ return oauth2_proxy_build_login_url_full (proxy, redirect_uri, NULL);
+}
+
+/**
+ * oauth2_proxy_get_access_token:
+ * @proxy: an #OAuth2Proxy
+ *
+ * Get the current request or access token.
+ *
+ * Returns: the token, or %NULL if there is no token yet. This string is owned
+ * by #OAuth2Proxy and should not be freed.
+ */
+const char *
+oauth2_proxy_get_access_token (OAuth2Proxy *proxy)
+{
+ return proxy->priv->access_token;
+}
+
+/**
+ * oauth2_proxy_set_access_token:
+ * @proxy: an #OAuth2Proxy
+ * @token: the access token
+ *
+ * Set the access token.
+ */
+void
+oauth2_proxy_set_access_token (OAuth2Proxy *proxy, const char *access_token)
+{
+ g_return_if_fail (OAUTH2_IS_PROXY (proxy));
+
+ if (proxy->priv->access_token)
+ g_free (proxy->priv->access_token);
+
+ proxy->priv->access_token = g_strdup (access_token);
+}
+
+/**
+ * oauth2_proxy_extract_access_token:
+ * @url: the url which contains an access token in its fragment
+ *
+ * A utility function to extract the access token from the url that results from
+ * the redirection after the user authenticates
+ */
+char *
+oauth2_proxy_extract_access_token (const char *url)
+{
+ GHashTable *params;
+ char *token = NULL;
+ SoupURI *soupuri = soup_uri_new (url);
+
+ if (soupuri->fragment != NULL) {
+ params = soup_form_decode (soupuri->fragment);
+
+ if (params) {
+ char *encoded = g_hash_table_lookup (params, "access_token");
+ if (encoded)
+ token = soup_uri_decode (encoded);
+
+ g_hash_table_destroy (params);
+ }
+ }
+
+ return token;
+}
diff --git a/rest/oauth2-proxy.h b/rest/oauth2-proxy.h
new file mode 100644
index 0000000..0473c62
--- /dev/null
+++ b/rest/oauth2-proxy.h
@@ -0,0 +1,95 @@
+/*
+ * librest - RESTful web services access
+ * Copyright (c) 2008, 2009, 2010 Intel Corporation.
+ *
+ * Authors: Rob Bradford <rob@linux.intel.com>
+ * Ross Burton <ross@linux.intel.com>
+ * Jonathon Jongsma <jonathon.jongsma@collabora.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU Lesser General Public License,
+ * version 2.1, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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 this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#ifndef _OAUTH2_PROXY
+#define _OAUTH2_PROXY
+
+#include <rest/rest-proxy.h>
+
+G_BEGIN_DECLS
+
+#define OAUTH2_TYPE_PROXY oauth2_proxy_get_type()
+
+#define OAUTH2_PROXY(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST ((obj), OAUTH2_TYPE_PROXY, OAuth2Proxy))
+
+#define OAUTH2_PROXY_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST ((klass), OAUTH2_TYPE_PROXY, OAuth2ProxyClass))
+
+#define OAUTH2_IS_PROXY(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE ((obj), OAUTH2_TYPE_PROXY))
+
+#define OAUTH2_IS_PROXY_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE ((klass), OAUTH2_TYPE_PROXY))
+
+#define OAUTH2_PROXY_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS ((obj), OAUTH2_TYPE_PROXY, OAuth2ProxyClass))
+
+typedef struct _OAuth2ProxyPrivate OAuth2ProxyPrivate;
+
+/**
+ * OAuth2Proxy:
+ *
+ * #OAuth2Proxy has no publicly available members.
+ */
+typedef struct {
+ RestProxy parent;
+ OAuth2ProxyPrivate *priv;
+} OAuth2Proxy;
+
+typedef struct {
+ RestProxyClass parent_class;
+ /*< private >*/
+ /* padding for future expansion */
+ gpointer _padding_dummy[8];
+} OAuth2ProxyClass;
+
+GType oauth2_proxy_get_type (void);
+
+RestProxy* oauth2_proxy_new (const char *client_id,
+ const char *auth_endpoint,
+ const gchar *url_format,
+ gboolean binding_required);
+
+RestProxy* oauth2_proxy_new_with_token (const char *client_id,
+ const char *access_token,
+ const char *auth_endpoint,
+ const gchar *url_format,
+ gboolean binding_required);
+
+char * oauth2_proxy_build_login_url_full (OAuth2Proxy *proxy,
+ const char* redirect_uri,
+ GHashTable* extra_params);
+
+char * oauth2_proxy_build_login_url (OAuth2Proxy *proxy,
+ const char* redirect_uri);
+
+const char * oauth2_proxy_get_access_token (OAuth2Proxy *proxy);
+
+void oauth2_proxy_set_access_token (OAuth2Proxy *proxy, const char *access_token);
+
+char * oauth2_proxy_extract_access_token (const char *url);
+
+G_END_DECLS
+
+#endif /* _OAUTH2_PROXY */
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 0a112f3..fe265e6 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -1,7 +1,4 @@
-TESTS = proxy threaded oauth oauth-async flickr
-# TODO: oauth-async is failing due to infinite looping for some reason. Need to
-# fix this.
-XFAIL_TESTS = oauth-async
+TESTS = proxy threaded oauth oauth-async oauth2 flickr
AM_CPPFLAGS = $(SOUP_CFLAGS) -I$(top_srcdir)
AM_LDFLAGS = $(SOUP_LIBS) ../rest/librest-@API_VERSION@.la ../rest-extras/librest-extras-@API_VERSION@.la
@@ -12,4 +9,5 @@ proxy_SOURCES = proxy.c
threaded_SOURCES = threaded.c
oauth_SOURCES = oauth.c
oauth_async_SOURCES = oauth-async.c
+oauth2_SOURCES = oauth2.c
flickr_SOURCES = flickr.c
diff --git a/tests/oauth2.c b/tests/oauth2.c
new file mode 100644
index 0000000..e992b6a
--- /dev/null
+++ b/tests/oauth2.c
@@ -0,0 +1,56 @@
+/*
+ * librest - RESTful web services access
+ * Copyright (c) 2010 Intel Corporation.
+ *
+ * Authors: Jonathon Jongsma <jonathon.jongsma@collabora.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU Lesser General Public License,
+ * version 2.1, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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 this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#include <rest/oauth2-proxy.h>
+#include <string.h>
+
+void
+test_extract_token ()
+{
+ char *token;
+
+ /* test a url without a fragment */
+ token = oauth2_proxy_extract_access_token ("http://example.com/");
+ g_assert (token == NULL);
+
+ /* test a url with a fragment but without an access_token parameter */
+ token = oauth2_proxy_extract_access_token ("http://example.com/foo?foo=1#bar");
+ g_assert (token == NULL);
+
+ /* test simple access_token */
+ token = oauth2_proxy_extract_access_token ("http://example.com/foo?foo=1#access_token=1234567890_12.34561abcdefg&bar");
+ g_assert (strcmp(token, "1234567890_12.34561abcdefg") == 0);
+
+ /* test access_token with url encoding */
+ token = oauth2_proxy_extract_access_token ("http://example.com/foo?foo=1#access_token=1234567890%5F12%2E34561abcdefg&bar");
+ g_assert (strcmp(token, "1234567890_12.34561abcdefg") == 0);
+}
+
+int
+main (int argc, char **argv)
+{
+ g_thread_init (NULL);
+ g_type_init ();
+
+ test_extract_token ();
+
+ return 0;
+}