SingleLogOut unit tests

This commit is contained in:
Valentin Samir 2016-06-29 20:51:58 +02:00
parent d4b9d66051
commit 3334f87601
4 changed files with 77 additions and 42 deletions

View file

@ -20,7 +20,6 @@ from django.utils import timezone
from picklefield.fields import PickledObjectField from picklefield.fields import PickledObjectField
import re import re
import os
import sys import sys
import logging import logging
from importlib import import_module from importlib import import_module
@ -428,46 +427,27 @@ class Ticket(models.Model):
self.user.username self.user.username
) )
) )
try: xml = u"""<samlp:LogoutRequest xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol"
xml = u"""<samlp:LogoutRequest xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" ID="%(id)s" Version="2.0" IssueInstant="%(datetime)s">
ID="%(id)s" Version="2.0" IssueInstant="%(datetime)s"> <saml:NameID xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion"></saml:NameID>
<saml:NameID xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion"></saml:NameID> <samlp:SessionIndex>%(ticket)s</samlp:SessionIndex>
<samlp:SessionIndex>%(ticket)s</samlp:SessionIndex> </samlp:LogoutRequest>""" % \
</samlp:LogoutRequest>""" % \ {
{ 'id': utils.gen_saml_id(),
'id': os.urandom(20).encode("hex"), 'datetime': timezone.now().isoformat(),
'datetime': timezone.now().isoformat(), 'ticket': self.value
'ticket': self.value }
} if self.service_pattern.single_log_out_callback:
if self.service_pattern.single_log_out_callback: url = self.service_pattern.single_log_out_callback
url = self.service_pattern.single_log_out_callback else:
else: url = self.service
url = self.service async_list.append(
async_list.append( session.post(
session.post( url.encode('utf-8'),
url.encode('utf-8'), data={'logoutRequest': xml.encode('utf-8')},
data={'logoutRequest': xml.encode('utf-8')}, timeout=settings.CAS_SLO_TIMEOUT
timeout=settings.CAS_SLO_TIMEOUT
)
) )
except Exception as error: )
error = utils.unpack_nested_exception(error)
logger.warning(
"Error durring SLO for user %s on service %s: %s" % (
self.user.username,
self.service,
error
)
)
if request is not None:
messages.add_message(
request,
messages.WARNING,
_(u'Error during service logout %(service)s:\n%(error)s') %
{'service': self.service, 'error': error}
)
else:
sys.stderr.write("%r\n" % error)
class ServiceTicket(Ticket): class ServiceTicket(Ticket):

View file

@ -1,3 +1,4 @@
"""Tests module for utils"""
from django.test import TestCase from django.test import TestCase
import six import six

View file

@ -20,7 +20,8 @@ from cas_server.tests.utils import (
get_auth_client, get_auth_client,
get_user_ticket_request, get_user_ticket_request,
get_pgt, get_pgt,
get_proxy_ticket get_proxy_ticket,
get_validated_ticket
) )
from cas_server.tests.mixin import BaseServicePattern, XmlContent from cas_server.tests.mixin import BaseServicePattern, XmlContent
@ -386,6 +387,15 @@ class LoginTestCase(TestCase, BaseServicePattern):
@override_settings(CAS_AUTH_CLASS='cas_server.auth.TestAuthUser') @override_settings(CAS_AUTH_CLASS='cas_server.auth.TestAuthUser')
class LogoutTestCase(TestCase): class LogoutTestCase(TestCase):
"""test fot the logout view""" """test fot the logout view"""
def setUp(self):
self.service = 'http://127.0.0.1:45678'
self.service_pattern = models.ServicePattern.objects.create(
name="localhost",
pattern="^https?://127\.0\.0\.1(:[0-9]+)?(/.*)?$",
single_log_out=True
)
models.ReplaceAttributName.objects.create(name="*", service_pattern=self.service_pattern)
def test_logout(self): def test_logout(self):
"""logout is idempotent""" """logout is idempotent"""
client = Client() client = Client()
@ -477,6 +487,37 @@ class LogoutTestCase(TestCase):
response = client.get('/logout?service=https://www.example.com') response = client.get('/logout?service=https://www.example.com')
self.assert_redirect_to_service(client, response) self.assert_redirect_to_service(client, response)
def test_logout_slo(self):
"""test logout from a service with SLO support"""
(httpd, host, port) = utils.HttpParamsHandler.run()[0:3]
service = "http://%s:%s" % (host, port)
(client, ticket) = get_validated_ticket(service)[:2]
client.get('/logout')
params = httpd.PARAMS
self.assertTrue(b'logoutRequest' in params and params[b'logoutRequest'])
root = etree.fromstring(params[b'logoutRequest'][0])
self.assertTrue(
root.xpath(
"//samlp:LogoutRequest",
namespaces={"samlp": "urn:oasis:names:tc:SAML:2.0:protocol"}
)
)
session_index = root.xpath(
"//samlp:SessionIndex",
namespaces={"samlp": "urn:oasis:names:tc:SAML:2.0:protocol"}
)
self.assertEqual(len(session_index), 1)
self.assertEqual(session_index[0].text, ticket.value)
# SLO error are displayed on logout page
(client, ticket) = get_validated_ticket(self.service)[:2]
response = client.get('/logout')
self.assertTrue(b"Error during service logout" in response.content)
def test_ajax_logout(self): def test_ajax_logout(self):
"""test ajax logout""" """test ajax logout"""
client = get_auth_client() client = get_auth_client()

View file

@ -50,7 +50,19 @@ def get_user_ticket_request(service):
session_key=client.session.session_key session_key=client.session.session_key
) )
ticket = models.ServiceTicket.objects.get(value=ticket_value) ticket = models.ServiceTicket.objects.get(value=ticket_value)
return (user, ticket) return (user, ticket, client)
def get_validated_ticket(service):
(ticket, auth_client) = get_user_ticket_request(service)[1:3]
client = Client()
response = client.get('/validate', {'ticket': ticket.value, 'service': service})
assert (response.status_code == 200)
assert (response.content == b'yes\ntest\n')
ticket = models.ServiceTicket.objects.get(value=ticket.value)
return (auth_client, ticket)
def get_pgt(): def get_pgt():
@ -71,6 +83,7 @@ def get_pgt():
def get_proxy_ticket(service): def get_proxy_ticket(service):
"""Return a ProxyTicket waiting for validation"""
params = get_pgt() params = get_pgt()
# get a proxy ticket # get a proxy ticket