Skip to content

Commit

Permalink
Enabling different slo endpoint for responses to IdP-initiated logout…
Browse files Browse the repository at this point in the history
…. Merge branch 'BeritJanssen-master'
  • Loading branch information
pitbulk committed Jan 8, 2021
2 parents 4380bf1 + 9fdb11d commit 271938e
Show file tree
Hide file tree
Showing 7 changed files with 99 additions and 8 deletions.
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -304,6 +304,9 @@ This is the ``settings.json`` file:
"singleLogoutService": {
// URL Location of the IdP where SLO Request will be sent.
"url": "https://app.onelogin.com/trust/saml2/http-redirect/slo/<onelogin_connector_id>",
// URL Location where the <Response> from the SP will returned (after IdP-initiated logout)
// OPTIONAL: only specify if different from url parameter
"responseUrl": "https://app.onelogin.com/trust/saml2/http-redirect/slo_return/<onelogin_connector_id>"
// SAML protocol binding to be used when returning the <Response>
// message. OneLogin Toolkit supports the HTTP-Redirect binding
// only for this endpoint.
Expand Down
18 changes: 12 additions & 6 deletions src/onelogin/saml2/auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,7 @@ def process_slo(self, keep_local_session=False, request_id=None, delete_session_
if security['logoutResponseSigned']:
self.add_response_signature(parameters, security['signatureAlgorithm'])

return self.redirect_to(self.get_slo_url(), parameters)
return self.redirect_to(self.get_slo_response_url(), parameters)
else:
self.__errors.append('invalid_binding')
raise OneLogin_Saml2_Error(
Expand Down Expand Up @@ -454,8 +454,7 @@ def get_sso_url(self):
:returns: An URL, the SSO endpoint of the IdP
:rtype: string
"""
idp_data = self.__settings.get_idp_data()
return idp_data['singleSignOnService']['url']
return self.__settings.get_idp_sso_url()

def get_slo_url(self):
"""
Expand All @@ -464,9 +463,16 @@ def get_slo_url(self):
:returns: An URL, the SLO endpoint of the IdP
:rtype: string
"""
idp_data = self.__settings.get_idp_data()
if 'url' in idp_data['singleLogoutService']:
return idp_data['singleLogoutService']['url']
return self.__settings.get_idp_slo_url()

def get_slo_response_url(self):
"""
Gets the SLO return URL for IdP-initiated logout.
:returns: an URL, the SLO return endpoint of the IdP
:rtype: string
"""
return self.__settings.get_idp_slo_response_url()

def add_request_signature(self, request_data, sign_algorithm=OneLogin_Saml2_Constants.RSA_SHA1):
"""
Expand Down
2 changes: 1 addition & 1 deletion src/onelogin/saml2/logout_request.py
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ def __init__(self, settings, request=None, name_id=None, session_index=None, nq=
{
'id': uid,
'issue_instant': issue_instant,
'single_logout_url': idp_data['singleLogoutService']['url'],
'single_logout_url': self.__settings.get_idp_slo_response_url(),
'entity_id': sp_data['entityId'],
'name_id': name_id_obj,
'session_index': session_index_str,
Expand Down
2 changes: 1 addition & 1 deletion src/onelogin/saml2/logout_response.py
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,7 @@ def build(self, in_response_to):
{
'id': uid,
'issue_instant': issue_instant,
'destination': idp_data['singleLogoutService']['url'],
'destination': self.__settings.get_idp_slo_response_url(),
'in_response_to': in_response_to,
'entity_id': sp_data['entityId'],
'status': "urn:oasis:names:tc:SAML:2.0:status:Success"
Expand Down
31 changes: 31 additions & 0 deletions src/onelogin/saml2/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -506,6 +506,37 @@ def check_sp_certs(self):
cert = self.get_sp_cert()
return key is not None and cert is not None

def get_idp_sso_url(self):
"""
Gets the IdP SSO URL.
:returns: An URL, the SSO endpoint of the IdP
:rtype: string
"""
idp_data = self.get_idp_data()
return idp_data['singleSignOnService']['url']

def get_idp_slo_url(self):
"""
Gets the IdP SLO URL.
:returns: An URL, the SLO endpoint of the IdP
:rtype: string
"""
idp_data = self.get_idp_data()
if 'url' in idp_data['singleLogoutService']:
return idp_data['singleLogoutService']['url']

def get_idp_slo_response_url(self):
"""
Gets the IdP SLO return URL for IdP-initiated logout.
:returns: an URL, the SLO return endpoint of the IdP
:rtype: string
"""
slo_data = self.get_idp_data()['singleLogoutService']
return slo_data.get('responseUrl', self.get_idp_slo_url())

def get_sp_key(self):
"""
Returns the x509 private key of the SP.
Expand Down
16 changes: 16 additions & 0 deletions tests/src/OneLogin/saml2_tests/auth_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,22 @@ def testGetSLOurl(self):
slo_url = settings_info['idp']['singleLogoutService']['url']
self.assertEqual(auth.get_slo_url(), slo_url)

def testGetSLOresponseUrl(self):
"""
Tests the get_slo_response_url method of the OneLogin_Saml2_Auth class
"""
settings_info = self.loadSettingsJSON()
settings_info['idp']['singleLogoutService']['responseUrl'] = "http://idp.example.com/SingleLogoutReturn.php"
auth = OneLogin_Saml2_Auth(self.get_request(), old_settings=settings_info)
slo_url = settings_info['idp']['singleLogoutService']['responseUrl']
self.assertEqual(auth.get_slo_response_url(), slo_url)
# test that the function falls back to the url setting if responseUrl is not set
settings_info['idp']['singleLogoutService'].pop('responseUrl')
auth = OneLogin_Saml2_Auth(self.get_request(), old_settings=settings_info)
slo_url = settings_info['idp']['singleLogoutService']['url']
self.assertEqual(auth.get_slo_response_url(), slo_url)


def testGetSessionIndex(self):
"""
Tests the get_session_index method of the OneLogin_Saml2_Auth class
Expand Down
35 changes: 35 additions & 0 deletions tests/src/OneLogin/saml2_tests/settings_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,41 @@ def testGetSchemasPath(self):
base = settings.get_base_path()
self.assertEqual(join(base, 'lib', 'schemas') + sep, settings.get_schemas_path())

def testGetIdPSSOurl(self):
"""
Tests the get_idp_sso_url method of the OneLogin_Saml2_Settings class
"""
settings_info = self.loadSettingsJSON()
settings = OneLogin_Saml2_Settings(settings_info)

sso_url = settings_info['idp']['singleSignOnService']['url']
self.assertEqual(settings.get_idp_sso_url(), sso_url)

def testGetIdPSLOurl(self):
"""
Tests the get_idp_slo_url method of the OneLogin_Saml2_Settings class
"""
settings_info = self.loadSettingsJSON()
settings = OneLogin_Saml2_Settings(settings_info)

slo_url = settings_info['idp']['singleLogoutService']['url']
self.assertEqual(settings.get_idp_slo_url(), slo_url)

def testGetIdPSLOresponseUrl(self):
"""
Tests the get_idp_slo_response_url method of the OneLogin_Saml2_Settings class
"""
settings_info = self.loadSettingsJSON()
settings_info['idp']['singleLogoutService']['responseUrl'] = "http://idp.example.com/SingleLogoutReturn.php"
settings = OneLogin_Saml2_Settings(settings_info)
slo_url = settings_info['idp']['singleLogoutService']['responseUrl']
self.assertEqual(settings.get_idp_slo_response_url(), slo_url)
# test that the function falls back to the url setting if responseUrl is not set
settings_info['idp']['singleLogoutService'].pop('responseUrl')
settings = OneLogin_Saml2_Settings(settings_info)
slo_url = settings_info['idp']['singleLogoutService']['url']
self.assertEqual(settings.get_idp_slo_response_url(), slo_url)

def testGetSPCert(self):
"""
Tests the get_sp_cert method of the OneLogin_Saml2_Settings
Expand Down

0 comments on commit 271938e

Please sign in to comment.