Source code for onelogin.saml2.logout_response

# -*- coding: utf-8 -*-

""" OneLogin_Saml2_Logout_Response class


Logout Response class of SAML Python Toolkit.

"""

from onelogin.saml2 import compat
from onelogin.saml2.constants import OneLogin_Saml2_Constants
from onelogin.saml2.utils import OneLogin_Saml2_Utils, OneLogin_Saml2_ValidationError
from onelogin.saml2.xml_templates import OneLogin_Saml2_Templates
from onelogin.saml2.xml_utils import OneLogin_Saml2_XML


[docs]class OneLogin_Saml2_Logout_Response(object): """ This class handles a Logout Response. It Builds or parses a Logout Response object and validates it. """ def __init__(self, settings, response=None): """ Constructs a Logout Response object (Initialize params from settings and if provided load the Logout Response. Arguments are: * (OneLogin_Saml2_Settings) settings. Setting data * (string) response. An UUEncoded SAML Logout response from the IdP. """ self._settings = settings self._error = None self.id = None if response is not None: self._logout_response = compat.to_string(OneLogin_Saml2_Utils.decode_base64_and_inflate(response, ignore_zip=True)) self.document = OneLogin_Saml2_XML.to_etree(self._logout_response) self.id = self.document.get('ID', None)
[docs] def get_issuer(self): """ Gets the Issuer of the Logout Response Message :return: The Issuer :rtype: string """ issuer = None issuer_nodes = self._query('/samlp:LogoutResponse/saml:Issuer') if len(issuer_nodes) == 1: issuer = OneLogin_Saml2_XML.element_text(issuer_nodes[0]) return issuer
[docs] def get_status(self): """ Gets the Status :return: The Status :rtype: string """ entries = self._query('/samlp:LogoutResponse/samlp:Status/samlp:StatusCode') if len(entries) == 0: return None status = entries[0].attrib['Value'] return status
[docs] def is_valid(self, request_data, request_id=None, raise_exceptions=False): """ Determines if the SAML LogoutResponse is valid :param request_id: The ID of the LogoutRequest sent by this SP to the IdP :type request_id: string :param raise_exceptions: Whether to return false on failure or raise an exception :type raise_exceptions: Boolean :return: Returns if the SAML LogoutResponse is or not valid :rtype: boolean """ self._error = None try: idp_data = self._settings.get_idp_data() idp_entity_id = idp_data['entityId'] get_data = request_data['get_data'] if self._settings.is_strict(): res = OneLogin_Saml2_XML.validate_xml(self.document, 'saml-schema-protocol-2.0.xsd', self._settings.is_debug_active()) if isinstance(res, str): raise OneLogin_Saml2_ValidationError( 'Invalid SAML Logout Request. Not match the saml-schema-protocol-2.0.xsd', OneLogin_Saml2_ValidationError.INVALID_XML_FORMAT ) security = self._settings.get_security_data() # Check if the InResponseTo of the Logout Response matches the ID of the Logout Request (requestId) if provided in_response_to = self.get_in_response_to() if request_id is not None and in_response_to and in_response_to != request_id: raise OneLogin_Saml2_ValidationError( 'The InResponseTo of the Logout Response: %s, does not match the ID of the Logout request sent by the SP: %s' % (in_response_to, request_id), OneLogin_Saml2_ValidationError.WRONG_INRESPONSETO ) # Check issuer issuer = self.get_issuer() if issuer is not None and issuer != idp_entity_id: raise OneLogin_Saml2_ValidationError( 'Invalid issuer in the Logout Response (expected %(idpEntityId)s, got %(issuer)s)' % { 'idpEntityId': idp_entity_id, 'issuer': issuer }, OneLogin_Saml2_ValidationError.WRONG_ISSUER ) current_url = OneLogin_Saml2_Utils.get_self_url_no_query(request_data) # Check destination destination = self.document.get('Destination', None) if destination: if not OneLogin_Saml2_Utils.normalize_url(url=destination).startswith(OneLogin_Saml2_Utils.normalize_url(url=current_url)): raise OneLogin_Saml2_ValidationError( 'The LogoutResponse was received at %s instead of %s' % (current_url, destination), OneLogin_Saml2_ValidationError.WRONG_DESTINATION ) if security['wantMessagesSigned']: if 'Signature' not in get_data: raise OneLogin_Saml2_ValidationError( 'The Message of the Logout Response is not signed and the SP require it', OneLogin_Saml2_ValidationError.NO_SIGNED_MESSAGE ) return True # pylint: disable=R0801 except Exception as err: self._error = str(err) debug = self._settings.is_debug_active() if debug: print(err) if raise_exceptions: raise return False
def _query(self, query): """ Extracts a node from the Etree (Logout Response Message) :param query: Xpath Expression :type query: string :return: The queried node :rtype: Element """ return OneLogin_Saml2_XML.query(self.document, query)
[docs] def build(self, in_response_to, status=OneLogin_Saml2_Constants.STATUS_SUCCESS): """ Creates a Logout Response object. :param in_response_to: InResponseTo value for the Logout Response. :type in_response_to: string :param: status: The status of the response :type: status: string """ sp_data = self._settings.get_sp_data() self.id = self._generate_request_id() issue_instant = OneLogin_Saml2_Utils.parse_time_to_SAML(OneLogin_Saml2_Utils.now()) logout_response = OneLogin_Saml2_Templates.LOGOUT_RESPONSE % { "id": self.id, "issue_instant": issue_instant, "destination": self._settings.get_idp_slo_response_url(), "in_response_to": in_response_to, "entity_id": sp_data["entityId"], "status": status, } self._logout_response = logout_response
[docs] def get_in_response_to(self): """ Gets the ID of the LogoutRequest which this response is in response to :returns: ID of LogoutRequest this LogoutResponse is in response to or None if it is not present :rtype: str """ return self.document.get('InResponseTo')
[docs] def get_response(self, deflate=True): """ Returns a Logout Response object. :param deflate: It makes the deflate process optional :type: bool :return: Logout Response maybe deflated and base64 encoded :rtype: string """ if deflate: response = OneLogin_Saml2_Utils.deflate_and_base64_encode(self._logout_response) else: response = OneLogin_Saml2_Utils.b64encode(self._logout_response) return response
[docs] def get_error(self): """ After executing a validation process, if it fails this method returns the cause """ return self._error
[docs] def get_xml(self): """ Returns the XML that will be sent as part of the response or that was received at the SP :return: XML response body :rtype: string """ return self._logout_response
def _generate_request_id(self): """ Generate an unique logout response ID. """ return OneLogin_Saml2_Utils.generate_unique_id()