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.
This commit is contained in:
parent
4123450e9f
commit
ff8373ee6a
@ -206,7 +206,7 @@ class CASClientV2(CASClientBase, ReturnUnicode):
|
|||||||
def parse_attributes_xml_element(cls, element, charset):
|
def parse_attributes_xml_element(cls, element, charset):
|
||||||
attributes = dict()
|
attributes = dict()
|
||||||
for attribute in element:
|
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 tag in attributes:
|
||||||
if isinstance(attributes[tag], list):
|
if isinstance(attributes[tag], list):
|
||||||
attributes[tag].append(cls.u(attribute.text, charset))
|
attributes[tag].append(cls.u(attribute.text, charset))
|
||||||
|
@ -29,6 +29,15 @@
|
|||||||
</ConfirmationMethod>
|
</ConfirmationMethod>
|
||||||
</SubjectConfirmation>
|
</SubjectConfirmation>
|
||||||
</Subject>
|
</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/">
|
{% for name, value in attributes %} <Attribute AttributeName="{{name}}" AttributeNamespace="http://www.ja-sig.org/products/cas/">
|
||||||
<AttributeValue>{{value}}</AttributeValue>
|
<AttributeValue>{{value}}</AttributeValue>
|
||||||
</Attribute>
|
</Attribute>
|
||||||
|
@ -2,8 +2,14 @@
|
|||||||
<cas:authenticationSuccess>
|
<cas:authenticationSuccess>
|
||||||
<cas:user>{{username}}</cas:user>
|
<cas:user>{{username}}</cas:user>
|
||||||
<cas:attributes>
|
<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}}>
|
{% for key, value in attributes %} <cas:{{key}}>{{value}}</cas:{{key}}>
|
||||||
{% endfor %} </cas:attributes>
|
{% 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}}"/>
|
{% for key, value in attributes %} <cas:attribute name="{{key}}" value="{{value}}"/>
|
||||||
{% endfor %}{% if proxyGrantingTicket %} <cas:proxyGrantingTicket>{{proxyGrantingTicket}}</cas:proxyGrantingTicket>
|
{% endfor %}{% if proxyGrantingTicket %} <cas:proxyGrantingTicket>{{proxyGrantingTicket}}</cas:proxyGrantingTicket>
|
||||||
{% endif %}{% if proxies %} <cas:proxies>
|
{% endif %}{% if proxies %} <cas:proxies>
|
||||||
|
@ -149,15 +149,23 @@ class XmlContent(object):
|
|||||||
namespaces={'cas': "http://www.yale.edu/tp/cas"}
|
namespaces={'cas': "http://www.yale.edu/tp/cas"}
|
||||||
)
|
)
|
||||||
self.assertEqual(len(attributes), 1)
|
self.assertEqual(len(attributes), 1)
|
||||||
|
ignore_attrs = {"authenticationDate", "longTermAuthenticationRequestTokenUsed", "isFromNewLogin"}
|
||||||
|
ignored_attrs = 0
|
||||||
attrs1 = set()
|
attrs1 = set()
|
||||||
for attr in attributes[0]:
|
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"})
|
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()
|
attrs2 = set()
|
||||||
for attr in attributes:
|
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()
|
original = set()
|
||||||
for key, value in original_attributes.items():
|
for key, value in original_attributes.items():
|
||||||
if isinstance(value, list):
|
if isinstance(value, list):
|
||||||
|
@ -1907,8 +1907,10 @@ class SamlValidateTestCase(TestCase, BaseServicePattern, XmlContent):
|
|||||||
"//samla:AttributeStatement/samla:Attribute",
|
"//samla:AttributeStatement/samla:Attribute",
|
||||||
namespaces={'samla': "urn:oasis:names:tc:SAML:1.0:assertion"}
|
namespaces={'samla': "urn:oasis:names:tc:SAML:1.0:assertion"}
|
||||||
)
|
)
|
||||||
|
ignore_attrs = {"authenticationDate", "longTermAuthenticationRequestTokenUsed", "isFromNewLogin"} - set(original_attributes.keys())
|
||||||
attrs = set()
|
attrs = set()
|
||||||
for attr in attributes:
|
for attr in attributes:
|
||||||
|
if not attr.attrib['AttributeName'] in ignore_attrs:
|
||||||
attrs.add((attr.attrib['AttributeName'], attr.getchildren()[0].text))
|
attrs.add((attr.attrib['AttributeName'], attr.getchildren()[0].text))
|
||||||
original = set()
|
original = set()
|
||||||
for key, value in original_attributes.items():
|
for key, value in original_attributes.items():
|
||||||
|
@ -264,7 +264,9 @@ class DummyCAS(BaseHTTPServer.BaseHTTPRequestHandler):
|
|||||||
template = loader.get_template('cas_server/serviceValidate.xml')
|
template = loader.get_template('cas_server/serviceValidate.xml')
|
||||||
context = Context({
|
context = Context({
|
||||||
'username': self.server.username,
|
'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"))
|
self.wfile.write(return_bytes(template.render(context), "utf8"))
|
||||||
else:
|
else:
|
||||||
@ -301,6 +303,8 @@ class DummyCAS(BaseHTTPServer.BaseHTTPRequestHandler):
|
|||||||
'ResponseID': utils.gen_saml_id(),
|
'ResponseID': utils.gen_saml_id(),
|
||||||
'username': self.server.username,
|
'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"))
|
self.wfile.write(return_bytes(template.render(context), "utf8"))
|
||||||
else:
|
else:
|
||||||
|
@ -1153,7 +1153,9 @@ class ValidateService(View):
|
|||||||
params = {
|
params = {
|
||||||
'username': self.ticket.username(),
|
'username': self.ticket.username(),
|
||||||
'attributes': self.ticket.attributs_flat(),
|
'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 pgtUrl is set, require https or localhost
|
||||||
if self.pgt_url and (
|
if self.pgt_url and (
|
||||||
@ -1415,7 +1417,10 @@ class SamlValidate(CsrfExemptView):
|
|||||||
'Recipient': self.target,
|
'Recipient': self.target,
|
||||||
'ResponseID': utils.gen_saml_id(),
|
'ResponseID': utils.gen_saml_id(),
|
||||||
'username': self.ticket.username(),
|
'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(
|
logger.info(
|
||||||
"SamlValidate: ticket %s validated for user %s on service %s." % (
|
"SamlValidate: ticket %s validated for user %s on service %s." % (
|
||||||
|
Loading…
Reference in New Issue
Block a user