Skip to content

Commit 7fe509c

Browse files
committed
merge conflicts
2 parents 14e7d95 + a40b562 commit 7fe509c

File tree

6 files changed

+108
-34
lines changed

6 files changed

+108
-34
lines changed

README.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -676,7 +676,7 @@ example::
676676

677677
cd tests/
678678
coverage erase
679-
coverage run ./manage.py test djangosaml2
679+
coverage run ./manage.py test djangosaml2 testprofiles
680680
coverage report -m
681681

682682

djangosaml2/tests/__init__.py

Lines changed: 100 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -17,51 +17,65 @@
1717
import datetime
1818
import re
1919
import sys
20-
20+
from importlib import import_module
2121
from unittest import mock, skip
22+
from urllib.parse import parse_qs, urlparse
2223

2324
from django.conf import settings
2425
from django.contrib.auth import SESSION_KEY, get_user_model
2526
from django.contrib.auth.models import AnonymousUser
27+
from django.core.exceptions import ImproperlyConfigured
2628
from django.http.request import HttpRequest
2729
from django.template import Context, Template
28-
from django.test import TestCase, Client
30+
from django.test import Client, TestCase
2931
from django.test.client import RequestFactory
32+
from django.urls import reverse
33+
from django.utils.encoding import force_text
3034
from djangosaml2 import views
3135
from djangosaml2.cache import OutstandingQueriesCache
3236
from djangosaml2.conf import get_config
3337
from djangosaml2.middleware import SamlSessionMiddleware
3438
from djangosaml2.signals import post_authenticated, pre_user_save
3539
from djangosaml2.tests import conf
36-
from djangosaml2.tests.utils import SAMLPostFormParser
3740
from djangosaml2.tests.auth_response import auth_response
38-
from djangosaml2.views import finish_logout
39-
from djangosaml2.utils import (saml2_from_httpredirect_request,
41+
from djangosaml2.tests.utils import SAMLPostFormParser
42+
from djangosaml2.utils import (get_idp_sso_supported_bindings,
4043
get_session_id_from_saml2,
41-
get_subject_id_from_saml2)
42-
from importlib import import_module
44+
get_subject_id_from_saml2,
45+
saml2_from_httpredirect_request)
46+
from djangosaml2.views import finish_logout
4347
from saml2.config import SPConfig
4448
from saml2.s_utils import decode_base64_and_inflate, deflate_and_base64_encode
4549

46-
try:
47-
from django.urls import reverse
48-
except ImportError:
49-
from django.core.urlresolvers import reverse
50-
try:
51-
from django.utils.encoding import force_text
52-
except ImportError:
53-
from django.utils.text import force_text
54-
try:
55-
from django.utils.six.moves.urllib.parse import urlparse, parse_qs
56-
except ImportError:
57-
from urllib.parse import urlparse, parse_qs
58-
59-
6050
User = get_user_model()
6151

6252
PY_VERSION = sys.version_info[:2]
6353

6454

55+
def dummy_loader(request):
56+
return 'dummy_loader'
57+
58+
59+
non_callable = 'just a string'
60+
61+
62+
class UtilsTests(TestCase):
63+
def test_get_config_valid_path(self):
64+
self.assertEqual(get_config('djangosaml2.tests.dummy_loader'), 'dummy_loader')
65+
66+
def test_get_config_wrongly_formatted_path(self):
67+
with self.assertRaisesMessage(ImproperlyConfigured, 'SAML config loader must be a callable object.'):
68+
get_config('djangosaml2.tests.non_callable')
69+
70+
def test_get_config_nonsense_path(self):
71+
with self.assertRaisesMessage(ImproperlyConfigured, 'Error importing SAML config loader lalala.nonexisting.blabla: "No module named \'lalala\'"'):
72+
get_config('lalala.nonexisting.blabla')
73+
74+
def test_get_config_missing_function(self):
75+
with self.assertRaisesMessage(ImproperlyConfigured, 'Module "djangosaml2.tests" does not define a "nonexisting_function" config loader'):
76+
get_config('djangosaml2.tests.nonexisting_function')
77+
78+
6579
class SAML2Tests(TestCase):
6680

6781
urls = 'djangosaml2.tests.urls'
@@ -117,6 +131,32 @@ def render_template(self, text):
117131
def b64_for_post(self, xml_text, encoding='utf-8'):
118132
return base64.b64encode(xml_text.encode(encoding)).decode('ascii')
119133

134+
def test_get_idp_sso_supported_bindings_noargs(self):
135+
settings.SAML_CONFIG = conf.create_conf(
136+
sp_host='sp.example.com',
137+
idp_hosts=['idp.example.com'],
138+
metadata_file='remote_metadata_one_idp.xml',
139+
)
140+
idp_id = 'https://idp.example.com/simplesaml/saml2/idp/metadata.php'
141+
self.assertEqual(list(get_idp_sso_supported_bindings())[0], list(settings.SAML_CONFIG['service']['sp']['idp'][idp_id]['single_sign_on_service'].keys())[0])
142+
143+
def test_get_idp_sso_supported_bindings_unknown_idp(self):
144+
settings.SAML_CONFIG = conf.create_conf(
145+
sp_host='sp.example.com',
146+
idp_hosts=['idp.example.com'],
147+
metadata_file='remote_metadata_one_idp.xml',
148+
)
149+
self.assertEqual(get_idp_sso_supported_bindings(idp_entity_id='random'), [])
150+
151+
def test_get_idp_sso_supported_bindings_no_idps(self):
152+
settings.SAML_CONFIG = conf.create_conf(
153+
sp_host='sp.example.com',
154+
idp_hosts=[],
155+
metadata_file='remote_metadata_no_idp.xml',
156+
)
157+
with self.assertRaisesMessage(ImproperlyConfigured, "No IdP configured!"):
158+
get_idp_sso_supported_bindings()
159+
120160
def test_unsigned_post_authn_request(self):
121161
"""
122162
Test that unsigned authentication requests via POST binding
@@ -161,6 +201,24 @@ def test_login_evil_redirect(self):
161201

162202
self.assertEqual(params['RelayState'], [settings.LOGIN_REDIRECT_URL, ])
163203

204+
def test_no_redirect(self):
205+
"""
206+
Make sure that if we give an empty path as the next parameter,
207+
it is replaced with the default LOGIN_REDIRECT_URL.
208+
"""
209+
210+
# monkey patch SAML configuration
211+
settings.SAML_CONFIG = conf.create_conf(
212+
sp_host='sp.example.com',
213+
idp_hosts=['idp.example.com'],
214+
metadata_file='remote_metadata_one_idp.xml',
215+
)
216+
response = self.client.get(reverse('saml2_login') + '?next=')
217+
url = urlparse(response['Location'])
218+
params = parse_qs(url.query)
219+
220+
self.assertEqual(params['RelayState'], [settings.LOGIN_REDIRECT_URL, ])
221+
164222
def test_login_one_idp(self):
165223
# monkey patch SAML configuration
166224
settings.SAML_CONFIG = conf.create_conf(
@@ -236,7 +294,6 @@ def test_login_several_idps(self):
236294
if 'AuthnRequest xmlns' not in decode_base64_and_inflate(saml_request).decode('utf-8'):
237295
raise Exception('Not a valid AuthnRequest')
238296

239-
240297
def test_assertion_consumer_service(self):
241298
# Get initial number of users
242299
initial_user_count = User.objects.count()
@@ -293,6 +350,27 @@ def test_assertion_consumer_service(self):
293350
self.assertEqual(url.path, settings.LOGIN_REDIRECT_URL)
294351
self.assertEqual(force_text(new_user.id), client.session[SESSION_KEY])
295352

353+
def test_assertion_consumer_service_already_logged_in_allowed(self):
354+
self.client.force_login(User.objects.create(username='user', password='pass'))
355+
356+
settings.SAML_IGNORE_AUTHENTICATED_USERS_ON_LOGIN = True
357+
358+
came_from = '/dummy-url/'
359+
response = self.client.get(reverse('saml2_login') + f'?next={came_from}')
360+
self.assertEqual(response.status_code, 302)
361+
url = urlparse(response['Location'])
362+
self.assertEqual(url.path, came_from)
363+
364+
def test_assertion_consumer_service_already_logged_in_error(self):
365+
self.client.force_login(User.objects.create(username='user', password='pass'))
366+
367+
settings.SAML_IGNORE_AUTHENTICATED_USERS_ON_LOGIN = False
368+
369+
came_from = '/dummy-url/'
370+
response = self.client.get(reverse('saml2_login') + f'?next={came_from}')
371+
self.assertEqual(response.status_code, 200)
372+
self.assertInHTML("<p>You are already logged in and you are trying to go to the login page again.</p>", response.content.decode())
373+
296374
def test_assertion_consumer_service_no_session(self):
297375
settings.SAML_CONFIG = conf.create_conf(
298376
sp_host='sp.example.com',
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
<?xml version="1.0"?>
2+
<md:EntitiesDescriptor xmlns:md="urn:oasis:names:tc:SAML:2.0:metadata" xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
3+
</md:EntitiesDescriptor>

djangosaml2/views.py

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
from django.conf import settings
2020
from django.contrib import auth
2121
from django.contrib.auth.decorators import login_required
22+
from django.contrib.auth.views import LogoutView
2223
from django.core.exceptions import PermissionDenied, SuspiciousOperation
2324
from django.http import HttpResponseBadRequest # 40x
2425
from django.http import HttpResponseRedirect # 30x
@@ -31,7 +32,7 @@
3132
from django.views.generic import View
3233
from saml2 import BINDING_HTTP_POST, BINDING_HTTP_REDIRECT
3334
from saml2.client_base import LogoutError
34-
from saml2.config import SPConfig
35+
# from saml2.config import SPConfig
3536
from saml2.ident import code, decode
3637
from saml2.mdstore import SourceNotFound
3738
from saml2.metadata import entity_descriptor
@@ -54,13 +55,6 @@
5455
get_idp_sso_supported_bindings, get_location,
5556
validate_referral_url)
5657

57-
try:
58-
from django.contrib.auth.views import LogoutView
59-
django_logout = LogoutView.as_view()
60-
except ImportError:
61-
from django.contrib.auth.views import logout as django_logout
62-
63-
6458
logger = logging.getLogger('djangosaml2')
6559

6660

@@ -569,7 +563,7 @@ def finish_logout(request, response, next_page=None):
569563
next_page = settings.LOGOUT_REDIRECT_URL
570564
logger.debug('Performing django logout with a next_page of %s',
571565
next_page)
572-
return django_logout(request, next_page=next_page)
566+
return LogoutView.as_view()(request, next_page=next_page)
573567
else:
574568
logger.error('Unknown error during the logout')
575569
return render(request, "djangosaml2/logout_error.html", {})

tests/testprofiles/__init__.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +0,0 @@
1-

tests/testprofiles/tests.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323

2424
from djangosaml2.backends import Saml2Backend, set_attribute
2525

26-
from .models import TestUser
26+
from testprofiles.models import TestUser
2727

2828

2929
class BackendUtilMethodsTests(TestCase):

0 commit comments

Comments
 (0)