Skip to content

Commit 46d24f6

Browse files
authored
Merge pull request #439 from jkakavas/fix_sane_defaults
Ensure signature checking for SAML Responses is enabled by default
2 parents d8eef64 + 61fa999 commit 46d24f6

File tree

6 files changed

+41
-14
lines changed

6 files changed

+41
-14
lines changed

src/saml2/client_base.py

Lines changed: 24 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -113,17 +113,30 @@ def __init__(self, config=None, identity_cache=None, state_cache=None,
113113
else:
114114
self.state = state_cache
115115

116-
self.logout_requests_signed = False
117-
self.allow_unsolicited = False
118-
self.authn_requests_signed = False
119-
self.want_assertions_signed = False
120-
self.want_response_signed = False
121-
for foo in ["allow_unsolicited", "authn_requests_signed",
122-
"logout_requests_signed", "want_assertions_signed",
123-
"want_response_signed"]:
124-
v = self.config.getattr(foo, "sp")
125-
if v is True or v == 'true':
126-
setattr(self, foo, True)
116+
attribute_defaults = {
117+
"logout_requests_signed": False,
118+
"allow_unsolicited": False,
119+
"authn_requests_signed": False,
120+
"want_assertions_signed": False,
121+
"want_response_signed": True,
122+
}
123+
124+
for attr, val_default in attribute_defaults.items():
125+
val_config = self.config.getattr(attr, "sp")
126+
if val_config is None:
127+
val = val_default
128+
else:
129+
val = val_config
130+
131+
if val == 'true':
132+
val = True
133+
134+
setattr(self, attr, val)
135+
136+
if self.entity_type == "sp" and not any([self.want_assertions_signed,
137+
self.want_response_signed]):
138+
logger.warning("The SAML service provider accepts unsigned SAML Responses " +
139+
"and Assertions. This configuration is insecure.")
127140

128141
self.artifact2response = {}
129142

tests/test_51_client.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -405,6 +405,7 @@ def test_response_1(self):
405405
destination="http://lingon.catalogix.se:8087/",
406406
sp_entity_id="urn:mace:example.com:saml:roland:sp",
407407
name_id_policy=nameid_policy,
408+
sign_response=True,
408409
409410
authn=AUTHN)
410411

@@ -449,6 +450,7 @@ def test_response_1(self):
449450
in_response_to="id2",
450451
destination="http://lingon.catalogix.se:8087/",
451452
sp_entity_id="urn:mace:example.com:saml:roland:sp",
453+
sign_response=True,
452454
name_id_policy=nameid_policy,
453455
454456
authn=AUTHN)
@@ -905,7 +907,6 @@ def test_sign_then_encrypt_assertion2(self):
905907
node_id=assertion.id)
906908

907909
sigass = rm_xmltag(sigass)
908-
909910
response = sigver.response_factory(
910911
in_response_to="_012345",
911912
destination="http://lingon.catalogix.se:8087/",
@@ -928,6 +929,8 @@ def test_sign_then_encrypt_assertion2(self):
928929

929930
resp_str = base64.encodestring(enctext.encode('utf-8'))
930931
# Now over to the client side
932+
# Explicitely allow unsigned responses for this and the following 2 tests
933+
self.client.want_response_signed = False
931934
resp = self.client.parse_authn_request_response(
932935
resp_str, BINDING_HTTP_POST,
933936
{"_012345": "http://foo.example.com/service"})
@@ -1329,6 +1332,9 @@ def test_sign_then_encrypt_assertion_advice_2(self):
13291332

13301333
def test_signed_redirect(self):
13311334

1335+
# Revert configuration change to disallow unsinged responses
1336+
self.client.want_response_signed = True
1337+
13321338
msg_str = "%s" % self.client.create_authn_request(
13331339
"http://localhost:8088/sso", message_id="id1")[1]
13341340

@@ -1560,6 +1566,8 @@ def test_post_sso(self):
15601566
response = self.client.send(**http_args)
15611567
print(response.text)
15621568
_dic = unpack_form(response.text, "SAMLResponse")
1569+
# Explicitly allow unsigned responses for this test
1570+
self.client.want_response_signed = False
15631571
resp = self.client.parse_authn_request_response(_dic["SAMLResponse"],
15641572
BINDING_HTTP_POST,
15651573
{sid: "/"})

tests/test_60_sp.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,8 @@
5353
class TestSP():
5454
def setup_class(self):
5555
self.sp = make_plugin("rem", saml_conf="server_conf")
56+
# Explicitly allow unsigned responses for this test
57+
self.sp.saml_client.want_response_signed = False
5658
self.server = Server(config_file="idp_conf")
5759

5860
def teardown_class(self):

tests/test_63_ecp.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,8 @@ def test_complete_flow():
136136
assert inst.text == "XYZ"
137137

138138
# parse the response
139-
139+
# Explicitly allow unsigned responses for this test
140+
sp.want_response_signed = False
140141
resp = sp.parse_authn_request_response(respdict["body"], None, {sid: "/"})
141142

142143
print(resp.response)

tests/test_65_authn_query.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,8 @@ def test_flow():
9292
# ------- @SP ----------
9393

9494
xmlstr = get_msg(hinfo, binding)
95+
# Explicitly allow unsigned responses for this test
96+
sp.want_response_signed = False
9597
aresp = sp.parse_authn_request_response(xmlstr, binding,
9698
{resp.in_response_to: "/"})
9799

tests/test_68_assertion_id.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,8 @@ def test_basic_flow():
7878
# --------- @SP -------------
7979

8080
xmlstr = get_msg(hinfo, binding)
81-
81+
# Explicitly allow unsigned responses for this test
82+
sp.want_response_signed = False
8283
aresp = sp.parse_authn_request_response(xmlstr, binding,
8384
{resp.in_response_to: "/"})
8485

0 commit comments

Comments
 (0)