1
1
"""
2
2
Tests for the SAML frontend module src/frontends/saml2.py.
3
3
"""
4
+ import copy
4
5
import itertools
5
6
import re
6
7
from collections import Counter
28
29
from satosa .internal import AuthenticationInformation
29
30
from satosa .internal import InternalData
30
31
from satosa .state import State
31
- from satosa .context import Context
32
32
from tests .users import USERS
33
33
from tests .util import FakeSP , create_metadata_from_config_dict
34
34
@@ -298,14 +298,14 @@ def test_acr_mapping_per_idp_in_authn_response(self, context, idp_conf, sp_conf,
298
298
]
299
299
)
300
300
def test_respect_sp_entity_categories (
301
- self ,
302
- context ,
303
- entity_category ,
304
- entity_category_module ,
305
- expected_attributes ,
306
- idp_conf ,
307
- sp_conf ,
308
- internal_response
301
+ self ,
302
+ context ,
303
+ entity_category ,
304
+ entity_category_module ,
305
+ expected_attributes ,
306
+ idp_conf ,
307
+ sp_conf ,
308
+ internal_response
309
309
):
310
310
idp_metadata_str = create_metadata_from_config_dict (idp_conf )
311
311
idp_conf ["service" ]["idp" ]["policy" ]["default" ]["entity_categories" ] = [entity_category_module ]
@@ -365,7 +365,7 @@ def test_metadata_endpoint(self, context, idp_conf):
365
365
assert idp_conf ["entityid" ] in resp .message
366
366
367
367
def test_custom_attribute_release_with_less_attributes_than_entity_category (
368
- self , context , idp_conf , sp_conf , internal_response
368
+ self , context , idp_conf , sp_conf , internal_response
369
369
):
370
370
idp_metadata_str = create_metadata_from_config_dict (idp_conf )
371
371
idp_conf ["service" ]["idp" ]["policy" ]["default" ]["entity_categories" ] = ["swamid" ]
@@ -387,8 +387,8 @@ def test_custom_attribute_release_with_less_attributes_than_entity_category(
387
387
internal_response .requester = sp_conf ["entityid" ]
388
388
resp = self .get_auth_response (samlfrontend , context , internal_response , sp_conf , idp_metadata_str )
389
389
assert len (resp .ava .keys ()) == (
390
- len (expected_attributes )
391
- - len (custom_attributes [internal_response .auth_info .issuer ][internal_response .requester ]["exclude" ])
390
+ len (expected_attributes )
391
+ - len (custom_attributes [internal_response .auth_info .issuer ][internal_response .requester ]["exclude" ])
392
392
)
393
393
394
394
@@ -431,6 +431,7 @@ def test_load_idp_dynamic_entity_id(self, idp_conf):
431
431
432
432
class TestSAMLVirtualCoFrontend (TestSAMLFrontend ):
433
433
BACKEND = "test_backend"
434
+ BACKEND_1 = "test_backend_1"
434
435
CO = "MESS"
435
436
CO_O = "organization"
436
437
CO_C = "countryname"
@@ -442,7 +443,7 @@ class TestSAMLVirtualCoFrontend(TestSAMLFrontend):
442
443
CO_C : ["US" ],
443
444
CO_CO : ["United States" ],
444
445
CO_NOREDUORGACRONYM : ["MESS" ]
445
- }
446
+ }
446
447
KEY_SSO = "single_sign_on_service"
447
448
448
449
@pytest .fixture
@@ -471,10 +472,10 @@ def frontend(self, idp_conf, sp_conf):
471
472
# endpoints, and the collaborative organization configuration to
472
473
# create the configuration for the frontend.
473
474
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
+ }
478
479
479
480
# Use a richer set of internal attributes than what is provided
480
481
# for the parent class so that we can test for the static SAML
@@ -504,10 +505,13 @@ def context(self, context):
504
505
that would be available during a SAML flow and that would include
505
506
a path and target_backend that indicates the CO.
506
507
"""
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 )
509
509
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
511
515
512
516
def test_create_state_data (self , frontend , context , idp_conf ):
513
517
frontend ._create_co_virtual_idp (context )
@@ -542,6 +546,17 @@ def test_create_co_virtual_idp(self, frontend, context, idp_conf):
542
546
assert idp_server .config .entityid == expected_entityid
543
547
assert all (sso in sso_endpoints for sso in expected_endpoints )
544
548
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
+
545
560
def test_register_endpoints (self , frontend , context ):
546
561
idp_server = frontend ._create_co_virtual_idp (context )
547
562
url_map = frontend .register_endpoints ([self .BACKEND ])
@@ -553,6 +568,28 @@ def test_register_endpoints(self, frontend, context):
553
568
for endpoint in all_idp_endpoints :
554
569
assert any (pat .match (endpoint ) for pat in compiled_regex )
555
570
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
+
556
593
def test_co_static_attributes (self , frontend , context , internal_response ,
557
594
idp_conf , sp_conf ):
558
595
# Use the frontend and context fixtures to dynamically create the
@@ -563,9 +600,8 @@ def test_co_static_attributes(self, frontend, context, internal_response,
563
600
# and then use those to dynamically update the ipd_conf fixture.
564
601
co_name = frontend ._get_co_name (context )
565
602
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 )
569
605
570
606
# Use a utility function to serialize the idp_conf IdP configuration
571
607
# 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,
597
633
"name_id_policy" : NameIDPolicy (format = NAMEID_FORMAT_TRANSIENT ),
598
634
"in_response_to" : None ,
599
635
"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 ],
603
639
"sp_entity_id" : sp_conf ["entityid" ],
604
640
"binding" : BINDING_HTTP_REDIRECT
605
641
}
@@ -616,42 +652,42 @@ def test_co_static_attributes(self, frontend, context, internal_response,
616
652
class TestSubjectTypeToSamlNameIdFormat :
617
653
def test_should_default_to_persistent (self ):
618
654
assert (
619
- subject_type_to_saml_nameid_format ("unmatched" )
620
- == NAMEID_FORMAT_PERSISTENT
655
+ subject_type_to_saml_nameid_format ("unmatched" )
656
+ == NAMEID_FORMAT_PERSISTENT
621
657
)
622
658
623
659
def test_should_map_persistent (self ):
624
660
assert (
625
- subject_type_to_saml_nameid_format (NAMEID_FORMAT_PERSISTENT )
626
- == NAMEID_FORMAT_PERSISTENT
661
+ subject_type_to_saml_nameid_format (NAMEID_FORMAT_PERSISTENT )
662
+ == NAMEID_FORMAT_PERSISTENT
627
663
)
628
664
629
665
def test_should_map_transient (self ):
630
666
assert (
631
- subject_type_to_saml_nameid_format (NAMEID_FORMAT_TRANSIENT )
632
- == NAMEID_FORMAT_TRANSIENT
667
+ subject_type_to_saml_nameid_format (NAMEID_FORMAT_TRANSIENT )
668
+ == NAMEID_FORMAT_TRANSIENT
633
669
)
634
670
635
671
def test_should_map_emailaddress (self ):
636
672
assert (
637
- subject_type_to_saml_nameid_format (NAMEID_FORMAT_EMAILADDRESS )
638
- == NAMEID_FORMAT_EMAILADDRESS
673
+ subject_type_to_saml_nameid_format (NAMEID_FORMAT_EMAILADDRESS )
674
+ == NAMEID_FORMAT_EMAILADDRESS
639
675
)
640
676
641
677
def test_should_map_unspecified (self ):
642
678
assert (
643
- subject_type_to_saml_nameid_format (NAMEID_FORMAT_UNSPECIFIED )
644
- == NAMEID_FORMAT_UNSPECIFIED
679
+ subject_type_to_saml_nameid_format (NAMEID_FORMAT_UNSPECIFIED )
680
+ == NAMEID_FORMAT_UNSPECIFIED
645
681
)
646
682
647
683
def test_should_map_public (self ):
648
684
assert (
649
- subject_type_to_saml_nameid_format ("public" )
650
- == NAMEID_FORMAT_PERSISTENT
685
+ subject_type_to_saml_nameid_format ("public" )
686
+ == NAMEID_FORMAT_PERSISTENT
651
687
)
652
688
653
689
def test_should_map_pairwise (self ):
654
690
assert (
655
- subject_type_to_saml_nameid_format ("pairwise" )
656
- == NAMEID_FORMAT_TRANSIENT
691
+ subject_type_to_saml_nameid_format ("pairwise" )
692
+ == NAMEID_FORMAT_TRANSIENT
657
693
)
0 commit comments