After an evaluation, GNOME has moved from Bugzilla to GitLab. Learn more about GitLab.
No new issues can be reported in GNOME Bugzilla anymore.
To report an issue in a GNOME project, go to GNOME GitLab.
Do not go to GNOME Gitlab for: Bluefish, Doxygen, GnuCash, GStreamer, java-gnome, LDTP, NetworkManager, Tomboy.
Bug 646285 - Add OAuth 2 support
Add OAuth 2 support
Status: RESOLVED FIXED
Product: libgdata
Classification: Platform
Component: General
git master
Other All
: Normal enhancement
: Future
Assigned To: libgdata-maint
libgdata-maint
Depends on:
Blocks:
 
 
Reported: 2011-03-30 23:32 UTC by Philip Withnall
Modified: 2014-09-21 12:59 UTC
See Also:
GNOME target: ---
GNOME version: ---



Description Philip Withnall 2011-03-30 23:32:55 UTC
Following on from bug #644946, it turns out that OAuth 2 support is needed in libgdata to support OpenID authentication.

See:
http://apiblog.youtube.com/2011/03/clientlogin-fail.html
Comment 1 Philip Withnall 2011-05-03 08:26:36 UTC
Due to the GNOME Online Accounts work going on at the moment, it's probably a good idea to push this forward to 0.10.
Comment 2 David Zeuthen (not reading bugmail) 2011-05-11 20:05:22 UTC
Cool, thanks for working on this. I expect GOA to initially use OAuth 1.0 tokens for Google accounts but at some point we might switch to OAuth 2.0. It would be nice to have support for both versions since 2.0 is not backwards compatible with 1.0.
Comment 3 Philip Withnall 2011-05-11 20:18:11 UTC
In outline, I'm currently implementing it using the following API:
 • A GDataAuthorizer interface which can basically just append headers to HTTP requests (which in practice are ClientLogin tokens or OAuth tokens).
 • A GDataAuthorizationDomain class which represents a single authorization domain or, in Google's terminology, a scope.
 • A GDataClientLoginAuthorizer which implements GDataAuthorizer and provides the same functionality as is provided as present by gdata_service_authenticate().
 • A GDataOAuth2Authorizer (name not finalised) which also implements GDataAuthorizer and implements OAuth 2 support.

Client applications would have one instance of a class implementing GDataAuthorizer, which they'd set up with the authorisation domains they're interested in and pass to the GDataServices they want to use. It would then attach all the appropriate HTTP headers to their requests.

Adding support for OAuth 1 should be as simple as adding a GDataOAuth1Authorizer which implements GDataAuthorizer and has methods to do all the OAuth 1-specific authentication and authorisation interaction with the Google accounts service. I'll see if I get time to implement it once I've got the rest of the stuff working.

How does this sound?
Comment 4 David Zeuthen (not reading bugmail) 2011-05-11 22:04:09 UTC
(In reply to comment #3)
> In outline, I'm currently implementing it using the following API:
>  • A GDataAuthorizer interface which can basically just append headers to HTTP
> requests (which in practice are ClientLogin tokens or OAuth tokens).
>  • A GDataAuthorizationDomain class which represents a single authorization
> domain or, in Google's terminology, a scope.
>  • A GDataClientLoginAuthorizer which implements GDataAuthorizer and provides
> the same functionality as is provided as present by
> gdata_service_authenticate().
>  • A GDataOAuth2Authorizer (name not finalised) which also implements
> GDataAuthorizer and implements OAuth 2 support.
> 
> Client applications would have one instance of a class implementing
> GDataAuthorizer, which they'd set up with the authorisation domains they're
> interested in and pass to the GDataServices they want to use. It would then
> attach all the appropriate HTTP headers to their requests.
> 
> Adding support for OAuth 1 should be as simple as adding a
> GDataOAuth1Authorizer which implements GDataAuthorizer and has methods to do
> all the OAuth 1-specific authentication and authorisation interaction with the
> Google accounts service. I'll see if I get time to implement it once I've got
> the rest of the stuff working.
> 
> How does this sound?

Sounds great as long as I can do stuff like this

 authorizer = g_data_oauth2_authorizer_new (access_token);

and

 authorizer = g_data_oauth1_authorizer_new (consumer_key, consumer_secret, access_token, access_token_secret);

where @access_token, @access_token_secret, @consumer_key, @consumer_secret are all obtained from either GOA or some other mechanism (it could very well be that the app is managing its own tokens).

Some day we could even have

 authorizer = g_data_oauth2_authorizer_new_for_goa_account (account);

that tracks a #GoaGoogleAccount instance or something (for example, picks up the new access token when it has changed)  but that's a bit premature I think. First things first.

There might be one twist, however - IIRC the OAuth 1.0 stuff requires a cryptographic signature _per request_ and IIRC that signature is a function of a number of things. So it might need to be computed very late in the process once all the other headers are in place. If you are using librest all this is terribly simple, you just create a OAuthProxy (using access_token and access_token_secret) instead of just a RestProxy (I haven't actually read the libdata code so I don't know if you are using librest).

Anyway, OAuth 2.0 is a lot simpler - you simply just add the

 Authorization: OAuth <access_token>

HTTP header and you are done. This means that it's only suitable to use OAuth 2.0 on https connections but IMO that's fine.

Re: GDataAuthorizationDomain - this is only needed when you obtain the access_token so for the GOA stuff I don't care too much about it since I've already dealt with it in the control center pane when the user authenticated (again, you might want it if the app itself is managing its tokens).
Comment 5 Philip Withnall 2011-06-05 15:55:12 UTC
I've just pushed two commits which remove the old authentication mechanism, replace it with a GDataClientLoginAuthorizer, and then add a GDataOAuth1Authorizer.

All that remains to do is add a GDataOAuth2Authorizer, but that's less urgent.

I've decided that adding support for GOA to directly use its own access token is best left for a GOA-specific implementation of the GDataAuthorizer interface, which would live in e-d-s. That approach is neater than adding access-token (etc.) properties to GDataOAuth1Authorizer.

I'll try and make an unstable 0.9.0 release with these changes sometime before the IM, Contacts & Social hackfest the week after next. Any comments on the API (probably of GDataAuthorizer) would be appreciated before then!

commit 47d20c21e8986cdbab21098428dd57bca203f6ad
Author: Philip Withnall <philip@tecnocode.co.uk>
Date:   Sun May 29 22:38:39 2011 +0100

    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

 Makefile.am                       |    4 +-
 README                            |    1 +
 configure.ac                      |    3 +-
 docs/reference/gdata-docs.xml     |    1 +
 docs/reference/gdata-sections.txt |   32 +
 gdata/gdata-authorizer.c          |   12 +-
 gdata/gdata-oauth1-authorizer.c   | 1337 +++++++++++++++++++++++++++++++++++++
 gdata/gdata-oauth1-authorizer.h   |   97 +++
 gdata/gdata.h                     |    1 +
 gdata/gdata.symbols               |   16 +
 gdata/tests/Makefile.am           |    3 +
 gdata/tests/common.c              |   28 +-
 gdata/tests/common.h              |    1 +
 gdata/tests/oauth1-authorizer.c   | 1048 +++++++++++++++++++++++++++++
 po/POTFILES.in                    |    1 +
 15 files changed, 2575 insertions(+), 10 deletions(-)

commit 2957118536be2c51c9e4c8c14b52c95db7717725
Author: Philip Withnall <philip@tecnocode.co.uk>
Date:   Thu May 5 23:29:14 2011 +0100

    core: Remove the old authentication API in favour of a new GDataAuthorizer API
    
    This separates authentication and authorisation from the services themselves,
    allowing authorisation schemes to be plugged in as they pop into and out of
    fashion.
    
    This removes the old gdata_service_authenticate() methods, replacing
    them with an equivalent GDataClientLoginAuthorizer.
    
    Full test cases are provided, covering everything except parsing of error
    responses from the server by GDataClientLoginAuthorizer.
    
    This makes the following API changes:
     • Rename GDataAuthenticationError to GDataClientLoginAuthorizerError
       Rename GDATA_AUTHENTICATION_ERROR and gdata_authentication_error_quark()
       similarly.
     • Remove gdata_service_authenticate() in favour of
       using GDataClientLoginAuthorizer with GDataService::authorizer:
        - Remove gdata_service_authenticate(),
          gdata_service_authenticate_async() and
          gdata_service_authenticate_finish().
        - Replace gdata_service_is_authenticated() by
          gdata_service_is_authorized() with much the same functionality.
        - Add GDataService::authorizer, gdata_service_get_authorizer(),
          gdata_service_set_authorizer() and
          gdata_service_get_authorization_domains().
        - Remove gdata_service_get_client_id() in favour of
          GDataClientLoginAuthorizer::client-id.
        - Remove gdata_service_get_username() in favour of
          GDataClientLoginAuthorizer::username.
        - Remove gdata_service_get_password() in favour of
          GDataClientLoginAuthorizer::password.
        - Remove GDataServiceClass->service_name in favour of
          GDataAuthorizationDomain::service-name.
        - Remove GDataServiceClass->authentication_uri and
          GDataServiceClass->parse_authentication_response in favour of
          different GDataAuthorizer implementations.
        - Add GDataAuthorizer parameters to and remove client_id parameters from:
          gdata_calendar_service_new(), gdata_contacts_service_new(),
          gdata_documents_service_new(), gdata_picasaweb_service_new() and
          gdata_youtube_service_new().
     • Add GDataAuthorizationDomain.
        - Add GDataServiceClass->get_authorization_domains and
          gdata_service_get_authorization_domains().
        - Add auth. domain getters to various GDataService subclasses:
          gdata_youtube_service_get_primary_authorization_domain(),
          gdata_contacts_service_get_primary_authorization_domain(),
          gdata_calendar_service_get_primary_authorization_domain(),
          gdata_picasaweb_service_get_primary_authorization_domain(),
          gdata_documents_service_get_primary_authorization_domain() and
          gdata_documents_service_get_spreadsheet_authorization_domain().
        - Add auth. domain properties to various standalone request objects:
          GDataDownloadStream::authorization-domain with
          gdata_download_stream_get_authorization_domain(),
          GDataUploadStream::authorization-domain with
          gdata_upload_stream_get_authorization_domain() and
          GDataBatchOperation::authorization-domain with
          gdata_batch_operation_get_authorization_domain().
        - Add GDataAccessHandlerIface->get_authorization_domain. This doesn't
          have to be implemented by existing GDataAccessHandlers, but it's
          highly recommended.
        - Add a GDataAuthorizationDomain parameter to
          GDataServiceClass->append_query_headers,
          gdata_service_query(), gdata_service_query_async(),
          gdata_service_query_single_entry(),
          gdata_service_query_single_entry_async(), gdata_service_insert_entry(),
          gdata_service_insert_entry_async(), gdata_service_update_entry(),
          gdata_service_update_entry_async(), gdata_service_delete_entry(),
          gdata_service_delete_entry_async(),
          gdata_batchable_create_operation(),
          gdata_download_stream_new() and gdata_upload_stream_new().
     • Add GDataAuthorizer as described above, implemented by
       GDataClientLoginAuthorizer.
    
    Helps: bgo#646285

 Makefile.am                                        |   10 +-
 docs/reference/gdata-docs.xml                      |    7 +
 docs/reference/gdata-sections.txt                  |   94 ++-
 gdata/gdata-access-handler.c                       |   14 +-
 gdata/gdata-access-handler.h                       |    9 +-
 gdata/gdata-authorization-domain.c                 |  197 ++++
 gdata/gdata-authorization-domain.h                 |   69 ++
 gdata/gdata-authorizer.c                           |  310 +++++
 gdata/gdata-authorizer.h                           |   90 ++
 gdata/gdata-batch-operation.c                      |   66 +-
 gdata/gdata-batch-operation.h                      |    2 +
 gdata/gdata-batchable.c                            |   18 +-
 gdata/gdata-batchable.h                            |    4 +-
 gdata/gdata-client-login-authorizer.c              | 1218 ++++++++++++++++++++
 gdata/gdata-client-login-authorizer.h              |  130 +++
 gdata/gdata-download-stream.c                      |   79 ++-
 gdata/gdata-download-stream.h                      |    3 +-
 gdata/gdata-private.h                              |   49 +-
 gdata/gdata-service.c                              | 1048 ++++++-----------
 gdata/gdata-service.h                              |  101 +--
 gdata/gdata-upload-stream.c                        |   90 ++-
 gdata/gdata-upload-stream.h                        |    6 +-
 gdata/gdata.h                                      |    3 +
 gdata/gdata.symbols                                |   46 +-
 gdata/media/gdata-media-content.c                  |    2 +-
 gdata/media/gdata-media-thumbnail.c                |    2 +-
 gdata/services/calendar/gdata-calendar-calendar.c  |   11 +-
 gdata/services/calendar/gdata-calendar-service.c   |   88 +-
 gdata/services/calendar/gdata-calendar-service.h   |    4 +-
 gdata/services/contacts/gdata-contacts-contact.c   |    6 +-
 gdata/services/contacts/gdata-contacts-service.c   |   81 +-
 gdata/services/contacts/gdata-contacts-service.h   |    4 +-
 .../services/documents/gdata-documents-document.c  |   18 +-
 gdata/services/documents/gdata-documents-entry.c   |    8 +
 gdata/services/documents/gdata-documents-service.c |  205 ++--
 gdata/services/documents/gdata-documents-service.h |    6 +-
 .../documents/gdata-documents-spreadsheet.c        |    3 +-
 gdata/services/picasaweb/gdata-picasaweb-service.c |  109 ++-
 gdata/services/picasaweb/gdata-picasaweb-service.h |    4 +-
 gdata/services/youtube/gdata-youtube-service.c     |  109 ++-
 gdata/services/youtube/gdata-youtube-service.h     |    4 +-
 gdata/services/youtube/gdata-youtube-video.c       |    2 +-
 gdata/tests/Makefile.am                            |    6 +
 gdata/tests/authorization.c                        |  795 +++++++++++++
 gdata/tests/calendar.c                             |   90 +-
 gdata/tests/client-login-authorizer.c              |  745 ++++++++++++
 gdata/tests/common.h                               |   11 +-
 gdata/tests/contacts.c                             |  110 ++-
 gdata/tests/documents.c                            |  167 ++-
 gdata/tests/general.c                              |    7 +-
 gdata/tests/memory.c                               |    7 +-
 gdata/tests/picasaweb.c                            |   84 +-
 gdata/tests/streams.c                              |    8 +-
 gdata/tests/youtube.c                              |  104 ++-
 po/POTFILES.in                                     |    1 +
 55 files changed, 5178 insertions(+), 1286 deletions(-)
Comment 6 Philip Withnall 2011-07-04 19:21:47 UTC
(In reply to comment #5)
> I've just pushed two commits which remove the old authentication mechanism,
> replace it with a GDataClientLoginAuthorizer, and then add a
> GDataOAuth1Authorizer.
> 
> All that remains to do is add a GDataOAuth2Authorizer, but that's less urgent.

Adding an OAuth 2 implementation has become even less urgent now that I've noticed that Google's experimental implementation of OAuth 2 is 6 revisions behind the RFC.

I think it's safer to leave this until the RFC is ratified and Google standardise on the final revision.
Comment 7 Philip Withnall 2014-09-21 12:59:33 UTC
Fixed.

commit c54b759085dfeb5f59aea7d1ac620620958ac29e
Author: Philip Withnall <philip@tecnocode.co.uk>
Date:   Sun Jul 3 21:37:49 2011 +0100

    core: Add a GDataOAuth2Authorizer for OAuth 2.0 support
    
    This adds a new GDataAuthorizer subclass to support OAuth 2.0
    authorisation, which is needed for the Google Tasks unit tests.
    
    This includes support for all Google OAuth 2.0 features (note that
    Google’s implementation of OAuth 2.0 is not entirely standard, so this
    OAuth 2.0 authoriser cannot be used outside of Google’s services). It
    includes full unit tests too.
    
    New API:
     • GDATA_OAUTH2_REDIRECT_URI_OOB
     • GDATA_OAUTH2_REDIRECT_URI_OOB_AUTO
     • GDataOAuth2Authorizer
    
    https://bugzilla.gnome.org/show_bug.cgi?id=646285

 Makefile.am                                                                              |    5 +-
 docs/reference/gdata-docs.xml                                                            |    1 +
 docs/reference/gdata-sections.txt                                                        |   34 +
 gdata/gdata-authorizer.c                                                                 |   10 +-
 gdata/gdata-client-login-authorizer.c                                                    |    2 +
 gdata/gdata-oauth1-authorizer.c                                                          |    5 +-
 gdata/gdata-oauth2-authorizer.c                                                          | 1485 ++++++++++++++++++++++++++++++++++++++++++
 gdata/gdata-oauth2-authorizer.h                                                          |  128 ++++
 gdata/gdata.h                                                                            |    1 +
 gdata/gdata.symbols                                                                      |   16 +
 gdata/tests/Makefile.am                                                                  |   11 +
 gdata/tests/oauth2-authorizer.c                                                          | 1030 +++++++++++++++++++++++++++++
 gdata/tests/traces/oauth2-authorizer/oauth2-authorizer-refresh-authorization-authorized  |   34 +
 .../tests/traces/oauth2-authorizer/oauth2-authorizer-refresh-authorization-unauthorized  |    0
 gdata/tests/traces/oauth2-authorizer/oauth2-authorizer-request-authorization-async       |   35 +
 .../oauth2-authorizer/oauth2-authorizer-request-authorization-async-bad-credentials      |   31 +
 .../traces/oauth2-authorizer/oauth2-authorizer-request-authorization-async-cancellation  |    0
 gdata/tests/traces/oauth2-authorizer/oauth2-authorizer-request-authorization-sync        |   35 +
 .../oauth2-authorizer/oauth2-authorizer-request-authorization-sync-bad-credentials       |   31 +
 .../traces/oauth2-authorizer/oauth2-authorizer-request-authorization-sync-cancellation   |    0
 gdata/tests/traces/oauth2-authorizer/setup-oauth2-authorizer-data-authenticated          |   35 +
 21 files changed, 2922 insertions(+), 7 deletions(-)