MongoDB Key Value Store

Manipulates key/value pairs according to an incident utilizing the MongoDB collection.

Database · MongoDB

Details

IDMongoDB Key Value Store
ProviderMongoDB Inc.
CategoryDatabase
From Version5.0.0
Docker Imagedemisto/py3-tools:1.0.0.114656
Supported ModulesAgentix XSIAM

README

Overview


Manipulates key/value pairs according to an incident utilizing the MongoDB collection.
This integration was integrated and tested with version v4.2.3 of MongoDB.

The account user must have appropriate permissions - root role to execute the API calls.

Configure MongoDB Key Value Store on Cortex XSOAR


  1. Navigate to Settings > Integrations > Servers & Services.
  2. Search for MongoDB Key Value Store.
  3. Click Add instance to create and configure a new integration instance.
    • Name: a textual name for the integration instance.
    • MongoDB username
    • URI (mongodb://IP/FQDN:Port Number)
    • MongoDB database name
    • MongoDB collection name
    • Use an SSL/TLS secured connection
    • Trust any certificate (not secure)
  4. Click Test to validate the URLs, token, and connection.

Commands


You can execute these commands from the Cortex XSOAR CLI, as part of an automation, or in a playbook.
After you successfully execute a command, a DBot message appears in the War Room with the command details.

  1. mongodb-write-key-value
  2. mongodb-get-key-value
  3. mongodb-list-key-values
  4. mongodb-delete-key
  5. mongodb-purge-entries
  6. mongodb-get-keys-number
  7. mongodb-list-incidents

1. mongodb-write-key-value


Adds a key/value record for the incident. If the key exists, the existing value is overwritten.*

Base Command

mongodb-write-key-value

Input
Argument Name Description Required
id The XSOAR incident number. Optional
key Name/Key. Required
value Assigns a value to the name/key. Required
Context Output
Path Type Description
MongoDB.Entry.ID String Entry ID.
MongoDB.Entry.Incident String Incident ID.
MongoDB.Entry.Key String Incident key.
MongoDB.Entry.Value String Incident value.
MongoDB.Entry.Modified Date Incident modified date.
Command Example

!mongodb-write-key-value key=demisto value=test5

Context Example
{
    "MongoDB.Entry": {
        "Incident": "6e1807d3-b0ae-40a0-8e82-dad33539c587", 
        "Value": "test5", 
        "ID": "5e92db8a225a4976e096eeb9", 
        "Key": "demisto", 
        "Modified": "2020-04-12T09:12:42+00:00"
    }
}
Human Readable Output

Incident “6e1807d3-b0ae-40a0-8e82-dad33539c587” - key/value collection - 1 document added

2. mongodb-get-key-value


Returns the value of the specified name/key of an incident.

Base Command

mongodb-get-key-value

Input
Argument Name Description Required
id The XSOAR incident number. Optional
key Name/Key. Required
Context Output
Path Type Description
MongoDB.Entry.Incident String Incident ID.
MongoDB.Entry.Key String Incident key.
MongoDB.Entry.Value String The value of the key.
Command Example

!mongodb-get-key-value key=demisto

Context Example
{
    "MongoDB.Entry": {
        "Incident": "6e1807d3-b0ae-40a0-8e82-dad33539c587", 
        "Value": "test5", 
        "Modified": "2020-04-12T09:12:42+00:00", 
        "Key": "demisto"
    }
}
Human Readable Output

The key and value that is stored for the incident

Incident Key Modified Value
6e1807d3-b0ae-40a0-8e82-dad33539c587 demisto 2020-04-12T09:12:42+00:00 test5

3. mongodb-list-key-values


Lists the keys and their values for the specified incident.

Base Command

mongodb-list-key-values

Input
Argument Name Description Required
id The XSOAR incident number. Optional
Context Output
Path Type Description
MongoDB.Incident.Incident String Incident ID.
MongoDB.Incident.Key String Incident key.
MongoDB.Incident.Value String The value of the key.
Command Example

!mongodb-list-key-values id=1234

Context Example
{
    "MongoDB.Incident": [
        {
            "Incident": "1234", 
            "Value": "test2", 
            "Key": "test"
        }, 
        {
            "Incident": "1234", 
            "Value": "test", 
            "Key": "demisto"
        }, 
        {
            "Incident": "1234", 
            "Value": "world", 
            "Key": "hello"
        }
    ]
}
Human Readable Output

The key/value paires stored in incident 1234

Key Value
test test2
demisto test
hello world

4. mongodb-delete-key


Deletes the key/value record for an incident.

Base Command

mongodb-delete-key

Input
Argument Name Description Required
id The XSOAR incident number. Optional
key Name/Key. Required
Context Output

There is no context output for this command.

Command Example

!mongodb-delete-key key=hello id=1234

Human Readable Output

Incident “1234” - key/value collection - 1 document deleted

5. mongodb-purge-entries


Purges all keys/values for an incident. A common use case for this command is when closing an incident. This command clears the entries for the closed incident from the database.

Base Command

mongodb-purge-entries

Input
Argument Name Description Required
id The XSOAR incident number. Optional
Context Output

There is no context output for this command.

Command Example

!mongodb-purge-entries id=2468

Human Readable Output

Incident “2468” key/value pairs purged - 1 document/record deleted

6. mongodb-get-keys-number


Returns the number of key/value pairs for an incident.

Base Command

mongodb-get-keys-number

Input
Argument Name Description Required
id The XSOAR incident number. Optional
Context Output

There is no context output for this command.

Command Example

!mongodb-get-keys-number id=1234

Human Readable Output

The count of the key/value pairs for the incident - 2

7. mongodb-list-incidents


Lists all incidents in the collection.

Base Command

mongodb-list-incidents

Input

There are no input arguments for this command.

Context Output

There is no context output for this command.

Command Example

!mongodb-list-incidents

Human Readable Output

List of incidents in collecion generic

Incidents
2468
1234
014f5f87-a1bf-4eac-8d36-2ec3b69693ef
6e1807d3-b0ae-40a0-8e82-dad33539c587

Configuration parameters

  • credentials — MongoDB username (required)
  • uri — URI (mongodb://<IP/FQDN>:<Port Number>) (required)
  • database — MongoDB database name (required)
  • collection — MongoDB collection name (required)
  • use_ssl — Use an SSL/TLS secured connection
  • insecure — Trust any certificate (not secure)

Commands (7)

  • mongodb-delete-key

    Deletes the key/value record for an incident.

  • mongodb-get-key-value

    Returns the value of the specified name/key of an incident.

  • mongodb-get-keys-number

    Returns the number of key/value pairs for an incident.

  • mongodb-list-incidents

    Lists all incidents in the collection.

  • mongodb-list-key-values

    Lists the keys and their values for the specified incident.

  • mongodb-purge-entries

    Purges all keys/values for an incident. A common use case for this command is when closing an incident. This command clears the entries for the closed incident from the database.

  • mongodb-write-key-value

    Adds a key/value record for the incident. If the key exists, the existing value is overwritten.

import demistomock as demisto
from CommonServerPython import *

from CommonServerUserPython import *

""" IMPORTS """
from datetime import datetime

from pymongo import MongoClient

""" GLOBALS/PARAMS """

# Get Credentials
USERNAME = demisto.params().get("credentials").get("identifier")
PASSWORD = demisto.params().get("credentials").get("password")
# Get Server
URI = demisto.params().get("uri")
# Get Database
DATABASE = demisto.params().get("database")
USE_SSL = demisto.params().get("use_ssl", False)
INSECURE = demisto.params().get("insecure", False)
TIMEOUT = 5000
if INSECURE and not USE_SSL:
    raise DemistoException('"Trust any certificate (not secure)" must be ticked with "Use TLS/SSL secured connection"')
if not INSECURE and not USE_SSL:
    # Connect to MongoDB - Need to add credentials and lock down MongoDB (add auth)
    CLIENT = MongoClient(  # type: ignore[var-annotated]
        URI,
        username=USERNAME,
        password=PASSWORD,
        authSource=DATABASE,
        authMechanism="SCRAM-SHA-1",
        ssl=USE_SSL,
        socketTimeoutMS=TIMEOUT,
    )
else:
    CLIENT = MongoClient(
        URI,
        username=USERNAME,
        password=PASSWORD,
        authSource=DATABASE,
        authMechanism="SCRAM-SHA-1",
        ssl=USE_SSL,
        tlsAllowInvalidCertificates=INSECURE,
        socketTimeoutMS=TIMEOUT,
    )

DB = CLIENT[DATABASE]
# Set Collection
COLLECTION_NAME = demisto.params().get("collection")
COLLECTION = DB[COLLECTION_NAME]


def get_investigation_id():
    investigation = demisto.investigation()
    investigation_id = investigation.get("id")

    return investigation_id


def test_module():
    """Check DB Status"""
    if CLIENT.server_info().get("ok") == 1.0:
        return "ok", {}, {}
    return "MongoDB Server Error", {}, {}


def write_key_value_command():
    """Write key/value document to MondoDB"""
    # Get Args needed for the command
    timestamp = datetime.utcnow().strftime("%Y-%m-%dT%H:%M:%S+00:00")
    incident = demisto.args().get("id", get_investigation_id())
    key = demisto.args().get("key")
    value = demisto.args().get("value")
    logjson = {incident: {"modified": timestamp, "key": key, "value": value}}
    # Check for previous record/document
    search = incident + ".key"
    cursor = COLLECTION.find_one({search: key})
    # If no record
    if not cursor:
        # Add to MongoDB
        result = COLLECTION.insert_one(logjson)
        entry_id = result.inserted_id
        context = {"ID": str(entry_id), "Incident": incident, "Modified": timestamp, "Key": key, "Value": value}
        ec = {"MongoDB.Entry(val.ID === obj.ID)": context}
        return f'Incident "{incident}" - key/value collection - 1 document added', ec, {}

    # Modify Existing Record
    object_id = cursor.get("_id")
    COLLECTION.update_one({"_id": object_id}, {"$set": {incident: {"key": key, "value": value, "modified": timestamp}}})
    context = {"ID": str(object_id), "Incident": incident, "Modified": timestamp, "Key": key, "Value": value}
    ec = {"MongoDB.Entry(val.ID === obj.ID)": context}
    return f'Incident "{incident}" - key/value collection - 1 document updated', ec, {}


def get_key_value_command():
    """Return value for key stored for the incident"""
    # Get Args needed for the command
    incident = demisto.args().get("id", get_investigation_id())
    key = demisto.args().get("key")
    # Search Collection for incident_id and key
    search = incident + ".key"
    result = COLLECTION.find_one({search: key}, {"_id": False})
    value = result[incident].get("value")  # type: ignore[index]
    contents = {
        "Incident": incident,
        "Key": key,
        "Value": value,
        "Modified": result.get(incident).get("modified"),  # type: ignore[union-attr]
    }
    human_readable = tableToMarkdown("The key and value that is stored for the incident", contents)
    ec = {"MongoDB.Entry(val.Key === obj.Key)": contents}
    return human_readable, ec, {}


def delete_key_command():
    """Removes the key/value pair specified by key and incident_id"""
    incident = demisto.args().get("id", get_investigation_id())
    key = demisto.args().get("key")
    # Search Collection for incident_id and key
    search = incident + ".key"
    cursor = COLLECTION.find_one({search: key})
    if cursor is not None:
        object_id = cursor.get("_id")
        COLLECTION.delete_one({"_id": object_id})
        return f'Incident "{incident}" - key/value collection - 1 document deleted', {}, {}
    return f'Key "{key}" for incident_id "{incident}" does not exist', {}, {}


def num_keys_command():
    """Returns the count of the key/value pairs for the incident"""
    # Get Args needed for the command
    incident = demisto.args().get("id", get_investigation_id())
    # Search Collection counting matching incident_id
    cursor = COLLECTION.find({})
    count = 0
    for i in cursor:
        if incident in i:
            count += 1
    return f"The count of the key/value pairs for the incident - {count!s}", {}, {}


def list_key_values_command():
    """Returns all the key/value pairs stored for the incident"""
    # Get Args needed for the command
    incident = demisto.args().get("id", get_investigation_id())
    # Search Collection for matching incident_id
    return_json = []  # type: ignore
    context = []
    found = False
    cursor = COLLECTION.find({}, {"_id": False})
    if cursor is None:
        # Collection doesn't exist - thus no records
        return_json = None  # type: ignore
    else:
        # Iterate, collecting any name/value pairs associated with the incident
        for i in cursor:
            if incident in i:
                found = True
                return_json.append({"Key": i[incident]["key"], "Value": i[incident]["value"]})
                context.append({"Incident": incident, "Key": i[incident]["key"], "Value": i[incident]["value"]})

    if not found:
        # Means no records were found with that incident_id
        # Discard empty return_json
        return_json = None  # type: ignore

    human_readable = tableToMarkdown(f"The key/value paires stored in incident {incident}", return_json)
    ec = {"MongoDB.Incident(val.Key === obj.Key)": context}
    # Return a useful status
    return human_readable, ec, {}


def purge_entries_command():
    """Purges all the key/value pairs stored for the incident"""
    incident = demisto.args().get("id", get_investigation_id())
    cursor = COLLECTION.find({})
    deleted = 0
    # Iterate, collecting any name/value pairs associated with the incident
    for i in cursor:
        if incident in i:
            object_id = i.get("_id")
            COLLECTION.delete_one({"_id": object_id})
            deleted += 1
    if deleted == 1:
        return f'Incident "{incident}" key/value pairs purged - {deleted!s} document/record deleted', {}, {}
    return f'Incident "{incident}" key/value pairs purged - {deleted!s} documents/records deleted', {}, {}


def list_incidents_command():
    """List all incidents in the collection"""
    cursor = COLLECTION.find({}, {"_id": False})
    incidents = []
    results: list = []
    for incident in cursor:
        for name in incident:
            incidents.append(name)
        for i in incidents:
            if i not in results:
                results.append(i)
    human_readable = tableToMarkdown(f"List of incidents in collecion {COLLECTION_NAME}", results, headers=["Incidents"])
    return human_readable, {}, {}


def main():
    LOG(f"Command being called is {demisto.command()}")
    try:
        if demisto.command() == "test-module":
            # This is the call made when pressing the integration test button.
            return_outputs(*test_module())
        elif demisto.command() == "mongodb-write-key-value":
            return_outputs(*write_key_value_command())
        elif demisto.command() == "mongodb-get-key-value":
            return_outputs(*get_key_value_command())
        elif demisto.command() == "mongodb-list-key-values":
            return_outputs(*list_key_values_command())
        elif demisto.command() == "mongodb-delete-key":
            return_outputs(*delete_key_command())
        elif demisto.command() == "mongodb-purge-entries":
            return_outputs(*purge_entries_command())
        elif demisto.command() == "mongodb-get-keys-number":
            return_outputs(*num_keys_command())
        elif demisto.command() == "mongodb-list-incidents":
            return_outputs(*list_incidents_command())
    except Exception as e:
        return_error(f"MongoDB: {e!s}", error=e)


if __name__ in ("__main__", "__builtin__", "builtins"):
    main()