diff options
author | Philip Withnall <philip.withnall@collabora.co.uk> | 2015-06-14 15:51:48 +0100 |
---|---|---|
committer | Philip Withnall <philip.withnall@collabora.co.uk> | 2015-06-16 17:22:03 +0100 |
commit | b80f8883dd7c15a62ae9756f34c8f3155d557a32 (patch) | |
tree | 311ccc37280566e1a225338ed5689da2e3ea8cb7 /gdata/gdata-oauth2-authorizer.c | |
parent | 0080aee2b88cd5ff24624c8c41d998e0bd5e9356 (diff) | |
download | libgdata-b80f8883dd7c15a62ae9756f34c8f3155d557a32.tar.gz |
core: Add GDataOAuth2Authorizer:refresh-token API
Add new API to allow the refresh token from an OAuth 2 authorizer to be
stored by an application and restored into a new GDataOAuth2Authorizer
instance (a cold start). This adds the following new API:
• GDataOAuth2Authorizer:refresh-token
• gdata_oauth2_authorizer_dup_refresh_token()
• gdata_oauth2_authorizer_set_refresh_token()
It does not add any new tests.
https://bugzilla.gnome.org/show_bug.cgi?id=750746
Diffstat (limited to 'gdata/gdata-oauth2-authorizer.c')
-rw-r--r-- | gdata/gdata-oauth2-authorizer.c | 119 |
1 files changed, 115 insertions, 4 deletions
diff --git a/gdata/gdata-oauth2-authorizer.c b/gdata/gdata-oauth2-authorizer.c index 994c1155..40628175 100644 --- a/gdata/gdata-oauth2-authorizer.c +++ b/gdata/gdata-oauth2-authorizer.c @@ -1,7 +1,7 @@ /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ /* * GData Client - * Copyright (C) Philip Withnall 2011, 2014 <philip@tecnocode.co.uk> + * Copyright (C) Philip Withnall 2011, 2014, 2015 <philip@tecnocode.co.uk> * * GData Client is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -49,6 +49,13 @@ * token can be used in future (with gdata_authorizer_refresh_authorization()) * to refresh authorization after the access token expires. * + * The refresh token may also be accessed as + * #GDataOAuth2Authorizer:refresh-token and saved by the application. It may + * later be set on a new instance of #GDataOAuth2Authorizer, and + * gdata_authorizer_refresh_authorization_async() called to establish a new + * access token without requiring the user to re-authenticate unless they have + * explicitly revoked the refresh token. + * * For an overview of the standard OAuth 2.0 flow, see * <ulink type="http" url="http://tools.ietf.org/html/rfc6749#section-1.2">RFC 6749</ulink>. * @@ -183,7 +190,9 @@ struct _GDataOAuth2AuthorizerPrivate { /* Mutex for access_token, refresh_token and authentication_domains. */ GMutex mutex; - /* These are both non-NULL when authorised, and both NULL otherwise. */ + /* These are both non-NULL when authorised. refresh_token may be + * non-NULL if access_token is NULL and refresh_authorization() has not + * yet been called on this authorizer. They may be both NULL. */ gchar *access_token; /* owned */ gchar *refresh_token; /* owned */ @@ -199,6 +208,7 @@ enum { PROP_LOCALE, PROP_TIMEOUT, PROP_PROXY_RESOLVER, + PROP_REFRESH_TOKEN, }; G_DEFINE_TYPE_WITH_CODE (GDataOAuth2Authorizer, gdata_oauth2_authorizer, @@ -354,6 +364,25 @@ gdata_oauth2_authorizer_class_init (GDataOAuth2AuthorizerClass *klass) "A GProxyResolver used to determine a proxy URI.", G_TYPE_PROXY_RESOLVER, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + /** + * GDataOAuth2Authorizer:refresh-token: + * + * The server provided refresh token, which can be stored and passed in + * to new #GDataOAuth2Authorizer instances before calling + * gdata_authorizer_refresh_authorization_async() to create a new + * short-lived access token. + * + * The refresh token is opaque data and must not be parsed. + * + * Since: UNRELEASED + */ + g_object_class_install_property (gobject_class, PROP_REFRESH_TOKEN, + g_param_spec_string ("refresh-token", + "Refresh Token", + "The server provided refresh token.", + NULL, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); } static void @@ -464,6 +493,11 @@ get_property (GObject *object, guint property_id, GValue *value, g_value_set_object (value, gdata_oauth2_authorizer_get_proxy_resolver (self)); break; + case PROP_REFRESH_TOKEN: + g_mutex_lock (&priv->mutex); + g_value_set_string (value, priv->refresh_token); + g_mutex_unlock (&priv->mutex); + break; default: /* We don't have any other property... */ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); @@ -505,6 +539,10 @@ set_property (GObject *object, guint property_id, const GValue *value, GParamSpe gdata_oauth2_authorizer_set_proxy_resolver (self, g_value_get_object (value)); break; + case PROP_REFRESH_TOKEN: + gdata_oauth2_authorizer_set_refresh_token (self, + g_value_get_string (value)); + break; default: /* We don't have any other property... */ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); @@ -524,8 +562,8 @@ process_request (GDataAuthorizer *self, GDataAuthorizationDomain *domain, g_mutex_lock (&priv->mutex); /* Sanity check */ - g_assert ((priv->access_token == NULL) == - (priv->refresh_token == NULL)); + g_assert ((priv->access_token == NULL) || + (priv->refresh_token != NULL)); if (priv->access_token != NULL && g_hash_table_lookup (priv->authentication_domains, @@ -1343,6 +1381,79 @@ gdata_oauth2_authorizer_get_client_secret (GDataOAuth2Authorizer *self) } /** + * gdata_oauth2_authorizer_dup_refresh_token: + * @self: a #GDataOAuth2Authorizer + * + * Returns the authorizer's refresh token, #GDataOAuth2Authorizer:refresh-token, + * as set by client code previously on the #GDataOAuth2Authorizer, or as + * returned by the most recent authentication operation. + * + * Return value: (transfer full): the authorizer's refresh token + * + * Since: UNRELEASED + */ +gchar * +gdata_oauth2_authorizer_dup_refresh_token (GDataOAuth2Authorizer *self) +{ + GDataOAuth2AuthorizerPrivate *priv; + gchar *refresh_token; /* owned */ + + g_return_val_if_fail (GDATA_IS_OAUTH2_AUTHORIZER (self), NULL); + + priv = self->priv; + + g_mutex_lock (&priv->mutex); + refresh_token = g_strdup (priv->refresh_token); + g_mutex_unlock (&priv->mutex); + + return refresh_token; +} + +/** + * gdata_oauth2_authorizer_set_refresh_token: + * @self: a #GDataOAuth2Authorizer + * @refresh_token: (nullable): the new refresh token, or %NULL to clear + * authorization + * + * Sets the authorizer's refresh token, #GDataOAuth2Authorizer:refresh-token. + * This is used to periodically refresh the access token. Set it to %NULL to + * clear the current authentication from the authorizer. + * + * Since: UNRELEASED + */ +void +gdata_oauth2_authorizer_set_refresh_token (GDataOAuth2Authorizer *self, + const gchar *refresh_token) +{ + GDataOAuth2AuthorizerPrivate *priv; + + g_return_if_fail (GDATA_IS_OAUTH2_AUTHORIZER (self)); + + priv = self->priv; + + g_mutex_lock (&priv->mutex); + + if (g_strcmp0 (priv->refresh_token, refresh_token) == 0) { + g_mutex_unlock (&priv->mutex); + return; + } + + /* Clear the access token; if the refresh token has changed, it can + * no longer be valid, and we must avoid the situation: + * (access_token != NULL) && (refresh_token == NULL) */ + g_free (priv->access_token); + priv->access_token = NULL; + + /* Update the refresh token. */ + g_free (priv->refresh_token); + priv->refresh_token = g_strdup (refresh_token); + + g_mutex_unlock (&priv->mutex); + + g_object_notify (G_OBJECT (self), "refresh-token"); +} + +/** * gdata_oauth2_authorizer_get_locale: * @self: a #GDataOAuth2Authorizer * |