[gnome-online-accounts] google: Implement OAuth 2.0



commit d52fb78b2cbb776ff2994e7b170eb8e4c242c833
Author: Debarshi Ray <debarshir gnome org>
Date:   Thu Sep 13 15:02:10 2012 +0200

    google: Implement OAuth 2.0
    
    As of April 20, 2012 [1] GMail finally implements the SASL XOAUTH2
    mechanism. With that Google now supports OAuth 2.0 for all the
    different services that we care about.
    
    Unlike their OAuth 1.0 implementation, they don't support "anonymous"
    keys with OAuth 2.0. We need to register for a client_id /
    client_secret pair. However, we are allowed to embed the client_secret
    in our source code:
    https://developers.google.com/accounts/docs/OAuth2InstalledApp#overview
    
    With this we can leverage services like GTalk and Google Drive that
    did not support OAuth 1.0. For starters, the scope for GTalk has been
    added so that Empathy can use it.
    
    [1] https://developers.google.com/google-apps/gmail/oauth_protocol
        The documentation was updated retroactively because it did not
        mention anything about OAuth 2.0 weeks after the mentioned date.
        Yay Google!
    
    Fixes: https://bugzilla.gnome.org/661065

 configure.ac                       |   18 ++--
 src/goabackend/goagoogleprovider.c |  203 +++++++++++++-----------------------
 2 files changed, 82 insertions(+), 139 deletions(-)
---
diff --git a/configure.ac b/configure.ac
index f07c7db..3f8ca5d 100644
--- a/configure.ac
+++ b/configure.ac
@@ -103,14 +103,18 @@ AC_ARG_WITH(google-consumer-secret,
                             [Google OAuth 1.0 consumer secret])],
                             [],
                             [])
-if test "$with_google_consumer_key" = ""; then
-  with_google_consumer_key=anonymous
+if test "$with_google_client_id" = ""; then
+  with_google_client_id=923794261470.apps.googleusercontent.com
 fi
-if test "$with_google_consumer_secret" = ""; then
-  with_google_consumer_secret=anonymous
+if test "$with_google_client_secret" = ""; then
+  with_google_client_secret=SlVBAcxamM0TBPlvX2c1zbEY
 fi
-AC_DEFINE_UNQUOTED(GOA_GOOGLE_CONSUMER_KEY, ["$with_google_consumer_key"], [Google OAuth 1.0 consumer key])
-AC_DEFINE_UNQUOTED(GOA_GOOGLE_CONSUMER_SECRET, ["$with_google_consumer_secret"], [Google OAuth 1.0 consumer secret])
+AC_DEFINE_UNQUOTED(GOA_GOOGLE_CLIENT_ID,
+                   ["$with_google_client_id"],
+                   [Google OAuth 2.0 client id])
+AC_DEFINE_UNQUOTED(GOA_GOOGLE_CLIENT_SECRET,
+                   ["$with_google_client_secret"],
+                   [Google OAuth 2.0 client secret])
 if test "$enable_google" != "no"; then
   AC_DEFINE(GOA_GOOGLE_ENABLED, 1, [Enable Google data provider])
 fi
@@ -340,7 +344,7 @@ echo "
 	cppflags:                       ${CPPFLAGS}
 	introspection:		        ${found_introspection}
 
-	Google provider:                ${enable_google} (OAuth 1.0, key:${with_google_consumer_key} secret:${with_google_consumer_secret})
+	Google provider:                ${enable_google} (OAuth 2.0, id:${with_google_client_id} secret:${with_google_client_secret})
 	Microsoft Exchange provider:    ${enable_exchange}
 	Kerberos provider:              ${enable_kerberos}
 	Twitter provider:               ${enable_twitter} (OAuth 1.0, key:${with_twitter_consumer_key} secret:${with_twitter_consumer_secret})
diff --git a/src/goabackend/goagoogleprovider.c b/src/goabackend/goagoogleprovider.c
index 7a65d28..592b288 100644
--- a/src/goabackend/goagoogleprovider.c
+++ b/src/goabackend/goagoogleprovider.c
@@ -18,6 +18,7 @@
  * Boston, MA 02111-1307, USA.
  *
  * Author: David Zeuthen <davidz redhat com>
+ *         Debarshi Ray <debarshir gnome org>
  */
 
 #include "config.h"
@@ -27,7 +28,7 @@
 #include <json-glib/json-glib.h>
 
 #include "goaprovider.h"
-#include "goaoauthprovider.h"
+#include "goaoauth2provider.h"
 #include "goagoogleprovider.h"
 
 /**
@@ -39,14 +40,14 @@
 struct _GoaGoogleProvider
 {
   /*< private >*/
-  GoaOAuthProvider parent_instance;
+  GoaOAuth2Provider parent_instance;
 };
 
 typedef struct _GoaGoogleProviderClass GoaGoogleProviderClass;
 
 struct _GoaGoogleProviderClass
 {
-  GoaOAuthProviderClass parent_class;
+  GoaOAuth2ProviderClass parent_class;
 };
 
 /**
@@ -57,7 +58,7 @@ struct _GoaGoogleProviderClass
  * #GoaGoogleProvider is used for handling Google accounts.
  */
 
-G_DEFINE_TYPE_WITH_CODE (GoaGoogleProvider, goa_google_provider, GOA_TYPE_OAUTH_PROVIDER,
+G_DEFINE_TYPE_WITH_CODE (GoaGoogleProvider, goa_google_provider, GOA_TYPE_OAUTH2_PROVIDER,
                          g_io_extension_point_implement (GOA_PROVIDER_EXTENSION_POINT_NAME,
 							 g_define_type_id,
 							 "google",
@@ -79,89 +80,67 @@ get_provider_name (GoaProvider *_provider,
 }
 
 static const gchar *
-get_consumer_key (GoaOAuthProvider *provider)
+get_authorization_uri (GoaOAuth2Provider *provider)
 {
-  return GOA_GOOGLE_CONSUMER_KEY;
+  return "https://accounts.google.com/o/oauth2/auth";;
 }
 
 static const gchar *
-get_consumer_secret (GoaOAuthProvider *provider)
+get_token_uri (GoaOAuth2Provider *provider)
 {
-  return GOA_GOOGLE_CONSUMER_SECRET;
+  return "https://accounts.google.com/o/oauth2/token";;
 }
 
 static const gchar *
-get_request_uri (GoaOAuthProvider *provider)
+get_redirect_uri (GoaOAuth2Provider *provider)
 {
-  return "https://www.google.com/accounts/OAuthGetRequestToken";;
+  return "http://localhost";;
 }
 
-static gchar *
-build_authorization_uri (GoaOAuthProvider  *provider,
-                         const gchar       *authorization_uri,
-                         const gchar       *escaped_oauth_token)
+static const gchar *
+get_scope (GoaOAuth2Provider *provider)
 {
-  return g_strdup_printf ("%s"
-                          "?oauth_token=%s&btmpl=mobile",
-                          authorization_uri,
-                          escaped_oauth_token);
-}
+  return /* Read-only access to the user's email address */
+         "https://www.googleapis.com/auth/userinfo.email "
 
-static gchar **
-get_request_uri_params (GoaOAuthProvider *provider)
-{
-  GPtrArray *p;
-  p = g_ptr_array_new ();
-  g_ptr_array_add (p, g_strdup ("xoauth_displayname"));
-  g_ptr_array_add (p, g_strdup ("GNOME"));
-
-  g_ptr_array_add (p, g_strdup ("scope"));
-  g_ptr_array_add (p, g_strdup (
-    /* Display email address: cf. https://sites.google.com/site/oauthgoog/Home/emaildisplayscope */
-    "https://www.googleapis.com/auth/userinfo#email "
-    /* IMAP, SMTP access: http://code.google.com/apis/gmail/oauth/protocol.html */
-    "https://mail.google.com/ "
-    /* Calendar data API: http://code.google.com/apis/calendar/data/2.0/developers_guide.html */
-    "https://www.google.com/calendar/feeds "
-    /* Contacts API: http://code.google.com/apis/contacts/docs/3.0/developers_guide.html */
-    "https://www.google.com/m8/feeds/ "
-    /* Documents API: http://code.google.com/apis/documents/docs/3.0/developers_guide_protocol.html */
-    "https://docs.google.com/feeds/ "
-    "https://spreadsheets.google.com/feeds/ "
-    "https://docs.googleusercontent.com/";));
-  g_ptr_array_add (p, NULL);
-
-  /* NOTE: Increase the number returned in get_crededentials_generation if adding scopes */
-
-  return (gchar **) g_ptr_array_free (p, FALSE);
+         /* Google Calendar API */
+         "https://www.googleapis.com/auth/calendar "
+
+         /* Google Contacts API */
+         "https://www.google.com/m8/feeds/ "
+
+         /* Google Documents List Data API */
+         "https://docs.google.com/feeds/ "
+         "https://docs.googleusercontent.com/ "
+         "https://spreadsheets.google.com/feeds/ "
+
+         /* GMail IMAP and SMTP access */
+         "https://mail.google.com/ "
+
+         /* Google Talk */
+         "https://www.googleapis.com/auth/googletalk";;
 }
 
 static guint
 get_credentials_generation (GoaProvider *provider)
 {
-  return 2;
+  return 3;
 }
 
 static const gchar *
-get_authorization_uri (GoaOAuthProvider *provider)
+get_client_id (GoaOAuth2Provider *provider)
 {
-  return "https://www.google.com/accounts/OAuthAuthorizeToken";;
+  return GOA_GOOGLE_CLIENT_ID;
 }
 
 static const gchar *
-get_token_uri (GoaOAuthProvider *provider)
+get_client_secret (GoaOAuth2Provider *provider)
 {
-  return "https://www.google.com/accounts/OAuthGetAccessToken";;
+  return GOA_GOOGLE_CLIENT_SECRET;
 }
 
 static const gchar *
-get_callback_uri (GoaOAuthProvider *provider)
-{
-  return "https://www.gnome.org/goa-1.0/oauth";;
-}
-
-static const gchar *
-get_authentication_cookie (GoaOAuthProvider *provider)
+get_authentication_cookie (GoaOAuth2Provider *provider)
 {
   return "LSID";
 }
@@ -169,18 +148,16 @@ get_authentication_cookie (GoaOAuthProvider *provider)
 /* ---------------------------------------------------------------------------------------------------- */
 
 static gchar *
-get_identity_sync (GoaOAuthProvider  *provider,
-                   const gchar       *access_token,
-                   const gchar       *access_token_secret,
-                   gchar            **out_presentation_identity,
-                   GCancellable      *cancellable,
-                   GError           **error)
+get_identity_sync (GoaOAuth2Provider  *provider,
+                   const gchar        *access_token,
+                   gchar             **out_presentation_identity,
+                   GCancellable       *cancellable,
+                   GError            **error)
 {
   RestProxy *proxy;
   RestProxyCall *call;
   JsonParser *parser;
   JsonObject *json_object;
-  JsonObject *json_data_object;
   gchar *ret;
   gchar *email;
 
@@ -192,15 +169,10 @@ get_identity_sync (GoaOAuthProvider  *provider,
 
   /* TODO: cancellable */
 
-  proxy = oauth_proxy_new_with_token (goa_oauth_provider_get_consumer_key (provider),
-                                      goa_oauth_provider_get_consumer_secret (provider),
-                                      access_token,
-                                      access_token_secret,
-                                      "https://www.googleapis.com/userinfo/email";,
-                                      FALSE);
+  proxy = rest_proxy_new ("https://www.googleapis.com/oauth2/v2/userinfo";, FALSE);
   call = rest_proxy_new_call (proxy);
   rest_proxy_call_set_method (call, "GET");
-  rest_proxy_call_add_param (call, "alt", "json");
+  rest_proxy_call_add_param (call, "access_token", access_token);
 
   if (!rest_proxy_call_sync (call, error))
     goto out;
@@ -226,17 +198,7 @@ get_identity_sync (GoaOAuthProvider  *provider,
     }
 
   json_object = json_node_get_object (json_parser_get_root (parser));
-  json_data_object = json_object_get_object_member (json_object, "data");
-  if (json_data_object == NULL)
-    {
-      g_set_error (error,
-                   GOA_ERROR,
-                   GOA_ERROR_FAILED,
-                   _("Didn't find data member in JSON data"));
-      goto out;
-    }
-
-  email = g_strdup (json_object_get_string_member (json_data_object, "email"));
+  email = g_strdup (json_object_get_string_member (json_object, "email"));
   if (email == NULL)
     {
       g_set_error (error,
@@ -264,52 +226,32 @@ get_identity_sync (GoaOAuthProvider  *provider,
 /* ---------------------------------------------------------------------------------------------------- */
 
 static gboolean
-is_deny_node (GoaOAuthProvider *provider, WebKitDOMNode *node)
+is_deny_node (GoaOAuth2Provider *provider, WebKitDOMNode *node)
 {
-  WebKitDOMHTMLInputElement *input_element;
+  WebKitDOMHTMLElement *element;
   gboolean ret;
-  gchar *name;
+  gchar *id;
 
-  name = NULL;
+  id = NULL;
   ret = FALSE;
 
-  if (!WEBKIT_DOM_IS_HTML_INPUT_ELEMENT (node))
+  if (!WEBKIT_DOM_IS_HTML_BUTTON_ELEMENT (node))
     goto out;
 
-  input_element = WEBKIT_DOM_HTML_INPUT_ELEMENT (node);
-  name = webkit_dom_html_input_element_get_name (input_element);
-  if (g_strcmp0 (name, "deny") != 0)
+  element = WEBKIT_DOM_HTML_ELEMENT (node);
+  id = webkit_dom_html_element_get_id (element);
+  if (g_strcmp0 (id, "submit_deny_access") != 0)
     goto out;
 
   ret = TRUE;
 
  out:
-  g_free (name);
+  g_free (id);
   return ret;
 }
 
 /* ---------------------------------------------------------------------------------------------------- */
 
-static gchar *
-parse_request_token_error (GoaOAuthProvider *provider, RestProxyCall *call)
-{
-  const gchar *payload;
-  gchar *msg;
-  guint status;
-
-  msg = NULL;
-
-  payload = rest_proxy_call_get_payload (call);
-  status = rest_proxy_call_get_status_code (call);
-
-  if (status == 400 && g_str_has_prefix (payload, "Timestamp is too far from current time"))
-    msg = g_strdup (_("Your system time is invalid. Check your date and time settings."));
-
-  return msg;
-}
-
-/* ---------------------------------------------------------------------------------------------------- */
-
 static gboolean
 build_object (GoaProvider         *provider,
               GoaObjectSkeleton   *object,
@@ -502,13 +444,13 @@ build_object (GoaProvider         *provider,
 /* ---------------------------------------------------------------------------------------------------- */
 
 static gboolean
-get_use_external_browser (GoaOAuthProvider *provider)
+get_use_external_browser (GoaOAuth2Provider *provider)
 {
   return FALSE;
 }
 
 static gboolean
-get_use_mobile_browser (GoaOAuthProvider *provider)
+get_use_mobile_browser (GoaOAuth2Provider *provider)
 {
   return TRUE;
 }
@@ -560,7 +502,7 @@ show_account (GoaProvider         *provider,
 /* ---------------------------------------------------------------------------------------------------- */
 
 static void
-add_account_key_values (GoaOAuthProvider  *provider,
+add_account_key_values (GoaOAuth2Provider  *provider,
                         GVariantBuilder   *builder)
 {
   g_variant_builder_add (builder, "{ss}", "MailEnabled", "true");
@@ -581,7 +523,7 @@ static void
 goa_google_provider_class_init (GoaGoogleProviderClass *klass)
 {
   GoaProviderClass *provider_class;
-  GoaOAuthProviderClass *oauth_class;
+  GoaOAuth2ProviderClass *oauth2_class;
 
   provider_class = GOA_PROVIDER_CLASS (klass);
   provider_class->get_provider_type          = get_provider_type;
@@ -590,22 +532,19 @@ goa_google_provider_class_init (GoaGoogleProviderClass *klass)
   provider_class->show_account               = show_account;
   provider_class->get_credentials_generation = get_credentials_generation;
 
-  oauth_class = GOA_OAUTH_PROVIDER_CLASS (klass);
-  oauth_class->get_identity_sync        = get_identity_sync;
-  oauth_class->is_deny_node             = is_deny_node;
-  oauth_class->get_consumer_key         = get_consumer_key;
-  oauth_class->get_consumer_secret      = get_consumer_secret;
-  oauth_class->get_request_uri          = get_request_uri;
-  oauth_class->get_request_uri_params   = get_request_uri_params;
-  oauth_class->get_authorization_uri    = get_authorization_uri;
-  oauth_class->get_token_uri            = get_token_uri;
-  oauth_class->get_callback_uri         = get_callback_uri;
-  oauth_class->get_authentication_cookie = get_authentication_cookie;
-  oauth_class->build_authorization_uri  = build_authorization_uri;
-  oauth_class->get_use_external_browser = get_use_external_browser;
-  oauth_class->get_use_mobile_browser   = get_use_mobile_browser;
-  oauth_class->add_account_key_values   = add_account_key_values;
-  oauth_class->parse_request_token_error = parse_request_token_error;
+  oauth2_class = GOA_OAUTH2_PROVIDER_CLASS (klass);
+  oauth2_class->get_authentication_cookie = get_authentication_cookie;
+  oauth2_class->get_authorization_uri     = get_authorization_uri;
+  oauth2_class->get_client_id             = get_client_id;
+  oauth2_class->get_client_secret         = get_client_secret;
+  oauth2_class->get_identity_sync         = get_identity_sync;
+  oauth2_class->get_redirect_uri          = get_redirect_uri;
+  oauth2_class->get_scope                 = get_scope;
+  oauth2_class->is_deny_node              = is_deny_node;
+  oauth2_class->get_token_uri             = get_token_uri;
+  oauth2_class->get_use_external_browser  = get_use_external_browser;
+  oauth2_class->get_use_mobile_browser    = get_use_mobile_browser;
+  oauth2_class->add_account_key_values    = add_account_key_values;
 }
 
 /* ---------------------------------------------------------------------------------------------------- */



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]