GNOME Bugzilla – Bug 646285
Add OAuth 2 support
Last modified: 2014-09-21 12:59:33 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
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.
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.
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?
(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).
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(-)
(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.
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(-)