Skip to content

Commit f60a6f8

Browse files
authored
Merge pull request #276 from akx/remove-server-port-from-request-data
Deprecate server_port from request data dictionary
2 parents 25f35fa + f435584 commit f60a6f8

File tree

8 files changed

+41
-57
lines changed

8 files changed

+41
-57
lines changed

README.md

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -573,7 +573,6 @@ This parameter has the following scheme:
573573
req = {
574574
"http_host": "",
575575
"script_name": "",
576-
"server_port": "",
577576
"get_data": "",
578577
"post_data": "",
579578

@@ -594,16 +593,14 @@ def prepare_from_django_request(request):
594593
return {
595594
'http_host': request.META['HTTP_HOST'],
596595
'script_name': request.META['PATH_INFO'],
597-
'server_port': request.META['SERVER_PORT'],
598596
'get_data': request.GET.copy(),
599597
'post_data': request.POST.copy()
600598
}
601599

602600
def prepare_from_flask_request(request):
603601
url_data = urlparse(request.url)
604602
return {
605-
'http_host': request.host,
606-
'server_port': url_data.port,
603+
'http_host': request.netloc,
607604
'script_name': request.path,
608605
'get_data': request.args.copy(),
609606
'post_data': request.form.copy()

demo-django/demo/views.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@ def prepare_django_request(request):
2020
'https': 'on' if request.is_secure() else 'off',
2121
'http_host': request.META['HTTP_HOST'],
2222
'script_name': request.META['PATH_INFO'],
23-
'server_port': request.META['SERVER_PORT'],
2423
'get_data': request.GET.copy(),
2524
# Uncomment if using ADFS as IdP, https://github.com/onelogin/python-saml/pull/144
2625
# 'lowercase_urlencoding': True,

demo-flask/index.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,9 @@ def init_saml_auth(req):
2121

2222
def prepare_flask_request(request):
2323
# If server is behind proxys or balancers use the HTTP_X_FORWARDED fields
24-
url_data = urlparse(request.url)
2524
return {
2625
'https': 'on' if request.scheme == 'https' else 'off',
27-
'http_host': request.host,
28-
'server_port': url_data.port,
26+
'http_host': request.netloc,
2927
'script_name': request.path,
3028
'get_data': request.args.copy(),
3129
# Uncomment if using ADFS as IdP, https://github.com/onelogin/python-saml/pull/144

demo-tornado/views.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -157,9 +157,8 @@ def prepare_tornado_request(request):
157157

158158
result = {
159159
'https': 'on' if request == 'https' else 'off',
160-
'http_host': tornado.httputil.split_host_and_port(request.host)[0],
160+
'http_host': request.host,
161161
'script_name': request.path,
162-
'server_port': tornado.httputil.split_host_and_port(request.host)[1],
163162
'get_data': dataDict,
164163
'post_data': dataDict,
165164
'query_string': request.query

demo_pyramid/demo_pyramid/views.py

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,19 +15,16 @@ def init_saml_auth(req):
1515

1616

1717
def prepare_pyramid_request(request):
18-
# Uncomment this portion to set the request.scheme and request.server_port
18+
# Uncomment this portion to set the request.scheme
1919
# based on the supplied `X-Forwarded` headers.
2020
# Useful for running behind reverse proxies or balancers.
2121
#
2222
# if 'X-Forwarded-Proto' in request.headers:
2323
# request.scheme = request.headers['X-Forwarded-Proto']
24-
# if 'X-Forwarded-Port' in request.headers:
25-
# request.server_port = int(request.headers['X-Forwarded-Port'])
2624

2725
return {
2826
'https': 'on' if request.scheme == 'https' else 'off',
2927
'http_host': request.host,
30-
'server_port': request.server_port,
3128
'script_name': request.path,
3229
'get_data': request.GET.copy(),
3330
# Uncomment if using ADFS as IdP, https://github.com/onelogin/python-saml/pull/144

src/onelogin/saml2/utils.py

Lines changed: 19 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
"""
1111

1212
import base64
13+
import warnings
1314
from copy import deepcopy
1415
import calendar
1516
from datetime import datetime
@@ -254,27 +255,25 @@ def get_self_url_host(request_data):
254255
:rtype: string
255256
"""
256257
current_host = OneLogin_Saml2_Utils.get_self_host(request_data)
257-
port = ''
258-
if OneLogin_Saml2_Utils.is_https(request_data):
259-
protocol = 'https'
260-
else:
261-
protocol = 'http'
262-
263-
if 'server_port' in request_data and request_data['server_port'] is not None:
264-
port_number = str(request_data['server_port'])
265-
port = ':' + port_number
258+
protocol = 'https' if OneLogin_Saml2_Utils.is_https(request_data) else 'http'
266259

267-
if protocol == 'http' and port_number == '80':
268-
port = ''
269-
elif protocol == 'https' and port_number == '443':
270-
port = ''
260+
if request_data.get('server_port') is not None:
261+
warnings.warn(
262+
'The server_port key in request data is deprecated. '
263+
'The http_host key should include a port, if required.',
264+
category=DeprecationWarning,
265+
)
266+
port_suffix = ':%s' % request_data['server_port']
267+
if not current_host.endswith(port_suffix):
268+
if not ((protocol == 'https' and port_suffix == ':443') or (protocol == 'http' and port_suffix == ':80')):
269+
current_host += port_suffix
271270

272-
return '%s://%s%s' % (protocol, current_host, port)
271+
return '%s://%s' % (protocol, current_host)
273272

274273
@staticmethod
275274
def get_self_host(request_data):
276275
"""
277-
Returns the current host.
276+
Returns the current host (which may include a port number part).
278277
279278
:param request_data: The request as a dict
280279
:type: dict
@@ -283,22 +282,11 @@ def get_self_host(request_data):
283282
:rtype: string
284283
"""
285284
if 'http_host' in request_data:
286-
current_host = request_data['http_host']
285+
return request_data['http_host']
287286
elif 'server_name' in request_data:
288-
current_host = request_data['server_name']
289-
else:
290-
raise Exception('No hostname defined')
291-
292-
if ':' in current_host:
293-
current_host_data = current_host.split(':')
294-
possible_port = current_host_data[-1]
295-
try:
296-
int(possible_port)
297-
current_host = current_host_data[0]
298-
except ValueError:
299-
current_host = ':'.join(current_host_data)
300-
301-
return current_host
287+
warnings.warn("The server_name key in request data is undocumented & deprecated.", category=DeprecationWarning)
288+
return request_data['server_name']
289+
raise Exception('No hostname defined')
302290

303291
@staticmethod
304292
def is_https(request_data):
@@ -312,6 +300,7 @@ def is_https(request_data):
312300
:rtype: boolean
313301
"""
314302
is_https = 'https' in request_data and request_data['https'] != 'off'
303+
# TODO: this use of server_port should be removed too
315304
is_https = is_https or ('server_port' in request_data and str(request_data['server_port']) == '443')
316305
return is_https
317306

tests/src/OneLogin/saml2_tests/response_test.py

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
# MIT License
55

66
from base64 import b64decode
7+
78
from lxml import etree
89
from datetime import datetime
910
from datetime import timedelta
@@ -1528,22 +1529,31 @@ def testIsInValidEncIssues(self):
15281529
self.assertFalse(response_5.is_valid(request_data))
15291530
self.assertEqual('The NameID of the Response is not encrypted and the SP require it', response_5.get_error())
15301531

1532+
def testIsInValidEncIssues_2(self):
15311533
settings_info_2 = self.loadSettingsJSON('settings3.json')
15321534
settings_info_2['strict'] = True
15331535
settings_info_2['security']['wantNameIdEncrypted'] = True
15341536
settings_2 = OneLogin_Saml2_Settings(settings_info_2)
15351537

15361538
request_data = {
1537-
'http_host': 'pytoolkit.com',
1538-
'server_port': 8000,
15391539
'script_name': '',
15401540
'request_uri': '?acs',
15411541
}
1542-
1543-
message_2 = self.file_contents(join(self.data_path, 'responses', 'valid_encrypted_assertion_encrypted_nameid.xml.base64'))
1544-
response_6 = OneLogin_Saml2_Response(settings_2, message_2)
1545-
self.assertFalse(response_6.is_valid(request_data))
1546-
self.assertEqual('The attributes have expired, based on the SessionNotOnOrAfter of the AttributeStatement of this Response', response_6.get_error())
1542+
for separate_port in (False, True):
1543+
if separate_port:
1544+
request_data.update({
1545+
'http_host': 'pytoolkit.com',
1546+
'server_port': 8000,
1547+
})
1548+
else:
1549+
request_data.update({
1550+
'http_host': 'pytoolkit.com:8000',
1551+
})
1552+
1553+
message_2 = self.file_contents(join(self.data_path, 'responses', 'valid_encrypted_assertion_encrypted_nameid.xml.base64'))
1554+
response_6 = OneLogin_Saml2_Response(settings_2, message_2)
1555+
self.assertFalse(response_6.is_valid(request_data))
1556+
self.assertEqual('The attributes have expired, based on the SessionNotOnOrAfter of the AttributeStatement of this Response', response_6.get_error())
15471557

15481558
def testIsInValidCert(self):
15491559
"""

tests/src/OneLogin/saml2_tests/utils_test.py

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -190,7 +190,7 @@ def testGetselfhost(self):
190190
request_data = {
191191
'http_host': 'example.com:443'
192192
}
193-
self.assertEqual('example.com', OneLogin_Saml2_Utils.get_self_host(request_data))
193+
self.assertEqual('example.com:443', OneLogin_Saml2_Utils.get_self_host(request_data))
194194

195195
request_data = {
196196
'http_host': 'example.com:ok'
@@ -211,11 +211,6 @@ def testisHTTPS(self):
211211
}
212212
self.assertTrue(OneLogin_Saml2_Utils.is_https(request_data))
213213

214-
request_data = {
215-
'server_port': '80'
216-
}
217-
self.assertFalse(OneLogin_Saml2_Utils.is_https(request_data))
218-
219214
request_data = {
220215
'server_port': '443'
221216
}

0 commit comments

Comments
 (0)