|
24 | 24 | import platform
|
25 | 25 | import shelve
|
26 | 26 | import traceback
|
27 |
| -from urlparse import parse_qs |
| 27 | +from urlparse import parse_qs, urlparse |
28 | 28 |
|
29 |
| -from paste.httpexceptions import HTTPSeeOther |
| 29 | +from paste.httpexceptions import HTTPSeeOther, HTTPRedirection |
30 | 30 | from paste.httpexceptions import HTTPNotImplemented
|
31 | 31 | from paste.httpexceptions import HTTPInternalServerError
|
32 | 32 | from paste.request import parse_dict_querystring
|
@@ -133,6 +133,7 @@ def __init__(self, rememberer_name, config, saml_client, wayf, cache,
|
133 | 133 | self.cache = cache
|
134 | 134 | self.discosrv = discovery
|
135 | 135 | self.idp_query_param = idp_query_param
|
| 136 | + self.logout_endpoints = [urlparse(ep)[2] for ep in config.endpoint("single_logout_service")] |
136 | 137 |
|
137 | 138 | try:
|
138 | 139 | self.metadata = self.conf.metadata
|
@@ -282,10 +283,22 @@ def challenge(self, environ, _status, _app_headers, _forget_headers):
|
282 | 283 |
|
283 | 284 | _cli = self.saml_client
|
284 | 285 |
|
285 |
| - # this challenge consist in logging out |
286 |
| - if 'rwpc.logout' in environ: |
287 |
| - # ignore right now? |
288 |
| - pass |
| 286 | + |
| 287 | + if 'REMOTE_USER' in environ: |
| 288 | + name_id = decode(environ["REMOTE_USER"]) |
| 289 | + |
| 290 | + _cli = self.saml_client |
| 291 | + path_info = environ['PATH_INFO'] |
| 292 | + |
| 293 | + if 'samlsp.logout' in environ: |
| 294 | + responses = _cli.global_logout(name_id) |
| 295 | + return self._handle_logout(responses) |
| 296 | + |
| 297 | + if 'samlsp.pending' in environ: |
| 298 | + response = environ['samlsp.pending'] |
| 299 | + if isinstance(response, HTTPRedirection): |
| 300 | + response.headers += _forget_headers |
| 301 | + return response |
289 | 302 |
|
290 | 303 | #logger = environ.get('repoze.who.logger','')
|
291 | 304 |
|
@@ -405,7 +418,8 @@ def identify(self, environ):
|
405 | 418 | """
|
406 | 419 | #logger = environ.get('repoze.who.logger', '')
|
407 | 420 |
|
408 |
| - if "CONTENT_LENGTH" not in environ or not environ["CONTENT_LENGTH"]: |
| 421 | + query = parse_dict_querystring(environ) |
| 422 | + if ("CONTENT_LENGTH" not in environ or not environ["CONTENT_LENGTH"]) and "SAMLResponse" not in query: |
409 | 423 | logger.debug('[identify] get or empty post')
|
410 | 424 | return {}
|
411 | 425 |
|
@@ -443,10 +457,28 @@ def identify(self, environ):
|
443 | 457 | logger.info("[sp.identify] --- SAMLResponse ---")
|
444 | 458 | # check for SAML2 authN response
|
445 | 459 | #if self.debug:
|
| 460 | + path_info = environ['PATH_INFO'] |
| 461 | + logout = False |
| 462 | + if path_info in self.logout_endpoints: |
| 463 | + logout = True |
446 | 464 | try:
|
447 |
| - session_info = self._eval_authn_response( |
448 |
| - environ, cgi_field_storage_to_dict(post), |
449 |
| - binding=binding) |
| 465 | + if logout: |
| 466 | + response = self.saml_client.parse_logout_request_response(post["SAMLResponse"], binding) |
| 467 | + if response: |
| 468 | + action = self.saml_client.handle_logout_response(response) |
| 469 | + request = None |
| 470 | + if type(action) == dict: |
| 471 | + request = self._handle_logout(action) |
| 472 | + else: |
| 473 | + #logout complete |
| 474 | + request = HTTPSeeOther(headers=[('Location', "/")]) |
| 475 | + if request: |
| 476 | + environ['samlsp.pending'] = request |
| 477 | + return {} |
| 478 | + else: |
| 479 | + session_info = self._eval_authn_response( |
| 480 | + environ, cgi_field_storage_to_dict(post), |
| 481 | + binding=binding) |
450 | 482 | except Exception, err:
|
451 | 483 | environ["s2repoze.saml_error"] = err
|
452 | 484 | return {}
|
@@ -532,6 +564,13 @@ def authenticate(self, environ, identity=None):
|
532 | 564 | else:
|
533 | 565 | return None
|
534 | 566 |
|
| 567 | + def _handle_logout(self, responses): |
| 568 | + ht_args = responses[responses.keys()[0]][1] |
| 569 | + if not ht_args["data"] and ht_args["headers"][0][0] == "Location": |
| 570 | + logger.debug('redirect to: %s' % ht_args["headers"][0][1]) |
| 571 | + return HTTPSeeOther(headers=ht_args["headers"]) |
| 572 | + else: |
| 573 | + return ht_args["data"] |
535 | 574 |
|
536 | 575 | def make_plugin(remember_name=None, # plugin for remember
|
537 | 576 | cache="", # cache
|
|
0 commit comments