1.1 --- a/WebStack/Resources/OpenIDInitiation.py Tue Nov 13 23:17:11 2007 +0000
1.2 +++ b/WebStack/Resources/OpenIDInitiation.py Sat Nov 17 00:30:16 2007 +0000
1.3 @@ -38,9 +38,9 @@
1.4 The optional 'openid_mode' parameter may be set to "checkid_immediate"
1.5 or "checkid_setup" (the default).
1.6
1.7 - If the optional 'use_redirect' flag is set to 0, a confirmation screen
1.8 - is given instead of redirecting the user back to the original
1.9 - application.
1.10 + If the optional 'use_redirect' flag is set to a false value (which is
1.11 + not the default), a confirmation screen is given instead of immediately
1.12 + redirecting the user to the OpenID provider.
1.13
1.14 The optional 'urlencoding' parameter allows a special encoding to be
1.15 used in producing the redirection path.
1.16 @@ -101,11 +101,11 @@
1.17 )
1.18
1.19 # Show the success page anyway.
1.20 + # Offer a POST-based form for redirection.
1.21
1.22 - self.show_success(trans, url)
1.23 + self.show_success(trans, provider, app, claimed_identifier, local_identifier)
1.24
1.25 # Redirect to the OpenID provider URL.
1.26 - # NOTE: Offer a POST-based form for redirection.
1.27
1.28 if self.use_redirect:
1.29 trans.redirect(url)
1.30 @@ -157,16 +157,19 @@
1.31 out = trans.get_response_stream()
1.32 out.write(self.initiation_page % app)
1.33
1.34 - def show_success(self, trans, url):
1.35 + def show_success(self, trans, provider, app, claimed_identifier, local_identifier):
1.36
1.37 """
1.38 Writes a success screen using the transaction 'trans', including details
1.39 - of the OpenID provider 'url'.
1.40 + of the OpenID 'provider', the 'app' URL, 'claimed_identifier' and
1.41 + 'local_identifier'.
1.42 """
1.43
1.44 trans.set_content_type(WebStack.Generic.ContentType("text/html", self.encoding))
1.45 out = trans.get_response_stream()
1.46 - out.write(self.success_page % (url, url))
1.47 + out.write(self.success_page % (
1.48 + provider, self.openid_ns, self.openid_mode, app, claimed_identifier, local_identifier)
1.49 + )
1.50
1.51 initiation_page = """
1.52 <html>
1.53 @@ -177,8 +180,8 @@
1.54 <h1>Authenticate via OpenID</h1>
1.55 <form method="POST" name="openid_identifier">
1.56 <p>OpenID Identifier (URL): <input name="identity" type="text" size="32"/></p>
1.57 - <p><input name="initiate" type="submit" value="Login"/></p>
1.58 - <input name="app" type="hidden" value="%s"/>
1.59 + <p><input name="initiate" type="submit" value="Login" /></p>
1.60 + <input name="app" type="hidden" value="%s" />
1.61 </form>
1.62 </body>
1.63 </html>
1.64 @@ -191,7 +194,14 @@
1.65 </head>
1.66 <body>
1.67 <h1>Authenticate via OpenID</h1>
1.68 - <p>Please proceed to the OpenID provider: <a href="%s">%s</a>.</p>
1.69 + <form action="%s" method="POST" name="openid_redirect">
1.70 + <input name="openid.ns" type="hidden" value="%s" />
1.71 + <input name="openid.mode" type="hidden" value="%s" />
1.72 + <input name="openid.return_to" type="hidden" value="%s" />
1.73 + <input name="openid.claimed_id" type="hidden" value="%s" />
1.74 + <input name="openid.identity" type="hidden" value="%s" />
1.75 + <p>Please proceed to the OpenID provider: <input name="proceed" type="submit" value="Proceed!" /></p>
1.76 + </form>
1.77 </body>
1.78 </html>
1.79 """
2.1 --- a/WebStack/Resources/OpenIDLogin.py Tue Nov 13 23:17:11 2007 +0000
2.2 +++ b/WebStack/Resources/OpenIDLogin.py Sat Nov 17 00:30:16 2007 +0000
2.3 @@ -43,9 +43,9 @@
2.4 The optional 'associations' is a mapping from association handles to
2.5 secret keys.
2.6
2.7 - If the optional 'use_redirect' flag is set to 0, a confirmation screen
2.8 - is given instead of redirecting the user back to the original
2.9 - application.
2.10 + If the optional 'use_redirect' flag is set to a false value (which is
2.11 + not the default), a confirmation screen is given instead of immediately
2.12 + redirecting the user back to the original application.
2.13
2.14 The optional 'urlencoding' parameter allows a special encoding to be
2.15 used in producing the redirection path.
2.16 @@ -71,18 +71,18 @@
2.17
2.18 # Check for a submitted login form.
2.19
2.20 - fields_body = trans.get_fields_from_body(self.encoding)
2.21 + fields = trans.get_fields(self.encoding)
2.22
2.23 - if fields_body.has_key("login"):
2.24 + if fields.has_key("login"):
2.25
2.26 # Check a combination of local identifier and username together with
2.27 # the password.
2.28
2.29 - claimed_id = fields_body.get("claimed_id", [""])[0]
2.30 - local_id = fields_body.get("local_id", [""])[0]
2.31 - username = fields_body.get("username", [""])[0]
2.32 - password = fields_body.get("password", [""])[0]
2.33 - app = fields_body.get("app", [""])[0]
2.34 + claimed_id = fields.get("claimed_id", [""])[0]
2.35 + local_id = fields.get("local_id", [""])[0]
2.36 + username = fields.get("username", [""])[0]
2.37 + password = fields.get("password", [""])[0]
2.38 + app = fields.get("app", [""])[0]
2.39
2.40 # NOTE: Permit flexibility in the credentials.
2.41
2.42 @@ -92,13 +92,13 @@
2.43
2.44 # Check for an OpenID signature verification request.
2.45
2.46 - elif fields_body.get("openid.mode", [None])[0] == "check_authentication":
2.47 + elif fields.get("openid.mode", [None])[0] == "check_authentication":
2.48
2.49 # Obtain the secret key from recorded associations.
2.50
2.51 - handle = fields_body.get("openid.assoc_handle", [None])[0]
2.52 + handle = fields.get("openid.assoc_handle", [None])[0]
2.53 if handle is not None and self.associations.has_key(handle):
2.54 - valid = check_openid_signature(fields_body, self.associations[handle])
2.55 + valid = check_openid_signature(fields, self.associations[handle])
2.56 del self.associations[handle]
2.57 else:
2.58 valid = 0
2.59 @@ -112,10 +112,9 @@
2.60
2.61 # Otherwise, show the login form.
2.62
2.63 - fields_path = trans.get_fields_from_path(self.urlencoding)
2.64 - app = fields_path.get("openid.return_to", [""])[0]
2.65 - claimed_id = fields_path.get("openid.claimed_id", [""])[0]
2.66 - local_id = fields_path.get("openid.identity", [""])[0]
2.67 + app = fields.get("openid.return_to", [""])[0]
2.68 + claimed_id = fields.get("openid.claimed_id", [""])[0]
2.69 + local_id = fields.get("openid.identity", [""])[0]
2.70
2.71 self.show_login(trans, app, claimed_id, local_id)
2.72
2.73 @@ -168,9 +167,9 @@
2.74 url += "&%s=%s" % (name, trans.encode_path(value[0], self.urlencoding))
2.75
2.76 # Show the success page anyway.
2.77 - # NOTE: Offer a POST-based form for redirection.
2.78 + # Offer a POST-based form for redirection.
2.79
2.80 - self.show_success(trans, url)
2.81 + self.show_success(trans, app, "id_res", signed_names, signature, fields)
2.82 if self.use_redirect:
2.83 trans.redirect(url)
2.84 else:
2.85 @@ -207,16 +206,22 @@
2.86 out = trans.get_response_stream()
2.87 out.write(self.login_page % (app, claimed_id, local_id))
2.88
2.89 - def show_success(self, trans, app):
2.90 + def show_success(self, trans, app, mode, signed_names, signature, fields):
2.91
2.92 """
2.93 Writes a success screen using the transaction 'trans', including details
2.94 - of the 'app' which the client was attempting to access.
2.95 + of the 'app' which the client was attempting to access, the
2.96 + communications 'mode', the 'signed_names' indicating the fields which
2.97 + are signed, the 'signature' associated with the message, and a
2.98 + dictionary of 'fields' indicating other information.
2.99 """
2.100
2.101 trans.set_content_type(WebStack.Generic.ContentType("text/html", self.encoding))
2.102 out = trans.get_response_stream()
2.103 - out.write(self.success_page % (app, app))
2.104 + l = []
2.105 + for name, value in fields.items():
2.106 + l.append("""<input name="%s" type="hidden" value="%s" />""" % (name, value[0]))
2.107 + out.write(self.success_page % (app, self.openid_ns, mode, ",".join(signed_names), signature, "\n".join(l)))
2.108
2.109 login_page = """
2.110 <html>
2.111 @@ -244,7 +249,14 @@
2.112 </head>
2.113 <body>
2.114 <h1>Login Successful</h1>
2.115 - <p>Please proceed to the application: <a href="%s">%s</a></p>
2.116 + <form action="%s" method="POST" name="openid_redirect">
2.117 + <input name="openid.ns" type="hidden" value="%s" />
2.118 + <input name="openid.mode" type="hidden" value="%s" />
2.119 + <input name="openid.signed" type="hidden" value="%s" />
2.120 + <input name="openid.sig" type="hidden" value="%s" />
2.121 + %s
2.122 + <p>Please proceed to the application: <input name="proceed" type="submit" value="Proceed!" /></p>
2.123 + </form>
2.124 </body>
2.125 </html>
2.126 """
3.1 --- a/WebStack/Resources/OpenIDRedirect.py Tue Nov 13 23:17:11 2007 +0000
3.2 +++ b/WebStack/Resources/OpenIDRedirect.py Sat Nov 17 00:30:16 2007 +0000
3.3 @@ -37,16 +37,16 @@
3.4
3.5 "Respond using the given transaction 'trans'."
3.6
3.7 - fields_path = trans.get_fields_from_path(self.path_encoding)
3.8 + fields = trans.get_fields(self.path_encoding)
3.9
3.10 # If requested, attempt to verify OpenID assertions.
3.11 # http://openid.net/specs/openid-authentication-2_0-12.html#rfc.section.11
3.12
3.13 - if fields_path.get("openid.ns", [None])[0] == self.openid_ns and \
3.14 - fields_path.get("openid.mode", [None])[0] == "id_res":
3.15 + if fields.get("openid.ns", [None])[0] == self.openid_ns and \
3.16 + fields.get("openid.mode", [None])[0] == "id_res":
3.17
3.18 if self.authenticator.authenticate(trans, verify=1):
3.19 - trans.redirect(fields_path["openid.return_to"][0])
3.20 + trans.redirect(fields["openid.return_to"][0])
3.21
3.22 # Otherwise, handle the usual parameters and request details.
3.23
3.24 @@ -92,18 +92,18 @@
3.25 # If requested, attempt to verify OpenID assertions.
3.26
3.27 if verify:
3.28 - fields_path = trans.get_fields_from_path(self.urlencoding)
3.29 + fields = trans.get_fields(self.urlencoding)
3.30
3.31 # NOTE: Could expose all errors.
3.32
3.33 try:
3.34 # Test the details of the assertion.
3.35
3.36 - if self.test_url(fields_path) and \
3.37 - self.test_signature(fields_path) and \
3.38 - self.test_replay(fields_path):
3.39 + if self.test_url(fields) and \
3.40 + self.test_signature(fields) and \
3.41 + self.test_replay(fields):
3.42
3.43 - self.set_token(trans, fields_path["openid.identity"][0])
3.44 + self.set_token(trans, fields["openid.identity"][0])
3.45 return 1
3.46
3.47 # Incomplete assertion.
3.48 @@ -127,7 +127,7 @@
3.49 trans.set_user(username)
3.50 return valid
3.51
3.52 - def test_url(self, fields_path):
3.53 + def test_url(self, fields):
3.54
3.55 """
3.56 See:
3.57 @@ -136,9 +136,9 @@
3.58
3.59 # NOTE: Currently, this is not strict enough.
3.60
3.61 - return fields_path["openid.return_to"][0].startswith(self.app_url)
3.62 + return fields["openid.return_to"][0].startswith(self.app_url)
3.63
3.64 - def test_signature(self, fields_path):
3.65 + def test_signature(self, fields):
3.66
3.67 """
3.68 See:
3.69 @@ -146,7 +146,7 @@
3.70 http://openid.net/specs/openid-authentication-2_0-12.html#rfc.section.6
3.71 """
3.72
3.73 - handle = fields_path.get("openid.assoc_handle", [None])[0]
3.74 + handle = fields.get("openid.assoc_handle", [None])[0]
3.75
3.76 # With an association handle, look up the appropriate secret key and
3.77 # verify the signed items.
3.78 @@ -156,19 +156,19 @@
3.79 # Where an association exists, use the known secret key.
3.80
3.81 if self.associations.has_key(handle):
3.82 - return check_openid_signature(fields_path, self.associations[handle])
3.83 + return check_openid_signature(fields, self.associations[handle])
3.84
3.85 # Without an association, request verification of the signed items
3.86 # from the OpenID provider.
3.87
3.88 else:
3.89 - return self.test_signature_direct(fields_path)
3.90 + return self.test_signature_direct(fields)
3.91
3.92 # Without a handle, no signature verification can occur.
3.93
3.94 return 0
3.95
3.96 - def test_signature_direct(self, fields_path):
3.97 + def test_signature_direct(self, fields):
3.98
3.99 """
3.100 See:
3.101 @@ -178,7 +178,7 @@
3.102 # Make a POST request using the "openid." fields.
3.103
3.104 d = {}
3.105 - for name, values in fields_path.items():
3.106 + for name, values in fields.items():
3.107 if name.startswith("openid.") and name != "openid.mode":
3.108 d[name] = values[0]
3.109 d["openid.mode"] = "check_authentication"
3.110 @@ -187,7 +187,7 @@
3.111 # Send a POST request to the OpenID provider, reading the response and
3.112 # testing for certain fields and values.
3.113
3.114 - f = urllib.urlopen(fields_path["openid.op_endpoint"][0], data)
3.115 + f = urllib.urlopen(fields["openid.op_endpoint"][0], data)
3.116 try:
3.117 items = []
3.118 for line in f.readlines():
3.119 @@ -200,14 +200,14 @@
3.120 finally:
3.121 f.close()
3.122
3.123 - def test_replay(self, fields_path):
3.124 + def test_replay(self, fields):
3.125
3.126 """
3.127 See:
3.128 http://openid.net/specs/openid-authentication-2_0-12.html#rfc.section.11.3
3.129 """
3.130
3.131 - timestamp = fields_path["openid.response_nonce"][0]
3.132 + timestamp = fields["openid.response_nonce"][0]
3.133 # YYYY-MM-DDTHH:MM:SSZ...
3.134 year, month, day, hour, minute, second, unique = \
3.135 int(timestamp[0:4]), int(timestamp[5:7]), int(timestamp[8:10]), \