KeeperSecretsManager
Use the Keeper Secrets Manager integration to manage secrets and protect sensitive data through Keeper Vault.
Authentication & Identity Management · Keeper Secrets Manager
Details
| ID | KeeperSecretsManager |
|---|---|
| Provider | Keeper Security Inc. |
| Category | Authentication & Identity Management |
| From Version | 6.5.0 |
| Docker Image | demisto/keeper-ksm:1.0.0.10221838 |
| Supported Modules | Agentix XSIAM |
README
Manage Secrets and Protect Sensitive Data through Keeper Vault.
This integration was integrated and tested with version 16.3.5 of Keeper Secrets Manager.
Configure Keeper Secrets Manager in Cortex
| Parameter | Description | Required |
|---|---|---|
| KSM Configuration | The KSM config to use for connection. | True |
| Trust any certificate (not secure) | When ‘trust any certificate’ is selected, the integration ignores TLS/SSL certificate validation errors. Use to test connection issues or connect to a server without a valid certificate. | False |
| Fetches credentials | Fetches credentials from login records. | False |
| Concat username to credential object name | Use to make the credential object unique in case of duplicate names in different folders/secrets. | False |
| A comma-separated list of credential names to fetch. | Partial names are not supported. If left empty, all credentials will be fetched. | False |
Commands
You can execute these commands from the 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.
ksm-find-files
Search for records by full or partial file name match.
Base Command
ksm-find-files
Input
| Argument Name | Description | Required |
|---|---|---|
| file_name | File name text to search for. | Required |
| partial_match | Search for partial file name match. | Optional |
Context Output
| Path | Type | Description |
|---|---|---|
| KeeperSecretsManager.Files.record_uid | String | Record UID. |
| KeeperSecretsManager.Files.file_uid | String | File UID. |
| KeeperSecretsManager.Files.file_name | String | File Name. |
| KeeperSecretsManager.Files.file_size | String | File Size. |
Command example
!ksm-find-files file_name="blank.txt"
Context Example
{
"KeeperSecretsManager": {
"Files": [
{
"file_name": "blank.txt",
"file_size": 5,
"file_uid": "Z8F-lSBHmTiMMDQrRiBjUA",
"record_uid": "PNby7a3Mrh4OfPdkpdfFsA"
},
{
"file_name": "blank.txt",
"file_size": 5,
"file_uid": "xdsQvfDzD-W38_alIwJnMg",
"record_uid": "4FTOiJx-m31hDIlmief1Cg"
}
]
}
}
Human Readable Output
Records with attachments
Record Details
file_name file_size file_uid record_uid blank.txt 5 Z8F-lSBHmTiMMDQrRiBjUA PNby7a3Mrh4OfPdkpdfFsA blank.txt 5 xdsQvfDzD-W38_alIwJnMg 4FTOiJx-m31hDIlmief1Cg
ksm-find-records
Search for records by full or partial title match.
Base Command
ksm-find-records
Input
| Argument Name | Description | Required |
|---|---|---|
| title | Title text to search for. | Required |
| partial_match | Search for partial title match. | Optional |
Context Output
| Path | Type | Description |
|---|---|---|
| KeeperSecretsManager.Records.uid | String | Record UID. |
| KeeperSecretsManager.Records.type | String | Record Type. |
| KeeperSecretsManager.Records.title | String | Record Title. |
Command example
!ksm-find-records title="file"
Context Example
{
"KeeperSecretsManager": {
"Records": [
{
"uid": "WcizqXQGsk0Jho48Mn52MQ",
"type": "file",
"title": "files1"
},
{
"uid": "Px5xVljXRZ1dPYMQ9Yv05Q",
"type": "file",
"title": "files2"
}
]
}
}
Human Readable Output
Records
Record Details
uid type tite WcizqXQGsk0Jho48Mn52MQ file files1 Px5xVljXRZ1dPYMQ9Yv05Q file files2
ksm-get-field
Use this command to get field value from Keeper record.
Base Command
ksm-get-field
Input
| Argument Name | Description | Required |
|---|---|---|
| notation | Keeper KSM notation URI. | Required |
Context Output
| Path | Type | Description |
|---|---|---|
| KeeperSecretsManager.Field.field | String | Extracted field value. |
Command example
!ksm-get-field notation="keeper://6LJgiVzzD4ZJuxQYj_wN9A/field/login"
Context Example
{
"KeeperSecretsManager": {
"Field": "admin"
}
}
Human Readable Output
admin
ksm-get-file
Use this command to fetch the file attachment as a File.
Base Command
ksm-get-file
Input
| Argument Name | Description | Required |
|---|---|---|
| file_uid | File UID to search for. | Required |
| record_uid | Record UID to search for files. Search all records if empty. | Optional |
Context Output
There is no context output for this command.
Command example
!ksm-get-file file_uid="bZs6l8Hx9zkrRPYVFyuYLA"
Context Example
{
"File": {
"EntryID": "36@21232f297a57a5a743894a0e4a801fc3$&$9b10a24b-f008-42e0-8554-d24397e91996",
"Extension": "txt",
"Info": "text/plain; charset=utf-8",
"MD5": "8e15625d6c158ec48f374efb77bd2714",
"Name": "blank.txt",
"SHA1": "6184d6847d594ec75c4c07514d4bb490d5e166df",
"SHA256": "ff71cf74abb3ccb005b8b64371725db15edc42c1ad33413bbe561b2da3c85ef9",
"SHA512": "c7503ab487c392e8cbbe756fd7340bd83214c351dfd48a2c597285267621976a5e321fa88923917b8a2fb6895727da0a42123233258b4da485b0de7c91ba8610",
"SSDeep": "3:wO:wO",
"Size": 5,
"Type": "ASCII text, with no line terminators"
}
}
Human Readable Output
ksm-get-infofile
Use this command to fetch the file attachment as an Info File.
Base Command
ksm-get-infofile
Input
| Argument Name | Description | Required |
|---|---|---|
| file_uid | File UID to search for. | Required |
| record_uid | Record UID to search for files. Search all records if empty. | Optional |
Context Output
There is no context output for this command.
Command example
!ksm-get-infofile file_uid="bZs6l8Hx9zkrRPYVFyuYLA"
Context Example
{
"InfoFile": {
"EntryID": "40@21232f297a57a5a743894a0e4a801fc3$&$9b10a24b-f008-42e0-8554-d24397e91996",
"Extension": "txt",
"Info": "text/plain; charset=utf-8",
"Name": "blank.txt",
"Size": 5,
"Type": "ASCII text, with no line terminators"
}
}
Human Readable Output
ksm-list-credentials
Use this command to list all credentials in your Keeper Vault that are shared to the KSM application.
Base Command
ksm-list-credentials
Input
| Argument Name | Description | Required |
| — | — | — |
Context Output
| Path | Type | Description |
|---|---|---|
| KeeperSecretsManager.Creds.uid | String | Record UID. |
| KeeperSecretsManager.Creds.title | String | Record Title. |
| KeeperSecretsManager.Creds.name | String | Username. |
Command example
#### Context Example
```json
{
"KeeperSecretsManager": {
"Creds": [
{
"name": "IIS Admin",
"uid": "6LJgiVzzD4ZJuxQYj_wN9A",
"user": "admin"
},
{
"name": "nginx Admin",
"uid": "7W6exgzq_OeVF6Xh1EJ29g",
"user": "admin"
}
]
}
}
Human Readable Output
Credentials
Credential Details
name uid user IIS Admin 6LJgiVzzD4ZJuxQYj_wN9A admin nginx Admin 7W6exgzq_OeVF6Xh1EJ29g admin
ksm-list-files
Use this command to list all records that have file attachments.
Base Command
ksm-list-files
Input
| Argument Name | Description | Required |
|---|---|---|
| record_uids | A comma-separated list of record UIDs to search. If left empty all records with file attachments will be listed. | Optional |
Context Output
| Path | Type | Description |
|---|---|---|
| KeeperSecretsManager.Files.record_uid | String | Record UID. |
| KeeperSecretsManager.Files.file_uid | String | File UID. |
| KeeperSecretsManager.Files.file_name | String | File Name. |
| KeeperSecretsManager.Files.file_size | String | File Size. |
Command example
#### Context Example
```json
{
"KeeperSecretsManager": {
"Files": [
{
"file_name": "blank.txt",
"file_size": 5,
"file_uid": "bZs6l8Hx9zkrRPYVFyuYLA",
"record_uid": "RXd1m_fKO2XnAWzeUawM5A"
},
{
"file_name": "blank.txt",
"file_size": 5,
"file_uid": "xdsQvfDzD-W38_alIwJnMg",
"record_uid": "4FTOiJx-m31hDIlmief1Cg"
}
]
}
}
Human Readable Output
Records with attachments
Record Details
file_name file_size file_uid record_uid blank.txt 5 bZs6l8Hx9zkrRPYVFyuYLA RXd1m_fKO2XnAWzeUawM5A blank.txt 5 xdsQvfDzD-W38_alIwJnMg 4FTOiJx-m31hDIlmief1Cg
ksm-list-records
Use this command to list all records from your Keeper Vault that are shared to the application.
Base Command
ksm-list-records
Input
| Argument Name | Description | Required |
| — | — | — |
Context Output
| Path | Type | Description |
|---|---|---|
| KeeperSecretsManager.Records.uid | String | Record UID. |
| KeeperSecretsManager.Records.type | String | Record Type. |
| KeeperSecretsManager.Records.title | String | Record Title. |
Command example
#### Context Example
```json
{
"KeeperSecretsManager": {
"Records": [
{
"title": "files2",
"type": "file",
"uid": "RXd1m_fKO2XnAWzeUawM5A"
},
{
"title": "files1",
"type": "file",
"uid": "4FTOiJx-m31hDIlmief1Cg"
},
{
"title": "IIS Admin",
"type": "login",
"uid": "6LJgiVzzD4ZJuxQYj_wN9A"
},
{
"title": "nginx Admin",
"type": "login",
"uid": "7W6exgzq_OeVF6Xh1EJ29g"
}
]
}
}
Human Readable Output
Records
Record Details
title type uid files2 file RXd1m_fKO2XnAWzeUawM5A files1 file 4FTOiJx-m31hDIlmief1Cg IIS Admin login 6LJgiVzzD4ZJuxQYj_wN9A nginx Admin login 7W6exgzq_OeVF6Xh1EJ29g
Configuration parameters
credentials— KSM Configuration (required)insecure— Trust any certificate (not secure)isFetchCredentials— Fetches credentialsconcat_username_to_cred_name— Concat username to credential object namecredential_names— A comma-separated list of credential names to fetch.
Commands (8)
-
ksm-find-filesSearch for records by full or partial file name match.
-
ksm-find-recordsSearch for records by full or partial title match.
-
ksm-get-fieldUse this command to get field value from Keeper record.
-
ksm-get-fileUse this command to fetch the file attachment as a File.
-
ksm-get-infofileUse this command to fetch the file attachment as an Info File.
-
ksm-list-credentialsUse this command to list all credentials in your Keeper Vault that are shared to the KSM application.
-
ksm-list-filesUse this command to list all records that have file attachments.
-
ksm-list-recordsUse this command to list all records from your Keeper Vault that are shared to the application.
import demistomock as demisto # noqa: F401 from CommonServerPython import * # noqa: F401 """Keeper Secrets Manager Integration for Cortex XSOAR (aka Demisto) Manage Secrets and Protect Sensitive Data through Keeper Vault. """ from CommonServerUserPython import * # noqa import urllib3 import traceback from typing import Any from keeper_secrets_manager_core import SecretsManager from keeper_secrets_manager_core.storage import InMemoryKeyValueStorage # Disable insecure warnings urllib3.disable_warnings() # pylint: disable=no-member """ CONSTANTS """ APP_NAME = "keeper-secrets-manager" DATE_FORMAT = "%Y-%m-%dT%H:%M:%SZ" # ISO8601 format with UTC, default in XSOAR metadata_collector = YMLMetadataCollector( integration_name="KeeperSecretsManager", description="Use the Keeper Secrets Manager integration to manage secrets and protect" " sensitive data through Keeper Vault.", detailed_description="<p>Keeper Secrets Manager API is available for administrators" " and developers to integrate Keeper Vault data into their applications." " This integration fetches credentials. For more information," ' see <a href="https://xsoar.pan.dev/docs/reference/articles/managing-credentials">' "Managing Credentials</a>.</p>" " <p>This integration was integrated and tested with" " version 16.3.5 of Keeper Secrets Manager.</p>", display="Keeper Secrets Manager", category="Authentication", default_classifier=None, default_mapper_in=None, deprecated=None, docker_image="demisto/keeper-ksm:1.0.0.33394", fromversion="6.5.0", is_runonce=False, integration_subtype="python3", integration_type="python", is_feed=False, is_fetch=False, long_running=False, long_running_port=False, tests=["No tests"], conf=[ ConfKey( name="credentials", display="KSM Configuration", additional_info="The KSM config to use for connection.", required=True, key_type=ParameterTypes.TEXT_AREA_ENCRYPTED, ), ConfKey( name="insecure", display="Trust any certificate (not secure)", additional_info="When 'trust any certificate' is selected," " the integration ignores TLS/SSL certificate validation errors." " Use to test connection issues or connect to a server without a valid" " certificate.", required=False, key_type=ParameterTypes.BOOLEAN, ), ConfKey( name="isFetchCredentials", display="Fetches credentials", additional_info="Fetches credentials from login records.", default_value=False, required=False, key_type=ParameterTypes.BOOLEAN, ), ConfKey( name="concat_username_to_cred_name", display="Concat username to credential object name", additional_info="Use to make the credential object unique" " in case of duplicate names in different folders/secrets.", required=False, key_type=ParameterTypes.BOOLEAN, ), ConfKey( name="credential_names", display="A comma-separated list of credential names to fetch.", additional_info="Partial names are not supported. If left empty, all credentials will be fetched.", required=False, key_type=ParameterTypes.TEXT_AREA, ), # ConfKey(name="proxy", # display="Use system proxy settings", # required=False, # key_type=ParameterTypes.BOOLEAN), ], ) """ CLIENT CLASS """ class Client: """Client class to interact with the service API""" def __init__(self, credentials: str, insecure: bool): self.credentials = credentials self.verify_ssl_certs = not insecure try: config = InMemoryKeyValueStorage(credentials) except Exception: demisto.debug("Failed to initialize KSM configuration. Invalid credentials.") raise ValueError("Failed to initialize KSM configuration. Invalid credentials.") try: self.secrets_manager = SecretsManager(config=config, verify_ssl_certs=self.verify_ssl_certs) except Exception as e: demisto.debug("Failed to initialize KSM Client. " + str(e)) raise def ksm_get_field(self, notation: str) -> str: """Returns a simple python dict with the information provided in the input (notation). :type notation: ``str`` :param notation: Keeper URI notation to select desired field :return: field value :rtype: ``dict`` """ result = self.secrets_manager.get_notation(notation) return result or "" def ksm_list_records(self) -> list[dict[str, str]]: result = [] records = self.secrets_manager.get_secrets() or [] for r in records: result.append({"uid": r.uid, "type": r.type, "title": r.title}) return result def ksm_find_records(self, title: str, partial_match: bool = True) -> list[dict[str, str]]: result = [] title = title.lower() records = self.secrets_manager.get_secrets() or [] for r in records: record_title: str = str(r.title).lower() if r.title else "" if record_title == title or (partial_match and title and record_title.__contains__(title)): result.append({"uid": r.uid, "type": r.type, "title": r.title}) return result def ksm_fetch_credentials(self) -> list[dict[str, str]]: result = [] records = self.secrets_manager.get_secrets() or [] for r in records: if r.type == "login": result.append({"user": r.get_standard_field_value("login", True), "password": r.password, "name": r.title}) return result def list_credentials(self) -> list[dict[str, str]]: result = [] records = self.secrets_manager.get_secrets() or [] for r in records: if r.type == "login": result.append({"name": r.title, "user": r.get_standard_field_value("login", True), "uid": r.uid}) return result def ksm_list_files(self, record_uids: list[str]) -> list[dict[str, str]]: result = [] records = self.secrets_manager.get_secrets(record_uids) or [] for r in records: files = r.files or [] for f in files: result.append( {"record_uid": r.uid, "file_uid": f.f.get("fileUid", ""), "file_name": f.name or f.title, "file_size": f.size} ) return result def ksm_find_files(self, file_name: str, partial_match: bool = True) -> list[dict[str, str]]: result = [] file_name = file_name.lower() records = self.secrets_manager.get_secrets() or [] for r in records: files = r.files or [] for f in files: fname: str = str(f.name).lower() if f.name else "" if fname == file_name or (partial_match and file_name and fname.__contains__(file_name)): result.append( {"record_uid": r.uid, "file_uid": f.f.get("fileUid", ""), "file_name": f.name, "file_size": f.size} ) return result def ksm_get_file(self, record_uid: str, file_uid: str) -> list[tuple[str, bytes]]: result = [] record_filter = [record_uid] if record_uid else [] records = self.secrets_manager.get_secrets(record_filter) or [] for r in records: files = r.files or [] for f in files: if file_uid == f.f.get("fileUid", ""): result.append((f.name or f.title, f.get_file_data())) return result """ HELPER FUNCTIONS """ """ COMMAND FUNCTIONS """ def fetch_credentials(client: Client): params: dict = demisto.params() args: dict = demisto.args() credentials_str = params.get("credential_names") credentials_names_from_configuration = argToList(credentials_str) credentials_name = args.get("identifier") concat_username_to_cred_name = argToBoolean(params.get("concat_username_to_cred_name") or "false") demisto.debug("Name of credential used: ", credentials_name) demisto.debug("Name of credentials used: ", credentials_names_from_configuration) credentials = [] try: credentials = client.ksm_fetch_credentials() except Exception as e: demisto.debug(f"Could not fetch credentials. Error: {e}") credentials = [] if concat_username_to_cred_name: for i in range(len(credentials)): credentials[i]["name"] = f"{credentials[i].get('name', '')}_{credentials[i].get('user', '')}" if credentials_name: credentials = list(filter(lambda c: c.get("name", "") == credentials_name, credentials)) if len(credentials) > 1: credentials = credentials[:1] # Important - always return a list containing up to one set of credentials. # If no list or a list with more than one element will be returned, # the credentials tab will fail to load. elif credentials_names_from_configuration: credentials = list(filter(lambda c: c.get("name", "") in credentials_names_from_configuration, credentials)) demisto.credentials(credentials) LIST_CREDENTIALS_OUTPUTS = [ OutputArgument(name="uid", output_type=str, description="Record UID."), OutputArgument(name="title", output_type=str, description="Record Title."), OutputArgument(name="name", output_type=str, description="Username."), ] @metadata_collector.command( command_name="ksm-list-credentials", outputs_prefix="KeeperSecretsManager.Creds", outputs_list=LIST_CREDENTIALS_OUTPUTS, restore=True, description="Use this command to list all credentials in your Keeper Vault that are shared to the KSM application.", ) def list_credentials_command(client: Client, args: dict[str, Any], **kwargs) -> CommandResults: """Lists all credentials available to the KSM application. :param client: the client object with the given params :return: the credentials info without the explicit password """ demisto.debug("list_credentials_command - command_name: " + str(kwargs.get("command_name", ""))) creds_list = client.list_credentials() markdown = "### Credentials\n" markdown += tableToMarkdown("Credential Details", creds_list) results = CommandResults( readable_output=markdown, outputs_prefix="KeeperSecretsManager.Creds", outputs_key_field="name", outputs=creds_list, raw_response=creds_list, ) return results @metadata_collector.command( command_name="ksm-get-field", outputs_prefix="KeeperSecretsManager.Field", inputs_list=[InputArgument(name="notation", required=True, description="Keeper KSM notation URI.")], description="Use this command to get field value from Keeper record.", ) def get_field_command(client: Client, args: dict[str, Any], **kwargs) -> CommandResults: """Get field command - returns field value. Args: client (Client): KeeperSecretsManager client to use. notation (str): The Keeper notation URI used to find the field in the record. required. :return: A ``CommandResults`` object that is then passed to ``return_results``, that contains the field value. Context Outputs: field (str): Extracted field value. """ demisto.debug("get_field_command - command_name: " + str(kwargs.get("command_name", ""))) notation = args.get("notation", None) if not notation: raise ValueError("notation URI not specified") result = client.ksm_get_field(notation) readable_output = f"## {result}" results = CommandResults( readable_output=readable_output, outputs_prefix="KeeperSecretsManager.Field", outputs_key_field="", outputs=result ) return results GET_RECORDS_OUTPUTS = [ OutputArgument(name="uid", output_type=str, description="Record UID."), OutputArgument(name="type", output_type=str, description="Record Type."), OutputArgument(name="title", output_type=str, description="Record Title."), ] @metadata_collector.command( command_name="ksm-list-records", outputs_prefix="KeeperSecretsManager.Records", outputs_list=GET_RECORDS_OUTPUTS, restore=True, description="Use this command to list all records from your Keeper Vault that are shared to the application.", ) def list_records_command(client: Client, args: dict[str, Any], **kwargs) -> CommandResults: """List records command - returns list of record info. Args: client (Client): KeeperSecretsManager client to use. :return: A ``CommandResults`` object that is then passed to ``return_results``, that contains the list with records info. :rtype: ``CommandResults`` """ demisto.debug("list_records_command - command_name: " + str(kwargs.get("command_name", ""))) records = client.ksm_list_records() markdown = "### Records\n" markdown += tableToMarkdown("Record Details", records) results = CommandResults( readable_output=markdown, outputs_prefix="KeeperSecretsManager.Records", outputs_key_field="uid", outputs=records ) return results @metadata_collector.command( command_name="ksm-find-records", outputs_prefix="KeeperSecretsManager.Records", outputs_list=GET_RECORDS_OUTPUTS, restore=True, inputs_list=[ InputArgument(name="title", required=True, description="Title text to search for."), InputArgument(name="partial_match", required=False, default=False, description="Search for partial title match."), ], description="Search for records by full or partial title match.", ) def find_records_command(client: Client, args: dict[str, Any], **kwargs) -> CommandResults: """Find records command - returns list of record info. Args: client (Client): KeeperSecretsManager client to use. title (str): Title text to search for. partial_match (bool): Flag for partial title match. :return: A ``CommandResults`` object that is then passed to ``return_results``, that contains the list with records info. :rtype: ``CommandResults`` """ demisto.debug("find_records_command - command_name: " + str(kwargs.get("command_name", ""))) title = args.get("title") or "" partial_match = args.get("partial_match", None) partial_match = bool(partial_match) demisto.debug(f"Find records with title={title} and partial_match={partial_match}") records = client.ksm_find_records(title, partial_match) markdown = "### Records\n" markdown += tableToMarkdown("Record Details", records) results = CommandResults( readable_output=markdown, outputs_prefix="KeeperSecretsManager.Records", outputs_key_field="uid", outputs=records ) return results GET_FILES_OUTPUTS = [ OutputArgument(name="record_uid", output_type=str, description="Record UID."), OutputArgument(name="file_uid", output_type=str, description="File UID."), OutputArgument(name="file_name", output_type=str, description="File Name."), OutputArgument(name="file_size", output_type=str, description="File Size."), ] @metadata_collector.command( command_name="ksm-list-files", outputs_prefix="KeeperSecretsManager.Files", outputs_list=GET_FILES_OUTPUTS, restore=True, inputs_list=[ InputArgument( name="record_uids", required=False, default="", description="A comma-separated list of record UIDs to search." " If left empty all records with file attachments will be listed.", ) ], description="Use this command to list all records that have file attachments.", ) def list_files_command(client: Client, args: dict[str, Any], **kwargs) -> CommandResults: """List files command - returns list of record and file info. Args: client (Client): KeeperSecretsManager client to use. record_uids (str): The CSV list of record UIDs to search for files. :return: A ``CommandResults`` object that is then passed to ``return_results``, that contains the list with records and files info. :rtype: ``CommandResults`` """ demisto.debug("list_files_command - command_name: " + str(kwargs.get("command_name", ""))) record_uids_str = args.get("record_uids") or "" record_uids = argToList(record_uids_str) demisto.debug("List files for record UIDs: ", record_uids_str) records = client.ksm_list_files(record_uids) markdown = "### Records with attachments\n" markdown += tableToMarkdown("Record Details", records) results = CommandResults( readable_output=markdown, outputs_prefix="KeeperSecretsManager.Files", outputs_key_field="file_uid", outputs=records ) return results @metadata_collector.command( command_name="ksm-find-files", outputs_prefix="KeeperSecretsManager.Files", outputs_list=GET_FILES_OUTPUTS, restore=True, inputs_list=[ InputArgument(name="file_name", required=True, description="File name text to search for."), InputArgument(name="partial_match", required=False, default=False, description="Search for partial file name match."), ], description="Search for records by full or partial file name match.", ) def find_files_command(client: Client, args: dict[str, Any], **kwargs) -> CommandResults: """Find files command - returns list of record and file info. Args: client (Client): KeeperSecretsManager client to use. file_name (str): The file name text to search for. partial_match (bool): Flag for partial file name match. :return: A ``CommandResults`` object that is then passed to ``return_results``, that contains the list with records and files info. :rtype: ``CommandResults`` """ demisto.debug("find_files_command - command_name: " + str(kwargs.get("command_name", ""))) file_name = args.get("file_name") or "" partial_match = args.get("partial_match", None) partial_match = bool(partial_match) demisto.debug(f"Find records with file_name={file_name} and partial_match={partial_match}") records = client.ksm_find_files(file_name, partial_match) markdown = "### Records with attachments\n" markdown += tableToMarkdown("Record Details", records) results = CommandResults( readable_output=markdown, outputs_prefix="KeeperSecretsManager.Files", outputs_key_field="file_uid", outputs=records ) return results @metadata_collector.command( command_name="ksm-get-file", inputs_list=[ InputArgument(name="file_uid", required=True, description="File UID to search for."), InputArgument( name="record_uid", required=False, default="", description="Record UID to search for files. Search all records if empty.", ), ], description="Use this command to fetch the file attachment as a File.", ) def get_file_command(client: Client, args: dict[str, Any], **kwargs) -> dict | None: """Get file command - returns the file attachment as a File. Args: client (Client): KeeperSecretsManager client to use. file_uid (str): The file UID to search for. required. record_uid (str): The record UID to search for files. Searches all records if record UID is empty. :return: A ``CommandResults`` object that is then passed to ``return_results``, that contains the list with records and files info. :rtype: ``CommandResults`` """ demisto.debug("get_file_command - command_name: " + str(kwargs.get("command_name", ""))) record_uid = args.get("record_uid") or "" file_uid = args.get("file_uid", None) if not file_uid: raise ValueError("file_uid not specified") demisto.debug(f'Get file UID: "{file_uid}" from record UID:"{record_uid}"') files = client.ksm_get_file(record_uid, file_uid) if files: file_result = fileResult(filename=files[0][0], data=files[0][1]) # file_result["Contents"] = files[0][1] return file_result return None @metadata_collector.command( command_name="ksm-get-infofile", inputs_list=[ InputArgument(name="file_uid", required=True, description="File UID to search for."), InputArgument( name="record_uid", required=False, default="", description="Record UID to search for files. Search all records if empty.", ), ], description="Use this command to fetch the file attachment as an Info File.", ) def get_infofile_command(client: Client, args: dict[str, Any], **kwargs) -> dict | None: """Get info file command - returns the file attachment as an Info File. Args: client (Client): KeeperSecretsManager client to use. file_uid (str): The file UID to search for. required. record_uid (str): The record UID to search for files. Searches all records if record UID is empty. :return: A ``CommandResults`` object that is then passed to ``return_results``, that contains the list with records and files info. :rtype: ``CommandResults`` """ demisto.debug("get_infofile_command - command_name: " + str(kwargs.get("command_name", ""))) record_uid = args.get("record_uid") or "" file_uid = args.get("file_uid", None) if not file_uid: raise ValueError("file_uid not specified") demisto.debug(f'Get file UID: "{file_uid}" from record UID:"{record_uid}"') files = client.ksm_get_file(record_uid, file_uid) if files: file_result = fileResult(filename=files[0][0], data=files[0][1], file_type=EntryType.ENTRY_INFO_FILE) # file_result["Contents"] = files[0][1] return file_result return None def test_module(client: Client) -> str: """Tests API connectivity and authentication' Returning 'ok' indicates that the integration works like it is supposed to. Connection to the service is successful. Raises exceptions if something goes wrong. :type client: ``Client`` :param Client: client to use :return: 'ok' if test passed, anything else will fail the test. :rtype: ``str`` """ message: str = "" try: # Tests connectivity and authentication to KSM service. # This validates all the inputs given in the integration configuration panel, # either manually or by using an API that uses them. client.secrets_manager.get_secrets(["AAAAAAAAAAAAAAAAAAAAA"]) message = "ok" except Exception as e: message = str(e) return message """ MAIN FUNCTION """ def main() -> None: # pragma: no cover """main function, parses params and runs command functions :return: :rtype: """ credentials = demisto.params().get("credentials") insecure = demisto.params().get("insecure", False) command = demisto.command() try: demisto.debug(f"Command being called in KSM is: {command}") client = Client(credentials=credentials, insecure=insecure) if command == "test-module": return_results(test_module(client)) elif command == "fetch-credentials": fetch_credentials(client) elif command == "ksm-list-credentials": return_results(list_credentials_command(client, demisto.args())) elif command == "ksm-list-records": return_results(list_records_command(client, demisto.args())) elif command == "ksm-get-field": return_results(get_field_command(client, demisto.args())) elif command == "ksm-list-files": return_results(list_files_command(client, demisto.args())) elif command == "ksm-get-file": return_results(get_file_command(client, demisto.args())) elif command == "ksm-get-infofile": return_results(get_infofile_command(client, demisto.args())) elif command == "ksm-find-records": return_results(find_records_command(client, demisto.args())) elif command == "ksm-find-files": return_results(find_files_command(client, demisto.args())) except Exception as e: demisto.error(traceback.format_exc()) return_error(f"Failed to execute {command} command.\nError:\n{e!s}") """ ENTRY POINT """ if __name__ in ("__main__", "__builtin__", "builtins"): main()