Skip to content

Commit f416983

Browse files
committed
Add support for SingleSignOnService with HTTP-POST binding
Warning, this changes the return type of `prepare_for_authentication` by including the chosen binding, and opens the door for supporting other SingleSignOnService bindings.
1 parent d38e947 commit f416983

File tree

3 files changed

+31
-13
lines changed

3 files changed

+31
-13
lines changed

src/saml2/client.py

Lines changed: 22 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ class Saml2Client(Base):
4242
""" The basic pySAML2 service provider class """
4343

4444
def prepare_for_authenticate(self, entityid=None, relay_state="",
45-
binding=saml2.BINDING_HTTP_REDIRECT, vorg="",
45+
binding=None, vorg="",
4646
nameid_format=None,
4747
scoping=None, consent=None, extensions=None,
4848
sign=None,
@@ -64,20 +64,31 @@ def prepare_for_authenticate(self, entityid=None, relay_state="",
6464
:return: session id and AuthnRequest info
6565
"""
6666

67-
destination = self._sso_location(entityid, binding)
67+
expected_binding = binding
6868

69-
reqid, req = self.create_authn_request(destination, vorg, scoping,
70-
response_binding, nameid_format,
71-
consent=consent,
72-
extensions=extensions, sign=sign,
73-
**kwargs)
74-
_req_str = "%s" % req
69+
for binding in [BINDING_HTTP_REDIRECT, BINDING_HTTP_POST]:
70+
if expected_binding and binding != expected_binding:
71+
continue
7572

76-
logger.info("AuthNReq: %s" % _req_str)
73+
destination = self._sso_location(entityid, binding)
74+
logger.info("destination to provider: %s" % destination)
7775

78-
info = self.apply_binding(binding, _req_str, destination, relay_state)
76+
reqid, request = self.create_authn_request(
77+
destination, vorg, scoping, response_binding, nameid_format,
78+
consent=consent,
79+
extensions=extensions, sign=sign,
80+
**kwargs)
7981

80-
return reqid, info
82+
_req_str = str(request)
83+
84+
logger.info("AuthNReq: %s" % _req_str)
85+
86+
http_info = self.apply_binding(binding, _req_str, destination,
87+
relay_state)
88+
89+
return reqid, binding, http_info
90+
else:
91+
raise SignonError("No binding available for singon")
8192

8293
def global_logout(self, name_id, reason="", expire=None, sign=None):
8394
""" More or less a layer of indirection :-/

src/saml2/client_base.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,10 @@ class VerifyError(SAMLError):
7171
pass
7272

7373

74+
class SignonError(SAMLError):
75+
pass
76+
77+
7478
class LogoutError(SAMLError):
7579
pass
7680

tests/test_51_client.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -619,10 +619,11 @@ def setup_class(self):
619619
def test_do_authn(self):
620620
binding = BINDING_HTTP_REDIRECT
621621
response_binding = BINDING_HTTP_POST
622-
sid, http_args = self.client.prepare_for_authenticate(
622+
sid, auth_binding, http_args = self.client.prepare_for_authenticate(
623623
IDP, "http://www.example.com/relay_state",
624624
binding=binding, response_binding=response_binding)
625625

626+
assert binding == auth_binding
626627
assert isinstance(sid, basestring)
627628
assert len(http_args) == 4
628629
assert http_args["headers"][0][0] == "Location"
@@ -669,11 +670,13 @@ def test_logout_1(self):
669670
def test_post_sso(self):
670671
binding = BINDING_HTTP_POST
671672
response_binding = BINDING_HTTP_POST
672-
sid, http_args = self.client.prepare_for_authenticate(
673+
sid, auth_binding, http_args = self.client.prepare_for_authenticate(
673674
"urn:mace:example.com:saml:roland:idp", relay_state="really",
674675
binding=binding, response_binding=response_binding)
675676
_dic = unpack_form(http_args["data"][3])
676677

678+
assert binding == auth_binding
679+
677680
req = self.server.parse_authn_request(_dic["SAMLRequest"], binding)
678681
resp_args = self.server.response_args(req.message, [response_binding])
679682
assert resp_args["binding"] == response_binding

0 commit comments

Comments
 (0)