Skip to content

Commit a4666a7

Browse files
authored
Merge pull request #11 from securenative/SN-1556-align-sdk
Sn 1556 align sdk
2 parents 1b48050 + aa337f4 commit a4666a7

75 files changed

Lines changed: 1818 additions & 555 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -261,6 +261,7 @@ ehthumbs_vista.db
261261
# Recycle Bin used on file shares
262262
$RECYCLE.BIN/
263263

264+
*.ini
264265
# Windows Installer files
265266
*.cab
266267
*.msi

README.md

Lines changed: 144 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -1,98 +1,169 @@
1-
# Python SDK for Secure Native
1+
<p align="center">
2+
<a href="https://www.securenative.com"><img src="https://user-images.githubusercontent.com/45174009/77826512-f023ed80-7120-11ea-80e0-58aacde0a84e.png" alt="SecureNative Logo"/></a>
3+
</p>
24

3-
## How to get it?
4-
the python SDK is published to PyPi so you can just use `pip` to install it:
5+
<p align="center">
6+
<b>A Cloud-Native Security Monitoring and Protection for Modern Applications</b>
7+
</p>
8+
<p align="center">
9+
<a href="https://github.com/securenative/securenative-python">
10+
<img alt="Github Actions" src="https://github.com/securenative/securenative-java/workflows/CI/badge.svg">
11+
</a>
12+
</p>
13+
<p align="center">
14+
<a href="https://docs.securenative.com">Documentation</a> |
15+
<a href="https://docs.securenative.com/quick-start">Quick Start</a> |
16+
<a href="https://blog.securenative.com">Blog</a> |
17+
<a href="">Chat with us on Slack!</a>
18+
</p>
19+
<hr/>
20+
21+
22+
[SecureNative](https://www.securenative.com/) performs user monitoring by analyzing user interactions with your application and various factors such as network, devices, locations and access patterns to stop and prevent account takeover attacks.
23+
24+
25+
## Install the SDK
26+
27+
When using PyPi, run the following:
528
```bash
629
pip install securenative
730
```
831

932
## Initialize the SDK
10-
Go to the settings page of your SecureNative account and find your API key, afterwards add this line on your application main module.
33+
34+
To get your *API KEY*, login to your SecureNative account and go to project settings page:
35+
36+
### Option 1: Initialize via Config file
37+
SecureNative can automatically load your config from *securenative.ini* file or from the file that is specified in your *SECURENATIVE_CONFIG_FILE* env variable:
38+
1139
```python
12-
import securenative
40+
from securenative.securenative import SecureNative
1341

14-
# Many lines of code ...
1542

16-
if __name__=='__main__':
17-
# Your bootstrap code
18-
securenative.init('API_KEY') # Should be called before any other call to secure native
43+
secureative = SecureNative.init()
1944
```
45+
### Option 2: Initialize via API Key
2046

21-
## Tracking Events (async)
22-
Once the SDK has been initialized, you can start sending new events with the `track` function:
2347
```python
24-
import securenative
25-
from securenative.event_options import Event, User
48+
from securenative.securenative import SecureNative
2649

27-
def my_login_function():
28-
# Many lines of code ...
29-
30-
event = Event( # Build the event from the request's context
31-
event_type=securenative.event_types.login,
32-
ip='35.199.23.1',
33-
remote_ip='35.199.23.2',
34-
user_agent='Mozilla/5.0 (Linux; U; Android 4.4.2; zh-cn; GT-I9500 Build/KOT49H) AppleWebKit/537.36 (KHTML, like Gecko)Version/4.0 MQQBrowser/5.0 QQ-URL-Manager Mobile Safari/537.36',
35-
sn_cookie_value='eyJjaWQiOiJkYzgyYjdhZS00ODFkLTQyODItYTMyZC0xZTU1Njk2ZjNmZTQiLCJmcCI6Ijk5NGYzZjVjZTRiYWUwODQzMTRhOTFkNzgyN2I1MWYuMjQ3MDBmOWYxOTg2ODAwYWI0ZmNjODgwNTMwZGQwZWQifQ',
36-
user=User(
37-
user_id='1',
38-
user_email='1@example.com',
39-
user_name='example example'
40-
)
41-
)
42-
43-
# Track it:
44-
securenative.track(event)
45-
46-
# Many lines of code ...
4750

51+
securenative = SecureNative.init_with_api_key("YOUR_API_KEY")
4852
```
4953

50-
## Verification Events (sync)
51-
Once the SDK has been initialized, you can protect sensitive operation by calling the `verify` function, this function will return the risk analysis of the current user.
54+
### Option 3: Initialize via ConfigurationBuilder
55+
```python
56+
from securenative.securenative import SecureNative
57+
58+
59+
securenative = SecureNative.init_with_options(SecureNative.config_builder()
60+
.with_api_key("API_KEY")
61+
.with_max_events(10)
62+
.with_log_level("ERROR")
63+
.build())
64+
```
5265

66+
## Getting SecureNative instance
67+
Once initialized, sdk will create a singleton instance which you can get:
5368
```python
54-
import securenative
55-
from securenative.event_options import Event, User
69+
from securenative.securenative import SecureNative
70+
71+
72+
secureNative = SecureNative.get_instance()
73+
```
74+
75+
## Tracking events
76+
77+
Once the SDK has been initialized, tracking requests sent through the SDK
78+
instance. Make sure you build event with the EventBuilder:
79+
80+
```python
81+
from securenative.securenative import SecureNative
82+
from securenative.event_options_builder import EventOptionsBuilder
83+
from securenative.enums.event_types import EventTypes
84+
from securenative.models.user_traits import UserTraits
85+
5686

57-
def my_change_password_function():
58-
# Many lines of code...
87+
securenative = SecureNative.get_instance()
88+
89+
context = SecureNative.context_builder().\
90+
with_ip("127.0.0.1").\
91+
with_client_token("SECURED_CLIENT_TOKEN").\
92+
with_headers({"user-agent", "Mozilla/5.0 (iPad; U; CPU OS 3_2_1 like Mac OS X; en-us) AppleWebKit/531.21.10 (KHTML, like Gecko) Mobile/7B405"}).\
93+
build()
94+
95+
event_options = EventOptionsBuilder(EventTypes.LOG_IN).\
96+
with_user_id("USER_ID").\
97+
with_user_traits(UserTraits("USER_NAME", "USER_EMAIL")).\
98+
with_context(context).\
99+
with_properties({"prop1": "CUSTOM_PARAM_VALUE", "prop2": True, "prop3": 3}).\
100+
build()
101+
102+
securenative.track(event_options)
103+
```
104+
105+
You can also create request context from requests:
106+
107+
```python
108+
from securenative.securenative import SecureNative
109+
from securenative.event_options_builder import EventOptionsBuilder
110+
from securenative.enums.event_types import EventTypes
111+
from securenative.models.user_traits import UserTraits
112+
113+
114+
def track(request):
115+
securenative = SecureNative.get_instance()
116+
context = SecureNative.context_builder().from_http_request(request).build()
117+
118+
event_options = EventOptionsBuilder(EventTypes.LOG_IN).\
119+
with_user_id("USER_ID").\
120+
with_user_traits(UserTraits("USER_NAME", "USER_EMAIL")).\
121+
with_context(context).\
122+
with_properties({"prop1": "CUSTOM_PARAM_VALUE", "prop2": True, "prop3": 3}).\
123+
build()
59124

60-
event = Event( # Build the event from the request's context
61-
event_type=securenative.event_types.verify,
62-
ip='35.199.23.1',
63-
remote_ip='35.199.23.2',
64-
user_agent='Mozilla/5.0 (Linux; U; Android 4.4.2; zh-cn; GT-I9500 Build/KOT49H) AppleWebKit/537.36 (KHTML, like Gecko)Version/4.0 MQQBrowser/5.0 QQ-URL-Manager Mobile Safari/537.36',
65-
sn_cookie_value='eyJjaWQiOiJkYzgyYjdhZS00ODFkLTQyODItYTMyZC0xZTU1Njk2ZjNmZTQiLCJmcCI6Ijk5NGYzZjVjZTRiYWUwODQzMTRhOTFkNzgyN2I1MWYuMjQ3MDBmOWYxOTg2ODAwYWI0ZmNjODgwNTMwZGQwZWQifQ',
66-
user=User(
67-
user_id='1',
68-
user_email='1@example.com',
69-
user_name='example example'
70-
)
71-
)
72-
73-
result = securenative.verify(event)
74-
if result['riskLevel'] == 'high':
75-
return 'Cannot change password'
76-
elif result['riskLevel'] == 'medium':
77-
return 'MFA'
78-
79-
# Many lines of code...
125+
securenative.track(event_options)
80126
```
81127

82-
## Verifying Incoming Webhooks
83-
You can use the SDK to verify incoming webhooks from Secure Native, just call the `veriy_webhook` function which return a boolean which indicates if the webhook came from Secure Native servers.
128+
## Verify events
129+
130+
**Example**
131+
84132
```python
85-
import securenative
86-
87-
@post('/sn/webhook')
88-
def sn_webhook_handler(headers, body):
89-
sig_header = headers["X-SecureNative"]
90-
if securenative.verify_webhook(sig_header, body):
91-
# Handle the webhook
92-
level = body['riskLevel']
93-
pass
94-
else:
95-
# This reqeust wasn't sent from Secure Native servers, you can dismiss/investigate it
96-
pass
133+
from securenative.securenative import SecureNative
134+
from securenative.event_options_builder import EventOptionsBuilder
135+
from securenative.enums.event_types import EventTypes
136+
from securenative.models.user_traits import UserTraits
137+
138+
139+
def track(request):
140+
securenative = SecureNative.get_instance()
141+
context = SecureNative.context_builder().from_http_request(request).build()
142+
143+
event_options = EventOptionsBuilder(EventTypes.LOG_IN).\
144+
with_user_id("USER_ID").\
145+
with_user_traits(UserTraits("USER_NAME", "USER_EMAIL")).\
146+
with_context(context).\
147+
with_properties({"prop1": "CUSTOM_PARAM_VALUE", "prop2": True, "prop3": 3}).\
148+
build()
97149

150+
verify_result = securenative.verify(event_options)
151+
verify_result.risk_level # Low, Medium, High
152+
verify_result.score # Risk score: 0 -1 (0 - Very Low, 1 - Very High)
153+
verify_result.triggers # ["TOR", "New IP", "New City"]
98154
```
155+
156+
## Webhook signature verification
157+
158+
Apply our filter to verify the request is from us, for example:
159+
160+
```python
161+
from securenative.securenative import SecureNative
162+
163+
164+
def webhook_endpoint(request):
165+
securenative = SecureNative.get_instance()
166+
167+
# Checks if request is verified
168+
is_verified = securenative.verify_request_payload(request)
169+
```

requirements.txt

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
1-
requests~=2.22.0
2-
pycrypto~=2.6.1
1+
requests~=2.23.0
2+
pycrypto~=2.6.1
3+
crypto==1.4.1

securenative/__init__.py

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +0,0 @@
1-
from securenative.config import sdk_version
2-
import securenative.event_types
3-
from securenative.sdk import SecureNative, SecureNativeOptions
4-
from securenative.event_options import Event, User
5-
from securenative.singleton import init, flush, track, verify_webhook, verify

securenative/api_manager.py

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
from securenative.enums.api_route import ApiRoute
2+
from securenative.enums.failover_strategy import FailOverStrategy
3+
from securenative.enums.risk_level import RiskLevel
4+
from securenative.logger import Logger
5+
from securenative.models.sdk_event import SDKEvent
6+
from securenative.models.verify_result import VerifyResult
7+
8+
9+
class ApiManager(object):
10+
11+
def __init__(self, event_manager, securenative_options):
12+
self.event_manager = event_manager
13+
self.options = securenative_options
14+
15+
def track(self, event_options):
16+
Logger.debug("Track event call")
17+
event = SDKEvent(event_options, self.options)
18+
return self.event_manager.send_async(event, ApiRoute.TRACK.value)
19+
20+
def verify(self, event_options):
21+
Logger.debug("Verify event call")
22+
event = SDKEvent(event_options, self.options)
23+
try:
24+
self.event_manager.send_sync(event, ApiRoute.VERIFY.value, False)
25+
except Exception as e:
26+
Logger.debug("Failed to call verify; {}".format(e))
27+
if self.options.fail_over_strategy is FailOverStrategy.FAIL_OPEN.value:
28+
return VerifyResult(RiskLevel.LOW.value, 0, None)
29+
return VerifyResult(RiskLevel.HIGH.value, 1, None)

securenative/config.py

Lines changed: 0 additions & 2 deletions
This file was deleted.

securenative/config/__init__.py

Whitespace-only changes.
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
from securenative.config.securenative_options import SecureNativeOptions
2+
from securenative.enums.failover_strategy import FailOverStrategy
3+
4+
5+
class ConfigurationBuilder(object):
6+
7+
def __init__(self):
8+
self.api_key = None
9+
self.api_url = "https://api.securenative.com/collector/api/v1"
10+
self.interval = 1000
11+
self.max_events = 1000
12+
self.timeout = 1500
13+
self.auto_send = True
14+
self.disable = False
15+
self.log_level = "CRITICAL"
16+
self.fail_over_strategy = FailOverStrategy.FAIL_OPEN.value
17+
18+
@staticmethod
19+
def default_config_builder():
20+
return ConfigurationBuilder()
21+
22+
def with_api_key(self, api_key):
23+
self.api_key = api_key
24+
return self
25+
26+
def with_api_url(self, api_url):
27+
self.api_url = api_url
28+
return self
29+
30+
def with_interval(self, interval):
31+
self.interval = interval
32+
return self
33+
34+
def with_max_events(self, max_events):
35+
self.max_events = max_events
36+
return self
37+
38+
def with_timeout(self, timeout):
39+
self.timeout = timeout
40+
return self
41+
42+
def with_auto_send(self, auto_send):
43+
self.auto_send = auto_send
44+
return self
45+
46+
def with_disable(self, disable):
47+
self.disable = disable
48+
return self
49+
50+
def with_log_level(self, log_level):
51+
self.log_level = log_level
52+
return self
53+
54+
def with_fail_over_strategy(self, fail_over_strategy):
55+
if fail_over_strategy != FailOverStrategy.FAIL_OPEN.value and \
56+
fail_over_strategy != FailOverStrategy.FAIL_CLOSED.value:
57+
self.fail_over_strategy = FailOverStrategy.FAIL_OPEN.value
58+
return self
59+
self.fail_over_strategy = fail_over_strategy
60+
return self
61+
62+
@staticmethod
63+
def get_default_securenative_options():
64+
return SecureNativeOptions()

0 commit comments

Comments
 (0)