How to use OpenID to log in as any member with any rights on a Plone site

published Jul 10, 2009 12:26   by admin ( last modified Jul 10, 2009 12:26 )

Here is a solution that allows any of your regular members on your site to

  • Claim an OpenID url as their own,
  • Use OpenID to log on to your site
  • And automatically be switched over to their normal user, no password or extra login required.

This is just proof-of-concept code and part of my summer hacks.

Currently (Plone 3) it is possible to have users log in to your site through OpenID, but they become kind of zombie members: If you assign roles to them in the Plone UI, the roles don't stick. But if an OpenId login can transfer into a normal plone member OpenId becomes more useful in Plone.

 

Here is how it works:

Setup

You need to install three products

  1. The OpenId Product that comes with Plone
  2. OneTimeTokenPAS

  3. A product that makes a user's properties searchable, such as Remember

Remember can be installed via buildout. With OneTimeTokenPAS after installing it via buildout, I had to manually place it in the products folder for it to work, and I had to delete the egg in the egg cache, and Products.OneTimeTokenPAS from the buildout config so the egg won't reappear at subsequent buildouts.

 

We need something to test on. Install Remember and then create a normal member. There is a location field for each member. Fill in an OpenID url here. Go to portal catalog and make sure that the location field is searchable. I created an index called "location", indexes "getLocation".

Install OneTimeTokenPAS and follow the instructions regarding the acl_users folder, to enable authentication and extraction, and move it to the top among the authentication plugins.

Install OpenID support by adding the product.

Execution

Make a python script in the root of your Plone site with the following contents:

# Get url to site
portal_url = container.absolute_url()
# So what is the id of the currently logged in user
# (will be an openId url for openId logged in users in Plone)?
oldUserId = container.portal_membership.getAuthenticatedMember().getId()
# Search to see if any member on the site has indicated that that url is their openId
# We search each user's "location" field here (with the Member content type of
# the remember product), but better to use a dedicated
# OpenID field for serious use.
# Lose trailing slash of openId identifier
oldUserId = oldUserId[:-1]
res = container.portal_catalog(portal_type='Member',location=oldUserId)
# Get the id of that user
try:
userId = res[0].getId
except IndexError:
return "Nobody has claimed %s as their open id url" % oldUserId
# prepare a login to switch to that user
tokenTool = container.onetimetoken_storage
token = tokenTool.setToken(userId)
logincode = '?logincode=%s' % tokenTool.setToken(userId)
url = portal_url + logincode
# Kill the auth cookie of the old user, or onetimetoken in acl_users won't kick in
context.REQUEST.response.setCookie('__ac','')
# Redirect to the token login, effectively logging in the user with no action on
# her part
context.REQUEST.response.redirect(url)

 Proxy the script as "Manager". Now after the user has logged in as an OpenID user, he can click on a link that goes to the above script. It would probably be possible to have the above script execute autmatically on OpenID login too.

 

Update 2009-07-10

I just realised that a malicious user could block another user out by claiming his OpenID. In this way the good guy user would get logged into the bad guy's account. But the good guy could then just alter the OpenID claim of that account, log out and get logged in to the right one. So a non issue (so far).