Skip to content

Commit d960ec5

Browse files
committed
Fix encode ADFS issue.
1 parent a24f585 commit d960ec5

4 files changed

Lines changed: 27 additions & 8 deletions

File tree

demo-django/demo/views.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ def prepare_django_request(request):
2323
'script_name': request.META['PATH_INFO'],
2424
'server_port': request.META['SERVER_PORT'],
2525
'get_data': request.GET.copy(),
26+
# Uncomment if using ADFS as IdP, https://github.com/onelogin/python-saml/pull/144
27+
# 'lowercase_urlencoding': True,
2628
'post_data': request.POST.copy()
2729
}
2830
return result

demo-flask/index.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ def prepare_flask_request(request):
2828
'server_port': url_data.port,
2929
'script_name': request.path,
3030
'get_data': request.args.copy(),
31+
# Uncomment if using ADFS as IdP, https://github.com/onelogin/python-saml/pull/144
32+
# 'lowercase_urlencoding': True,
3133
'post_data': request.form.copy()
3234
}
3335

src/onelogin/saml2/auth.py

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -386,7 +386,7 @@ def add_response_signature(self, response_data, sign_algorithm=OneLogin_Saml2_Co
386386
return self.__build_signature(response_data, 'SAMLResponse', sign_algorithm)
387387

388388
@staticmethod
389-
def __build_sign_query(saml_data, relay_state, algorithm, saml_type):
389+
def __build_sign_query(saml_data, relay_state, algorithm, saml_type, lowercase_urlencoding=False):
390390
"""
391391
Build sign query
392392
@@ -401,12 +401,14 @@ def __build_sign_query(saml_data, relay_state, algorithm, saml_type):
401401
402402
:param saml_type: The target URL the user should be redirected to
403403
:type saml_type: string SAMLRequest | SAMLResponse
404-
"""
405404
406-
sign_data = ['%s=%s' % (saml_type, OneLogin_Saml2_Utils.escape_url(saml_data))]
405+
:param lowercase_urlencoding: lowercase or no
406+
:type lowercase_urlencoding: boolean
407+
"""
408+
sign_data = ['%s=%s' % (saml_type, OneLogin_Saml2_Utils.escape_url(saml_data, lowercase_urlencoding))]
407409
if relay_state is not None:
408-
sign_data.append('RelayState=%s' % OneLogin_Saml2_Utils.escape_url(relay_state))
409-
sign_data.append('SigAlg=%s' % OneLogin_Saml2_Utils.escape_url(algorithm))
410+
sign_data.append('RelayState=%s' % OneLogin_Saml2_Utils.escape_url(relay_state, lowercase_urlencoding))
411+
sign_data.append('SigAlg=%s' % OneLogin_Saml2_Utils.escape_url(algorithm, lowercase_urlencoding))
410412
return '&'.join(sign_data)
411413

412414
def __build_signature(self, data, saml_type, sign_algorithm=OneLogin_Saml2_Constants.RSA_SHA1):
@@ -502,10 +504,15 @@ def __validate_signature(self, data, saml_type):
502504
if isinstance(sign_alg, bytes):
503505
sign_alg = sign_alg.decode('utf8')
504506

507+
lowercase_urlencoding = False
508+
if 'lowercase_urlencoding' in self.__request_data.keys():
509+
lowercase_urlencoding = self.__request_data['lowercase_urlencoding']
510+
505511
signed_query = self.__build_sign_query(data[saml_type],
506512
data.get('RelayState', None),
507513
sign_alg,
508-
saml_type)
514+
saml_type,
515+
)
509516

510517
if not OneLogin_Saml2_Utils.validate_binary_sign(signed_query,
511518
OneLogin_Saml2_Utils.b64decode(signature),

src/onelogin/saml2/utils.py

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,15 +41,23 @@ class OneLogin_Saml2_Utils(object):
4141
4242
"""
4343
@staticmethod
44-
def escape_url(url):
44+
def escape_url(url, lowercase_urlencoding=False):
4545
"""
4646
escape the non-safe symbols in url
47+
The encoding used by ADFS 3.0 is not compatible with
48+
python's quote_plus (ADFS produces lower case hex numbers and quote_plus produces
49+
upper case hex numbers)
4750
:param url: the url to escape
4851
:type url: str
52+
53+
:param lowercase_urlencoding: lowercase or no
54+
:type lowercase_urlencoding: boolean
55+
4956
:return: the escaped url
5057
:rtype str
5158
"""
52-
return quote_plus(url)
59+
encoded = quote_plus(url)
60+
return re.sub(r"%[A-F0-9]{2}", lambda m: m.group(0).lower(), encoded) if lowercase_urlencoding else encoded
5361

5462
@staticmethod
5563
def b64encode(data):

0 commit comments

Comments
 (0)