|
1 | 1 | """ |
2 | 2 | Tests for the SAML frontend module src/backends/saml2.py. |
3 | 3 | """ |
4 | | -from urllib import parse |
5 | | -import re |
6 | 4 | import os.path |
| 5 | +import re |
| 6 | +from urllib.parse import urlparse, parse_qs, parse_qsl |
7 | 7 |
|
8 | | -from saml2 import BINDING_HTTP_POST |
| 8 | +from saml2 import BINDING_HTTP_POST, BINDING_HTTP_REDIRECT |
9 | 9 | from saml2.authn_context import PASSWORD |
10 | 10 | from saml2.config import IdPConfig |
11 | 11 | from saml2.entity_category.edugain import COC |
12 | 12 | from saml2.entity_category.swamid import RESEARCH_AND_EDUCATION, HEI, SFS_1993_1153, NREN, EU |
13 | | - |
14 | 13 | from saml2.extension.idpdisc import BINDING_DISCO |
15 | | - |
16 | 14 | from saml2.saml import NAME_FORMAT_URI, NAMEID_FORMAT_TRANSIENT, NAMEID_FORMAT_PERSISTENT |
17 | 15 |
|
18 | 16 | from satosa.backends.saml2 import SamlBackend |
|
33 | 31 | 'edupersontargetedid': {'saml': ['eduPersonTargetedID'], 'openid': ['sub'], |
34 | 32 | 'facebook': ['id']}, |
35 | 33 | 'name': {'saml': ['cn'], 'openid': ['name'], 'facebook': ['name']}, |
36 | | - 'address': {'openid': ['address->street_address'], 'saml': ['postaladdress']}, |
37 | 34 | 'surname': {'saml': ['sn', 'surname'], 'openid': ['family_name'], |
38 | | - 'facebook': ['last_name']}}, 'separator': '->'} |
| 35 | + 'facebook': ['last_name']}}} |
39 | 36 |
|
40 | 37 |
|
41 | 38 | class TestConfiguration(object): |
@@ -65,7 +62,7 @@ def __init__(self): |
65 | 62 | "name": "Proxy IdP", |
66 | 63 | "endpoints": { |
67 | 64 | "single_sign_on_service": [ |
68 | | - ("%s/sso/post" % idp_base, BINDING_HTTP_POST), |
| 65 | + ("%s/sso/redirect" % idp_base, BINDING_HTTP_REDIRECT), |
69 | 66 | ], |
70 | 67 | }, |
71 | 68 | "policy": { |
@@ -122,6 +119,12 @@ def __init__(self): |
122 | 119 | "sp_metadata") |
123 | 120 | idp_metadata = FileGenerator.get_instance().create_metadata(self.idpconfig, "idp_metadata") |
124 | 121 | self.spconfig["config"]["metadata"]["local"].append(idp_metadata.name) |
| 122 | + |
| 123 | + idp2_config = self.idpconfig.copy() |
| 124 | + idp2_config["entityid"] = "just_an_extra_idp" |
| 125 | + idp_metadata2 = FileGenerator.get_instance().create_metadata(idp2_config, "idp2_metadata") |
| 126 | + self.spconfig["config"]["metadata"]["local"].append(idp_metadata2.name) |
| 127 | + |
125 | 128 | self.idpconfig["metadata"]["local"].append(sp_metadata.name) |
126 | 129 |
|
127 | 130 | @staticmethod |
@@ -205,8 +208,7 @@ def test_start_auth_name_id_policy(): |
205 | 208 |
|
206 | 209 | assert resp.status == "303 See Other", "Must be a redirect to the discovery server." |
207 | 210 |
|
208 | | - disco_resp = parse.parse_qs(resp.message.replace( |
209 | | - TestConfiguration.get_instance().spconfig["disco_srv"] + "?", "")) |
| 211 | + disco_resp = parse_qs(urlparse(resp.message).query) |
210 | 212 | sp_config = TestConfiguration.get_instance().spconfig["config"] |
211 | 213 | sp_disco_resp = sp_config["service"]["sp"]["endpoints"]["discovery_response"][0][0] |
212 | 214 | assert "return" in disco_resp and disco_resp["return"][0].startswith(sp_disco_resp), \ |
@@ -266,22 +268,41 @@ def auth_req_callback_func(context, internal_resp): |
266 | 268 | resp = samlbackend.start_auth(context, internal_req) |
267 | 269 | assert resp.status == "303 See Other", "Must be a redirect to the discovery server." |
268 | 270 |
|
269 | | - sp_disco_resp = spconfig["config"]["service"]["sp"]["endpoints"]["discovery_response"][0][0] |
270 | | - disco_resp = parse.parse_qs(resp.message.replace(spconfig["disco_srv"] + "?", "")) |
271 | | - info = parse.parse_qs(disco_resp["return"][0].replace(sp_disco_resp + "?", "")) |
| 271 | + disco_resp = parse_qs(urlparse(resp.message).query) |
| 272 | + |
| 273 | + info = parse_qs(urlparse(disco_resp["return"][0]).query) |
272 | 274 | info[samlbackend.idp_disco_query_param] = idpconfig["entityid"] |
273 | 275 | context = Context() |
274 | 276 | context.request = info |
275 | 277 | context.state = state |
276 | 278 | resp = samlbackend.disco_response(context) |
277 | | - assert resp.status == "200 OK", "A post must be 200 OK." |
278 | | - sp_url, req_params = fakeidp.get_post_action_body(resp.message) |
| 279 | + assert resp.status == "303 See Other" |
| 280 | + req_params = dict(parse_qsl(urlparse(resp.message).query)) |
279 | 281 | url, fake_idp_resp = fakeidp.handle_auth_req( |
280 | 282 | req_params["SAMLRequest"], |
281 | 283 | req_params["RelayState"], |
282 | | - BINDING_HTTP_POST, |
| 284 | + BINDING_HTTP_REDIRECT, |
283 | 285 | "testuser1") |
284 | 286 | context = Context() |
285 | 287 | context.request = fake_idp_resp |
286 | 288 | context.state = state |
287 | 289 | samlbackend.authn_response(context, BINDING_HTTP_POST) |
| 290 | + |
| 291 | + |
| 292 | +def test_redirect_to_idp_if_only_one_idp_in_metadata(monkeypatch): |
| 293 | + sp_config = TestConfiguration.get_instance().spconfig |
| 294 | + monkeypatch.delitem(sp_config, "disco_srv") |
| 295 | + monkeypatch.setitem(sp_config["config"]["metadata"], "local", [ |
| 296 | + FileGenerator.get_instance().create_metadata(None, "idp_metadata").name]) |
| 297 | + |
| 298 | + samlbackend = SamlBackend(None, INTERNAL_ATTRIBUTES, sp_config) |
| 299 | + |
| 300 | + state = State() |
| 301 | + state.add("test", "state") |
| 302 | + context = Context() |
| 303 | + context.state = state |
| 304 | + internal_req = InternalRequest(UserIdHashType.transient, None) |
| 305 | + resp = samlbackend.start_auth(context, internal_req) |
| 306 | + |
| 307 | + assert resp.status == "303 See Other" |
| 308 | + assert resp.message.split("?")[0] == "http://test.tester.se/sso/redirect" |
0 commit comments