Hello,
as I anticipated to Ben on IRC some days ago, I'm (slowly...)
working on updating paste.auth.open_id to the latest version of
python-openid (1.1).
I'm not an expert on openid nor paste, but I'm trying to find my
way. The new version of openid needs a "session" dict where it stores
data about the user request between round trips to the authentication
server.
As I had some difficulties using the user http session, I tried to
just put a plain dict there. Well, it works, but as I am not at all
sure it is correct (what happens with concurrent users?) I am sending
the patch here for review.
Meanwhile, I'll work on another version that uses the user session
(using paste.session) and that creates a new openid consumer at every
request (as recommended by the documentation).
mic
--
Michele Campeotto - http://micampe.it
You know there ain't no devil
there's just God when he's drunk.
-- Tom Waits
Index: paste/auth/open_id.py
===================================================================
--- paste/auth/open_id.py (revision 5969)
+++ paste/auth/open_id.py (working copy)
@@ -72,9 +72,12 @@
# Python-OpenID.
# sys.path.append('/path/to/openid/')
-from openid.store import filestore
+from openid.store.dumbstore import DumbStore
+from openid.store.filestore import FileOpenIDStore
from openid.consumer import consumer
from openid.oidutil import appendArgs
+from yadis.discover import DiscoveryFailure
+from urljr.fetchers import HTTPFetchingError
class AuthOpenIDHandler(object):
"""
@@ -108,8 +111,8 @@
A function called like ``url_to_username(environ, url)``, which should
return a string username. If not given, the URL will be the username.
"""
- store = filestore.FileOpenIDStore(data_store_path)
- self.oidconsumer = consumer.OpenIDConsumer(store)
+ store = FileOpenIDStore(data_store_path)
+ self.oidconsumer = consumer.Consumer({}, store)
self.app = app
self.auth_prefix = auth_prefix
@@ -184,45 +187,37 @@
oidconsumer = self.oidconsumer
- # Then, ask the library to begin the authorization.
- # Here we find out the identity server that will verify the
- # user's identity, and get a token that allows us to
- # communicate securely with the identity server.
- status, info = oidconsumer.beginAuth(openid_url)
-
- # If the URL was unusable (either because of network
- # conditions, a server error, or that the response returned
- # was not an OpenID identity page), the library will return
- # an error code. Let the user know that that URL is unusable.
- if status in [consumer.HTTP_FAILURE, consumer.PARSE_ERROR]:
- if status == consumer.HTTP_FAILURE:
- fmt = 'Failed to retrieve <q>%s</q>'
- else:
- fmt = 'Could not find OpenID information in <q>%s</q>'
-
+ try:
+ # Then, ask the library to begin the authorization.
+ # Here we find out the identity server that will verify the
+ # user's identity, and get a token that allows us to
+ # communicate securely with the identity server.
+ response = oidconsumer.begin(openid_url)
+ # If the URL was unusable (either because of network
+ # conditions, a server error, or that the response returned
+ # was not an OpenID identity page), the library will return
+ # an error code. Let the user know that that URL is unusable.
+ except HTTPFetchingError, exc:
+ fmt = 'Error retrieving identity URL: <q>%s</q>'
message = fmt % (cgi.escape(openid_url),)
return self.render(request, message, css_class='error', form_contents=openid_url)
- elif status == consumer.SUCCESS:
- # The URL was a valid identity URL. Now we construct a URL
- # that will get us to process the server response. We will
- # need the token from the beginAuth call when processing
- # the response. A cookie or a session object could be used
- # to accomplish this, but for simplicity here we just add
- # it as a query parameter of the return-to URL.
- return_to = self.build_url(request, 'process', token=info.token)
-
- # Now ask the library for the URL to redirect the user to
- # his OpenID server. It is required for security that the
- # return_to URL must be under the specified trust_root. We
- # just use the base_url for this server as a trust root.
- redirect_url = oidconsumer.constructRedirect(
- info, return_to, trust_root=request['base_url'])
-
- # Send the redirect response
- return self.redirect(request, redirect_url)
+ except DiscoveryFailure, exc:
+ fmt = 'Could not find OpenID information in <q>%s</q>'
+ message = fmt % (cgi.escape(openid_url),)
+ return self.render(request, message, css_class='error', form_contents=openid_url)
else:
- assert False, 'Not reached'
+ if request is None:
+ fmt = 'No OpenID services found for <q>%s</q>'
+ message = fmt % (cgi.escape(openid_url),)
+ return self.render(request, message, css_class='error', form_contents=openid_url)
+ else:
+ trust_root = request['base_url']
+ return_to = self.build_url(request, 'process')
+ redirect_url = response.redirectURL(trust_root, return_to)
+ # Send the redirect response
+ return self.redirect(request, redirect_url)
+
def do_process(self, request):
"""Handle the redirect from the OpenID server.
"""
@@ -235,48 +230,42 @@
# us. Status is a code indicating the response type. info is
# either None or a string containing more information about
# the return type.
- status, info = oidconsumer.completeAuth(token, request['query'])
+ response = oidconsumer.complete(request['query'])
css_class = 'error'
openid_url = None
- if status == consumer.FAILURE and info:
+ if response.status == consumer.FAILURE and response.identity_url:
# In the case of failure, if info is non-None, it is the
# URL that we were verifying. We include it in the error
# message to help the user figure out what happened.
- openid_url = info
fmt = "Verification of %s failed."
- message = fmt % (cgi.escape(openid_url),)
- elif status == consumer.SUCCESS:
+ message = fmt % (cgi.escape(response.identity_url),)
+ elif response.status == consumer.SUCCESS:
# Success means that the transaction completed without
# error. If info is None, it means that the user cancelled
# the verification.
css_class = 'alert'
- if info:
- # This is a successful verification attempt. If this
- # was a real application, we would do our login,
- # comment posting, etc. here.
- openid_url = info
- if self.url_to_username:
- username = self.url_to_username(request['environ'], openid_url)
- else:
- username = openid_url
- if 'paste.auth_tkt.set_user' in request['environ']:
- request['environ']['paste.auth_tkt.set_user'](username)
- if not self.login_redirect:
- fmt = ("If you had supplied a login redirect path, you would have "
- "been redirected there. "
- "You have successfully verified %s as your identity.")
- message = fmt % (cgi.escape(openid_url),)
- else:
- # @@: This stuff doesn't make sense to me; why not a remote redirect?
- #request['environ']['paste.auth.open_id'] = openid_url
- #request['environ']['PATH_INFO'] = self.login_redirect
- #return self.app(request['environ'], request['start'])
- exc = httpexceptions.HTTPTemporaryRedirect(self.login_redirect)
- return exc.wsgi_application(request['environ'], request['start'])
+ if self.url_to_username:
+ username = self.url_to_username(request['environ'], response.identity_url)
else:
- # cancelled
- message = 'Verification cancelled'
+ username = response.identity_url
+ if 'paste.auth_tkt.set_user' in request['environ']:
+ request['environ']['paste.auth_tkt.set_user'](username)
+ if not self.login_redirect:
+ fmt = ("If you had supplied a login redirect path, you would have "
+ "been redirected there. "
+ "You have successfully verified %s as your identity.")
+ message = fmt % (cgi.escape(response.identity_url),)
+ else:
+ # @@: This stuff doesn't make sense to me; why not a remote redirect?
+ #request['environ']['paste.auth.open_id'] = openid_url
+ #request['environ']['PATH_INFO'] = self.login_redirect
+ #return self.app(request['environ'], request['start'])
+ exc = httpexceptions.HTTPTemporaryRedirect(self.login_redirect)
+ return exc.wsgi_application(request['environ'], request['start'])
+ elif response.status == consumer.CANCEL:
+ # cancelled
+ message = 'Verification cancelled'
else:
# Either we don't understand the code or there is no
# openid_url included with the error. Give a generic
_______________________________________________
Paste-users mailing list
[email protected]
http://webwareforpython.org/cgi-bin/mailman/listinfo/paste-users