ServiceNow CMDB
ServiceNow CMDB is a service‑centric foundation that proactively analyzes service‑impacting changes, identifies issues, and eliminates outages.
IT Services · ServiceNow
Details
| ID | ServiceNow CMDB |
|---|---|
| Provider | ServiceNow |
| Category | IT Services |
| From Version | 5.0.0 |
| Docker Image | demisto/auth-utils:1.0.0.10133006 |
| Supported Modules | Attack Surface Management Exposure Management Agentix Cortex Cloud Cloud Runtime Security Cloud Posture Security XSIAM EDR |
README
ServiceNow CMDB is a service‑centric foundation that proactively
analyzes service‑impacting changes, identifies issues, and eliminates outages.
Configure ServiceNow_CMDB in Cortex
Instance Configuration
The integration supports three types of authorization:
- Basic authorization using username and password.
- OAuth 2.0 authorization.
- JWT authentication.
OAuth 2.0 Authorization
To use OAuth 2.0 authorization, perform the following steps:
- Login to your ServiceNow instance and create an endpoint to access your instance (please see Snow OAuth for more information).
- Copy the Client Id and Client Secret (click the lock next to the client secret to reveal it) that were automatically generated when creating the endpoint into the Client ID and Client Secret fields of the instance configuration.
- (Recommended) Enter the ServiceNow account Username and Password in the instance configuration. When provided, the integration automatically performs the initial OAuth login on first use. It also automatically renews the refresh token when it expires.
- Select the Use OAuth Login checkbox and click Done.
- If you did not provide Username and Password in step 3, run the command !servicenow-cmdb-oauth-login from the CLI and fill in the username and password of the ServiceNow instance. This step generates and saves to the integration context a refresh token to the ServiceNow instance and is required only the first time after configuring a new instance. If you provided Username and Password, this step is handled automatically.
- (Optional) Test the created instance by running the
!servicenow-cmdb-oauth-testcommand.
Notes:
- When running the !servicenow-cmdb-oauth-login command, a refresh token is generated and will be used to produce new access tokens after the current access token has expired.
- If the Username and Password fields are configured, the integration will automatically perform the initial login and renew the refresh token when it expires — no manual commands are needed. Otherwise, you will have to run the servicenow-cmdb-oauth-login command for the initial login and again each time the refresh token expires.
- The grant type used to get an access token is
Client credentials. See the Snow documentation for more information.
JWT Authentication
Prerequisites in order to support JWT
- Create a Java Key Store and upload it to the instance by accessing from the upper menu: All > System Definition > Certificates. The private key will be used as an integration parameter.
- Configure a JWT signing key by accessing: All→System OAuth→JWT Keys using the keystore from above and keep the Key ID as it will be used as kid integration parameter.
- Create a JWT provider with a JWT signing key by accessing: All→System OAuth→JWT providers. Claim Name sub in Standard Claims has to be existing non-admin servicenow user with all necessary roles.
- Connect to an OAuth provider and create an OAuth application registry by accessing All→System OAuth→Application Registry:
- aud in JWT provider has to be equal to Client ID from OAuth JWT application - update JWT provider If necessary.
- The value of kid in JWT Verifier Maps has to be the same as Key Id in JWT signing key.
The value can be updated if necessary.
- Create API Access Policy or add Authentication profile to existing Policy by accessing: All→System Web Services→API Access Policies→Rest API Access Policies
IMPORTANT:
- The Standard Authentication Profile of type Oauth should be already present in ServiceNow and has to be added to the Policy.
API Access Policy should be configured as global in order to cover all available resources and not just now/table - Granting JWT to admin is not allowed.
You should have a non-admin user with all necessary roles (only non-admin roles) in addition to the existing role snc_platform_rest_api_access that is required to make API calls.
Using Multi Factor Authentication (MFA)
MFA can be used both when using basic authorization and OAuth 2.0 authorization, however we strongly recommend using OAuth 2.0 when using MFA.
If MFA is enabled for your user, perform the following steps:
- Open the Google Authenticator application on your mobile device and make note of the number. The number refreshes every 30 seconds.
- Enter your username and password, and append the One Time Password (OTP) that you currently see on your mobile device to your password without any extra spaces. For example, if your password is 12345 and the current OTP code is 424 058, enter 12345424058.
Notes:
- When using basic authorization, you will have to update your password with the current OTP every time the current code expires (30 seconds), therefore, we recommend using OAuth 2.0 authorization.
- For using OAuth 2.0 see the above instructions. The OTP code should be appended to the password parameter in the !servicenow-cmdb-oauth-login command.
| Parameter | Description | Required |
|---|---|---|
| ServiceNow URL, in the format https://company.service-now.com/ | True | |
| Use OAuth Login | Check this box to use OAuth 2.0 authentication. See (?) for more information. | False |
| Use JWT Authentication | Select this checkbox to use JWT authentication. See (?) for more information. | False |
| Client ID/JWT Audience (aud) | False | |
| Client Secret | False | |
| Username | False | |
| Password | False | |
| Private key | False | |
| Kid (Key Id) | False | |
| Sub | False | |
| Iss (Issuer) | If not set, Client ID will be used. | False |
| Trust any certificate (not secure) | False | |
| Use system proxy settings | 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.
servicenow-cmdb-records-list
Query records for a CMDB class.
Base Command
servicenow-cmdb-records-list
Input
| Argument Name | Description | Required |
|---|---|---|
| class | The name of the class to query. | Required |
| query | An encoded query string used to filter the results. For more information about querying in ServiceNow, see https://docs.servicenow.com/bundle/paris-servicenow-platform/page/use/common-ui-elements/reference/r_OpAvailableFiltersQueries.html | Optional |
| limit | The maximum number of results returned per page (default: 50). | Optional |
| offset | The number of records to exclude from the query (default: 0). | Optional |
Context Output
| Path | Type | Description |
|---|---|---|
| ServiceNowCMDB.Class | String | The name of CMDB table that was queried. |
| ServiceNowCMDB.Records | Unknown | A list of all the records that were found in the CMDB table. |
Command Example
!servicenow-cmdb-records-list class=cmdb_ci_linux_server limit=3
Context Example
{
"ServiceNowCMDB": {
"Class": "cmdb_ci_linux_server",
"Records": [
{
"name": "Test Linux Server 2",
"sys_id": "0ad329e3db27901026fca015ca9619fb"
},
{
"name": "Update Name Test",
"sys_id": "18295cefdbd0241026fca015ca9619f7"
},
{
"name": "new design updated name",
"sys_id": "2a41eb4e1b739810042611b4bd4bcb9d"
}
]
}
}
Human Readable Output
Found 3 records for class cmdb_ci_linux_server
name sys_id Test Linux Server 2 0ad329e3db27901026fca015ca9619fb Update Name Test 18295cefdbd0241026fca015ca9619f7 new design updated name 2a41eb4e1b739810042611b4bd4bcb9d
servicenow-cmdb-record-get-by-id
Query attributes and relationship information for a specific record.
Base Command
servicenow-cmdb-record-get-by-id
Input
| Argument Name | Description | Required |
|---|---|---|
| class | The name of the class to query. | Required |
| sys_id | The ID of the record that should be queried. | Required |
| fields | A comma-separated list of the fields to return for the queried record. | Optional |
| relation_limit | The maximum number of relations returned (default: 50). | Optional |
| relation_offset | The number of records to exclude from the relations query (default: 0). | Optional |
Context Output
| Path | Type | Description |
|---|---|---|
| ServiceNowCMDB.Record.SysID | String | The sys_id of the record that was queried. |
| ServiceNowCMDB.Record.Class | String | The name of the class from which the record was queried. |
| ServiceNowCMDB.Record.Attributes | Unknown | The attributes that were returned in the response for the queried record. |
| ServiceNowCMDB.Record.OutboundRelations | Unknown | A list of all the outbound relations of the queried record. |
| ServiceNowCMDB.Record.InboundRelations | Unknown | A list of all the inbound relations of the queried record. |
Command Example
!servicenow-cmdb-record-get-by-id class=cmdb_ci_linux_server sys_id=a8decc3f1b9c2410042611b4bd4bcb7d
Context Example
{
"ServiceNowCMDB": {
"Record": {
"Attributes": {
"asset": {
"display_value": "Unknown",
"link": "https://ven03941.service-now.com/api/now/table/alm_asset/60decc3f1b9c2410042611b4bd4bcb7f",
"value": "60decc3f1b9c2410042611b4bd4bcb7f"
},
"asset_tag": "",
"assigned": "",
"assigned_to": "",
"assignment_group": "",
"attributes": "",
"can_print": "false",
"category": "Hardware",
"cd_rom": "false",
"cd_speed": "",
"change_control": "",
"chassis_type": "",
"checked_in": "",
"checked_out": "",
"classification": "Production",
"comments": "",
"company": "",
"correlation_id": "",
"cost": "",
"cost_cc": "USD",
"cost_center": "",
"cpu_core_count": "",
"cpu_core_thread": "",
"cpu_count": "",
"cpu_manufacturer": "",
"cpu_name": "",
"cpu_speed": "",
"cpu_type": "",
"default_gateway": "",
"delivery_date": "",
"department": "",
"discovery_source": "ServiceNow",
"disk_space": "",
"dns_domain": "",
"dr_backup": "",
"due": "",
"due_in": "",
"duplicate_of": "",
"fault_count": "0",
"firewall_status": "Intranet",
"first_discovered": "2020-11-12 06:18:25",
"floppy": "",
"form_factor": "",
"fqdn": "",
"gl_account": "",
"hardware_status": "installed",
"hardware_substatus": "",
"host_name": "",
"install_date": "",
"install_status": "1",
"invoice_number": "",
"ip_address": "",
"justification": "",
"kernel_release": "",
"last_discovered": "2020-11-12 06:18:25",
"lease_id": "",
"location": "",
"mac_address": "",
"maintenance_schedule": "",
"managed_by": "",
"manufacturer": "",
"model_id": {
"display_value": "Unknown",
"link": "https://ven03941.service-now.com/api/now/table/cmdb_model/4ed329e3db27901026fca015ca9619fc",
"value": "4ed329e3db27901026fca015ca9619fc"
},
"model_number": "",
"monitor": "false",
"name": "Record For README",
"object_id": "",
"operational_status": "1",
"order_date": "",
"os": "",
"os_address_width": "",
"os_domain": "",
"os_service_pack": "",
"os_version": "",
"owned_by": "",
"po_number": "",
"purchase_date": "",
"ram": "",
"schedule": "",
"serial_number": "",
"short_description": "",
"skip_sync": "false",
"start_date": "",
"subcategory": "Computer",
"support_group": "",
"supported_by": "",
"sys_class_name": "cmdb_ci_linux_server",
"sys_class_path": "/!!/!2/!(/!!/!0",
"sys_created_by": "admin",
"sys_created_on": "2020-11-12 06:18:25",
"sys_domain": {
"display_value": "global",
"link": "https://ven03941.service-now.com/api/now/table/sys_user_group/global",
"value": "global"
},
"sys_domain_path": "/",
"sys_id": "a8decc3f1b9c2410042611b4bd4bcb7d",
"sys_mod_count": "0",
"sys_tags": "",
"sys_updated_by": "admin",
"sys_updated_on": "2020-11-12 06:18:25",
"unverified": "false",
"used_for": "Production",
"vendor": "",
"virtual": "false",
"warranty_expiration": ""
},
"Class": "cmdb_ci_linux_server",
"InboundRelations": [
{
"sys_id": "eb3f84331b5c2410042611b4bd4bcbf9",
"target": {
"display_value": "CMS App FLX",
"link": "https://ven03941.service-now.com/api/now/cmdb/instance/cmdb_ci/829e953a0ad3370200af63483498b1ea",
"value": "829e953a0ad3370200af63483498b1ea"
},
"type": {
"display_value": "Uses::Used by",
"link": "https://ven03941.service-now.com/api/now/table/cmdb_rel_type/cb5592603751200032ff8c00dfbe5d17",
"value": "cb5592603751200032ff8c00dfbe5d17"
}
}
],
"OutboundRelations": [],
"SysID": "a8decc3f1b9c2410042611b4bd4bcb7d"
}
}
}
Human Readable Output
Found the following attributes and relations for record a8decc3f1b9c2410042611b4bd4bcb7d
Attributes
Name SysID Record For README a8decc3f1b9c2410042611b4bd4bcb7d Inbound Relations
SysID Target Display Value Type Display Value eb3f84331b5c2410042611b4bd4bcbf9 CMS App FLX Uses::Used by
servicenow-cmdb-record-create
Create a record with associated relations and attributes.
Base Command
servicenow-cmdb-record-create
Input
| Argument Name | Description | Required |
|---|---|---|
| class | The name of the class to add the record to. | Required |
| source | The discovery source value. You can see all available values from sys_choice table with query GOTOelementLIKEdiscovery_source^name=cmdb_ci. (default: “ServiceNow”). | Optional |
| attributes | A comma-separated list of attributes that should be added to the created record. Input format: attribute=value pairs, e.g., “name=test, ram=1024”. | Required |
| inbound_relations | A comma-separated list of dictionaries. Each dictionary represents an inbound relation that should be added to the created record. | Optional |
| outbound_relations | A comma-separated list of dictionaries. Each dictionary represents an outbound relation that should be added to the created record. | Optional |
| fields | A comma-separated list of fields to return for the created record. | Optional |
| relation_limit | The maximum number of relations returned (default: 50). | Optional |
| relation_offset | The number of records to exclude from the relations query (default: 0). | Optional |
Context Output
| Path | Type | Description |
|---|---|---|
| ServiceNowCMDB.Record.SysID | String | The sys_id of the record that was created. |
| ServiceNowCMDB.Record.Class | String | The name of the class from which the record was created. |
| ServiceNowCMDB.Record.Attributes | Unknown | The attributes that were returned in the response for the created record. |
| ServiceNowCMDB.Record.OutboundRelations | Unknown | A list of all the outbound relations of the created record. |
| ServiceNowCMDB.Record.InboundRelations | Unknown | A list of all the inbound relations of the created record. |
Command Example
!servicenow-cmdb-record-create class=cmdb_ci_linux_server attributes="name=README Record"
Context Example
{
"ServiceNowCMDB": {
"Record": {
"Attributes": {
"asset": {
"display_value": "Unknown",
"link": "https://ven03941.service-now.com/api/now/table/alm_asset/964098b3db50641026fca015ca9619a8",
"value": "964098b3db50641026fca015ca9619a8"
},
"asset_tag": "",
"assigned": "",
"assigned_to": "",
"assignment_group": "",
"attributes": "",
"can_print": "false",
"category": "Hardware",
"cd_rom": "false",
"cd_speed": "",
"change_control": "",
"chassis_type": "",
"checked_in": "",
"checked_out": "",
"classification": "Production",
"comments": "",
"company": "",
"correlation_id": "",
"cost": "",
"cost_cc": "USD",
"cost_center": "",
"cpu_core_count": "",
"cpu_core_thread": "",
"cpu_count": "",
"cpu_manufacturer": "",
"cpu_name": "",
"cpu_speed": "",
"cpu_type": "",
"default_gateway": "",
"delivery_date": "",
"department": "",
"discovery_source": "ServiceNow",
"disk_space": "",
"dns_domain": "",
"dr_backup": "",
"due": "",
"due_in": "",
"duplicate_of": "",
"fault_count": "0",
"firewall_status": "Intranet",
"first_discovered": "2020-11-12 06:24:49",
"floppy": "",
"form_factor": "",
"fqdn": "",
"gl_account": "",
"hardware_status": "installed",
"hardware_substatus": "",
"host_name": "",
"install_date": "",
"install_status": "1",
"invoice_number": "",
"ip_address": "",
"justification": "",
"kernel_release": "",
"last_discovered": "2020-11-12 06:24:49",
"lease_id": "",
"location": "",
"mac_address": "",
"maintenance_schedule": "",
"managed_by": "",
"manufacturer": "",
"model_id": {
"display_value": "Unknown",
"link": "https://ven03941.service-now.com/api/now/table/cmdb_model/4ed329e3db27901026fca015ca9619fc",
"value": "4ed329e3db27901026fca015ca9619fc"
},
"model_number": "",
"monitor": "false",
"name": "README Record",
"object_id": "",
"operational_status": "1",
"order_date": "",
"os": "",
"os_address_width": "",
"os_domain": "",
"os_service_pack": "",
"os_version": "",
"owned_by": "",
"po_number": "",
"purchase_date": "",
"ram": "",
"schedule": "",
"serial_number": "",
"short_description": "",
"skip_sync": "false",
"start_date": "",
"subcategory": "Computer",
"support_group": "",
"supported_by": "",
"sys_class_name": "cmdb_ci_linux_server",
"sys_class_path": "/!!/!2/!(/!!/!0",
"sys_created_by": "admin",
"sys_created_on": "2020-11-12 06:24:49",
"sys_domain": {
"display_value": "global",
"link": "https://ven03941.service-now.com/api/now/table/sys_user_group/global",
"value": "global"
},
"sys_domain_path": "/",
"sys_id": "d64098b3db50641026fca015ca9619a7",
"sys_mod_count": "0",
"sys_tags": "",
"sys_updated_by": "admin",
"sys_updated_on": "2020-11-12 06:24:49",
"unverified": "false",
"used_for": "Production",
"vendor": "",
"virtual": "false",
"warranty_expiration": ""
},
"Class": "cmdb_ci_linux_server",
"InboundRelations": [],
"OutboundRelations": [],
"SysID": "d64098b3db50641026fca015ca9619a7"
}
}
}
Human Readable Output
Record d64098b3db50641026fca015ca9619a7 was created successfully
Attributes
Name SysID README Record d64098b3db50641026fca015ca9619a7
servicenow-cmdb-record-update
Update a record with the given attributes.
Base Command
servicenow-cmdb-record-update
Input
| Argument Name | Description | Required |
|---|---|---|
| class | The class name of the record that should be updated. | Required |
| sys_id | The ID of the record that should be updated. | Required |
| source | The discovery source value. You can see all available values from sys_choice table with query GOTOelementLIKEdiscovery_source^name=cmdb_ci. (default: “ServiceNow”). | Optional |
| attributes | A comma-separated list of the attributes that should be updated in the record. Input format: attribute=value pairs, e.g., “name=test,ram=1024”. | Required |
| fields | A comma-separated list of the fields to return for the updated record. | Optional |
| relation_limit | The maximum number of relations returned (default: 50). | Optional |
| relation_offset | The number of records to exclude from the relations query (default: 0). | Optional |
Context Output
| Path | Type | Description |
|---|---|---|
| ServiceNowCMDB.Record.SysID | String | The sys_id of the record that was updated. |
| ServiceNowCMDB.Record.Class | String | The class name of the updated record. |
| ServiceNowCMDB.Record.Attributes | Unknown | The attributes that were returned in the response for the updated record. |
| ServiceNowCMDB.Record.OutboundRelations | Unknown | A list of all the outbound relations of the updated record. |
| ServiceNowCMDB.Record.InboundRelations | Unknown | A list of all the inbound relations of the updated record. |
Command Example
!servicenow-cmdb-record-update class=cmdb_ci_linux_server sys_id=a8decc3f1b9c2410042611b4bd4bcb7d attributes="name=Update Name README"
Context Example
{
"ServiceNowCMDB": {
"Record": {
"Attributes": {
"asset": {
"display_value": "Unknown",
"link": "https://ven03941.service-now.com/api/now/table/alm_asset/60decc3f1b9c2410042611b4bd4bcb7f",
"value": "60decc3f1b9c2410042611b4bd4bcb7f"
},
"asset_tag": "",
"assigned": "",
"assigned_to": "",
"assignment_group": "",
"attributes": "",
"can_print": "false",
"category": "Hardware",
"cd_rom": "false",
"cd_speed": "",
"change_control": "",
"chassis_type": "",
"checked_in": "",
"checked_out": "",
"classification": "Production",
"comments": "",
"company": "",
"correlation_id": "",
"cost": "",
"cost_cc": "USD",
"cost_center": "",
"cpu_core_count": "",
"cpu_core_thread": "",
"cpu_count": "",
"cpu_manufacturer": "",
"cpu_name": "",
"cpu_speed": "",
"cpu_type": "",
"default_gateway": "",
"delivery_date": "",
"department": "",
"discovery_source": "ServiceNow",
"disk_space": "",
"dns_domain": "",
"dr_backup": "",
"due": "",
"due_in": "",
"duplicate_of": "",
"fault_count": "0",
"firewall_status": "Intranet",
"first_discovered": "2020-11-12 06:18:25",
"floppy": "",
"form_factor": "",
"fqdn": "",
"gl_account": "",
"hardware_status": "installed",
"hardware_substatus": "",
"host_name": "",
"install_date": "",
"install_status": "1",
"invoice_number": "",
"ip_address": "",
"justification": "",
"kernel_release": "",
"last_discovered": "2020-11-12 06:24:53",
"lease_id": "",
"location": "",
"mac_address": "",
"maintenance_schedule": "",
"managed_by": "",
"manufacturer": "",
"model_id": {
"display_value": "Unknown",
"link": "https://ven03941.service-now.com/api/now/table/cmdb_model/4ed329e3db27901026fca015ca9619fc",
"value": "4ed329e3db27901026fca015ca9619fc"
},
"model_number": "",
"monitor": "false",
"name": "Update Name README",
"object_id": "",
"operational_status": "1",
"order_date": "",
"os": "",
"os_address_width": "",
"os_domain": "",
"os_service_pack": "",
"os_version": "",
"owned_by": "",
"po_number": "",
"purchase_date": "",
"ram": "",
"schedule": "",
"serial_number": "",
"short_description": "",
"skip_sync": "false",
"start_date": "",
"subcategory": "Computer",
"support_group": "",
"supported_by": "",
"sys_class_name": "cmdb_ci_linux_server",
"sys_class_path": "/!!/!2/!(/!!/!0",
"sys_created_by": "admin",
"sys_created_on": "2020-11-12 06:18:25",
"sys_domain": {
"display_value": "global",
"link": "https://ven03941.service-now.com/api/now/table/sys_user_group/global",
"value": "global"
},
"sys_domain_path": "/",
"sys_id": "a8decc3f1b9c2410042611b4bd4bcb7d",
"sys_mod_count": "1",
"sys_tags": "",
"sys_updated_by": "admin",
"sys_updated_on": "2020-11-12 06:24:53",
"unverified": "false",
"used_for": "Production",
"vendor": "",
"virtual": "false",
"warranty_expiration": ""
},
"Class": "cmdb_ci_linux_server",
"InboundRelations": [
{
"sys_id": "eb3f84331b5c2410042611b4bd4bcbf9",
"target": {
"display_value": "CMS App FLX",
"link": "https://ven03941.service-now.com/api/now/cmdb/instance/cmdb_ci/829e953a0ad3370200af63483498b1ea",
"value": "829e953a0ad3370200af63483498b1ea"
},
"type": {
"display_value": "Uses::Used by",
"link": "https://ven03941.service-now.com/api/now/table/cmdb_rel_type/cb5592603751200032ff8c00dfbe5d17",
"value": "cb5592603751200032ff8c00dfbe5d17"
}
}
],
"OutboundRelations": [],
"SysID": "a8decc3f1b9c2410042611b4bd4bcb7d"
}
}
}
Human Readable Output
Updated record a8decc3f1b9c2410042611b4bd4bcb7d successfully
Attributes
Name SysID Update Name README a8decc3f1b9c2410042611b4bd4bcb7d Inbound Relations
SysID Target Display Value Type Display Value eb3f84331b5c2410042611b4bd4bcbf9 CMS App FLX Uses::Used by
servicenow-cmdb-record-add-relations
Add a new relation to an existing record.
Base Command
servicenow-cmdb-record-add-relations
Input
| Argument Name | Description | Required |
|---|---|---|
| class | The class name of the record. | Required |
| sys_id | The ID of the record to which the relations should be added. | Required |
| source | The discovery source value. You can see all available values from sys_choice table with query GOTOelementLIKEdiscovery_source^name=cmdb_ci. (default: “ServiceNow”). | Optional |
| inbound_relations | A comma-separated list of dictionaries. Each dictionary represents an inbound relation that should be added to the created record. | Optional |
| outbound_relations | A comma-separated list of dictionaries. Each dictionary represents an outbound relation that should be added to the created record. | Optional |
| fields | A comma-separated list of the fields to return for the record. | Optional |
| relation_limit | The maximum number of relations returned (default: 50). | Optional |
| relation_offset | The number of records to exclude from the relations query (default: 0). | Optional |
Context Output
| Path | Type | Description |
|---|---|---|
| ServiceNowCMDB.Record.SysID | String | The sys_id of the record that was updated. |
| ServiceNowCMDB.Record.Class | String | The class name of the record. |
| ServiceNowCMDB.Record.Attributes | Unknown | The attributes that were returned in the response for the updated record. |
| ServiceNowCMDB.Record.OutboundRelations | Unknown | A list of all the outbound relations of the record. |
| ServiceNowCMDB.Record.InboundRelations | Unknown | A list of all the inbound relations of the record. |
Command Example
!servicenow-cmdb-record-add-relations class=cmdb_ci_linux_server sys_id=a8decc3f1b9c2410042611b4bd4bcb7d inbound_relations="[{'type': 'cb5592603751200032ff8c00dfbe5d17','target':'829e953a0ad3370200af63483498b1ea','sys_class_name':'cmdb_ci_appl'}]"
Context Example
{
"ServiceNowCMDB": {
"Record": {
"Attributes": {
"asset": {
"display_value": "Unknown",
"link": "https://ven03941.service-now.com/api/now/table/alm_asset/60decc3f1b9c2410042611b4bd4bcb7f",
"value": "60decc3f1b9c2410042611b4bd4bcb7f"
},
"asset_tag": "",
"assigned": "",
"assigned_to": "",
"assignment_group": "",
"attributes": "",
"can_print": "false",
"category": "Hardware",
"cd_rom": "false",
"cd_speed": "",
"change_control": "",
"chassis_type": "",
"checked_in": "",
"checked_out": "",
"classification": "Production",
"comments": "",
"company": "",
"correlation_id": "",
"cost": "",
"cost_cc": "USD",
"cost_center": "",
"cpu_core_count": "",
"cpu_core_thread": "",
"cpu_count": "",
"cpu_manufacturer": "",
"cpu_name": "",
"cpu_speed": "",
"cpu_type": "",
"default_gateway": "",
"delivery_date": "",
"department": "",
"discovery_source": "ServiceNow",
"disk_space": "",
"dns_domain": "",
"dr_backup": "",
"due": "",
"due_in": "",
"duplicate_of": "",
"fault_count": "0",
"firewall_status": "Intranet",
"first_discovered": "2020-11-12 06:18:25",
"floppy": "",
"form_factor": "",
"fqdn": "",
"gl_account": "",
"hardware_status": "installed",
"hardware_substatus": "",
"host_name": "",
"install_date": "",
"install_status": "1",
"invoice_number": "",
"ip_address": "",
"justification": "",
"kernel_release": "",
"last_discovered": "2020-11-12 06:24:53",
"lease_id": "",
"location": "",
"mac_address": "",
"maintenance_schedule": "",
"managed_by": "",
"manufacturer": "",
"model_id": {
"display_value": "Unknown",
"link": "https://ven03941.service-now.com/api/now/table/cmdb_model/4ed329e3db27901026fca015ca9619fc",
"value": "4ed329e3db27901026fca015ca9619fc"
},
"model_number": "",
"monitor": "false",
"name": "Update Name README",
"object_id": "",
"operational_status": "1",
"order_date": "",
"os": "",
"os_address_width": "",
"os_domain": "",
"os_service_pack": "",
"os_version": "",
"owned_by": "",
"po_number": "",
"purchase_date": "",
"ram": "",
"schedule": "",
"serial_number": "",
"short_description": "",
"skip_sync": "false",
"start_date": "",
"subcategory": "Computer",
"support_group": "",
"supported_by": "",
"sys_class_name": "cmdb_ci_linux_server",
"sys_class_path": "/!!/!2/!(/!!/!0",
"sys_created_by": "admin",
"sys_created_on": "2020-11-12 06:18:25",
"sys_domain": {
"display_value": "global",
"link": "https://ven03941.service-now.com/api/now/table/sys_user_group/global",
"value": "global"
},
"sys_domain_path": "/",
"sys_id": "a8decc3f1b9c2410042611b4bd4bcb7d",
"sys_mod_count": "1",
"sys_tags": "",
"sys_updated_by": "admin",
"sys_updated_on": "2020-11-12 06:24:53",
"unverified": "false",
"used_for": "Production",
"vendor": "",
"virtual": "false",
"warranty_expiration": ""
},
"Class": "cmdb_ci_linux_server",
"InboundRelations": [
{
"sys_id": "b34050bbdb10641026fca015ca961985",
"target": {
"display_value": "CMS App FLX",
"link": "https://ven03941.service-now.com/api/now/cmdb/instance/cmdb_ci/829e953a0ad3370200af63483498b1ea",
"value": "829e953a0ad3370200af63483498b1ea"
},
"type": {
"display_value": "Uses::Used by",
"link": "https://ven03941.service-now.com/api/now/table/cmdb_rel_type/cb5592603751200032ff8c00dfbe5d17",
"value": "cb5592603751200032ff8c00dfbe5d17"
}
},
{
"sys_id": "eb3f84331b5c2410042611b4bd4bcbf9",
"target": {
"display_value": "CMS App FLX",
"link": "https://ven03941.service-now.com/api/now/cmdb/instance/cmdb_ci/829e953a0ad3370200af63483498b1ea",
"value": "829e953a0ad3370200af63483498b1ea"
},
"type": {
"display_value": "Uses::Used by",
"link": "https://ven03941.service-now.com/api/now/table/cmdb_rel_type/cb5592603751200032ff8c00dfbe5d17",
"value": "cb5592603751200032ff8c00dfbe5d17"
}
}
],
"OutboundRelations": [],
"SysID": "a8decc3f1b9c2410042611b4bd4bcb7d"
}
}
}
Human Readable Output
New relations were added to a8decc3f1b9c2410042611b4bd4bcb7d record successfully
Attributes
Name SysID Update Name README a8decc3f1b9c2410042611b4bd4bcb7d Inbound Relations
SysID Target Display Value Type Display Value b34050bbdb10641026fca015ca961985,
eb3f84331b5c2410042611b4bd4bcbf9CMS App FLX,
CMS App FLXUses::Used by,
Uses::Used by
servicenow-cmdb-record-delete-relations
Delete a relation of an existing record.
Base Command
servicenow-cmdb-record-delete-relations
Input
| Argument Name | Description | Required |
|---|---|---|
| class | The class name of the record. | Required |
| sys_id | The ID of the record from which a relation should be deleted. | Required |
| relation_sys_id | The ID of the relation that should be deleted. | Required |
| fields | A comma-separated list of the fields to return for the record. | Optional |
| relation_limit | The maximum number of relations returned (default: 50). | Optional |
| relation_offset | The number of records to exclude from the relations query (default: 0). | Optional |
Context Output
| Path | Type | Description |
|---|---|---|
| ServiceNowCMDB.Record.SysID | String | The sys_id of the record that was updated. |
| ServiceNowCMDB.Record.Class | String | The class name of the record. |
| ServiceNowCMDB.Record.Attributes | Unknown | The attributes that were returned in the response for the updated record. |
| ServiceNowCMDB.Record.OutboundRelations | Unknown | A list of all the outbound relations of the record. |
| ServiceNowCMDB.Record.InboundRelations | Unknown | A list of all the inbound relations of the record. |
Command Example
!servicenow-cmdb-record-delete-relations class=cmdb_ci_linux_server relation_sys_id=b376af86dbbf981026fca015ca961981 sys_id=2a41eb4e1b739810042611b4bd4bcb9d
Context Example
{
"ServiceNowCMDB": {
"Record": {
"Attributes": {
"asset": {
"display_value": "Unknown",
"link": "https://ven03941.service-now.com/api/now/table/alm_asset/964098b3db50641026fca015ca9619a8",
"value": "964098b3db50641026fca015ca9619a8"
},
"asset_tag": "",
"assigned": "",
"assigned_to": "",
"assignment_group": "",
"attributes": "",
"can_print": "false",
"category": "Hardware",
"cd_rom": "false",
"cd_speed": "",
"change_control": "",
"chassis_type": "",
"checked_in": "",
"checked_out": "",
"classification": "Production",
"comments": "",
"company": "",
"correlation_id": "",
"cost": "",
"cost_cc": "USD",
"cost_center": "",
"cpu_core_count": "",
"cpu_core_thread": "",
"cpu_count": "",
"cpu_manufacturer": "",
"cpu_name": "",
"cpu_speed": "",
"cpu_type": "",
"default_gateway": "",
"delivery_date": "",
"department": "",
"discovery_source": "ServiceNow",
"disk_space": "",
"dns_domain": "",
"dr_backup": "",
"due": "",
"due_in": "",
"duplicate_of": "",
"fault_count": "0",
"firewall_status": "Intranet",
"first_discovered": "2020-11-12 06:24:49",
"floppy": "",
"form_factor": "",
"fqdn": "",
"gl_account": "",
"hardware_status": "installed",
"hardware_substatus": "",
"host_name": "",
"install_date": "",
"install_status": "1",
"invoice_number": "",
"ip_address": "",
"justification": "",
"kernel_release": "",
"last_discovered": "2020-11-12 06:24:49",
"lease_id": "",
"location": "",
"mac_address": "",
"maintenance_schedule": "",
"managed_by": "",
"manufacturer": "",
"model_id": {
"display_value": "Unknown",
"link": "https://ven03941.service-now.com/api/now/table/cmdb_model/4ed329e3db27901026fca015ca9619fc",
"value": "4ed329e3db27901026fca015ca9619fc"
},
"model_number": "",
"monitor": "false",
"name": "README Record",
"object_id": "",
"operational_status": "1",
"order_date": "",
"os": "",
"os_address_width": "",
"os_domain": "",
"os_service_pack": "",
"os_version": "",
"owned_by": "",
"po_number": "",
"purchase_date": "",
"ram": "",
"schedule": "",
"serial_number": "",
"short_description": "",
"skip_sync": "false",
"start_date": "",
"subcategory": "Computer",
"support_group": "",
"supported_by": "",
"sys_class_name": "cmdb_ci_linux_server",
"sys_class_path": "/!!/!2/!(/!!/!0",
"sys_created_by": "admin",
"sys_created_on": "2020-11-12 06:24:49",
"sys_domain": {
"display_value": "global",
"link": "https://ven03941.service-now.com/api/now/table/sys_user_group/global",
"value": "global"
},
"sys_domain_path": "/",
"sys_id": "d64098b3db50641026fca015ca9619a7",
"sys_mod_count": "0",
"sys_tags": "",
"sys_updated_by": "admin",
"sys_updated_on": "2020-11-12 06:24:49",
"unverified": "false",
"used_for": "Production",
"vendor": "",
"virtual": "false",
"warranty_expiration": ""
},
"Class": "cmdb_ci_linux_server",
"InboundRelations": [],
"OutboundRelations": [],
"SysID": "2a41eb4e1b739810042611b4bd4bcb9d"
}
}
}
Human Readable Output
Deleted relation b376af86dbbf981026fca015ca961981 successfully from 2a41eb4e1b739810042611b4bd4bcb9d record
Attributes
Name SysID Update Name README 2a41eb4e1b739810042611b4bd4bcb9d
servicenow-cmdb-oauth-login
This function should be used once before running any command when using OAuth authorization.
Base Command
servicenow-cmdb-oauth-login
Input
| Argument Name | Description | Required |
|---|---|---|
| username | The username that should be used for login. | Required |
| password | The password that should be used for login. | Required |
Context Output
There is no context output for this command.
Command Example
!servicenow-cmdb-oauth-login username=username password=password
Human Readable Output
###Logged in successfully.
A refresh token was saved to the integration context. This token will be used to generate a new access token once the current one expires.
servicenow-cmdb-oauth-test
Test the instance configuration when using OAuth authorization.
Base Command
servicenow-cmdb-oauth-test
Input
There are no input arguments for this command.
Context Output
There is no context output for this command.
Command Example
!servicenow-cmdb-oauth-test
Human Readable Output
###Instance Configured Successfully.
Configuration parameters
url— ServiceNow URL, in the format https://company.service-now.com/ (required)use_oauth— Use OAuth Loginuse_jwt— Use JWT Authenticationcredentials— Client ID/JWT Audience (aud)basic_credentials— Usernameprivate_key—kid— Kid (Key Id)sub— Subiss— Iss (Issuer)insecure— Trust any certificate (not secure)proxy— Use system proxy settings
Commands (8)
-
servicenow-cmdb-oauth-loginThis function should be used once before running any command when using OAuth authorization.
-
servicenow-cmdb-oauth-testTest the instance configuration when using OAuth authorization.
-
servicenow-cmdb-record-add-relationsAdd a new relation to an existing record.
-
servicenow-cmdb-record-createCreate a record with associated relations and attributes.
-
servicenow-cmdb-record-delete-relationsDelete a relation of an existing record.
-
servicenow-cmdb-record-get-by-idQuery attributes and relationship information for a specific record.
-
servicenow-cmdb-record-updateUpdate a record with the given attributes.
-
servicenow-cmdb-records-listQuery records for a CMDB class.
import pytest from ServiceNow_CMDB import ( Client, add_relation_command, create_record_command, delete_relation_command, get_record_command, main, records_list_command, update_record_command, ) from ServiceNowApiModule import ServiceNowClient from test_data.response_constants import ( ADD_RELATION_RESPONSE, CREATE_RECORD_RESPONSE, DELETE_RELATION_RESPONSE, GET_RECORD_RESPONSE, RECORDS_LIST_EMPTY_RESPONSE, RECORDS_LIST_RESPONSE_WITH_RECORDS, UPDATE_RECORD_RESPONSE, ) from test_data.result_constants import ( EXPECTED_ADD_RELATION, EXPECTED_CREATE_RECORD, EXPECTED_DELETE_RELATION, EXPECTED_GET_RECORD, EXPECTED_RECORDS_LIST_NO_RECORDS, EXPECTED_RECORDS_LIST_WITH_RECORDS, EXPECTED_UPDATE_RECORD, ) @pytest.mark.parametrize( "response, expected_result", [ (RECORDS_LIST_RESPONSE_WITH_RECORDS, EXPECTED_RECORDS_LIST_WITH_RECORDS), (RECORDS_LIST_EMPTY_RESPONSE, EXPECTED_RECORDS_LIST_NO_RECORDS), ], ) def test_records_list_command(response, expected_result, mocker): """ Given: - The records list command. When: - Mocking the response from the http request once to a response containing records, and once to a response with no records. Then: - Validate that in the first case when the response contains records, the context has both `Class` and `Records` keys. In the second case, when no records are in the response, validate the context has only the `Class` key. """ client = Client() mocker.patch.object(ServiceNowClient, "http_request", return_value=response) result = records_list_command(client, args={"class": "test_class"}) assert expected_result == result[1] def test_get_record_command(mocker): """ Given: - The get record by id command. When: - Mocking the response from the http request to a response containing several attributes, inbound and outbound relations of the record. Then: - Validate that the output context of the command contains all attributes and relations that were returned. """ client = Client() mocker.patch.object(ServiceNowClient, "http_request", return_value=GET_RECORD_RESPONSE) result = get_record_command(client, args={"class": "test_class", "sys_id": "record_id"}) assert result[1] == EXPECTED_GET_RECORD def test_create_record_command(mocker): """ Given: - The create record command. When: - Mocking the response from the http request to a response containing the attributes of the new record with no inbound or outbound relations. Then: - Validate that the context output contains the `Class`, `SysId` and `Attributes` keys according to the mocked response, and that the inbound and outbound relations lists are empty. """ client = Client() mocker.patch.object(ServiceNowClient, "http_request", return_value=CREATE_RECORD_RESPONSE) result = create_record_command(client, args={"class": "test_class", "attributes": "name=Test Create Record"}) assert result[1] == EXPECTED_CREATE_RECORD def test_update_record_command(mocker): """ Given: - The update record command. When: - Mocking the response from the http request to a response containing the attributes of the updated record. Then: - Validate that the context output was changed according to the new attributes. """ client = Client() mocker.patch.object(ServiceNowClient, "http_request", return_value=UPDATE_RECORD_RESPONSE) result = update_record_command( client, args={"class": "test_class", "sys_id": "record_id", "attributes": "name=Test Create Record"} ) assert result[1] == EXPECTED_UPDATE_RECORD def test_add_relation_command(mocker): """ Given: - The add relation command. When: - Mocking the response from the http request to a response containing the attributes and the relations of the record. Then: - Validate that the `InboundRelations` key in the context output contains the added relation. """ client = Client() mocker.patch.object(ServiceNowClient, "http_request", return_value=ADD_RELATION_RESPONSE) result = add_relation_command( client, args={ "class": "test_class", "sys_id": "record_id", "inbound_relations": "[{'type': 'relation_type', 'target':'target', 'sys_class_name':'class_name'}]", }, ) assert result[1] == EXPECTED_ADD_RELATION def test_delete_relation_command(mocker): """ Given: - The delete relation command. When: - Mocking the response from the http request to a response containing the attributes and the relations of the record. Then: - Validate that the `InboundRelations` key in the context output is empty. """ client = Client() mocker.patch.object(ServiceNowClient, "http_request", return_value=DELETE_RELATION_RESPONSE) result = delete_relation_command(client, args={"class": "test_class", "sys_id": "record_id", "relation_sys_id": "rel_id"}) assert result[1] == EXPECTED_DELETE_RELATION def test_client_jwt_param_usage(mocker): """ Given: - JWT params provided to the ServiceNow CMDB Client When: - Initializing the Client with jwt_params Then: - ServiceNowClient is instantiated with the same jwt_params - The jwt attribute is set on the inner ServiceNowClient """ jwt_params = { "private_key": "-----BEGIN PRIVATE KEY-----test-----END PRIVATE KEY-----", "kid": "test_kid", "sub": "test_sub", "aud": "test_aud", "iss": "test_iss", } mocker.patch("ServiceNowApiModule.jwt.encode", return_value="jwt_token_stub") client = Client( username="user", password="pw", use_oauth=True, client_id="client_id", client_secret="client_secret", url="https://example.com", verify=True, proxy=False, jwt_params=jwt_params, ) assert hasattr(client.snow_client, "jwt") assert client.snow_client.jwt == "jwt_token_stub" def test_client_empty_jwt_param_usage(mocker): """ Given: - no JWT params provided to the ServiceNow CMDB Client When: - Initializing the Client Then: - ServiceNowClient is instantiated with the same jwt_params - The jwt attribute is set to None on the inner ServiceNowClient """ jwt_params = {} client = Client( username="user", password="pw", use_oauth=True, client_id="client_id", client_secret="client_secret", url="https://example.com", verify=True, proxy=False, jwt_params=jwt_params, ) assert hasattr(client.snow_client, "jwt") assert client.snow_client.jwt is None class TestCredentialFlowEndToEnd: """End-to-end tests for the new basic_credentials / credentials flow in main().""" BASE_PARAMS = { "url": "https://test.service-now.com", "insecure": False, "proxy": False, "use_oauth": False, "use_jwt": False, } def test_basic_auth_with_basic_credentials(self, mocker): """ Given: - basic_credentials param provides username and password. - OAuth is not enabled. When: - main() is called with the 'test-module' command. Then: - The Client is created with the username/password from basic_credentials. - test-module succeeds. """ params = { **self.BASE_PARAMS, "basic_credentials": {"identifier": "basic_user", "password": "basic_pass"}, "credentials": {"identifier": "oauth_id", "password": "oauth_secret"}, } mocker.patch("ServiceNow_CMDB.demisto.params", return_value=params) mocker.patch("ServiceNow_CMDB.demisto.command", return_value="test-module") return_results_mock = mocker.patch("ServiceNow_CMDB.return_results") mocker.patch.object(ServiceNowClient, "http_request", return_value={"result": []}) client_init_spy = mocker.patch("ServiceNow_CMDB.Client", wraps=Client) main() # Verify Client was called with basic_credentials values call_kwargs = client_init_spy.call_args[1] assert call_kwargs["username"] == "basic_user" assert call_kwargs["password"] == "basic_pass" assert call_kwargs["use_oauth"] is False return_results_mock.assert_called_once_with("ok") def test_basic_auth_legacy_fallback(self, mocker): """ Given: - basic_credentials param is empty (no username/password). - credentials param has identifier and password. - OAuth is not enabled. When: - main() is called with the 'test-module' command. Then: - The Client falls back to using credentials for username/password (legacy behavior). - test-module succeeds. """ params = { **self.BASE_PARAMS, "basic_credentials": {}, "credentials": {"identifier": "legacy_user", "password": "legacy_pass"}, } mocker.patch("ServiceNow_CMDB.demisto.params", return_value=params) mocker.patch("ServiceNow_CMDB.demisto.command", return_value="test-module") mocker.patch("ServiceNow_CMDB.demisto.debug") return_results_mock = mocker.patch("ServiceNow_CMDB.return_results") mocker.patch.object(ServiceNowClient, "http_request", return_value={"result": []}) client_init_spy = mocker.patch("ServiceNow_CMDB.Client", wraps=Client) main() # Verify Client was called with legacy fallback values from credentials call_kwargs = client_init_spy.call_args[1] assert call_kwargs["username"] == "legacy_user" assert call_kwargs["password"] == "legacy_pass" assert call_kwargs["use_oauth"] is False return_results_mock.assert_called_once_with("ok") def test_oauth_uses_credentials_for_client_id_secret(self, mocker): """ Given: - use_oauth is True. - credentials provides client_id (identifier) and client_secret (password). - basic_credentials provides username and password. When: - main() is called with the 'test-module' command. Then: - The Client is created with client_id/client_secret from credentials. - use_oauth is True. """ params = { **self.BASE_PARAMS, "use_oauth": True, "basic_credentials": {"identifier": "basic_user", "password": "basic_pass"}, "credentials": {"identifier": "my_client_id", "password": "my_client_secret"}, } mocker.patch("ServiceNow_CMDB.demisto.params", return_value=params) mocker.patch("ServiceNow_CMDB.demisto.command", return_value="test-module") # return_error must stop execution (like the real one does via sys.exit), # otherwise test_module continues to records_list which triggers auto-login HTTP calls. mocker.patch("ServiceNow_CMDB.return_error", side_effect=SystemExit("return_error called")) client_init_spy = mocker.patch("ServiceNow_CMDB.Client", wraps=Client) with pytest.raises(SystemExit): main() # Verify Client was called with OAuth params call_kwargs = client_init_spy.call_args[1] assert call_kwargs["client_id"] == "my_client_id" assert call_kwargs["client_secret"] == "my_client_secret" assert call_kwargs["use_oauth"] is True assert call_kwargs["username"] == "basic_user" assert call_kwargs["password"] == "basic_pass" def test_jwt_auth_flow(self, mocker): """ Given: - use_jwt is True, use_oauth is False. - credentials provides client_id and client_secret. - JWT params (private_key, kid, sub) are provided. When: - main() is called with the 'test-module' command. Then: - use_oauth is set to True (JWT implies OAuth). - jwt_params are passed to the Client. - The Client is created with the correct JWT configuration. """ params = { **self.BASE_PARAMS, "use_jwt": True, "basic_credentials": {"identifier": "basic_user", "password": "basic_pass"}, "credentials": {"identifier": "jwt_client_id", "password": "jwt_client_secret"}, "private_key": {"password": "-----BEGIN PRIVATE KEY-----test-----END PRIVATE KEY-----"}, "kid": "test_kid", "sub": "test_sub", } mocker.patch("ServiceNow_CMDB.demisto.params", return_value=params) mocker.patch("ServiceNow_CMDB.demisto.command", return_value="test-module") mocker.patch("ServiceNow_CMDB.return_results") mocker.patch("ServiceNowApiModule.jwt.encode", return_value="jwt_token_stub") mocker.patch.object(ServiceNowClient, "http_request", return_value={"result": []}) client_init_spy = mocker.patch("ServiceNow_CMDB.Client", wraps=Client) main() call_kwargs = client_init_spy.call_args[1] assert call_kwargs["use_oauth"] is True assert call_kwargs["client_id"] == "jwt_client_id" assert call_kwargs["client_secret"] == "jwt_client_secret" jwt_params = call_kwargs["jwt_params"] assert jwt_params["private_key"] == "-----BEGIN PRIVATE KEY-----test-----END PRIVATE KEY-----" assert jwt_params["kid"] == "test_kid" assert jwt_params["sub"] == "test_sub" assert jwt_params["aud"] == "jwt_client_id" def test_jwt_and_oauth_both_enabled_raises_error(self, mocker): """ Given: - Both use_jwt and use_oauth are True. When: - main() is called. Then: - A ValueError is raised indicating only one auth method should be chosen. """ params = { **self.BASE_PARAMS, "use_jwt": True, "use_oauth": True, "basic_credentials": {}, "credentials": {"identifier": "id", "password": "secret"}, } mocker.patch("ServiceNow_CMDB.demisto.params", return_value=params) mocker.patch("ServiceNow_CMDB.demisto.command", return_value="test-module") return_error_mock = mocker.patch("ServiceNow_CMDB.return_error") main() # The first call to return_error is for the auth method error; # a second call may occur because 'client' is not defined after the ValueError assert return_error_mock.call_count >= 1 assert "authentication method" in return_error_mock.call_args_list[0][0][0] def test_basic_auth_partial_credentials_triggers_fallback(self, mocker): """ Given: - basic_credentials has username but no password. - credentials has identifier and password. - OAuth is not enabled. When: - main() is called with the 'test-module' command. Then: - The Client falls back to credentials for both username and password. """ params = { **self.BASE_PARAMS, "basic_credentials": {"identifier": "partial_user", "password": ""}, "credentials": {"identifier": "fallback_user", "password": "fallback_pass"}, } mocker.patch("ServiceNow_CMDB.demisto.params", return_value=params) mocker.patch("ServiceNow_CMDB.demisto.command", return_value="test-module") mocker.patch("ServiceNow_CMDB.demisto.debug") mocker.patch("ServiceNow_CMDB.return_results") mocker.patch.object(ServiceNowClient, "http_request", return_value={"result": []}) client_init_spy = mocker.patch("ServiceNow_CMDB.Client", wraps=Client) main() call_kwargs = client_init_spy.call_args[1] assert call_kwargs["username"] == "fallback_user" assert call_kwargs["password"] == "fallback_pass" def test_no_credentials_at_all(self, mocker): """ Given: - Both basic_credentials and credentials are empty. - OAuth is not enabled. When: - main() is called with the 'test-module' command. Then: - The Client is created with empty string username/password (from empty credentials fallback). """ params = { **self.BASE_PARAMS, "basic_credentials": {}, "credentials": {}, } mocker.patch("ServiceNow_CMDB.demisto.params", return_value=params) mocker.patch("ServiceNow_CMDB.demisto.command", return_value="test-module") mocker.patch("ServiceNow_CMDB.demisto.debug") mocker.patch("ServiceNow_CMDB.return_results") mocker.patch.object(ServiceNowClient, "http_request", return_value={"result": []}) client_init_spy = mocker.patch("ServiceNow_CMDB.Client", wraps=Client) main() call_kwargs = client_init_spy.call_args[1] # Falls back to credentials which are also empty, .get() returns "" by default assert call_kwargs["username"] == "" assert call_kwargs["password"] == "" def test_oauth_login_command_with_new_credentials(self, mocker): """ Given: - use_oauth is True. - credentials provides client_id and client_secret. - basic_credentials provides username and password. When: - main() is called with the 'servicenow-cmdb-oauth-login' command. Then: - The login command is executed with the correct client configuration. """ params = { **self.BASE_PARAMS, "use_oauth": True, "basic_credentials": {"identifier": "basic_user", "password": "basic_pass"}, "credentials": {"identifier": "my_client_id", "password": "my_client_secret"}, } mocker.patch("ServiceNow_CMDB.demisto.params", return_value=params) mocker.patch("ServiceNow_CMDB.demisto.command", return_value="servicenow-cmdb-oauth-login") mocker.patch("ServiceNow_CMDB.demisto.args", return_value={"username": "login_user", "password": "login_pass"}) mocker.patch.object(ServiceNowClient, "login") return_outputs_mock = mocker.patch("ServiceNow_CMDB.return_outputs") client_init_spy = mocker.patch("ServiceNow_CMDB.Client", wraps=Client) main() call_kwargs = client_init_spy.call_args[1] assert call_kwargs["client_id"] == "my_client_id" assert call_kwargs["client_secret"] == "my_client_secret" assert call_kwargs["use_oauth"] is True return_outputs_mock.assert_called_once()