Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added support for webhooks and updated documentation #2

Merged
merged 1 commit into from
Dec 9, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
63 changes: 62 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ This tool supports the following connectors:
- Google BigQuery
- Panther SIEM
- Elasticsearch
- WebHook

### Other SIEM Integrations

Expand Down Expand Up @@ -52,7 +53,14 @@ if __name__ == '__main__':

### CSV

The CSV Export function will output to a specified CSV file. Currently, it will overwrite the file if it already exists.
The CSV Export function will output to a specified CSV file. Currently, it will overwrite the file if it already exists.

Initializing Options:

| Option | Required | Default | Description |
|---------|----------|-------------|-----------------------------------------------------------------------------------------------------------------------------------------------------|
| file | True | None | The name of the file to write the CSV results out to |
| columns | False | All Columns | The names of the column headers and the order for the columns. Must match the property names for the issues. If not passed default columns are used |

```python
import os
Expand Down Expand Up @@ -87,6 +95,12 @@ The BigQuery connector will send data to the specified Table within BigQuery. Cu
2. In a terminal run `gcloud auth login`
3. In a terminal run `gcloud config set project $MY_PROJECT_ID`

Initializing Options:

| Option | Required | Default | Description |
|--------|----------|---------|----------------------------------------------------------------------------------|
| table | True | None | This is the table in the format of `dataset.table` that results will be added to |

```python
import os
from core.socket_reports import Reports
Expand Down Expand Up @@ -114,6 +128,14 @@ The Panther connector requires you to have an HTTP connector setup in the Panthe

Configuration can be found [here](panther/README.md)

Initializing Options:

| Option | Required | Default | Description |
|---------|----------|---------|-------------------------------------------------------------------------------------------------------|
| token | False | None | Token to use if you are using Bearer token. Default method if custom headers are not passed to `send` |
| url | True | None | Panther Webhook URL to POST data to |
| timeout | False | 10 | Timeout in seconds for requests |

```python
import os
from core.socket_reports import Reports
Expand Down Expand Up @@ -171,3 +193,42 @@ if __name__ == '__main__':
for issue in issue_data:
es.add_document(issue, elastic_index)
```

### WebHook
The WebHook integration is a simple wrapper for sending an HTTP(s) Request to the desired URL.

Initialize Options:

| Option | Required | Default | Description |
|--------------|----------|----------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------|
| url | True | None | URL for the WebHook |
| headers | False | `{'User-Agent': 'SocketPythonScript/0.0.1', "accept": "application/json", 'Content-Type': "application/json"}` | Default set of headers to use if not specified |
| auth_headers | False | None | Dictionary of auth headers to use to authenticate to the WebHook |
| params | False | None | Dictionary of query params to use if needed |
| timeout | False | 10 | Time in seconds to timeout out a request |

```python
import os
from core.socket_reports import Reports
from core.connectors.webhook import Webhook


if __name__ == '__main__':
socket_org = os.getenv("SOCKET_ORG") or exit(1)
api_key = os.getenv("SOCKET_API_KEY") or exit(1)
start_date = os.getenv("START_DATE") or exit(1)
reports = Reports(
org=socket_org,
api_key=api_key,
start_date=start_date
)
issue_data = reports.get_issues()
webhook_url = os.getenv("WEBHOOK_URL") or exit(1)
webhook_auth_headers = os.getenv("WEBHOOK_AUTH_HEADERS") or {
'Authorization': 'Bearer EXAMPLE'
}
webhook = Webhook(webhook_url)
for issue in issue_data:
issue_json = json.loads(str(issue))
webhook.send(issue_json)
```
Empty file added core/connectors/__init__.py
Empty file.
7 changes: 4 additions & 3 deletions core/connectors/panther.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ class Panther:
url: str
timeout: int

def __init__(self, token: str, url: str, timeout: int = 10):
def __init__(self, url: str, token: str = None, timeout: int = 10):
self.token = token
self.url = url
self.timeout = timeout
Expand All @@ -21,11 +21,12 @@ def do_request(

if headers is None:
headers = {
'Authorization': f"Bearer {self.token}",
'User-Agent': 'SocketPythonScript/0.0.1',
"accept": "application/json",
'Content-Type': "application/json"
}
if self.token is not None:
headers['Authorization'] = f"Bearer {self.token}"
response = requests.request(
method.upper(),
self.url,
Expand All @@ -41,7 +42,7 @@ def do_request(
result = response.text
return result

def send_to_webhook(self, payload: str, headers: dict = None):
def send(self, payload: str, headers: dict = None):
response = self.do_request(
method="POST",
payload=payload,
Expand Down
17 changes: 13 additions & 4 deletions core/connectors/socket_csv.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import json
import csv
from core.socket_reports.classes import IssueRecord
from core import columns as default_columns


class SocketCSV:
Expand All @@ -10,17 +11,25 @@ class SocketCSV:
def __init__(self, file: str, columns: list = None):
self.file = file
self.columns = columns
if self.columns is None:
self.columns = default_columns

def write_csv(self, data: list):
with open(self.file, 'w', newline='') as file:
writer = csv.writer(file)
writer.writerow(self.columns)
if self.columns is not None:
writer.writerow(self.columns)
for issue in data:
writer.writerow(self.create_row(issue))

def create_row(self, issue: IssueRecord) -> tuple:
row = ()
for column in self.columns:
value = getattr(issue, column)
row += (value,)
if self.columns is not None:
for column in self.columns:
value = getattr(issue, column)
row += (value,)
else:
data = json.loads(str(issue))
for value in data:
row += (value,)
return row
69 changes: 69 additions & 0 deletions core/connectors/webhook.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import json
import urllib.parse

import requests
import urllib


class Webhook:
headers: dict
method: str
params: dict
auth_headers: dict
timeout: int
url: str

def __init__(
self,
url: str,
headers: dict = None,
auth_headers: dict = None,
method: str = "POST",
params: dict = None,
timeout: int = 10
):
self.headers = headers
self.auth_headers = auth_headers
self.method = method
self.params = params
self.timeout = timeout
self.url = url

def send(self, payload: dict):
headers = self.get_headers()
url = self.create_url(self.url, self.params)
data = json.dumps(payload)
response = requests.request(
self.method.upper(),
url,
headers=headers,
data=data,
timeout=self.timeout
)
if response.status_code != 200:
print("Failed to post data")
print(response.text)
result = None
else:
result = response.text
return result

@staticmethod
def create_url(url: str, params: dict) -> str:
if params is not None:
query_params = urllib.parse.urlencode(params)
url = f"{url}?{query_params}"
return url

def get_headers(self):
headers = {
'User-Agent': 'SocketPythonScript/0.0.1',
"accept": "application/json",
'Content-Type': "application/json"
}
if self.headers is None and self.auth_headers is not None:
for name in self.auth_headers:
headers[name] = self.auth_headers[name]
elif self.headers is not None:
headers = self.headers
return headers
14 changes: 13 additions & 1 deletion socket-integration-example.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,13 @@
from core.connectors.bigquery import BigQuery
from core.connectors.panther import Panther
from core.connectors.socket_csv import SocketCSV
from core.connectors.webhook import Webhook


if __name__ == '__main__':
socket_org = os.getenv("SOCKET_ORG") or exit(1)
api_key = os.getenv("SOCKET_API_KEY") or exit(1)
start_date = os.getenv("START_DATE") or exit(1)
start_date = os.getenv("START_DATE") or None
reports = Reports(
org=socket_org,
api_key=api_key,
Expand Down Expand Up @@ -52,3 +53,14 @@
issue_json = json.loads(str(issue))
panther.send_to_webhook(str(issue))
print(f"Processed issue id: {issue.id}")

# Webhook Example
webhook_url = os.getenv("WEBHOOK_URL") or exit(1)
webhook_auth_headers = os.getenv("WEBHOOK_AUTH_HEADERS") or {
'Authorization': 'Bearer EXAMPLE'
}
webhook = Webhook(webhook_url)
for issue in issue_data:
issue_json = json.loads(str(issue))
webhook.send(issue_json)