summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorScott Koranda <skoranda@gmail.com>2017-09-23 10:00:33 -0500
committerScott Koranda <skoranda@gmail.com>2017-09-23 10:00:33 -0500
commit1952da2596f733d2aa80f1c9b0f95daa77dfcfd2 (patch)
tree7c0e41251c83924896918012152c44fc3c12c3a5
parent9cbbd9bd9f6bfa5e9ceace064dd1af4e2ff2f68c (diff)
downloadpysaml2-1952da2596f733d2aa80f1c9b0f95daa77dfcfd2.tar.gz
Fix for 459 HTTP_POST form nonconforming and shows submit
Fix for issue 459 "Form used with HTTP_POST binding nonconforming and shows submit button". The fix introduces an HTML5 DOCTYPE declaration and uses noscript tags appropriately to hide the submit button when Javascript is enabled. Modification of tests were necessary because the tests unecessarily relied on the response being a list of strings with the <form> element being the fourth item in the list, in order to unpack the form and pull out the SAMLResponse and relay state for comparison. The new tests do not require the response to be arbitrarily broken up as a list of strings.
-rw-r--r--src/saml2/pack.py49
-rw-r--r--tests/test_51_client.py12
-rw-r--r--tests/test_65_authn_query.py2
-rw-r--r--tests/test_68_assertion_id.py2
4 files changed, 43 insertions, 22 deletions
diff --git a/src/saml2/pack.py b/src/saml2/pack.py
index 728a516f..3bf39fc8 100644
--- a/src/saml2/pack.py
+++ b/src/saml2/pack.py
@@ -40,12 +40,35 @@ except ImportError:
import defusedxml.ElementTree
NAMESPACE = "http://schemas.xmlsoap.org/soap/envelope/"
-FORM_SPEC = """<form method="post" action="%s">
- <input type="hidden" name="%s" value="%s" />
- <input type="hidden" name="RelayState" value="%s" />
- <input type="submit" value="Submit" />
-</form>"""
+FORM_SPEC = """\
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8" />
+ </head>
+ <body onload="document.forms[0].submit()">
+ <noscript>
+ <p>
+ <strong>Note:</strong> Since your browser does not support JavaScript,
+ you must press the Continue button once to proceed.
+ </p>
+ </noscript>
+
+ <form action="{action}" method="post">
+ <div>
+ <input type="hidden" name="RelayState" value="{relay_state}"/>
+
+ <input type="hidden" name="{saml_type}" value="{saml_response}"/>
+ </div>
+ <noscript>
+ <div>
+ <input type="submit" value="Continue"/>
+ </div>
+ </noscript>
+ </form>
+ </body>
+</html>"""
def http_form_post_message(message, location, relay_state="",
typ="SAMLRequest", **kwargs):
@@ -58,8 +81,6 @@ def http_form_post_message(message, location, relay_state="",
:param relay_state: for preserving and conveying state information
:return: A tuple containing header information and a HTML message.
"""
- response = ["<head>", """<title>SAML 2.0 POST</title>""", "</head><body>"]
-
if not isinstance(message, six.string_types):
message = str(message)
if not isinstance(message, six.binary_type):
@@ -71,17 +92,17 @@ def http_form_post_message(message, location, relay_state="",
_msg = message
_msg = _msg.decode('ascii')
- response.append(FORM_SPEC % (location, typ, _msg, relay_state))
+ args = {
+ 'action' : location,
+ 'saml_type' : typ,
+ 'relay_state' : relay_state,
+ 'saml_response' : _msg
+ }
- response.append("""<script type="text/javascript">""")
- response.append(" window.onload = function ()")
- response.append(" { document.forms[0].submit(); }")
- response.append("""</script>""")
- response.append("</body>")
+ response = FORM_SPEC.format(**args)
return {"headers": [("Content-type", "text/html")], "data": response}
-
def http_post_message(message, relay_state="", typ="SAMLRequest", **kwargs):
"""
diff --git a/tests/test_51_client.py b/tests/test_51_client.py
index 937e0e20..bcc535af 100644
--- a/tests/test_51_client.py
+++ b/tests/test_51_client.py
@@ -1398,7 +1398,7 @@ class TestClient:
binding, info = resp[entity_ids[0]]
assert binding == BINDING_HTTP_POST
- _dic = unpack_form(info["data"][3])
+ _dic = unpack_form(info["data"])
res = self.server.parse_logout_request(_dic["SAMLRequest"],
BINDING_HTTP_POST)
assert b'<ns0:SessionIndex>_foo</ns0:SessionIndex>' in res.xmlstr
@@ -1428,7 +1428,7 @@ class TestClient:
binding, info = resp[entity_ids[0]]
assert binding == BINDING_HTTP_POST
- _dic = unpack_form(info["data"][3])
+ _dic = unpack_form(info["data"])
res = self.server.parse_logout_request(_dic["SAMLRequest"],
BINDING_HTTP_POST)
assert b'<ns0:SessionIndex>_foo</ns0:SessionIndex>' in res.xmlstr
@@ -1525,7 +1525,7 @@ class TestClientWithDummy():
sid, http_args = self.client.prepare_for_authenticate(
"urn:mace:example.com:saml:roland:idp", relay_state="really",
binding=binding, response_binding=response_binding)
- _dic = unpack_form(http_args["data"][3])
+ _dic = unpack_form(http_args["data"])
req = self.server.parse_authn_request(_dic["SAMLRequest"], binding)
resp_args = self.server.response_args(req.message, [response_binding])
@@ -1543,7 +1543,7 @@ class TestClientWithDummy():
response = self.client.send(**http_args)
print(response.text)
- _dic = unpack_form(response.text[3], "SAMLResponse")
+ _dic = unpack_form(response.text, "SAMLResponse")
resp = self.client.parse_authn_request_response(_dic["SAMLResponse"],
BINDING_HTTP_POST,
{sid: "/"})
@@ -1558,7 +1558,7 @@ class TestClientWithDummy():
sid, auth_binding, http_args = self.client.prepare_for_negotiated_authenticate(
"urn:mace:example.com:saml:roland:idp", relay_state="really",
binding=binding, response_binding=response_binding)
- _dic = unpack_form(http_args["data"][3])
+ _dic = unpack_form(http_args["data"])
assert binding == auth_binding
@@ -1578,7 +1578,7 @@ class TestClientWithDummy():
response = self.client.send(**http_args)
print(response.text)
- _dic = unpack_form(response.text[3], "SAMLResponse")
+ _dic = unpack_form(response.text, "SAMLResponse")
resp = self.client.parse_authn_request_response(_dic["SAMLResponse"],
BINDING_HTTP_POST,
{sid: "/"})
diff --git a/tests/test_65_authn_query.py b/tests/test_65_authn_query.py
index 54d529f8..68af10a1 100644
--- a/tests/test_65_authn_query.py
+++ b/tests/test_65_authn_query.py
@@ -28,7 +28,7 @@ def get_msg(hinfo, binding):
if binding == BINDING_SOAP:
xmlstr = hinfo["data"]
elif binding == BINDING_HTTP_POST:
- _inp = hinfo["data"][3]
+ _inp = hinfo["data"]
i = _inp.find(TAG1)
i += len(TAG1) + 1
j = _inp.find('"', i)
diff --git a/tests/test_68_assertion_id.py b/tests/test_68_assertion_id.py
index 52959f3a..283b4da6 100644
--- a/tests/test_68_assertion_id.py
+++ b/tests/test_68_assertion_id.py
@@ -27,7 +27,7 @@ def get_msg(hinfo, binding, response=False):
if binding == BINDING_SOAP:
msg = hinfo["data"]
elif binding == BINDING_HTTP_POST:
- _inp = hinfo["data"][3]
+ _inp = hinfo["data"]
i = _inp.find(TAG1)
i += len(TAG1) + 1
j = _inp.find('"', i)