Skip to content

Commit

Permalink
Add an option to use query string for validation
Browse files Browse the repository at this point in the history
When validating request or response signature in process_slo() we
currently rebuild query string from 'get_data' elements. This requires
URL encoding components of the string. Unfortunately, some IdPs (Azure
AD, ADFS) use lower-case encoding. To handle this, one needs to pass
lowercase_urlencoding=True. This complicates code that needs to support
different IdPs.

Instead, if 'query_string' is passed, take parts from it directly. This
avoids the need to URL encode them. This is similar to the
`retrieveParametersFromServer` argument in the PHP version.

This feature is disabled by default. Pass validate_signature_from_qs=True
to enable it.
  • Loading branch information
eltoder committed May 2, 2021
1 parent a866e22 commit 19e9d32
Showing 1 changed file with 26 additions and 10 deletions.
36 changes: 26 additions & 10 deletions src/onelogin/saml2/auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -528,6 +528,22 @@ def add_response_signature(self, response_data, sign_algorithm=OneLogin_Saml2_Co
"""
return self.__build_signature(response_data, 'SAMLResponse', sign_algorithm)

@staticmethod
def __build_sign_query_from_qs(query_string, saml_type):
"""
Build sign query from query string
:param query_string: The query string
:type query_string: str
:param saml_type: The target URL the user should be redirected to
:type saml_type: string SAMLRequest | SAMLResponse
"""
args = ('%s=' % saml_type, 'RelayState=', 'SigAlg=')
parts = query_string.split('&')
# Join in the order of arguments rather than the original order of parts.
return '&'.join(part for arg in args for part in parts if part.startswith(arg))

@staticmethod
def __build_sign_query(saml_data, relay_state, algorithm, saml_type, lowercase_urlencoding=False):
"""
Expand Down Expand Up @@ -660,16 +676,16 @@ def __validate_signature(self, data, saml_type, raise_exceptions=False):
if isinstance(sign_alg, bytes):
sign_alg = sign_alg.decode('utf8')

lowercase_urlencoding = False
if 'lowercase_urlencoding' in self.__request_data.keys():
lowercase_urlencoding = self.__request_data['lowercase_urlencoding']

signed_query = self.__build_sign_query(data[saml_type],
data.get('RelayState', None),
sign_alg,
saml_type,
lowercase_urlencoding
)
query_string = self.__request_data.get('query_string')
if query_string and self.__request_data.get('validate_signature_from_qs'):
signed_query = self.__build_sign_query_from_qs(query_string, saml_type)
else:
lowercase_urlencoding = self.__request_data.get('lowercase_urlencoding', False)
signed_query = self.__build_sign_query(data[saml_type],
data.get('RelayState'),
sign_alg,
saml_type,
lowercase_urlencoding)

if exists_multix509sign:
for cert in idp_data['x509certMulti']['signing']:
Expand Down

0 comments on commit 19e9d32

Please sign in to comment.