Skip to content

Commit 3f7127c

Browse files
author
Inbal Tako
committed
Support custom headers extraction
1 parent eb80d72 commit 3f7127c

File tree

11 files changed

+73
-22
lines changed

11 files changed

+73
-22
lines changed

README.md

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,6 @@ You can also create request context from requests:
111111

112112
```python
113113
from securenative.securenative import SecureNative
114-
from securenative.context.securenative_context import SecureNativeContext
115114
from securenative.models.event_options import EventOptions
116115
from securenative.enums.event_types import EventTypes
117116
from securenative.models.user_traits import UserTraits
@@ -120,7 +119,7 @@ from securenative.models.user_traits import UserTraits
120119
def track(request):
121120
securenative = SecureNative.get_instance()
122121

123-
context = SecureNativeContext.from_http_request(request)
122+
context = SecureNative.from_http_request(request)
124123
event_options = EventOptions(event=EventTypes.LOG_IN,
125124
user_id="1234",
126125
user_traits=UserTraits("Your Name", "name@gmail.com", "+1234567890"),
@@ -137,15 +136,14 @@ def track(request):
137136
```python
138137
from securenative.securenative import SecureNative
139138
from securenative.models.event_options import EventOptions
140-
from securenative.context.securenative_context import SecureNativeContext
141139
from securenative.enums.event_types import EventTypes
142140
from securenative.models.user_traits import UserTraits
143141

144142

145143
def verify(request):
146144
securenative = SecureNative.get_instance()
147145

148-
context = SecureNativeContext.from_http_request(request)
146+
context = SecureNative.from_http_request(request)
149147
event_options = EventOptions(event=EventTypes.LOG_IN,
150148
user_id="1234",
151149
user_traits=UserTraits("Your Name", "name@gmail.com", "+1234567890"),
@@ -173,3 +171,26 @@ def webhook_endpoint(request):
173171
is_verified = securenative.verify_request_payload(request)
174172
```
175173

174+
## Extract proxy headers from Cloudflare
175+
176+
You can specify custom header keys to allow extraction of client ip from different providers.
177+
This example demonstrates the usage of proxy headers for ip extraction from Cloudflare.
178+
179+
### Option 1: Using config file
180+
```ini
181+
SECURENATIVE_API_KEY: dsbe27fh3437r2yd326fg3fdg36f43
182+
SECURENATIVE_PROXY_HEADERS: ["CF-Connecting-IP"]
183+
```
184+
185+
Initialize sdk as shown above.
186+
187+
### Options 2: Using ConfigurationBuilder
188+
189+
```python
190+
from securenative.securenative import SecureNative
191+
from securenative.config.securenative_options import SecureNativeOptions
192+
193+
194+
options = SecureNativeOptions(api_key="YOUR_API_KEY", max_events=10, log_level="ERROR", proxy_headers=['CF-Connecting-IP'])
195+
securenative = SecureNative.init_with_options(options)
196+
```

VERSION

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

securenative/config/configuration_manager.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,4 +63,6 @@ def load_config(cls, resource_path):
6363
options.log_level),
6464
fail_over_strategy=cls._get_env_or_default(properties,
6565
"SECURENATIVE_FAILOVER_STRATEGY",
66-
options.fail_over_strategy))
66+
options.fail_over_strategy),
67+
proxy_headers=cls._get_env_or_default(properties, "SECURENATIVE_PROXY_HEADERS",
68+
options.proxy_headers))

securenative/config/securenative_options.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,10 @@ class SecureNativeOptions(object):
55

66
def __init__(self, api_key=None, api_url="https://api.securenative.com/collector/api/v1", interval=1000,
77
max_events=1000, timeout=1500, auto_send=True, disable=False, log_level="CRITICAL",
8-
fail_over_strategy=FailOverStrategy.FAIL_OPEN.value):
8+
fail_over_strategy=FailOverStrategy.FAIL_OPEN.value, proxy_headers=None):
99

10+
if proxy_headers is None:
11+
proxy_headers = []
1012
if fail_over_strategy != FailOverStrategy.FAIL_OPEN.value and \
1113
fail_over_strategy != FailOverStrategy.FAIL_CLOSED.value:
1214
self.fail_over_strategy = FailOverStrategy.FAIL_OPEN.value
@@ -21,3 +23,4 @@ def __init__(self, api_key=None, api_url="https://api.securenative.com/collector
2123
self.auto_send = auto_send
2224
self.disable = disable
2325
self.log_level = log_level
26+
self.proxy_headers = proxy_headers

securenative/context/securenative_context.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ def __init__(self, client_token=None, ip=None, remote_ip=None, headers=None, url
1414
self.body = body
1515

1616
@staticmethod
17-
def from_http_request(request):
17+
def from_http_request(request, options):
1818
try:
1919
client_token = request.cookies[RequestUtils.SECURENATIVE_COOKIE]
2020
except Exception:
@@ -28,6 +28,6 @@ def from_http_request(request):
2828
if Utils.is_null_or_empty(client_token):
2929
client_token = RequestUtils.get_secure_header_from_request(headers)
3030

31-
return SecureNativeContext(client_token, RequestUtils.get_client_ip_from_request(request),
31+
return SecureNativeContext(client_token, RequestUtils.get_client_ip_from_request(request, options),
3232
RequestUtils.get_remote_ip_from_request(request), headers, request.url,
3333
request.method, None)

securenative/securenative.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
from securenative.api_manager import ApiManager
22
from securenative.config.configuration_manager import ConfigurationManager
33
from securenative.config.securenative_options import SecureNativeOptions
4+
from securenative.context.securenative_context import SecureNativeContext
45
from securenative.event_manager import EventManager
56
from securenative.exceptions.securenative_config_exception import SecureNativeConfigException
67
from securenative.exceptions.securenative_sdk_Illegal_state_exception import SecureNativeSDKIllegalStateException
@@ -75,6 +76,10 @@ def verify(self, event_options):
7576
def _flush(cls):
7677
cls._securenative = None
7778

79+
@classmethod
80+
def from_http_request(cls, request):
81+
return SecureNativeContext.from_http_request(request, SecureNative._options)
82+
7883
def verify_request_payload(self, request):
7984
request_signature = request.header[SignatureUtils.SignatureHeader]
8085
body = request.body

securenative/utils/request_utils.py

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,16 @@ def get_secure_header_from_request(headers):
1010
return ""
1111

1212
@staticmethod
13-
def get_client_ip_from_request(request):
13+
def get_client_ip_from_request(request, options):
14+
if options and len(options.proxy_headers) > 0:
15+
for header in options.proxy_headers:
16+
try:
17+
if request.environ.get(header) is not None:
18+
return request.environ.get(header)
19+
except AttributeError:
20+
if request.headers[header] is not None:
21+
return request.headers[header]
22+
1423
try:
1524
x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR')
1625
if x_forwarded_for:

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.1"
5+
return "0.3.2"

tests/context_builder_test.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ def test_create_context_from_request(self):
2121
request.headers = {
2222
"x-securenative": "71532c1fad2c7f56118f7969e401f3cf080239140d208e7934e6a530818c37e544a0c2330a487bcc6fe4f662a57f265a3ed9f37871e80529128a5e4f2ca02db0fb975ded401398f698f19bb0cafd68a239c6caff99f6f105286ab695eaf3477365bdef524f5d70d9be1d1d474506b433aed05d7ed9a435eeca357de57817b37c638b6bb417ffb101eaf856987615a77a"}
2323

24-
context = SecureNativeContext.from_http_request(request)
24+
context = SecureNativeContext.from_http_request(request, None)
2525

2626
self.assertEqual(context.client_token,
2727
"71532c1fad2c7f56118f7969e401f3cf080239140d208e7934e6a530818c37e544a0c2330a487bcc6fe4f662a57f265a3ed9f37871e80529128a5e4f2ca02db0fb975ded401398f698f19bb0cafd68a239c6caff99f6f105286ab695eaf3477365bdef524f5d70d9be1d1d474506b433aed05d7ed9a435eeca357de57817b37c638b6bb417ffb101eaf856987615a77a")
@@ -47,7 +47,7 @@ def test_create_context_from_request_with_cookie(self):
4747
request.cookies = {"_sn":
4848
"71532c1fad2c7f56118f7969e401f3cf080239140d208e7934e6a530818c37e544a0c2330a487bcc6fe4f662a57f265a3ed9f37871e80529128a5e4f2ca02db0fb975ded401398f698f19bb0cafd68a239c6caff99f6f105286ab695eaf3477365bdef524f5d70d9be1d1d474506b433aed05d7ed9a435eeca357de57817b37c638b6bb417ffb101eaf856987615a77a"}
4949

50-
context = SecureNativeContext.from_http_request(request)
50+
context = SecureNativeContext.from_http_request(request, None)
5151

5252
self.assertEqual(context.client_token,
5353
"71532c1fad2c7f56118f7969e401f3cf080239140d208e7934e6a530818c37e544a0c2330a487bcc6fe4f662a57f265a3ed9f37871e80529128a5e4f2ca02db0fb975ded401398f698f19bb0cafd68a239c6caff99f6f105286ab695eaf3477365bdef524f5d70d9be1d1d474506b433aed05d7ed9a435eeca357de57817b37c638b6bb417ffb101eaf856987615a77a")

tests/encryption_utils_test.py

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
import unittest
22

3-
import pytest
4-
53
from securenative.utils.encryption_utils import EncryptionUtils
64

75

@@ -19,10 +17,3 @@ def test_decrypt(self):
1917

2018
self.assertEqual(result.cid, self.CID)
2119
self.assertEqual(result.fp, self.FP)
22-
23-
@pytest.mark.skip("Differences in crypto version fails this test when in reality it's passing")
24-
def test_encrypt(self):
25-
result = EncryptionUtils.encrypt(self.PAYLOAD, self.SECRET_KEY)
26-
27-
self.assertIsNotNone(result)
28-
self.assertGreater(len(self.PAYLOAD), len(result))

0 commit comments

Comments
 (0)