7
7
from urllib .parse import parse_qsl , urlparse
8
8
9
9
from Crypto .PublicKey import RSA
10
+ from bs4 import BeautifulSoup
10
11
from saml2 import server , BINDING_HTTP_POST , BINDING_HTTP_REDIRECT
11
12
from saml2 .authn_context import AuthnBroker , authn_context_class_ref , PASSWORD
12
13
from saml2 .cert import OpenSSLWrapper
13
14
from saml2 .client import Saml2Client
14
- from saml2 .config import config_factory , Config
15
+ from saml2 .config import Config
15
16
from saml2 .metadata import entity_descriptor
16
17
from saml2 .saml import name_id_from_string , NAMEID_FORMAT_TRANSIENT , NAMEID_FORMAT_PERSISTENT
17
18
from saml2 .samlp import NameIDPolicy
@@ -34,7 +35,8 @@ def __init__(self, config):
34
35
"""
35
36
Saml2Client .__init__ (self , config )
36
37
37
- def make_auth_req (self , entity_id , nameid_format = None , relay_state = "relay_state" , binding = BINDING_HTTP_REDIRECT ):
38
+ def make_auth_req (self , entity_id , nameid_format = None , relay_state = "relay_state" ,
39
+ request_binding = BINDING_HTTP_REDIRECT , response_binding = BINDING_HTTP_REDIRECT ):
38
40
"""
39
41
:type entity_id: str
40
42
:rtype: str
@@ -45,26 +47,23 @@ def make_auth_req(self, entity_id, nameid_format=None, relay_state="relay_state"
45
47
# Picks a binding to use for sending the Request to the IDP
46
48
_binding , destination = self .pick_binding (
47
49
'single_sign_on_service' ,
48
- [binding ], 'idpsso' ,
50
+ [request_binding ], 'idpsso' ,
49
51
entity_id = entity_id )
50
- # Binding here is the response binding that is which binding the
51
- # IDP shou ld use to return the response.
52
- acs = self .config .getattr ('endpoints' , 'sp' )[
53
- 'assertion_consumer_service' ]
54
- # just pick one
55
- return_binding = None
56
- for i in range (len (acs )):
57
- endp , return_binding = acs [i ]
58
- if return_binding == _binding :
59
- break
60
52
61
53
req_id , req = self .create_authn_request (destination ,
62
- binding = return_binding , nameid_format = nameid_format )
54
+ binding = response_binding , nameid_format = nameid_format )
63
55
ht_args = self .apply_binding (_binding , '%s' % req , destination ,
64
56
relay_state = relay_state )
65
57
66
- url = ht_args ['headers' ][0 ][1 ]
67
- return url
58
+ if _binding == BINDING_HTTP_POST :
59
+ form_post_html = "\n " .join (ht_args ["data" ])
60
+ doctree = BeautifulSoup (form_post_html , "html.parser" )
61
+ saml_request = doctree .find ("input" , {"name" : "SAMLRequest" })["value" ]
62
+ resp = {"SAMLRequest" : saml_request , "RelayState" : relay_state }
63
+ elif _binding == BINDING_HTTP_REDIRECT :
64
+ resp = dict (parse_qsl (urlparse (dict (ht_args ["headers" ])["Location" ]).query ))
65
+
66
+ return destination , resp
68
67
69
68
70
69
class FakeIdP (server .Server ):
@@ -120,7 +119,7 @@ def handle_auth_req(self, saml_request, relay_state, binding, userid,
120
119
121
120
if response_binding == BINDING_HTTP_POST :
122
121
saml_response = base64 .b64encode (str (_resp ).encode ("utf-8" ))
123
- resp = {' SAMLResponse' : saml_response , ' RelayState' : relay_state }
122
+ resp = {" SAMLResponse" : saml_response , " RelayState" : relay_state }
124
123
elif response_binding == BINDING_HTTP_REDIRECT :
125
124
http_args = self .apply_binding (response_binding , '%s' % _resp ,
126
125
destination , relay_state , response = True )
0 commit comments