11"""
22Tests for the SAML frontend module src/frontends/saml2.py.
33"""
4+ import copy
45import itertools
56import re
67from collections import Counter
2829from satosa .internal import AuthenticationInformation
2930from satosa .internal import InternalData
3031from satosa .state import State
31- from satosa .context import Context
3232from tests .users import USERS
3333from tests .util import FakeSP , create_metadata_from_config_dict
3434
@@ -431,6 +431,7 @@ def test_load_idp_dynamic_entity_id(self, idp_conf):
431431
432432class TestSAMLVirtualCoFrontend (TestSAMLFrontend ):
433433 BACKEND = "test_backend"
434+ BACKEND_1 = "test_backend_1"
434435 CO = "MESS"
435436 CO_O = "organization"
436437 CO_C = "countryname"
@@ -441,8 +442,8 @@ class TestSAMLVirtualCoFrontend(TestSAMLFrontend):
441442 CO_O : ["Medium Energy Synchrotron Source" ],
442443 CO_C : ["US" ],
443444 CO_CO : ["United States" ],
444- CO_NOREDUORGACRONYM : ["MESS" ]
445- }
445+ CO_NOREDUORGACRONYM : ["MESS" ],
446+ }
446447 KEY_SSO = "single_sign_on_service"
447448
448449 @pytest .fixture
@@ -471,10 +472,10 @@ def frontend(self, idp_conf, sp_conf):
471472 # endpoints, and the collaborative organization configuration to
472473 # create the configuration for the frontend.
473474 conf = {
474- "idp_config" : idp_conf ,
475- "endpoints" : ENDPOINTS ,
476- "collaborative_organizations" : [collab_org ]
477- }
475+ "idp_config" : idp_conf ,
476+ "endpoints" : ENDPOINTS ,
477+ "collaborative_organizations" : [collab_org ],
478+ }
478479
479480 # Use a richer set of internal attributes than what is provided
480481 # for the parent class so that we can test for the static SAML
@@ -504,10 +505,13 @@ def context(self, context):
504505 that would be available during a SAML flow and that would include
505506 a path and target_backend that indicates the CO.
506507 """
507- context .path = "{}/{}/sso/redirect" .format (self .BACKEND , self .CO )
508- context .target_backend = self .BACKEND
508+ return self ._make_context (context , self .BACKEND , self .CO )
509509
510- return context
510+ def _make_context (self , context , backend , co_name ):
511+ _context = copy .deepcopy (context )
512+ _context .path = "{}/{}/sso/redirect" .format (backend , co_name )
513+ _context .target_backend = backend
514+ return _context
511515
512516 def test_create_state_data (self , frontend , context , idp_conf ):
513517 frontend ._create_co_virtual_idp (context )
@@ -542,6 +546,17 @@ def test_create_co_virtual_idp(self, frontend, context, idp_conf):
542546 assert idp_server .config .entityid == expected_entityid
543547 assert all (sso in sso_endpoints for sso in expected_endpoints )
544548
549+ def test_create_co_virtual_idp_with_entity_id_templates (self , frontend , context ):
550+ frontend .idp_config ['entityid' ] = "{}/Saml2IDP/proxy.xml" .format (BASE_URL )
551+ expected_entity_id = "{}/Saml2IDP/proxy.xml/{}" .format (BASE_URL , self .CO )
552+ idp_server = frontend ._create_co_virtual_idp (context )
553+ assert idp_server .config .entityid == expected_entity_id
554+
555+ frontend .idp_config ['entityid' ] = "{}/<backend_name>/idp/<co_name>" .format (BASE_URL )
556+ expected_entity_id = "{}/{}/idp/{}" .format (BASE_URL , context .target_backend , self .CO )
557+ idp_server = frontend ._create_co_virtual_idp (context )
558+ assert idp_server .config .entityid == expected_entity_id
559+
545560 def test_register_endpoints (self , frontend , context ):
546561 idp_server = frontend ._create_co_virtual_idp (context )
547562 url_map = frontend .register_endpoints ([self .BACKEND ])
@@ -553,6 +568,28 @@ def test_register_endpoints(self, frontend, context):
553568 for endpoint in all_idp_endpoints :
554569 assert any (pat .match (endpoint ) for pat in compiled_regex )
555570
571+ def test_register_endpoints_throws_error_in_case_duplicate_entity_ids (self , frontend ):
572+ with pytest .raises (ValueError ):
573+ frontend .register_endpoints ([self .BACKEND , self .BACKEND_1 ])
574+
575+ def test_register_endpoints_with_metadata_endpoints (self , frontend , context ):
576+ frontend .idp_config ['entityid' ] = "{}/<backend_name>/idp/<co_name>" .format (BASE_URL )
577+ frontend .config ['entityid_endpoint' ] = True
578+ idp_server_1 = frontend ._create_co_virtual_idp (context )
579+ context_2 = self ._make_context (context , self .BACKEND_1 , self .CO )
580+ idp_server_2 = frontend ._create_co_virtual_idp (context_2 )
581+
582+ url_map = frontend .register_endpoints ([self .BACKEND , self .BACKEND_1 ])
583+ expected_idp_endpoints = [urlparse (endpoint [0 ]).path [1 :] for server in [idp_server_1 , idp_server_2 ]
584+ for endpoint in server .config ._idp_endpoints [self .KEY_SSO ]]
585+ for server in [idp_server_1 , idp_server_2 ]:
586+ expected_idp_endpoints .append (urlparse (server .config .entityid ).path [1 :])
587+
588+ compiled_regex = [re .compile (regex ) for regex , _ in url_map ]
589+
590+ for endpoint in expected_idp_endpoints :
591+ assert any (pat .match (endpoint ) for pat in compiled_regex )
592+
556593 def test_co_static_attributes (self , frontend , context , internal_response ,
557594 idp_conf , sp_conf ):
558595 # Use the frontend and context fixtures to dynamically create the
@@ -563,9 +600,8 @@ def test_co_static_attributes(self, frontend, context, internal_response,
563600 # and then use those to dynamically update the ipd_conf fixture.
564601 co_name = frontend ._get_co_name (context )
565602 backend_name = context .target_backend
566- idp_conf = frontend ._add_endpoints_to_config (idp_conf , co_name ,
567- backend_name )
568- idp_conf = frontend ._add_entity_id (idp_conf , co_name )
603+ idp_conf = frontend ._add_endpoints_to_config (idp_conf , co_name , backend_name )
604+ idp_conf = frontend ._add_entity_id (idp_conf , co_name , backend_name )
569605
570606 # Use a utility function to serialize the idp_conf IdP configuration
571607 # fixture to a string and then dynamically update the sp_conf
@@ -597,9 +633,9 @@ def test_co_static_attributes(self, frontend, context, internal_response,
597633 "name_id_policy" : NameIDPolicy (format = NAMEID_FORMAT_TRANSIENT ),
598634 "in_response_to" : None ,
599635 "destination" : sp_config .endpoint (
600- "assertion_consumer_service" ,
601- binding = BINDING_HTTP_REDIRECT
602- )[0 ],
636+ "assertion_consumer_service" ,
637+ binding = BINDING_HTTP_REDIRECT
638+ )[0 ],
603639 "sp_entity_id" : sp_conf ["entityid" ],
604640 "binding" : BINDING_HTTP_REDIRECT
605641 }
@@ -646,12 +682,10 @@ def test_should_map_unspecified(self):
646682
647683 def test_should_map_public (self ):
648684 assert (
649- subject_type_to_saml_nameid_format ("public" )
650- == NAMEID_FORMAT_PERSISTENT
685+ subject_type_to_saml_nameid_format ("public" ) == NAMEID_FORMAT_PERSISTENT
651686 )
652687
653688 def test_should_map_pairwise (self ):
654689 assert (
655- subject_type_to_saml_nameid_format ("pairwise" )
656- == NAMEID_FORMAT_TRANSIENT
690+ subject_type_to_saml_nameid_format ("pairwise" ) == NAMEID_FORMAT_TRANSIENT
657691 )
0 commit comments