diff --git a/cas_server/cas.py b/cas_server/cas.py
index 06ce8d2..3ec08bc 100644
--- a/cas_server/cas.py
+++ b/cas_server/cas.py
@@ -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))
diff --git a/cas_server/templates/cas_server/samlValidate.xml b/cas_server/templates/cas_server/samlValidate.xml
index 63d5cb2..d61bed1 100644
--- a/cas_server/templates/cas_server/samlValidate.xml
+++ b/cas_server/templates/cas_server/samlValidate.xml
@@ -29,6 +29,15 @@
+
+ {{auth_date}}
+
+
+ false{# we do not support long-term (Remember-Me) auth #}
+
+
+ {{is_new_login}}
+
{% for name, value in attributes %}
{{value}}
diff --git a/cas_server/templates/cas_server/serviceValidate.xml b/cas_server/templates/cas_server/serviceValidate.xml
index e41a022..f583dbe 100644
--- a/cas_server/templates/cas_server/serviceValidate.xml
+++ b/cas_server/templates/cas_server/serviceValidate.xml
@@ -2,8 +2,14 @@
{{username}}
+ {{auth_date}}
+ false{# we do not support long-term (Remember-Me) auth #}
+ {{is_new_login}}
{% for key, value in attributes %} {{value}}
{% endfor %}
+
+
+
{% for key, value in attributes %}
{% endfor %}{% if proxyGrantingTicket %} {{proxyGrantingTicket}}
{% endif %}{% if proxies %}
diff --git a/cas_server/tests/mixin.py b/cas_server/tests/mixin.py
index d791b53..e6930a7 100644
--- a/cas_server/tests/mixin.py
+++ b/cas_server/tests/mixin.py
@@ -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):
diff --git a/cas_server/tests/test_view.py b/cas_server/tests/test_view.py
index 016db3e..ebdb8bd 100644
--- a/cas_server/tests/test_view.py
+++ b/cas_server/tests/test_view.py
@@ -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):
diff --git a/cas_server/tests/utils.py b/cas_server/tests/utils.py
index bee39cf..3c74516 100644
--- a/cas_server/tests/utils.py
+++ b/cas_server/tests/utils.py
@@ -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:
diff --git a/cas_server/views.py b/cas_server/views.py
index 9bd7606..3af4077 100644
--- a/cas_server/views.py
+++ b/cas_server/views.py
@@ -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." % (