Commit ff8373ee authored by Valentin Samir's avatar Valentin Samir

Always return authenticationDate, longTermAuthenticationRequestTokenUsed and...

Always return authenticationDate, longTermAuthenticationRequestTokenUsed and isFromNewLogin attributes

As specified in the CAS response XML schema (see Appendix A).
Fix #37 as returned attributes are now never empty.
parent 4123450e
Pipeline #714 canceled with stage
......@@ -206,7 +206,7 @@ class CASClientV2(CASClientBase, ReturnUnicode):
def parse_attributes_xml_element(cls, element, charset):
attributes = dict()
for attribute in element:
tag = cls.self.u(attribute.tag, charset).split(u"}").pop()
tag = cls.u(attribute.tag, charset).split(u"}").pop()
if tag in attributes:
if isinstance(attributes[tag], list):
attributes[tag].append(cls.u(attribute.text, charset))
......
......@@ -29,6 +29,15 @@
</ConfirmationMethod>
</SubjectConfirmation>
</Subject>
<Attribute AttributeName="authenticationDate" AttributeNamespace="http://www.ja-sig.org/products/cas/">
<AttributeValue>{{auth_date}}</AttributeValue>
</Attribute>
<Attribute AttributeName="longTermAuthenticationRequestTokenUsed" AttributeNamespace="http://www.ja-sig.org/products/cas/">
<AttributeValue>false</AttributeValue>{# we do not support long-term (Remember-Me) auth #}
</Attribute>
<Attribute AttributeName="isFromNewLogin" AttributeNamespace="http://www.ja-sig.org/products/cas/">
<AttributeValue>{{is_new_login}}</AttributeValue>
</Attribute>
{% for name, value in attributes %} <Attribute AttributeName="{{name}}" AttributeNamespace="http://www.ja-sig.org/products/cas/">
<AttributeValue>{{value}}</AttributeValue>
</Attribute>
......
......@@ -2,8 +2,14 @@
<cas:authenticationSuccess>
<cas:user>{{username}}</cas:user>
<cas:attributes>
<cas:authenticationDate>{{auth_date}}</cas:authenticationDate>
<cas:longTermAuthenticationRequestTokenUsed>false</cas:longTermAuthenticationRequestTokenUsed>{# we do not support long-term (Remember-Me) auth #}
<cas:isFromNewLogin>{{is_new_login}}</cas:isFromNewLogin>
{% for key, value in attributes %} <cas:{{key}}>{{value}}</cas:{{key}}>
{% endfor %} </cas:attributes>
<cas:attribute name="authenticationDate" value="{{auth_date}}"/>
<cas:attribute name="longTermAuthenticationRequestTokenUsed" value="false"/>
<cas:attribute name="isFromNewLogin" value="{{is_new_login}}"/>
{% for key, value in attributes %} <cas:attribute name="{{key}}" value="{{value}}"/>
{% endfor %}{% if proxyGrantingTicket %} <cas:proxyGrantingTicket>{{proxyGrantingTicket}}</cas:proxyGrantingTicket>
{% endif %}{% if proxies %} <cas:proxies>
......
......@@ -149,15 +149,23 @@ class XmlContent(object):
namespaces={'cas': "http://www.yale.edu/tp/cas"}
)
self.assertEqual(len(attributes), 1)
ignore_attrs = {"authenticationDate", "longTermAuthenticationRequestTokenUsed", "isFromNewLogin"}
ignored_attrs = 0
attrs1 = set()
for attr in attributes[0]:
attrs1.add((attr.tag[len("http://www.yale.edu/tp/cas")+2:], attr.text))
name = attr.tag[len("http://www.yale.edu/tp/cas")+2:]
if not name in ignore_attrs:
attrs1.add((name, attr.text))
else:
ignored_attrs += 1
attributes = root.xpath("//cas:attribute", namespaces={'cas': "http://www.yale.edu/tp/cas"})
self.assertEqual(len(attributes), len(attrs1))
self.assertEqual(len(attributes), len(attrs1) + ignored_attrs)
attrs2 = set()
for attr in attributes:
attrs2.add((attr.attrib['name'], attr.attrib['value']))
name = attr.attrib['name']
if not name in ignore_attrs:
attrs2.add((name, attr.attrib['value']))
original = set()
for key, value in original_attributes.items():
if isinstance(value, list):
......
......@@ -1907,9 +1907,11 @@ class SamlValidateTestCase(TestCase, BaseServicePattern, XmlContent):
"//samla:AttributeStatement/samla:Attribute",
namespaces={'samla': "urn:oasis:names:tc:SAML:1.0:assertion"}
)
ignore_attrs = {"authenticationDate", "longTermAuthenticationRequestTokenUsed", "isFromNewLogin"} - set(original_attributes.keys())
attrs = set()
for attr in attributes:
attrs.add((attr.attrib['AttributeName'], attr.getchildren()[0].text))
if not attr.attrib['AttributeName'] in ignore_attrs:
attrs.add((attr.attrib['AttributeName'], attr.getchildren()[0].text))
original = set()
for key, value in original_attributes.items():
if isinstance(value, list):
......
......@@ -264,7 +264,9 @@ class DummyCAS(BaseHTTPServer.BaseHTTPRequestHandler):
template = loader.get_template('cas_server/serviceValidate.xml')
context = Context({
'username': self.server.username,
'attributes': self.server.attributes
'attributes': self.server.attributes,
'auth_date': timezone.now().replace(microsecond=0).isoformat(),
'is_new_login': 'true',
})
self.wfile.write(return_bytes(template.render(context), "utf8"))
else:
......@@ -301,6 +303,8 @@ class DummyCAS(BaseHTTPServer.BaseHTTPRequestHandler):
'ResponseID': utils.gen_saml_id(),
'username': self.server.username,
'attributes': self.server.attributes,
'auth_date': timezone.now().replace(microsecond=0).isoformat(),
'is_new_login': 'true',
})
self.wfile.write(return_bytes(template.render(context), "utf8"))
else:
......
......@@ -1153,7 +1153,9 @@ class ValidateService(View):
params = {
'username': self.ticket.username(),
'attributes': self.ticket.attributs_flat(),
'proxies': proxies
'proxies': proxies,
'auth_date': self.ticket.user.last_login.replace(microsecond=0).isoformat(),
'is_new_login': 'true' if self.ticket.renew else 'false'
}
# if pgtUrl is set, require https or localhost
if self.pgt_url and (
......@@ -1415,7 +1417,10 @@ class SamlValidate(CsrfExemptView):
'Recipient': self.target,
'ResponseID': utils.gen_saml_id(),
'username': self.ticket.username(),
'attributes': self.ticket.attributs_flat()
'attributes': self.ticket.attributs_flat(),
'auth_date': self.ticket.user.last_login.replace(microsecond=0).isoformat(),
'is_new_login': 'true' if self.ticket.renew else 'false'
}
logger.info(
"SamlValidate: ticket %s validated for user %s on service %s." % (
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment