As of 2012, it seems that the Google OpenID endpoint supports first and last name retrieval through the Attribute Exchange protocol. Here is some example Python code using the Pyramid web framework and Janrain's python-openid package.
from openid.consumer import consumer
from openid.extensions.ax import AttrInfo, FetchRequest, FetchResponse
from openid.store.filestore import FileOpenIDStore
from openid.store.sqlstore import PostgreSQLStore, MySQLStore, SQLiteStore
AX_FIRSTNAME = 'http://axschema.org/namePerson/first'
AX_LASTNAME = 'http://axschema.org/namePerson/last'
AX_EMAIL = 'http://axschema.org/contact/email'
@view_config(route_name='openID_start', permission=NO_PERMISSION_REQUIRED)
def start(request):
'Start openID authentication process'
params = request.params
openIDURL = params.get('openIDURL')
if not openIDURL:
return HTTPResponse('Parameter expected: openIDURL')
openIDConsumer = get_consumer(request)
try:
openIDRequest = openIDConsumer.begin(openIDURL)
except consumer.DiscoveryFailure, error:
return HTTPResponse('Discovery failed: %s' % escape(error))
else:
if not openIDRequest:
return HTTPResponse('Not an openID provider: %s' % escape(openIDURL))
axRequest = FetchRequest()
axRequest.add(AttrInfo(AX_FIRSTNAME, required=True))
axRequest.add(AttrInfo(AX_LASTNAME, required=True))
axRequest.add(AttrInfo(AX_EMAIL, required=True))
openIDRequest.addExtension(axRequest)
sourceURL = request.host_url
targetURL = request.route_url('openID_finish')
if openIDRequest.shouldSendRedirect():
return HTTPFound(location=openIDRequest.redirectURL(sourceURL, targetURL))
return HTTPResponse(openIDRequest.htmlMarkup(sourceURL, targetURL))
@view_config(route_name='openID_finish', permission=NO_PERMISSION_REQUIRED)
def finish(request):
'Finish openID authentication process'
openIDConsumer = get_consumer(request)
targetURL = request.route_url('openID_finish')
openIDResponse = openIDConsumer.complete(request.params, targetURL)
html = openIDResponse.status + '<br>'
for key, value in openIDResponse.__dict__.iteritems():
html += '%s: %s<br>' % (escape(key), escape(value))
html += '<br>'
if consumer.SUCCESS == openIDResponse.status:
axResponse = FetchResponse.fromSuccessResponse(openIDResponse)
html += 'First name: %s<br>' % escape(axResponse.get(AX_FIRSTNAME))
html += 'Last name: %s<br>' % escape(axResponse.get(AX_LASTNAME))
html += 'Email: %s<br>' % escape(axResponse.get(AX_EMAIL))
return HTTPResponse(html)
def get_consumer(request):
try:
openIDStore = {
'sqlite': SQLiteStore,
'postgresql': PostgreSQLStore,
'mysql': MySQLStore,
}[db.bind.name](db.bind.raw_connection())
except KeyError:
openIDStore = FileOpenIDStore('data/openIDs')
try:
openIDStore.createTables()
except:
pass
return consumer.Consumer(request.session, openIDStore)