32
32
from django .views .decorators .http import require_POST
33
33
from django .shortcuts import render
34
34
from django .template import TemplateDoesNotExist
35
- from django .utils .six import text_type , binary_type , PY3
35
+
36
+ try :
37
+ from django .utils .six import text_type , binary_type , PY3
38
+ except ImportError :
39
+ import sys
40
+ PY3 = sys .version_info [0 ] == 3
41
+ text_type = str
42
+ binary_type = bytes
43
+
36
44
from django .views .decorators .csrf import csrf_exempt
37
45
38
46
from saml2 import BINDING_HTTP_REDIRECT , BINDING_HTTP_POST
49
57
50
58
from djangosaml2 .cache import IdentityCache , OutstandingQueriesCache
51
59
from djangosaml2 .cache import StateCache
60
+ from djangosaml2 .exceptions import IdPConfigurationMissing
52
61
from djangosaml2 .conf import get_config
53
62
from djangosaml2 .overrides import Saml2Client
54
63
from djangosaml2 .signals import post_authenticated
@@ -136,6 +145,13 @@ def login(request,
136
145
selected_idp = request .GET .get ('idp' , None )
137
146
conf = get_config (config_loader_path , request )
138
147
148
+ kwargs = {}
149
+ # pysaml needs a string otherwise: "cannot serialize True (type bool)"
150
+ if getattr (conf , '_sp_force_authn' ):
151
+ kwargs ['force_authn' ] = "true"
152
+ if getattr (conf , '_sp_allow_create' , "false" ):
153
+ kwargs ['allow_create' ] = "true"
154
+
139
155
# is a embedded wayf needed?
140
156
idps = available_idps (conf )
141
157
if selected_idp is None and len (idps ) > 1 :
@@ -144,7 +160,13 @@ def login(request,
144
160
'available_idps' : idps .items (),
145
161
'came_from' : came_from ,
146
162
})
147
-
163
+ else :
164
+ # is the first one, otherwise next logger message will print None
165
+ if not idps :
166
+ raise IdPConfigurationMissing (('IdP configuration is missing or '
167
+ 'its metadata is expired.' ))
168
+ selected_idp = list (idps .keys ())[0 ]
169
+
148
170
# choose a binding to try first
149
171
sign_requests = getattr (conf , '_sp_authn_requests_signed' , False )
150
172
binding = BINDING_HTTP_POST if sign_requests else BINDING_HTTP_REDIRECT
@@ -184,7 +206,7 @@ def login(request,
184
206
session_id , result = client .prepare_for_authenticate (
185
207
entityid = selected_idp , relay_state = came_from ,
186
208
binding = binding , sign = False , sigalg = sigalg ,
187
- nsprefix = nsprefix )
209
+ nsprefix = nsprefix , ** kwargs )
188
210
except TypeError as e :
189
211
logger .error ('Unable to know which IdP to use' )
190
212
return HttpResponse (text_type (e ))
@@ -200,10 +222,11 @@ def login(request,
200
222
return HttpResponse (text_type (e ))
201
223
session_id , request_xml = client .create_authn_request (
202
224
location ,
203
- binding = binding )
225
+ binding = binding ,
226
+ ** kwargs )
204
227
try :
205
228
if PY3 :
206
- saml_request = base64 .b64encode (binary_type (request_xml , 'UTF-8' ))
229
+ saml_request = base64 .b64encode (binary_type (request_xml , 'UTF-8' )). decode ( 'utf-8' )
207
230
else :
208
231
saml_request = base64 .b64encode (binary_type (request_xml ))
209
232
@@ -458,7 +481,17 @@ def do_logout_service(request, data, binding, config_loader_path=None, next_page
458
481
relay_state = data .get ('RelayState' , '' ))
459
482
state .sync ()
460
483
auth .logout (request )
461
- return HttpResponseRedirect (get_location (http_info ))
484
+ if (
485
+ http_info .get ('method' , 'GET' ) == 'POST' and
486
+ 'data' in http_info and
487
+ ('Content-type' , 'text/html' ) in http_info .get ('headers' , [])
488
+ ):
489
+ # need to send back to the IDP a signed POST response with user session
490
+ # return HTML form content to browser with auto form validation
491
+ # to finally send request to the IDP
492
+ return HttpResponse (http_info ['data' ])
493
+ else :
494
+ return HttpResponseRedirect (get_location (http_info ))
462
495
else :
463
496
logger .error ('No SAMLResponse or SAMLRequest parameter found' )
464
497
raise Http404 ('No SAMLResponse or SAMLRequest parameter found' )
0 commit comments