# HG changeset patch # User paulb # Date 1194995802 0 # Node ID dd04c8b3bb0b4fa9806c31c60289ace91cbdedb2 # Parent 9dd43535b30bbea766efd351f53e0c0f1a0ee0b0 [project @ 2007-11-13 23:16:42 by paulb] Added the OpenIDRedirectResource class to handle redirection, adding a verify option to the OpenIDRedirectAuthenticator.authenticate method to support assertion verification. diff -r 9dd43535b30b -r dd04c8b3bb0b WebStack/Resources/OpenIDInitiation.py --- a/WebStack/Resources/OpenIDInitiation.py Tue Nov 13 23:15:50 2007 +0000 +++ b/WebStack/Resources/OpenIDInitiation.py Tue Nov 13 23:16:42 2007 +0000 @@ -105,6 +105,7 @@ self.show_success(trans, url) # Redirect to the OpenID provider URL. + # NOTE: Offer a POST-based form for redirection. if self.use_redirect: trans.redirect(url) diff -r 9dd43535b30b -r dd04c8b3bb0b WebStack/Resources/OpenIDLogin.py --- a/WebStack/Resources/OpenIDLogin.py Tue Nov 13 23:15:50 2007 +0000 +++ b/WebStack/Resources/OpenIDLogin.py Tue Nov 13 23:16:42 2007 +0000 @@ -84,6 +84,8 @@ password = fields_body.get("password", [""])[0] app = fields_body.get("app", [""])[0] + # NOTE: Permit flexibility in the credentials. + if self.authenticator.authenticate(trans, (local_id, username), password): self._redirect(trans, claimed_id, local_id, username, app) # The above method does not return. @@ -106,6 +108,8 @@ self.show_verification(trans, valid) # The above method does not return. + # NOTE: Permit association requests here. + # Otherwise, show the login form. fields_path = trans.get_fields_from_path(self.urlencoding) @@ -164,6 +168,7 @@ url += "&%s=%s" % (name, trans.encode_path(value[0], self.urlencoding)) # Show the success page anyway. + # NOTE: Offer a POST-based form for redirection. self.show_success(trans, url) if self.use_redirect: diff -r 9dd43535b30b -r dd04c8b3bb0b WebStack/Resources/OpenIDRedirect.py --- a/WebStack/Resources/OpenIDRedirect.py Tue Nov 13 23:15:50 2007 +0000 +++ b/WebStack/Resources/OpenIDRedirect.py Tue Nov 13 23:16:42 2007 +0000 @@ -21,11 +21,37 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA """ +from WebStack.Resources.LoginRedirect import LoginRedirectResource from WebStack.Helpers.Auth import Verifier, check_openid_signature import WebStack.Generic import datetime import urllib +class OpenIDRedirectResource(LoginRedirectResource): + + "A resource redirecting to an OpenID initiation page." + + openid_ns = "http://specs.openid.net/auth/2.0" + + def respond(self, trans): + + "Respond using the given transaction 'trans'." + + fields_path = trans.get_fields_from_path(self.path_encoding) + + # If requested, attempt to verify OpenID assertions. + # http://openid.net/specs/openid-authentication-2_0-12.html#rfc.section.11 + + if fields_path.get("openid.ns", [None])[0] == self.openid_ns and \ + fields_path.get("openid.mode", [None])[0] == "id_res": + + if self.authenticator.authenticate(trans, verify=1): + trans.redirect(fields_path["openid.return_to"][0]) + + # Otherwise, handle the usual parameters and request details. + + LoginRedirectResource.respond(self, trans) + class OpenIDRedirectAuthenticator(Verifier): """ @@ -52,56 +78,54 @@ self.replay_limit = replay_limit or self.replay_limit self.urlencoding = urlencoding or self.encoding - def authenticate(self, trans): + def authenticate(self, trans, verify=0): """ Authenticate the originator of 'trans', updating the object if successful and returning a true value if successful, or a false value otherwise. + + If the optional 'verify' parameter is specified as a true value, perform + verification on any """ - # First, try to authenticate with an application cookie. - - valid = Verifier.authenticate(self, trans) + # If requested, attempt to verify OpenID assertions. - # Without a valid login, attempt to verify OpenID assertions. - # http://openid.net/specs/openid-authentication-2_0-12.html#rfc.section.11 - - if not valid: + if verify: fields_path = trans.get_fields_from_path(self.urlencoding) - if fields_path.get("openid.ns", [None])[0] == self.openid_ns and \ - fields_path.get("openid.mode", [None])[0] == "id_res": - - # NOTE: Could expose all errors. + # NOTE: Could expose all errors. - try: - - if self.test_url(fields_path) and \ - self.test_signature(fields_path) and \ - self.test_replay(fields_path): + try: + # Test the details of the assertion. - self.set_token(trans, fields_path["openid.identity"][0]) + if self.test_url(fields_path) and \ + self.test_signature(fields_path) and \ + self.test_replay(fields_path): - # NOTE: Should return true and let the redirector do this. - trans.redirect(fields_path["openid.return_to"][0]) - #return 1 + self.set_token(trans, fields_path["openid.identity"][0]) + return 1 - # Incomplete assertion. + # Incomplete assertion. - except (KeyError, ValueError): - raise + except (KeyError, ValueError): + raise # Assertion failed or was incomplete. return 0 - # Update the transaction with the user details. + # Otherwise, try to authenticate with an application cookie. + + else: + valid = Verifier.authenticate(self, trans) - if valid: - username, token = self.get_username_and_token(trans) - trans.set_user(username) - return valid + # Update the transaction with the user details. + + if valid: + username, token = self.get_username_and_token(trans) + trans.set_user(username) + return valid def test_url(self, fields_path):