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

Reply via email to