Skip to content

Commit 094dfcf

Browse files
committed
chore: coverage improved, better handling of unknown idp entity id
1 parent 86a5dc7 commit 094dfcf

File tree

3 files changed

+40
-17
lines changed

3 files changed

+40
-17
lines changed

djangosaml2/tests/__init__.py

+16-3
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,9 @@
4040
saml2_from_httpredirect_request)
4141
from djangosaml2.views import (EchoAttributesView, finish_logout)
4242
from saml2.config import SPConfig
43-
from saml2.s_utils import decode_base64_and_inflate, deflate_and_base64_encode
43+
from saml2.s_utils import (decode_base64_and_inflate,
44+
deflate_and_base64_encode,
45+
UnknownSystemEntity)
4446

4547
from .auth_response import auth_response
4648
from .utils import SAMLPostFormParser
@@ -114,8 +116,9 @@ def test_get_idp_sso_supported_bindings_unknown_idp(self):
114116
idp_hosts=['idp.example.com'],
115117
metadata_file='remote_metadata_one_idp.xml',
116118
)
117-
self.assertEqual(get_idp_sso_supported_bindings(
118-
idp_entity_id='random'), [])
119+
120+
with self.assertRaises(UnknownSystemEntity):
121+
get_idp_sso_supported_bindings(idp_entity_id='random')
119122

120123
def test_get_idp_sso_supported_bindings_no_idps(self):
121124
settings.SAML_CONFIG = conf.create_conf(
@@ -189,6 +192,16 @@ def test_no_redirect(self):
189192

190193
self.assertEqual(params['RelayState'], [settings.LOGIN_REDIRECT_URL, ])
191194

195+
def test_unknown_idp(self):
196+
# monkey patch SAML configuration
197+
settings.SAML_CONFIG = conf.create_conf(
198+
sp_host='sp.example.com',
199+
metadata_file='remote_metadata_three_idps.xml',
200+
)
201+
202+
response = self.client.get(reverse('saml2_login')+'?idp=https://unknown.org')
203+
self.assertEqual(response.status_code, 403)
204+
192205
def test_login_one_idp(self):
193206
# monkey patch SAML configuration
194207
settings.SAML_CONFIG = conf.create_conf(

djangosaml2/utils.py

+3-2
Original file line numberDiff line numberDiff line change
@@ -68,8 +68,9 @@ def get_idp_sso_supported_bindings(idp_entity_id: Optional[str] = None, config:
6868
try:
6969
return list(meta.service(idp_entity_id, 'idpsso_descriptor', 'single_sign_on_service').keys())
7070
except UnknownSystemEntity:
71-
return []
72-
71+
raise UnknownSystemEntity
72+
except Exception as e:
73+
logger.error(f"get_idp_sso_supported_bindings failed with: {e}")
7374

7475
def get_location(http_info):
7576
"""Extract the redirect URL from a pysaml2 http_info object"""

djangosaml2/views.py

+21-12
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,13 @@ def get_next_path(self, request: HttpRequest) -> str:
125125
next_path = validate_referral_url(request, next_path)
126126
return next_path
127127

128+
def unknown_idp(self, request, idp):
129+
msg = (f'Error: IdP EntityID {idp} was not found in metadata')
130+
logger.error(msg)
131+
return HttpResponse(
132+
msg.format('Please contact technical support.'), status=403
133+
)
134+
128135
def get(self, request, *args, **kwargs):
129136
logger.debug('Login process started')
130137
next_path = self.get_next_path(request)
@@ -149,10 +156,10 @@ def get(self, request, *args, **kwargs):
149156

150157
try:
151158
conf = self.get_sp_config(request)
152-
except SourceNotFound as excp:
153-
msg = ('Error, IdP EntityID was not found in metadata: {}')
154-
logger.exception(msg.format(excp))
155-
return HttpResponse(msg.format('Please contact technical support.'), status=500)
159+
except SourceNotFound as excp: # pragma: no cover
160+
# this is deprecated and it's here only for the doubts that something
161+
# would happen the day after I'll remove it! :)
162+
return self.unknown_idp(request, idp='unknown')
156163

157164
# is a embedded wayf or DiscoveryService needed?
158165
configured_idps = available_idps(conf)
@@ -186,9 +193,9 @@ def get(self, request, *args, **kwargs):
186193
})
187194

188195
# is the first one, otherwise next logger message will print None
189-
if not configured_idps:
196+
if not configured_idps: # pragma: no cover
190197
raise IdPConfigurationMissing(
191-
('IdP configuration is missing or its metadata is expired.'))
198+
('IdP is missing or its metadata is expired.'))
192199
if selected_idp is None:
193200
selected_idp = list(configured_idps.keys())[0]
194201

@@ -202,15 +209,17 @@ def get(self, request, *args, **kwargs):
202209
)
203210
sso_kwargs['scoping'] = idp_scoping
204211

205-
206212
# choose a binding to try first
207213
binding = getattr(settings, 'SAML_DEFAULT_BINDING',
208214
saml2.BINDING_HTTP_POST)
209215
logger.debug(f'Trying binding {binding} for IDP {selected_idp}')
210216

211217
# ensure our selected binding is supported by the IDP
212-
supported_bindings = get_idp_sso_supported_bindings(
213-
selected_idp, config=conf)
218+
try:
219+
supported_bindings = get_idp_sso_supported_bindings(
220+
selected_idp, config=conf)
221+
except saml2.s_utils.UnknownSystemEntity:
222+
return self.unknown_idp(request, selected_idp)
214223

215224
if binding not in supported_bindings:
216225
logger.debug(
@@ -223,17 +232,17 @@ def get(self, request, *args, **kwargs):
223232
f'trying {saml2.BINDING_HTTP_REDIRECT}',
224233
)
225234
binding = saml2.BINDING_HTTP_REDIRECT
226-
else:
235+
else: # pragma: no cover
227236
logger.warning(
228237
f'IDP {selected_idp} does not support {binding} '
229238
f'trying {saml2.BINDING_HTTP_POST}',
230239
)
231240
binding = saml2.BINDING_HTTP_POST
232241
# if switched binding still not supported, give up
233-
if binding not in supported_bindings:
242+
if binding not in supported_bindings: # pragma: no cover
234243
raise UnsupportedBinding(
235244
f'IDP {selected_idp} does not support '
236-
f'{saml2.BINDING_HTTP_POST} and {saml2.BINDING_HTTP_REDIRECT}'
245+
f'{saml2.BINDING_HTTP_POST} or {saml2.BINDING_HTTP_REDIRECT}'
237246
)
238247

239248
client = Saml2Client(conf)

0 commit comments

Comments
 (0)