PageRenderTime 26ms CodeModel.GetById 21ms RepoModel.GetById 1ms app.codeStats 0ms

/djangosaml2/tests/__init__.py

https://bitbucket.org/leifj/djangosaml2
Python | 417 lines | 384 code | 18 blank | 15 comment | 0 complexity | 230bc7a64413e368840f02de376b65d2 MD5 | raw file
Possible License(s): Apache-2.0
  1. # Copyright (C) 2011 Yaco Sistemas (http://www.yaco.es)
  2. # Copyright (C) 2010 Lorenzo Gil Sanchez <lorenzo.gil.sanchez@gmail.com>
  3. #
  4. # Licensed under the Apache License, Version 2.0 (the "License");
  5. # you may not use this file except in compliance with the License.
  6. # You may obtain a copy of the License at
  7. #
  8. # http://www.apache.org/licenses/LICENSE-2.0
  9. #
  10. # Unless required by applicable law or agreed to in writing, software
  11. # distributed under the License is distributed on an "AS IS" BASIS,
  12. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. # See the License for the specific language governing permissions and
  14. # limitations under the License.
  15. import datetime
  16. import base64
  17. import re
  18. import urlparse
  19. from django.conf import settings
  20. from django.contrib.auth import SESSION_KEY
  21. from django.contrib.auth.models import User
  22. from django.core.management import call_command
  23. from django.db.models import loading
  24. from django.template import Template, Context
  25. from django.test import TestCase
  26. from saml2.s_utils import decode_base64_and_inflate, deflate_and_base64_encode
  27. from djangosaml2 import views
  28. from djangosaml2.backends import Saml2Backend
  29. from djangosaml2.cache import OutstandingQueriesCache
  30. from djangosaml2.conf import get_config_loader
  31. from djangosaml2.tests import conf
  32. from djangosaml2.tests.auth_response import auth_response
  33. from djangosaml2.tests.models import TestProfile
  34. from djangosaml2.signals import post_authenticated
  35. class SAML2Tests(TestCase):
  36. urls = 'djangosaml2.urls'
  37. def assertSAMLRequestsEquals(self, xml1, xml2):
  38. def remove_variable_attributes(xml_string):
  39. xml_string = re.sub(r' ID=".*?" ', ' ', xml_string)
  40. xml_string = re.sub(r' IssueInstant=".*?" ', ' ', xml_string)
  41. xml_string = re.sub(
  42. r'<saml:NameID xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion">.*</saml:NameID>',
  43. '<saml:NameID xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion"></saml:NameID>',
  44. xml_string)
  45. return xml_string
  46. self.assertEquals(remove_variable_attributes(xml1),
  47. remove_variable_attributes(xml2))
  48. def init_cookies(self):
  49. self.client.cookies[settings.SESSION_COOKIE_NAME] = 'testing'
  50. def add_outstanding_query(self, session_id, came_from):
  51. session = self.client.session
  52. oq_cache = OutstandingQueriesCache(session)
  53. oq_cache.set(session_id, came_from)
  54. session.save()
  55. self.client.cookies[settings.SESSION_COOKIE_NAME] = session.session_key
  56. def render_template(self, text):
  57. return Template(text).render(Context())
  58. def test_login_one_idp(self):
  59. # monkey patch SAML configuration
  60. settings.SAML_CONFIG = conf.create_conf(sp_host='sp.example.com',
  61. idp_hosts=['idp.example.com'])
  62. response = self.client.get('/login/')
  63. self.assertEquals(response.status_code, 302)
  64. location = response['Location']
  65. url = urlparse.urlparse(location)
  66. self.assertEquals(url.hostname, 'idp.example.com')
  67. self.assertEquals(url.path, '/simplesaml/saml2/idp/SSOService.php')
  68. params = urlparse.parse_qs(url.query)
  69. self.assert_('SAMLRequest' in params)
  70. self.assert_('RelayState' in params)
  71. saml_request = params['SAMLRequest'][0]
  72. expected_request = """<?xml version='1.0' encoding='UTF-8'?>
  73. <samlp:AuthnRequest AssertionConsumerServiceURL="http://sp.example.com/saml2/acs/" Destination="https://idp.example.com/simplesaml/saml2/idp/SSOService.php" ID="XXXXXXXXXXXXXXXXXXXXXX" IssueInstant="2010-01-01T00:00:00Z" ProtocolBinding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" ProviderName="Test SP" Version="2.0" xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol"><saml:Issuer Format="urn:oasis:names:tc:SAML:2.0:nameid-format:entity" xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion">http://sp.example.com/saml2/metadata/</saml:Issuer><samlp:NameIDPolicy AllowCreate="true" Format="urn:oasis:names:tc:SAML:2.0:nameid-format:transient" /></samlp:AuthnRequest>"""
  74. xml = decode_base64_and_inflate(saml_request)
  75. self.assertSAMLRequestsEquals(expected_request, xml)
  76. # if we set a next arg in the login view, it is preserverd
  77. # in the RelayState argument
  78. next = '/another-view/'
  79. response = self.client.get('/login/', {'next': next})
  80. self.assertEquals(response.status_code, 302)
  81. location = response['Location']
  82. url = urlparse.urlparse(location)
  83. self.assertEquals(url.hostname, 'idp.example.com')
  84. self.assertEquals(url.path, '/simplesaml/saml2/idp/SSOService.php')
  85. params = urlparse.parse_qs(url.query)
  86. self.assert_('SAMLRequest' in params)
  87. self.assert_('RelayState' in params)
  88. self.assertEquals(params['RelayState'][0], next)
  89. def test_login_several_idps(self):
  90. settings.SAML_CONFIG = conf.create_conf(sp_host='sp.example.com',
  91. idp_hosts=['idp1.example.com',
  92. 'idp2.example.com',
  93. 'idp3.example.com'])
  94. response = self.client.get('/login/')
  95. # a WAYF page should be displayed
  96. self.assertContains(response, 'Where are you from?', status_code=200)
  97. for i in range(1, 4):
  98. link = '/login/?idp=https://idp%d.example.com/simplesaml/saml2/idp/metadata.php&next=/'
  99. self.assertContains(response, link % i)
  100. # click on the second idp
  101. response = self.client.get('/login/', {
  102. 'idp': 'https://idp2.example.com/simplesaml/saml2/idp/metadata.php',
  103. 'next': '/',
  104. })
  105. self.assertEquals(response.status_code, 302)
  106. location = response['Location']
  107. url = urlparse.urlparse(location)
  108. self.assertEquals(url.hostname, 'idp2.example.com')
  109. self.assertEquals(url.path, '/simplesaml/saml2/idp/SSOService.php')
  110. params = urlparse.parse_qs(url.query)
  111. self.assert_('SAMLRequest' in params)
  112. self.assert_('RelayState' in params)
  113. saml_request = params['SAMLRequest'][0]
  114. expected_request = """<?xml version='1.0' encoding='UTF-8'?>
  115. <samlp:AuthnRequest AssertionConsumerServiceURL="http://sp.example.com/saml2/acs/" Destination="https://idp2.example.com/simplesaml/saml2/idp/SSOService.php" ID="XXXXXXXXXXXXXXXXXXXXXX" IssueInstant="2010-01-01T00:00:00Z" ProtocolBinding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" ProviderName="Test SP" Version="2.0" xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol"><saml:Issuer Format="urn:oasis:names:tc:SAML:2.0:nameid-format:entity" xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion">http://sp.example.com/saml2/metadata/</saml:Issuer><samlp:NameIDPolicy AllowCreate="true" Format="urn:oasis:names:tc:SAML:2.0:nameid-format:transient" /></samlp:AuthnRequest>"""
  116. xml = decode_base64_and_inflate(saml_request)
  117. self.assertSAMLRequestsEquals(expected_request, xml)
  118. def test_assertion_consumer_service(self):
  119. # there are no users in the database
  120. self.assertEquals(User.objects.count(), 0)
  121. settings.SAML_CONFIG = conf.create_conf(sp_host='sp.example.com',
  122. idp_hosts=['idp.example.com'])
  123. config = get_config_loader(views.DEFAULT_CONFIG_LOADER)
  124. # session_id should start with a letter since it is a NCName
  125. session_id = "a0123456789abcdef0123456789abcdef"
  126. came_from = '/another-view/'
  127. saml_response = auth_response({'uid': 'student'}, session_id, config)
  128. self.init_cookies()
  129. self.add_outstanding_query(session_id, came_from)
  130. # this will create a user
  131. response = self.client.post('/acs/', {
  132. 'SAMLResponse': base64.b64encode(str(saml_response)),
  133. 'RelayState': came_from,
  134. })
  135. self.assertEquals(response.status_code, 302)
  136. location = response['Location']
  137. url = urlparse.urlparse(location)
  138. self.assertEquals(url.hostname, 'testserver')
  139. self.assertEquals(url.path, came_from)
  140. self.assertEquals(User.objects.count(), 1)
  141. user_id = self.client.session[SESSION_KEY]
  142. user = User.objects.get(id=user_id)
  143. self.assertEquals(user.username, 'student')
  144. # let's create another user and log in with that one
  145. new_user = User.objects.create(username='teacher', password='not-used')
  146. session_id = "a1111111111111111111111111111111"
  147. came_from = '/'
  148. saml_response = auth_response({'uid': 'teacher'}, session_id, config)
  149. self.add_outstanding_query(session_id, came_from)
  150. response = self.client.post('/acs/', {
  151. 'SAMLResponse': base64.b64encode(str(saml_response)),
  152. 'RelayState': came_from,
  153. })
  154. self.assertEquals(response.status_code, 302)
  155. self.assertEquals(new_user.id, self.client.session[SESSION_KEY])
  156. def do_login(self):
  157. """Auxiliary method used in several tests (mainly logout tests)"""
  158. config = get_config_loader(views.DEFAULT_CONFIG_LOADER)
  159. session_id = "a0123456789abcdef0123456789abcdef"
  160. came_from = '/another-view/'
  161. saml_response = auth_response({'uid': 'student'}, session_id, config)
  162. self.init_cookies()
  163. self.add_outstanding_query(session_id, came_from)
  164. # this will create a user
  165. response = self.client.post('/acs/', {
  166. 'SAMLResponse': base64.b64encode(str(saml_response)),
  167. 'RelayState': came_from,
  168. })
  169. self.assertEquals(response.status_code, 302)
  170. def test_logout(self):
  171. settings.SAML_CONFIG = conf.create_conf(sp_host='sp.example.com',
  172. idp_hosts=['idp.example.com'])
  173. self.do_login()
  174. response = self.client.get('/logout/')
  175. self.assertEquals(response.status_code, 302)
  176. location = response['Location']
  177. url = urlparse.urlparse(location)
  178. self.assertEquals(url.hostname, 'idp.example.com')
  179. self.assertEquals(url.path,
  180. '/simplesaml/saml2/idp/SingleLogoutService.php')
  181. params = urlparse.parse_qs(url.query)
  182. self.assert_('SAMLRequest' in params)
  183. saml_request = params['SAMLRequest'][0]
  184. expected_request = """<?xml version='1.0' encoding='UTF-8'?>
  185. <samlp:LogoutRequest Destination="https://idp.example.com/simplesaml/saml2/idp/SingleLogoutService.php" ID="XXXXXXXXXXXXXXXXXXXXXX" IssueInstant="2010-01-01T00:00:00Z" Version="2.0" xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol"><saml:Issuer Format="urn:oasis:names:tc:SAML:2.0:nameid-format:entity" xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion">http://sp.example.com/saml2/metadata/</saml:Issuer><saml:NameID xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion">58bcc81ea14700f66aeb707a0eff1360</saml:NameID></samlp:LogoutRequest>"""
  186. xml = decode_base64_and_inflate(saml_request)
  187. self.assertSAMLRequestsEquals(expected_request, xml)
  188. def test_logout_service_local(self):
  189. settings.SAML_CONFIG = conf.create_conf(sp_host='sp.example.com',
  190. idp_hosts=['idp.example.com'])
  191. self.do_login()
  192. response = self.client.get('/logout/')
  193. self.assertEquals(response.status_code, 302)
  194. location = response['Location']
  195. url = urlparse.urlparse(location)
  196. self.assertEquals(url.hostname, 'idp.example.com')
  197. self.assertEquals(url.path,
  198. '/simplesaml/saml2/idp/SingleLogoutService.php')
  199. params = urlparse.parse_qs(url.query)
  200. self.assert_('SAMLRequest' in params)
  201. saml_request = params['SAMLRequest'][0]
  202. expected_request = """<?xml version='1.0' encoding='UTF-8'?>
  203. <samlp:LogoutRequest Destination="https://idp.example.com/simplesaml/saml2/idp/SingleLogoutService.php" ID="XXXXXXXXXXXXXXXXXXXXXX" IssueInstant="2010-01-01T00:00:00Z" Version="2.0" xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol"><saml:Issuer Format="urn:oasis:names:tc:SAML:2.0:nameid-format:entity" xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion">http://sp.example.com/saml2/metadata/</saml:Issuer><saml:NameID xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion">58bcc81ea14700f66aeb707a0eff1360</saml:NameID></samlp:LogoutRequest>"""
  204. xml = decode_base64_and_inflate(saml_request)
  205. self.assertSAMLRequestsEquals(expected_request, xml)
  206. # now simulate a logout response sent by the idp
  207. request_id = re.findall(r' ID="(.*?)" ', xml)[0]
  208. instant = datetime.datetime.now().strftime('%Y-%m-%dT%H:%M:%SZ')
  209. saml_response = """<?xml version='1.0' encoding='UTF-8'?>
  210. <samlp:LogoutResponse Destination="http://sp.example.com/saml2/ls/" ID="a140848e7ce2bce834d7264ecdde0151" InResponseTo="%s" IssueInstant="%s" Version="2.0" xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol"><saml:Issuer Format="urn:oasis:names:tc:SAML:2.0:nameid-format:entity" xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion">https://idp.example.com/simplesaml/saml2/idp/metadata.php</saml:Issuer><samlp:Status><samlp:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success" /></samlp:Status></samlp:LogoutResponse>""" % (
  211. request_id, instant)
  212. response = self.client.get('/ls/', {
  213. 'SAMLResponse': deflate_and_base64_encode(saml_response),
  214. })
  215. self.assertContains(response, "Logged out", status_code=200)
  216. self.assertEquals(self.client.session.keys(), [])
  217. def test_logout_service_global(self):
  218. settings.SAML_CONFIG = conf.create_conf(sp_host='sp.example.com',
  219. idp_hosts=['idp.example.com'])
  220. self.do_login()
  221. # now simulate a global logout process initiated by another SP
  222. subject_id = views._get_subject_id(self.client.session)
  223. instant = datetime.datetime.now().strftime('%Y-%m-%dT%H:%M:%SZ')
  224. saml_request = '<samlp:LogoutRequest ID="_9961abbaae6d06d251226cb25e38bf8f468036e57e" Version="2.0" IssueInstant="%s" Destination="http://sp.example.com/saml2/ls/" xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol"><saml:Issuer xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion">https://idp.example.com/simplesaml/saml2/idp/metadata.php</saml:Issuer><saml:NameID SPNameQualifier="http://sp.example.com/saml2/metadata/" Format="urn:oasis:names:tc:SAML:2.0:nameid-format:transient" xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion">%s</saml:NameID><samlp:SessionIndex>_1837687b7bc9faad85839dbeb319627889f3021757</samlp:SessionIndex></samlp:LogoutRequest>' % (
  225. instant, subject_id)
  226. response = self.client.get('/ls/', {
  227. 'SAMLRequest': deflate_and_base64_encode(saml_request),
  228. })
  229. self.assertEquals(response.status_code, 302)
  230. location = response['Location']
  231. url = urlparse.urlparse(location)
  232. self.assertEquals(url.hostname, 'idp.example.com')
  233. self.assertEquals(url.path,
  234. '/simplesaml/saml2/idp/SingleLogoutService.php')
  235. params = urlparse.parse_qs(url.query)
  236. self.assert_('SAMLResponse' in params)
  237. saml_response = params['SAMLResponse'][0]
  238. expected_response = """<?xml version='1.0' encoding='UTF-8'?>
  239. <samlp:LogoutResponse Destination="https://idp.example.com/simplesaml/saml2/idp/SingleLogoutService.php" ID="a140848e7ce2bce834d7264ecdde0151" InResponseTo="_9961abbaae6d06d251226cb25e38bf8f468036e57e" IssueInstant="2010-09-05T09:10:12Z" Version="2.0" xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol"><saml:Issuer Format="urn:oasis:names:tc:SAML:2.0:nameid-format:entity" xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion">http://sp.example.com/saml2/metadata/</saml:Issuer><samlp:Status><samlp:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success" /></samlp:Status></samlp:LogoutResponse>"""
  240. xml = decode_base64_and_inflate(saml_response)
  241. self.assertSAMLRequestsEquals(expected_response, xml)
  242. def test_metadata(self):
  243. settings.SAML_CONFIG = conf.create_conf(sp_host='sp.example.com',
  244. idp_hosts=['idp.example.com'])
  245. valid_until = datetime.datetime.utcnow() + datetime.timedelta(hours=24)
  246. valid_until = valid_until.strftime("%Y-%m-%dT%H:%M:%SZ")
  247. expected_metadata = """<?xml version='1.0' encoding='UTF-8'?>
  248. <md:EntityDescriptor entityID="http://sp.example.com/saml2/metadata/" validUntil="%s" xmlns:md="urn:oasis:names:tc:SAML:2.0:metadata"><md:SPSSODescriptor AuthnRequestsSigned="false" WantAssertionsSigned="true" protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol"><md:KeyDescriptor><ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#"><ds:X509Data><ds:X509Certificate>MIIDPjCCAiYCCQCkHjPQlll+mzANBgkqhkiG9w0BAQUFADBhMQswCQYDVQQGEwJF
  249. UzEQMA4GA1UECBMHU2V2aWxsYTEbMBkGA1UEChMSWWFjbyBTaXN0ZW1hcyBTLkwu
  250. MRAwDgYDVQQHEwdTZXZpbGxhMREwDwYDVQQDEwh0aWNvdGljbzAeFw0wOTEyMDQx
  251. OTQzNTJaFw0xMDEyMDQxOTQzNTJaMGExCzAJBgNVBAYTAkVTMRAwDgYDVQQIEwdT
  252. ZXZpbGxhMRswGQYDVQQKExJZYWNvIFNpc3RlbWFzIFMuTC4xEDAOBgNVBAcTB1Nl
  253. dmlsbGExETAPBgNVBAMTCHRpY290aWNvMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A
  254. MIIBCgKCAQEA7rMOMOaIZ/YYD5hYS6Hpjpovcu4k8gaIY+om9zCxLV5F8BLEfkxo
  255. Pk9IA3cRQNRxf7AXCFxEOH3nKy56AIi1gU7X6fCT30JBT8NQlYdgOVMLlR+tjy1b
  256. YV07tDa9U8gzjTyKQHgVwH0436+rmSPnacGj3fMwfySTMhtmrJmax0bIa8EB+gY1
  257. 77DBtvf8dIZIXLlGMQFloZeUspvHOrgNoEA9xU4E9AanGnV9HeV37zv3mLDUOQLx
  258. 4tk9sMQmylCpij7WZmcOV07DyJ/cEmnvHSalBTcyIgkcwlhmjtSgfCy6o5zuWxYd
  259. T9ia80SZbWzn8N6B0q+nq23+Oee9H0lvcwIDAQABMA0GCSqGSIb3DQEBBQUAA4IB
  260. AQCQBhKOqucJZAqGHx4ybDXNzpPethszonLNVg5deISSpWagy55KlGCi5laio/xq
  261. hHRx18eTzeCeLHQYvTQxw0IjZOezJ1X30DD9lEqPr6C+IrmZc6bn/pF76xsvdaRS
  262. gduNQPT1B25SV2HrEmbf8wafSlRARmBsyUHh860TqX7yFVjhYIAUF/El9rLca51j
  263. ljCIqqvT+klPdjQoZwODWPFHgute2oNRmoIcMjSnoy1+mxOC2Q/j7kcD8/etulg2
  264. XDxB3zD81gfdtT8VBFP+G4UrBa+5zFk6fT6U8a7ZqVsyH+rCXAdCyVlEC4Y5fZri
  265. ID4zT0FcZASGuthM56rRJJSx
  266. </ds:X509Certificate></ds:X509Data></ds:KeyInfo></md:KeyDescriptor><md:SingleLogoutService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" Location="http://sp.example.com/saml2/ls/" /><md:AssertionConsumerService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Location="http://sp.example.com/saml2/acs/" index="1" /><md:AttributeConsumingService index="1"><md:ServiceName xml:lang="en">Test SP</md:ServiceName><md:RequestedAttribute FriendlyName="uid" Name="urn:oid:0.9.2342.19200300.100.1.1" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri" isRequired="true" /><md:RequestedAttribute FriendlyName="eduPersonAffiliation" Name="urn:oid:1.3.6.1.4.1.5923.1.1.1.1" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri" isRequired="false" /></md:AttributeConsumingService></md:SPSSODescriptor><md:Organization><md:OrganizationName xml:lang="es">Ejemplo S.A.</md:OrganizationName><md:OrganizationName xml:lang="en">Example Inc.</md:OrganizationName><md:OrganizationDisplayName xml:lang="es">Ejemplo</md:OrganizationDisplayName><md:OrganizationDisplayName xml:lang="en">Example</md:OrganizationDisplayName><md:OrganizationURL xml:lang="es">http://www.example.es</md:OrganizationURL><md:OrganizationURL xml:lang="en">http://www.example.com</md:OrganizationURL></md:Organization><md:ContactPerson contactType="technical"><md:Company>Example Inc.</md:Company><md:GivenName>Technical givenname</md:GivenName><md:SurName>Technical surname</md:SurName><md:EmailAddress>technical@sp.example.com</md:EmailAddress></md:ContactPerson><md:ContactPerson contactType="administrative"><md:Company>Example Inc.</md:Company><md:GivenName>Administrative givenname</md:GivenName><md:SurName>Administrative surname</md:SurName><md:EmailAddress>administrative@sp.example.ccom</md:EmailAddress></md:ContactPerson></md:EntityDescriptor>"""
  267. expected_metadata = expected_metadata % valid_until
  268. response = self.client.get('/metadata/')
  269. self.assertEquals(response['Content-type'], 'text/xml; charset=utf8')
  270. self.assertEquals(response.status_code, 200)
  271. self.assertEquals(response.content, expected_metadata)
  272. def test_post_authenticated_signal(self):
  273. def signal_handler(signal, user, session_info):
  274. self.assertEquals(isinstance(user, User), True)
  275. post_authenticated.connect(signal_handler, dispatch_uid='test_signal')
  276. self.do_login()
  277. post_authenticated.disconnect(dispatch_uid='test_signal')
  278. def test_idplist_templatetag(self):
  279. settings.SAML_CONFIG = conf.create_conf(sp_host='sp.example.com',
  280. idp_hosts=['idp1.example.com',
  281. 'idp2.example.com',
  282. 'idp3.example.com'])
  283. rendered = self.render_template(
  284. '{% load idplist %}'
  285. '{% idplist as idps %}'
  286. '{% for url, name in idps.items %}'
  287. '{{ url }} - {{ name }}; '
  288. '{% endfor %}'
  289. )
  290. expected = u'https://idp2.example.com/simplesaml/saml2/idp/metadata.php - idp2.example.com IdP; https://idp3.example.com/simplesaml/saml2/idp/metadata.php - idp3.example.com IdP; https://idp1.example.com/simplesaml/saml2/idp/metadata.php - idp1.example.com IdP; '
  291. self.assertEqual(rendered, expected)
  292. class Saml2BackendTests(TestCase):
  293. def setUp(self):
  294. # with Django 1.4 we can patch the settings in a much
  295. # better way
  296. self.old_installed_apps = settings.INSTALLED_APPS
  297. settings.INSTALLED_APPS += (
  298. 'djangosaml2.tests',
  299. )
  300. # create the database tables for the tests models
  301. loading.cache.loaded = False
  302. call_command('syncdb', verbosity=0)
  303. self.old_auth_profile_module = settings.AUTH_PROFILE_MODULE
  304. settings.AUTH_PROFILE_MODULE = 'tests.TestProfile'
  305. def tearDown(self):
  306. settings.INSTALLED_APPS = self.old_installed_apps
  307. settings.AUTH_PROFILE_MODULE = self.old_auth_profile_module
  308. def test_update_user(self):
  309. # we need a user
  310. user = User.objects.create(username='john')
  311. backend = Saml2Backend()
  312. attribute_mapping = {
  313. 'uid': ('username', ),
  314. 'mail': ('email', ),
  315. 'cn': ('first_name', ),
  316. 'sn': ('last_name', ),
  317. }
  318. attributes = {
  319. 'uid': ('john', ),
  320. 'mail': ('john@example.com', ),
  321. 'cn': ('John', ),
  322. 'sn': ('Doe', ),
  323. }
  324. backend.update_user(user, attributes, attribute_mapping)
  325. self.assertEquals(user.email, 'john@example.com')
  326. self.assertEquals(user.first_name, 'John')
  327. self.assertEquals(user.last_name, 'Doe')
  328. # now we create a user profile and link it to the user
  329. profile = TestProfile.objects.create(user=user)
  330. attribute_mapping['saml_age'] = ('age', )
  331. attributes['saml_age'] = ('22', )
  332. backend.update_user(user, attributes, attribute_mapping)
  333. self.assertEquals(user.get_profile().age, '22')