summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRoland Hedberg <roland@catalogix.se>2017-09-28 15:11:37 +0200
committerGitHub <noreply@github.com>2017-09-28 15:11:37 +0200
commit34c3b87764c48c60799a53b98f2b01469eee9675 (patch)
tree9a9f9d5fd8826aad3f9bc7a061f13c3eb4861ff0
parent7b5cb73ac232ac7d1ed0f2a1bf19efdbaec1301e (diff)
parent232696285745f19f1d828519e34ec66427ad72a4 (diff)
downloadpysaml2-34c3b87764c48c60799a53b98f2b01469eee9675.tar.gz
Merge branch 'master' into fix_sane_defaults
-rw-r--r--src/saml2/attribute_converter.py2
-rw-r--r--src/saml2/pack.py49
-rw-r--r--src/saml2/validate.py14
-rw-r--r--tests/test_51_client.py10
-rw-r--r--tests/test_65_authn_query.py2
-rw-r--r--tests/test_68_assertion_id.py2
6 files changed, 52 insertions, 27 deletions
diff --git a/src/saml2/attribute_converter.py b/src/saml2/attribute_converter.py
index 3d52a816..3d32d226 100644
--- a/src/saml2/attribute_converter.py
+++ b/src/saml2/attribute_converter.py
@@ -246,7 +246,7 @@ def get_local_name(acs, attr, name_format):
for aconv in acs:
#print(ac.format, name_format)
if aconv.name_format == name_format:
- return aconv._fro[attr]
+ return aconv._fro.get(attr)
def d_to_local_name(acs, attr):
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/src/saml2/validate.py b/src/saml2/validate.py
index de68fc00..9fe12c4d 100644
--- a/src/saml2/validate.py
+++ b/src/saml2/validate.py
@@ -3,6 +3,7 @@ from six.moves.urllib.parse import urlparse
import re
import struct
import base64
+import time
from saml2 import time_util
@@ -42,8 +43,8 @@ NCNAME = re.compile("(?P<NCName>[a-zA-Z_](\w|[_.-])*)")
def valid_ncname(name):
match = NCNAME.match(name)
- if not match:
- raise NotValid("NCName")
+ #if not match: # hack for invalid authnRequest/ID from meteor saml lib
+ # raise NotValid("NCName")
return True
@@ -90,8 +91,10 @@ def validate_on_or_after(not_on_or_after, slack):
now = time_util.utc_now()
nooa = calendar.timegm(time_util.str_to_time(not_on_or_after))
if now > nooa + slack:
+ now_str=time.strftime('%Y-%M-%dT%H:%M:%SZ', time.gmtime(now))
raise ResponseLifetimeExceed(
- "Can't use it, it's too old %d > %d" % (now - slack, nooa))
+ "Can't use repsonse, too old (now=%s + slack=%d > " \
+ "not_on_or_after=%s" % (now_str, slack, not_on_or_after))
return nooa
else:
return False
@@ -102,8 +105,9 @@ def validate_before(not_before, slack):
now = time_util.utc_now()
nbefore = calendar.timegm(time_util.str_to_time(not_before))
if nbefore > now + slack:
- raise ToEarly("Can't use it yet %d <= %d" % (now + slack, nbefore))
-
+ now_str = time.strftime('%Y-%M-%dT%H:%M:%SZ', time.gmtime(now))
+ raise ToEarly("Can't use response yet: (now=%s + slack=%d) "
+ "<= notbefore=%s" % (now_str, slack, not_before))
return True
diff --git a/tests/test_51_client.py b/tests/test_51_client.py
index 688d73d7..42651fbe 100644
--- a/tests/test_51_client.py
+++ b/tests/test_51_client.py
@@ -1404,7 +1404,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
@@ -1434,7 +1434,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
@@ -1531,7 +1531,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])
@@ -1566,7 +1566,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
@@ -1586,7 +1586,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 bd258238..77ccaa9e 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 60e85828..31b7e8e0 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)