Skip to content

Commit 61a3c02

Browse files
authored
Merge pull request #44 from securenative/dev
Align ip extraction and add proxy headers tests
2 parents 2e376e7 + 88f9f99 commit 61a3c02

File tree

9 files changed

+124
-149
lines changed

9 files changed

+124
-149
lines changed

VERSION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
0.3.2
1+
0.3.3

requirements.txt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,6 @@ requests~=2.24.0
22
pycryptodome==3.9.8
33
responses==0.10.15
44
requests-mock==1.8.0
5-
pytest==5.4.3
5+
pytest==5.4.3
6+
setuptools~=49.6.0
7+
IPy~=1.0

securenative/config/configuration_manager.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77

88
class ConfigurationManager(object):
99
DEFAULT_CONFIG_FILE = "securenative.ini"
10-
CUSTOM_CONFIG_FILE_ENV_NAME = "SECURENATIVE_COMFIG_FILE"
10+
CUSTOM_CONFIG_FILE_ENV_NAME = "SECURENATIVE_CONFIG_FILE"
1111
config = ConfigParser()
1212

1313
@classmethod
@@ -35,8 +35,12 @@ def _get_resource_path(cls, env_name):
3535
@classmethod
3636
def _get_env_or_default(cls, properties, key, default):
3737
if os.environ.get(key):
38+
if "," in os.environ.get(key):
39+
return os.environ.get(key).split(",")
3840
return os.environ.get(key)
3941
if properties.get(key):
42+
if "," in properties.get(key):
43+
return properties.get(key).split(",")
4044
return properties.get(key)
4145
return default
4246

securenative/utils/ip_utils.py

Lines changed: 9 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import ipaddress
22
import re
3-
import socket
3+
from IPy import IP
44

55

66
class IpUtils(object):
@@ -17,21 +17,16 @@ def is_ip_address(ip_address):
1717

1818
@staticmethod
1919
def is_valid_public_ip(ip_address):
20-
try:
21-
socket.inet_aton(ip_address)
22-
except socket.error:
23-
return False
20+
ip = ipaddress.ip_address(ip_address)
2421

25-
ip = ipaddress.IPv4Address(ip_address)
26-
if ip.is_loopback \
27-
or not ip.is_global \
28-
or ip.is_private \
29-
or ip.is_link_local \
30-
or ip.is_multicast \
31-
or ip.is_reserved \
32-
or ip.is_unspecified:
22+
if ip.version is 4:
23+
if not ip.is_loopback and not ip.is_reserved and not ip.is_unspecified and IP(ip_address).iptype() is not "PRIVATE":
24+
return True
3325
return False
34-
return True
26+
27+
if not ip.is_unspecified and IP(ip_address).iptype() is not "PRIVATE":
28+
return True
29+
return False
3530

3631
@staticmethod
3732
def is_loop_back(ip_address):
Lines changed: 46 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
1+
from securenative.utils.ip_utils import IpUtils
2+
3+
14
class RequestUtils(object):
25
SECURENATIVE_COOKIE = "_sn"
36
SECURENATIVE_HEADER = "x-securenative"
7+
IP_HEADERS = ["HTTP_X_FORWARDED_FOR", "X_FORWARDED_FOR", "REMOTE_ADDR", "x-forwarded-for", "x-client-ip", "x-real-ip", "x-forwarded", "x-cluster-client-ip", "forwarded-for", "forwarded", "via"]
48

59
@staticmethod
610
def get_secure_header_from_request(headers):
@@ -15,33 +19,60 @@ def get_client_ip_from_request(request, options):
1519
for header in options.proxy_headers:
1620
try:
1721
if request.environ.get(header) is not None:
18-
return request.environ.get(header)
22+
ips = request.environ.get(header).split(',')
23+
return RequestUtils.get_valid_ip(ips)
1924
if request.headers[header] is not None:
20-
return request.headers[header]
25+
ips = request.headers[header].split(',')
26+
return RequestUtils.get_valid_ip(ips)
2127
except Exception:
2228
try:
2329
if request.headers[header] is not None:
24-
return request.headers[header]
30+
ips = request.headers[header].split(',')
31+
return RequestUtils.get_valid_ip(ips)
2532
except Exception:
2633
continue
2734

28-
try:
29-
x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR')
30-
if x_forwarded_for:
31-
ip = x_forwarded_for.split(',')[-1].strip()
32-
else:
33-
ip = request.META.get('REMOTE_ADDR')
35+
for header in RequestUtils.IP_HEADERS:
36+
try:
37+
ips = request.headers.get(header).split(',')
38+
return RequestUtils.get_valid_ip(ips)
39+
except Exception:
40+
continue
3441

35-
if ip is None or ip == "":
36-
ip = request.environ.get('HTTP_X_FORWARDED_FOR', request.environ.get('REMOTE_ADDR', ""))
42+
for header in RequestUtils.IP_HEADERS:
43+
try:
44+
ips = request.META.get(header).split(',')
45+
return RequestUtils.get_valid_ip(ips)
46+
except Exception:
47+
continue
3748

38-
return ip
39-
except Exception:
40-
return ""
49+
return ""
4150

4251
@staticmethod
4352
def get_remote_ip_from_request(request):
4453
try:
45-
return request.raw._original_response.fp.raw._sock.getpeername()[0]
54+
if len(request.raw._original_response.fp.raw._sock.getpeername()) > 0:
55+
return request.raw._original_response.fp.raw._sock.getpeername()[0]
4656
except Exception:
4757
return ""
58+
59+
@staticmethod
60+
def get_valid_ip(ips):
61+
if isinstance(ips, list):
62+
for ip in ips:
63+
ip = ip.strip()
64+
if IpUtils.is_valid_public_ip(ip):
65+
return ip
66+
67+
# No public ip found check for no loopback
68+
for ip in ips:
69+
ip = ip.strip()
70+
if not IpUtils.is_loop_back(ip):
71+
return ip
72+
73+
ip = ips.strip()
74+
if IpUtils.is_valid_public_ip(ip):
75+
return ip
76+
77+
if IpUtils.is_loop_back(ip):
78+
return ip

securenative/utils/version_utils.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,4 @@ class VersionUtils(object):
22

33
@staticmethod
44
def get_version():
5-
return "0.3.2"
5+
return "0.3.3"

tests/api_manager_test.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ def test_track_event(self):
5050

5151
@responses.activate
5252
def test_should_timeout_on_post(self):
53-
options = SecureNativeOptions(api_key="YOUR_API_KEY", auto_send=True, timeout=0,
53+
options = SecureNativeOptions(api_key="YOUR_API_KEY", auto_send=True, timeout=0.000001,
5454
api_url="https://api.securenative-stg.com/collector/api/v1")
5555

5656
responses.add(responses.POST, "https://api.securenative-stg.com/collector/api/v1/verify",

0 commit comments

Comments
 (0)