Skip to content

Commit 0ede13f

Browse files
authored
Merge pull request #171 from onelogin/open-craft-haikuginger/last-xml-document-hooks
Add hooks to retrieve last-sent and last-received requests and responses
2 parents 4b1c5cc + f428b72 commit 0ede13f

15 files changed

+363
-8
lines changed

README.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -827,11 +827,13 @@ Main class of OneLogin Python Toolkit
827827
* ***get_last_error_reason*** Returns the reason of the last error
828828
* ***get_sso_url*** Gets the SSO url.
829829
* ***get_slo_url*** Gets the SLO url.
830-
* ***get_last_request_id*** The ID of the last Request SAML message generated.
830+
* ***get_last_request_id*** The ID of the last Request SAML message generated (AuthNRequest, LogoutRequest).
831831
* ***build_request_signature*** Builds the Signature of the SAML Request.
832832
* ***build_response_signature*** Builds the Signature of the SAML Response.
833833
* ***get_settings*** Returns the settings info.
834834
* ***set_strict*** Set the strict mode active/disable.
835+
* ***get_last_request_xml*** Returns the most recently-constructed/processed XML SAML request (AuthNRequest, LogoutRequest)
836+
* ***get_last_response_xml*** Returns the most recently-constructed/processed XML SAML response (SAMLResponse, LogoutResponse). If the SAMLResponse was encrypted, by default tries to return the decrypted XML.
835837

836838
####OneLogin_Saml2_Auth - authn_request.py####
837839

src/onelogin/saml2/auth.py

Lines changed: 35 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313

1414
from base64 import b64encode
1515
from urllib import quote_plus
16+
from lxml import etree
1617

1718
from onelogin.saml2.settings import OneLogin_Saml2_Settings
1819
from onelogin.saml2.response import OneLogin_Saml2_Response
@@ -57,6 +58,8 @@ def __init__(self, request_data, old_settings=None, custom_base_path=None):
5758
self.__errors = []
5859
self.__error_reason = None
5960
self.__last_request_id = None
61+
self.__last_request = None
62+
self.__last_response = None
6063

6164
def get_settings(self):
6265
"""
@@ -90,7 +93,7 @@ def process_response(self, request_id=None):
9093
if 'post_data' in self.__request_data and 'SAMLResponse' in self.__request_data['post_data']:
9194
# AuthnResponse -- HTTP_POST Binding
9295
response = OneLogin_Saml2_Response(self.__settings, self.__request_data['post_data']['SAMLResponse'])
93-
96+
self.__last_response = response.get_xml_document()
9497
if response.is_valid(self.__request_data, request_id):
9598
self.__attributes = response.get_attributes()
9699
self.__nameid = response.get_nameid()
@@ -125,6 +128,7 @@ def process_slo(self, keep_local_session=False, request_id=None, delete_session_
125128

126129
if 'get_data' in self.__request_data and 'SAMLResponse' in self.__request_data['get_data']:
127130
logout_response = OneLogin_Saml2_Logout_Response(self.__settings, self.__request_data['get_data']['SAMLResponse'])
131+
self.__last_response = logout_response.get_xml()
128132
if not logout_response.is_valid(self.__request_data, request_id):
129133
self.__errors.append('invalid_logout_response')
130134
self.__error_reason = logout_response.get_error()
@@ -135,6 +139,7 @@ def process_slo(self, keep_local_session=False, request_id=None, delete_session_
135139

136140
elif 'get_data' in self.__request_data and 'SAMLRequest' in self.__request_data['get_data']:
137141
logout_request = OneLogin_Saml2_Logout_Request(self.__settings, self.__request_data['get_data']['SAMLRequest'])
142+
self.__last_request = logout_request.get_xml()
138143
if not logout_request.is_valid(self.__request_data):
139144
self.__errors.append('invalid_logout_request')
140145
self.__error_reason = logout_request.get_error()
@@ -145,6 +150,7 @@ def process_slo(self, keep_local_session=False, request_id=None, delete_session_
145150
in_response_to = logout_request.id
146151
response_builder = OneLogin_Saml2_Logout_Response(self.__settings)
147152
response_builder.build(in_response_to)
153+
self.__last_response = response_builder.get_xml()
148154
logout_response = response_builder.get_response()
149155

150156
parameters = {'SAMLResponse': logout_response}
@@ -285,12 +291,11 @@ def login(self, return_to=None, force_authn=False, is_passive=False, set_nameid_
285291
:rtype: string
286292
"""
287293
authn_request = OneLogin_Saml2_Authn_Request(self.__settings, force_authn, is_passive, set_nameid_policy)
288-
294+
self.__last_request = authn_request.get_xml()
289295
self.__last_request_id = authn_request.get_id()
290-
291296
saml_request = authn_request.get_request()
292-
parameters = {'SAMLRequest': saml_request}
293297

298+
parameters = {'SAMLRequest': saml_request}
294299
if return_to is not None:
295300
parameters['RelayState'] = return_to
296301
else:
@@ -336,9 +341,8 @@ def logout(self, return_to=None, name_id=None, session_index=None, nq=None):
336341
session_index=session_index,
337342
nq=nq
338343
)
339-
344+
self.__last_request = logout_request.get_xml()
340345
self.__last_request_id = logout_request.id
341-
342346
saml_request = logout_request.get_request()
343347

344348
parameters = {'SAMLRequest': logout_request.get_request()}
@@ -451,3 +455,28 @@ def __build_signature(self, saml_data, relay_state, saml_type, sign_algorithm=On
451455

452456
signature = dsig_ctx.signBinary(str(msg), sign_algorithm_transform)
453457
return b64encode(signature)
458+
459+
def get_last_response_xml(self, pretty_print_if_possible=False):
460+
"""
461+
Retrieves the raw XML (decrypted) of the last SAML response,
462+
or the last Logout Response generated or processed
463+
464+
:returns: SAML response XML
465+
:rtype: string|None
466+
"""
467+
response = None
468+
if self.__last_response is not None:
469+
if isinstance(self.__last_response, basestring):
470+
response = self.__last_response
471+
else:
472+
response = etree.tostring(self.__last_response, pretty_print=pretty_print_if_possible)
473+
return response
474+
475+
def get_last_request_xml(self):
476+
"""
477+
Retrieves the raw XML sent in the last SAML request
478+
479+
:returns: SAML request XML
480+
:rtype: string|None
481+
"""
482+
return self.__last_request or None

src/onelogin/saml2/authn_request.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,3 +149,11 @@ def get_id(self):
149149
:rtype: string
150150
"""
151151
return self.__id
152+
153+
def get_xml(self):
154+
"""
155+
Returns the XML that will be sent as part of the request
156+
:return: XML request body
157+
:rtype: string
158+
"""
159+
return self.__authn_request

src/onelogin/saml2/logout_request.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,15 @@ def get_request(self, deflate=True):
130130
request = b64encode(self.__logout_request)
131131
return request
132132

133+
def get_xml(self):
134+
"""
135+
Returns the XML that will be sent as part of the request
136+
or that was received at the SP
137+
:return: XML request body
138+
:rtype: string
139+
"""
140+
return self.__logout_request
141+
133142
@staticmethod
134143
def get_id(request):
135144
"""

src/onelogin/saml2/logout_response.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,15 @@ def get_response(self, deflate=True):
205205
response = b64encode(self.__logout_response)
206206
return response
207207

208+
def get_xml(self):
209+
"""
210+
Returns the XML that will be sent as part of the response
211+
or that was received at the SP
212+
:return: XML response body
213+
:rtype: string
214+
"""
215+
return self.__logout_response
216+
208217
def get_error(self):
209218
"""
210219
After executing a validation process, if it fails this method returns the cause

src/onelogin/saml2/response.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -632,3 +632,15 @@ def get_error(self):
632632
After executing a validation process, if it fails this method returns the cause
633633
"""
634634
return self.__error
635+
636+
def get_xml_document(self):
637+
"""
638+
If necessary, decrypt the XML response document, and return it.
639+
640+
:return: Decrypted XML response document
641+
:rtype: string
642+
"""
643+
if self.encrypted:
644+
return self.decrypted_document
645+
else:
646+
return self.document
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
<samlp:Response xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" ID="_5f468249609040c6a351ac1be0e9fc60533ff09d3d" Version="2.0" IssueInstant="2014-03-29T12:01:57Z" Destination="http://stuff.com/endpoints/endpoints/acs.php" InResponseTo="ONELOGIN_be60b8caf8e9d19b7a3551b244f116c947ff247d">
2+
<saml:Issuer>http://idp.example.com/</saml:Issuer>
3+
<samlp:Status>
4+
<samlp:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success"/>
5+
</samlp:Status>
6+
<saml:Assertion xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xs="http://www.w3.org/2001/XMLSchema" ID="_519c2712648ee09a06d1f9a08e9e835715fea60267" Version="2.0" IssueInstant="2014-03-29T12:01:57Z"><saml:Issuer>http://idp.example.com/</saml:Issuer><saml:Subject><saml:NameID SPNameQualifier="http://stuff.com/endpoints/metadata.php" Format="urn:oasis:names:tc:SAML:2.0:nameid-format:transient">_68392312d490db6d355555cfbbd8ec95d746516f60</saml:NameID><saml:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer"><saml:SubjectConfirmationData NotOnOrAfter="2055-06-07T20:17:08Z" InResponseTo="ONELOGIN_be60b8caf8e9d19b7a3551b244f116c947ff247d"/></saml:SubjectConfirmation></saml:Subject><saml:Conditions NotBefore="2011-01-26T03:23:48Z" NotOnOrAfter="2055-06-07T20:17:08Z"><saml:AudienceRestriction><saml:Audience>http://stuff.com/endpoints/metadata.php</saml:Audience></saml:AudienceRestriction></saml:Conditions><saml:AuthnStatement AuthnInstant="2014-03-29T11:59:43Z" SessionNotOnOrAfter="2055-06-07T20:17:08Z" SessionIndex="_7164a9a9f97828bfdb8d0ebc004a05d2e7d873f70c"><saml:AuthnContext><saml:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:Password</saml:AuthnContextClassRef></saml:AuthnContext></saml:AuthnStatement><saml:AttributeStatement><saml:Attribute Name="uid" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic"><saml:AttributeValue xsi:type="xs:string">test</saml:AttributeValue></saml:Attribute><saml:Attribute Name="mail" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic"><saml:AttributeValue xsi:type="xs:string">[email protected]</saml:AttributeValue></saml:Attribute><saml:Attribute Name="cn" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic"><saml:AttributeValue xsi:type="xs:string">test</saml:AttributeValue></saml:Attribute><saml:Attribute Name="sn" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic"><saml:AttributeValue xsi:type="xs:string">waa2</saml:AttributeValue></saml:Attribute><saml:Attribute Name="eduPersonAffiliation" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic"><saml:AttributeValue xsi:type="xs:string">user</saml:AttributeValue><saml:AttributeValue xsi:type="xs:string">admin</saml:AttributeValue></saml:Attribute></saml:AttributeStatement></saml:Assertion>
7+
</samlp:Response>
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
<samlp:Response xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" ID="_5f468249609040c6a351ac1be0e9fc60533ff09d3d" Version="2.0" IssueInstant="2014-03-29T12:01:57Z" Destination="http://stuff.com/endpoints/endpoints/acs.php" InResponseTo="ONELOGIN_be60b8caf8e9d19b7a3551b244f116c947ff247d">
2+
<saml:Issuer>http://idp.example.com/</saml:Issuer>
3+
<samlp:Status>
4+
<samlp:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success"/>
5+
</samlp:Status>
6+
<saml:Assertion xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xs="http://www.w3.org/2001/XMLSchema" ID="_519c2712648ee09a06d1f9a08e9e835715fea60267" Version="2.0" IssueInstant="2014-03-29T12:01:57Z"><saml:Issuer>http://idp.example.com/</saml:Issuer><saml:Subject><saml:NameID SPNameQualifier="http://stuff.com/endpoints/metadata.php" Format="urn:oasis:names:tc:SAML:2.0:nameid-format:transient">_68392312d490db6d355555cfbbd8ec95d746516f60</saml:NameID><saml:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer"><saml:SubjectConfirmationData NotOnOrAfter="2055-06-07T20:17:08Z" InResponseTo="ONELOGIN_be60b8caf8e9d19b7a3551b244f116c947ff247d"/></saml:SubjectConfirmation></saml:Subject><saml:Conditions NotBefore="2011-01-26T03:23:48Z" NotOnOrAfter="2055-06-07T20:17:08Z"><saml:AudienceRestriction><saml:Audience>http://stuff.com/endpoints/metadata.php</saml:Audience></saml:AudienceRestriction></saml:Conditions><saml:AuthnStatement AuthnInstant="2014-03-29T11:59:43Z" SessionNotOnOrAfter="2055-06-07T20:17:08Z" SessionIndex="_7164a9a9f97828bfdb8d0ebc004a05d2e7d873f70c"><saml:AuthnContext><saml:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:Password</saml:AuthnContextClassRef></saml:AuthnContext></saml:AuthnStatement><saml:AttributeStatement><saml:Attribute Name="uid" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic"><saml:AttributeValue xsi:type="xs:string">test</saml:AttributeValue></saml:Attribute><saml:Attribute Name="mail" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic"><saml:AttributeValue xsi:type="xs:string">[email protected]</saml:AttributeValue></saml:Attribute><saml:Attribute Name="cn" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic"><saml:AttributeValue xsi:type="xs:string">test</saml:AttributeValue></saml:Attribute><saml:Attribute Name="sn" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic"><saml:AttributeValue xsi:type="xs:string">waa2</saml:AttributeValue></saml:Attribute><saml:Attribute Name="eduPersonAffiliation" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic"><saml:AttributeValue xsi:type="xs:string">user</saml:AttributeValue><saml:AttributeValue xsi:type="xs:string">admin</saml:AttributeValue></saml:Attribute></saml:AttributeStatement></saml:Assertion>
7+
</samlp:Response>
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
<samlp:Response xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" ID="pfxc3d2b542-0f7e-8767-8e87-5b0dc6913375" Version="2.0" IssueInstant="2014-03-21T13:41:09Z" Destination="https://pitbulk.no-ip.org/newonelogin/demo1/index.php?acs" InResponseTo="ONELOGIN_5d9e319c1b8a67da48227964c28d280e7860f804">
2+
<saml:Issuer>https://pitbulk.no-ip.org/simplesaml/saml2/idp/metadata.php</saml:Issuer>
3+
<ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
4+
<ds:SignedInfo><ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
5+
<ds:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/>
6+
<ds:Reference URI="#pfxc3d2b542-0f7e-8767-8e87-5b0dc6913375"><ds:Transforms><ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/><ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/></ds:Transforms><ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/><ds:DigestValue>1dQFiYU0o2OF7c/RVV8Gpgb4u3I=</ds:DigestValue></ds:Reference></ds:SignedInfo><ds:SignatureValue>wRgBXOq/FiLZc2mureTC/j6zY709OikJ5HeUSruHTdYjEg9aZy1RbxlKIYEIfXpnX7NBoKxfAMm+O0fsrqOjgcYxTVkqZjOr71qiXNbtwjeAkdYSpk5brsAcnfcPdv8QReYr3D7t5ZVCgYuvXQ+dNELKeag7e1ASOzVqOdp5Z9Y=</ds:SignatureValue>
7+
<ds:KeyInfo><ds:X509Data><ds:X509Certificate>MIICgTCCAeoCCQCbOlrWDdX7FTANBgkqhkiG9w0BAQUFADCBhDELMAkGA1UEBhMCTk8xGDAWBgNVBAgTD0FuZHJlYXMgU29sYmVyZzEMMAoGA1UEBxMDRm9vMRAwDgYDVQQKEwdVTklORVRUMRgwFgYDVQQDEw9mZWlkZS5lcmxhbmcubm8xITAfBgkqhkiG9w0BCQEWEmFuZHJlYXNAdW5pbmV0dC5ubzAeFw0wNzA2MTUxMjAxMzVaFw0wNzA4MTQxMjAxMzVaMIGEMQswCQYDVQQGEwJOTzEYMBYGA1UECBMPQW5kcmVhcyBTb2xiZXJnMQwwCgYDVQQHEwNGb28xEDAOBgNVBAoTB1VOSU5FVFQxGDAWBgNVBAMTD2ZlaWRlLmVybGFuZy5ubzEhMB8GCSqGSIb3DQEJARYSYW5kcmVhc0B1bmluZXR0Lm5vMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDivbhR7P516x/S3BqKxupQe0LONoliupiBOesCO3SHbDrl3+q9IbfnfmE04rNuMcPsIxB161TdDpIesLCn7c8aPHISKOtPlAeTZSnb8QAu7aRjZq3+PbrP5uW3TcfCGPtKTytHOge/OlJbo078dVhXQ14d1EDwXJW1rRXuUt4C8QIDAQABMA0GCSqGSIb3DQEBBQUAA4GBACDVfp86HObqY+e8BUoWQ9+VMQx1ASDohBjwOsg2WykUqRXF+dLfcUH9dWR63CtZIKFDbStNomPnQz7nbK+onygwBspVEbnHuUihZq3ZUdmumQqCw4Uvs/1Uvq3orOo/WJVhTyvLgFVK2QarQ4/67OZfHd7R+POBXhophSMv1ZOo</ds:X509Certificate></ds:X509Data></ds:KeyInfo></ds:Signature>
8+
<samlp:Status>
9+
<samlp:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success"/>
10+
</samlp:Status>
11+
<saml:Assertion xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xs="http://www.w3.org/2001/XMLSchema" ID="_cccd6024116641fe48e0ae2c51220d02755f96c98d" Version="2.0" IssueInstant="2014-03-21T13:41:09Z">
12+
<saml:Issuer>https://pitbulk.no-ip.org/simplesaml/saml2/idp/metadata.php</saml:Issuer>
13+
<saml:Subject>
14+
<saml:NameID SPNameQualifier="https://pitbulk.no-ip.org/newonelogin/demo1/metadata.php" Format="urn:oasis:names:tc:SAML:2.0:nameid-format:transient">_b98f98bb1ab512ced653b58baaff543448daed535d</saml:NameID>
15+
<saml:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer">
16+
<saml:SubjectConfirmationData NotOnOrAfter="2023-09-22T19:01:09Z" Recipient="https://pitbulk.no-ip.org/newonelogin/demo1/index.php?acs" InResponseTo="ONELOGIN_5d9e319c1b8a67da48227964c28d280e7860f804"/>
17+
</saml:SubjectConfirmation>
18+
</saml:Subject>
19+
<saml:Conditions NotBefore="2014-03-21T13:40:39Z" NotOnOrAfter="2023-09-22T19:01:09Z">
20+
<saml:AudienceRestriction>
21+
<saml:Audience>https://pitbulk.no-ip.org/newonelogin/demo1/metadata.php</saml:Audience>
22+
</saml:AudienceRestriction>
23+
</saml:Conditions>
24+
<saml:AuthnStatement AuthnInstant="2014-03-21T13:41:09Z" SessionNotOnOrAfter="2014-03-21T21:41:09Z" SessionIndex="_9fe0c8dcd3302e7364fcab22a52748ebf2224df0aa">
25+
<saml:AuthnContext>
26+
<saml:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:Password</saml:AuthnContextClassRef>
27+
</saml:AuthnContext>
28+
</saml:AuthnStatement>
29+
<saml:AttributeStatement>
30+
<saml:Attribute Name="uid" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic">
31+
<saml:AttributeValue xsi:type="xs:string">test</saml:AttributeValue>
32+
</saml:Attribute>
33+
<saml:Attribute Name="mail" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic">
34+
<saml:AttributeValue xsi:type="xs:string">[email protected]</saml:AttributeValue>
35+
</saml:Attribute>
36+
<saml:Attribute Name="cn" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic">
37+
<saml:AttributeValue xsi:type="xs:string">test</saml:AttributeValue>
38+
</saml:Attribute>
39+
<saml:Attribute Name="sn" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic">
40+
<saml:AttributeValue xsi:type="xs:string">waa2</saml:AttributeValue>
41+
</saml:Attribute>
42+
<saml:Attribute Name="eduPersonAffiliation" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic">
43+
<saml:AttributeValue xsi:type="xs:string">user</saml:AttributeValue>
44+
<saml:AttributeValue xsi:type="xs:string">admin</saml:AttributeValue>
45+
</saml:Attribute>
46+
</saml:AttributeStatement>
47+
</saml:Assertion>
48+
</samlp:Response>

0 commit comments

Comments
 (0)