> For the complete documentation index, see [llms.txt](https://docs.blusapphire.io/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.blusapphire.io/log-forwarding/03_log-forwarding-guide/log-forward/zoho/zoho-vault-integration.md).

# 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.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.blusapphire.io/log-forwarding/03_log-forwarding-guide/log-forward/zoho/zoho-vault-integration.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
