I'm working on adding user profile photo management to my application. My app was already using the Profiles API and it's successfully able to hide/unhide users from the global GAL. However, when attempting to perform any sort of user profile photo management I'd get an "Authsub token has wrong scope" error. After some trial and error. I've found that the code fails if my OAuth token is scope for profiles:
https://www.google.com/m8/feeds/profiles (according to http://code.google.com/googleapps/domain/profiles/developers_guide.html#Auth ) but it works if I "widen" the scope to the Contacts API scope: https://www.google.com/m8/feeds (according to http://code.google.com/apis/contacts/docs/3.0/developers_guide.html#Auth) attached is a simple app that demos the issue by attempting to get the profile photo for every user in a GA domain and save it to a file. It should fail OOB with the AuthSub error when attempting to grab the 1st photo but if line 73 is uncommented and 74 is commented and then oauth.txt is recreated (with Contacts API scope this time) it should work. Jay -- You received this message because you are subscribed to the Google Groups "Google Contacts, Shared Contacts and User Profiles APIs" group. To post to this group, send email to [email protected] To unsubscribe from this group, send email to [email protected] For more options, visit this group at http://code.google.com/apis/contacts/community/forum.html
#!/usr/bin/env python # # User Photo Manager # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. """User Photo Manager (UPM) is a command line tool which allows Administrators to manage user profile photos""" __author__ = '[email protected] (Jay Lee)' __version__ = '0.1' __license__ = 'Apache License 2.0 (http://www.apache.org/licenses/LICENSE-2.0)' import pickle import os import gdata.apps.service import gdata.contacts.service import gdata.auth import sys import re from optparse import OptionParser import webbrowser def SetupOptionParser(): # Usage message is the module's docstring. parser = OptionParser(usage=__doc__) parser.add_option('--version', action='store_true', dest='version', help='just print User Profile Manager Version and then quit') parser.add_option('--debug', action='store_true', dest='debug', help='Turn on verbose debugging and connection information.') parser.add_option('--domain', dest='domain', help='Google Apps domain to use') return parser def loadOAuth(gdataObject): global domain oauthfile = open('oauth.txt', 'r') domain = oauthfile.readline()[0:-1] token = pickle.load(oauthfile) oauthfile.close() gdataObject.domain = domain client_id = '711837411296.apps.googleusercontent.com' client_secret = 'A0R_LC-PU0YKJCwCb9N3Njxt' gdataObject.SetOAuthInputParameters(gdata.auth.OAuthSignatureMethod.HMAC_SHA1, consumer_key=client_id, consumer_secret=client_secret) token.oauth_input_params = gdataObject._oauth_input_params gdataObject.SetOAuthToken(token) def doRequestOAuth(domain): api_key = 'AIzaSyAqi4Qo0Qrtx4FrEwIC4naWYF1q1I6Osa8' fetch_params = {'xoauth_displayname':'User Photo Manager', 'key':api_key} #scopes = ['https://www.google.com/m8/feeds/'] # Contacts API scopes = ['https://www.google.com/m8/feeds/profiles'] # Profiles API apps = gdata.apps.service.AppsService(domain=domain) apps.source = 'User Photo Manager %s / %s / %s / ' % (__version__, __author__, 'Python %s.%s.%s %s' % (sys.version_info[0], sys.version_info[1], sys.version_info[2], sys.version_info[3])) client_id = 'anonymous' client_secret = 'anonymous' apps.SetOAuthInputParameters(gdata.auth.OAuthSignatureMethod.HMAC_SHA1, consumer_key=client_id, consumer_secret=client_secret) try: request_token = apps.FetchOAuthRequestToken(scopes=scopes, extra_parameters=fetch_params) except gdata.service.FetchingOAuthRequestTokenFailed, e: if str(e).find('Timestamp') != -1: print "In order to use OAuth, your system time needs to be correct.\nPlease fix your time and try again." sys.exit(5) url_params = {'hd': domain} url = apps.GenerateOAuthAuthorizationURL(request_token=request_token, extra_params=url_params) raw_input("\nNow User Photo Manager will open a web page in order for you to grant %s access. Make sure you are logged in as an Administrator of your Google Apps domain before granting access. Press the Enter key to open your browser." % fetch_params['xoauth_displayname']) try: webbrowser.open(str(url)) except Exception, e: pass raw_input("\n\nYou should now see a web page asking you to grant %s\n" 'access. If the page didn\'t open, you can manually\n' 'go to %s to grant access.\n' '\n' 'Once you\'ve granted access, press the Enter key.' % (fetch_params['xoauth_displayname'], url)) try: final_token = apps.UpgradeToOAuthAccessToken(request_token) except gdata.service.TokenUpgradeFailed: print 'Failed to upgrade the token. Did you grant User Photo Manager access in your browser?' sys.exit(4) f = open('oauth.txt', 'w') f.write('%s\n' % domain) pickle.dump(final_token, f) f.close() def main(argv): options_parser = SetupOptionParser() (options, args) = options_parser.parse_args() if options.version: print 'User Photo Manager %s' % __version__ sys.exit(0) if not options.domain: options_parser.print_help() print "ERROR: --domain is required." return if not os.path.isfile('oauth.txt'): doRequestOAuth(options.domain) cs = gdata.contacts.service.ContactsService() if options.debug: cs.debug = True cs.ssl = True cs.source = 'User Photo Manager %s / %s / %s / ' % (__version__, __author__, 'Python %s.%s.%s %s' % (sys.version_info[0], sys.version_info[1], sys.version_info[2], sys.version_info[3])) loadOAuth(cs) profiles_feed = cs.GetProfilesFeed('/m8/feeds/profiles/domain/%s/full?v=3' % options.domain) for entry in profiles_feed.entry: user_address = entry.email[0].address.lower() user_domain = user_address[user_address.find('@')+1:] cs.domain = user_domain if user_address[:2] == '.@' or user_address[:27] == 'secure-data-connector-user@': continue print "Getting photo for %s:" % user_address try: photo = cs.GetPhoto(entry.link[0].href) except gdata.service.RequestError, e: print e filename = '%s.jpg' % (entry.email[0].address) photo_file = open(filename, 'wb') photo_file.write(photo) photo_file.close() if __name__ == '__main__': try: main(sys.argv) except KeyboardInterrupt: sys.exit(4)
