# Zoho Vault Integration

Log Integration procedure:

**Introduction**

This document describes a Python script designed to fetch audit logs from Zoho Vault and send them to Logstash for further processing. Prerequisites

• Client credentials for Zoho Vault API access:

o Client ID

o Client Secret

o Refresh Token

• Zoho Vault API URL for audit logs

• Permissions:

o AuditLogRead.All

o DeviceManagementManagedDevices.Read.All

o DeviceManagementManagedDevices.PrivilgedOperations.All

Configuration

• Access Token Retrieval Script

This script retrieves a fresh access token using the refresh token and stores it in a configuration file. Replace placeholders with your credentials and desired file paths.

Code Snippet (Access Token Retrieval Script)

Python

import requests

import time

def get\_new\_access\_token(refresh\_token, client\_id, client\_secret, redirect\_uri, grant\_type='refresh\_token'):

token\_url = "<https://accounts.zoho.com/oauth/v2/token>"

payload = {

'refresh\_token': refresh\_token,

'client\_id': client\_id,

'client\_secret': client\_secret,

'redirect\_uri': redirect\_uri,

'grant\_type': grant\_type

}

headers = {

'Content-Type': 'application/x-www-form-urlencoded'

}

response = requests.post(token\_url, data=payload, headers=headers)

if response.status\_code == 200:

return response.json()

else:

response.raise\_for\_status()

Configuration (Replace placeholders with your details)

grant\_type='refresh\_token'

refresh\_token = ''

client\_id = ''

client\_secret = ''

redirect\_uri = '<http://www.zoho.com/>'

access\_token\_file\_path = '/opt/lc/conf/zoho/vault\_access\_token.conf' # Specify the path to store the access token

token\_response = get\_new\_access\_token(refresh\_token, client\_id, client\_secret, redirect\_uri) access\_token = token\_response\['access\_token']

with open(access\_token\_file\_path, 'w') as file:

file.write(f'access\_token={access\_token}\n')

print('New access token stored in:', access\_token\_file\_path)

print('Token response:', token\_response)

• **Log Fetching and Processing Script**

This script fetches logs from Zoho Vault in pages, extracts details, and sends them to Logstash. Update configurations for API URL, log file path, and Logstash details.

**Code Snippet (Log Fetching and Processing Script)**

Python

import requests

import os

import socket

import json

from datetime import datetime

def read\_access\_token(file\_path):

try:

with open(file\_path, 'r') as file:

for line in file:

if line.startswith('access\_token='):

key, access\_token = line.strip().split('=')

return access\_token

except Exception as e:

print(f"An error occurred while reading the access token: {e}")

return None

def call\_api\_with\_access\_token(api\_url, access\_token,rows\_per\_page, page\_number): headers = {

'Authorization': f'Bearer {access\_token}'

}

```
params = {
    "rowsPerPage":rows_per_page,
    "page" : page_number
}

try:
    response = requests.get(api_url, headers=headers,params=params)
    response.raise_for_status()  # Raise an HTTPError for bad responses

    if response.status_code == 200:
        api_data = response.json()
        operation = api_data.get('operation', {})
        details = operation.get('Details', [])

        if details:
            data = details[0]
            start_count = details[1].get('start', 0)
            end_count = details[1].get('end', 0)
            totalrows_count = details[1].get('totalrows', 0)
            return start_count, end_count, totalrows_count,data
        else:
            return 0, 0, 0, {} # Handle case where data structure is unexpected

    else:
        print(f"Unexpected status code: {response.status_code}")
        print(response.text)  # Print response content for debugging
        return 0, 0, 0, {}

except requests.exceptions.HTTPError as err:
    print(f"HTTP error occurred: {err}")
    return 0, 0, 0, {}
except Exception as e:
    print(f"An error occurred: {e}")
    return 0, 0, 0, {}
```

def read\_last\_total\_count(log\_file\_path):

try:

with open(log\_file\_path, 'r') as log\_file:

lines = log\_file.readlines()

for line in reversed(lines):

if line.startswith('next\_start'):

total\_count = int(line.split('=')\[1].strip())

return total\_count

return 0 # If no valid total count found, start from 0

except FileNotFoundError:

return 0 # Start from 0 if file does not exist

def store\_total\_count\_to\_file(log\_file\_path, totalrows\_count):

updated\_lines = \[]

count\_updated = False

```
if os.path.exists(log_file_path):
    with open(log_file_path, 'r') as file:
        lines = file.readlines()
else:
    lines = []

for line in lines:
    if line.startswith("next_start"):
        count_updated = True
        updated_lines.append(f"next_start = {totalrows_count}\n")
    else:
        updated_lines.append(line)

if not count_updated:
    updated_lines.append(f"next_start = {totalrows_count}\n")

with open(log_file_path, 'w') as file:
    file.writelines(updated_lines)
```

def ensure\_log\_file(log\_file\_path):

if not os.path.exists(log\_file\_path):

with open(log\_file\_path, 'w') as file:

file.write(f"# Logcount for {datetime.now().strftime('%Y-%m-%d')}\n")

def send\_to\_logstash(logs):

status = -1

try:

with socket.socket(socket.AF\_INET, socket.SOCK\_STREAM) as sock: sock.connect((logstash\_host, logstash\_port))

for log in logs:

message = json.dumps(log)

sock.sendall(message.encode('utf-8'))

sock.sendall(b'\n')

status = 0

except Exception as e:

print(f"Failed to send logs to Logstash: {e}")

return status

Configuration

access\_token\_file\_path = '/opt/lc/conf/zoho/vault\_access\_token.conf' # Path to the conf file where the access token is stored

api\_url = '<https://vault.zoho.com/api/rest/json/v1/audit/logs>' # Replace with the actual API URL you want to call

log\_file\_path = '/opt/apps/zoho-vault/zoho\_audit\_activity.conf' # Path to the single log file rows\_per\_page = 25

page = 1

Logstash configuration

logstash\_host = 'localhost' # Change to your Logstash host if different

logstash\_port = 12337 # Change to your Logstash port if different

try:

flag = True

while flag:

previous\_totalrows\_count = read\_last\_total\_count(log\_file\_path)

if previous\_totalrows\_count == 0:

previous\_totalrows\_count = 1

start = previous\_totalrows\_count

access\_token = read\_access\_token(access\_token\_file\_path)

if access\_token:

start\_count, end\_count, totalrows\_count, details = call\_api\_with\_access\_token(api\_url, access\_token,rows\_per\_page,page)

start\_count = start

end\_count = end\_count

totalrows\_count = totalrows\_count

page += 1

if totalrows\_count == 0:

flag = False

else:

if totalrows\_count >= start:

ensure\_log\_file(log\_file\_path)

next\_start = end\_count + 1

store\_total\_count\_to\_file(log\_file\_path, next\_start)

send\_log = send\_to\_logstash(details)

if send\_log == -1:

print("unable to send logs to logstash")

flag = False

else: print('No new records added.')

flag = False

else:

print('Failed to retrieve the access token.')

```
print("Data retrieval and storage complete.")
```

except requests.exceptions.HTTPError as err:

print('HTTP error:', err)

except Exception as e:

print('An error occurred:', e)

Note: Copy the code from Meydan and SPC client.

3\. Setup a Logstash pipeline to fetch the logs at input port 12337/tcp and follow further steps.
