Skip to content

Commit fab9b42

Browse files
content-botroshani-delinea-githubroshanitambadkarJasBeilin
authored
Changes related to Cached credentials functionality (demisto#23379)
* Changes related to Cached credentials functionality (demisto#23166) * Changes related to Cached credentials functionality * Updated docker version * resolved validations errors * Resolve validation error * Fixed linter errors * Resolved linter errors * Resolved Linter error * updated files to resolve linter errors * updated version * Added Release notes * Updated Release notes * Resolved comments * Resolved validation errors * Resolved linter errors * Resolved comments on PR * Updated code. * Added Linter changes * Updated code * Updated validation changes * Updated docker image tag * Deleted 'Example-delinea-fetch-credentials.yml' playbook * Added test cases * Fixed RN and lint * Resolved linter error * Removed linter errors * Update DelineaSS.yml * Remove log * fixing RN * revert change * Update pack_metadata.json * Update DelineaSS.yml * Update 2_0_0.md Co-authored-by: vidhi dhand <[email protected]> Co-authored-by: Jas Beilin <[email protected]> Co-authored-by: Jasmine Beilin <[email protected]> * Update 2_0_0.md Co-authored-by: roshani-delinea-github <[email protected]> Co-authored-by: vidhi dhand <[email protected]> Co-authored-by: Jas Beilin <[email protected]> Co-authored-by: Jasmine Beilin <[email protected]>
1 parent 8dc6133 commit fab9b42

File tree

9 files changed

+323
-62
lines changed

9 files changed

+323
-62
lines changed

Packs/DelineaSS/Integrations/DelineaSS/DelineaSS.py

Lines changed: 67 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
1+
import urllib3
12
import demistomock as demisto
23
from CommonServerPython import *
34
from CommonServerUserPython import *
45
from typing import Dict
56

67
# Disable insecure warnings
7-
requests.packages.urllib3.disable_warnings()
8+
urllib3.disable_warnings()
89

910
''' CONSTANTS '''
1011
DATE_FORMAT = '%Y-%m-%dT%H:%M:%SZ'
@@ -99,49 +100,50 @@ def secretChangePassword(self, secret_id: str, newPassword: str) -> str:
99100
"newPassword": newPassword
100101
}
101102

102-
return self._http_request("POST", url_suffix="/api/v1/secrets/" + str(secret_id) + "/change-password", json_data=body)
103+
return self._http_request("POST", url_suffix="/api/v1/secrets/" + str(secret_id) + "/change-password",
104+
json_data=body)
103105

104106
def secretCreate(self, name: str, secret_template_id: str, **kwargs) -> str:
105-
secretJSON = {'name': name, 'secretTemplateId': secret_template_id, 'items': []} # type: Dict[str, Any]
107+
secretjson = {'name': name, 'secretTemplateId': secret_template_id, 'items': []} # type: Dict[str, Any]
106108

107109
for key, value in kwargs.items():
108110
JSON = {}
109111
if key == 'domain_item':
110112
JSON['fieldName'] = 'Domain'
111113
JSON['itemValue'] = value
112114
JSON['slug'] = 'domain'
113-
secretJSON['items'].append(JSON)
115+
secretjson['items'].append(JSON)
114116

115117
elif key == 'machine_item':
116118
JSON['fieldName'] = 'Machine'
117119
JSON['itemValue'] = value
118120
JSON['slug'] = 'machine'
119-
secretJSON['items'].append(JSON)
121+
secretjson['items'].append(JSON)
120122

121123
elif key == 'username_item':
122124
JSON['fieldName'] = 'Username'
123125
JSON['itemValue'] = value
124126
JSON['slug'] = 'username'
125-
secretJSON['items'].append(JSON)
127+
secretjson['items'].append(JSON)
126128

127129
elif key == 'password_item':
128130
JSON['fieldName'] = 'Password'
129131
JSON['itemValue'] = value
130132
JSON['slug'] = 'password'
131133
JSON['isPassword'] = "true"
132-
secretJSON['items'].append(JSON)
134+
secretjson['items'].append(JSON)
133135

134136
elif key == 'notes_item':
135137
JSON['fieldName'] = 'Notes'
136138
JSON['itemValue'] = value
137139
JSON['slug'] = 'notes'
138140
JSON['isNotes'] = "true"
139-
secretJSON['items'].append(JSON)
141+
secretjson['items'].append(JSON)
140142

141143
else:
142-
secretJSON[key] = value
144+
secretjson[key] = value
143145

144-
return self._http_request("POST", url_suffix="/api/v1/secrets", json_data=secretJSON)
146+
return self._http_request("POST", url_suffix="/api/v1/secrets", json_data=secretjson)
145147

146148
def secretDelete(self, id: int) -> str:
147149
return self._http_request("DELETE", url_suffix="/api/v1/secrets/" + str(id))
@@ -163,8 +165,8 @@ def searchFolder(self, search_folder: str) -> list:
163165
url_suffix = "/api/v1/folders/lookup?filter.searchText=" + search_folder
164166

165167
response_records = self._http_request("GET", url_suffix).get('records')
166-
idFolder = list(map(lambda x: x.get('id'), response_records))
167-
return idFolder
168+
idfolder = list(map(lambda x: x.get('id'), response_records))
169+
return idfolder
168170

169171
def folderDelete(self, folder_id: str) -> str:
170172
url_suffix = "/api/v1/folders/" + folder_id
@@ -476,7 +478,52 @@ def secret_rpc_changepassword_command(client, secret_id: str = '', newpassword:
476478
)
477479

478480

479-
def main(): # pragma: no cover
481+
def fetch_credentials_command(client, secretids):
482+
credentials: List[Any] = []
483+
try:
484+
secretsid = argToList(secretids)
485+
except Exception as e:
486+
demisto.debug(f"Could not fetch credentials: Provide valid secret id.{e}")
487+
credentials = []
488+
489+
for id in secretsid:
490+
if id not in secretsid:
491+
secretsid.append(id)
492+
493+
if len(secretsid) == 0:
494+
demisto.credentials(credentials)
495+
demisto.debug("Could not fetch credentials:\
496+
Enter valid secret ID to fetch credentials.\n For multiple ID use ,(e.g. 1,2)")
497+
credentials = []
498+
else:
499+
for secret_id in secretsid:
500+
secret = client.getSecret(secret_id)
501+
items = secret.get('items')
502+
for item in items:
503+
if item.get('fieldName') == 'Username':
504+
username = item.get('itemValue')
505+
if item.get('fieldName') == 'Password':
506+
password = item.get('itemValue')
507+
obj = {
508+
"user": username,
509+
"password": password,
510+
"name": str(secret.get('id'))
511+
}
512+
credentials.append(obj)
513+
514+
demisto.credentials(credentials)
515+
markdown = tableToMarkdown('Fetched Credentials', credentials)
516+
517+
return CommandResults(
518+
readable_output=markdown,
519+
outputs_prefix="Delinea.Secret.Fetch.Credentials",
520+
outputs_key_field="credentials",
521+
raw_response=credentials,
522+
outputs=credentials
523+
)
524+
525+
526+
def main():
480527
params = demisto.params()
481528
username = params.get('credentials').get('identifier')
482529
password = params.get('credentials').get('password')
@@ -485,8 +532,9 @@ def main(): # pragma: no cover
485532
url = params.get('url')
486533
proxy = params.get('proxy', False)
487534
verify = not params.get('insecure', False)
535+
secretids = params.get('secrets')
488536

489-
LOG(f'Command being called is {demisto.command()}')
537+
demisto.info(f'Command being called is {demisto.command()}')
490538

491539
delinea_commands = {
492540
'delinea-secret-password-get': secret_password_get_command,
@@ -509,18 +557,21 @@ def main(): # pragma: no cover
509557
'delinea-user-update': user_update_command,
510558
'delinea-user-delete': user_delete_command
511559
}
560+
command = demisto.command()
512561
try:
513562
client = Client(server_url=url,
514563
username=username,
515564
password=password,
516565
proxy=proxy,
517566
verify=verify)
518-
519-
command = demisto.command()
520567
if command in delinea_commands:
521568
return_results(
522569
delinea_commands[command](client, **demisto.args()) # type: ignore[operator]
523570
)
571+
if command == 'fetch-credentials':
572+
return_results(
573+
fetch_credentials_command(client, secretids)
574+
)
524575
elif command == 'test-module':
525576
result = test_module(client)
526577
demisto.results(result)

Packs/DelineaSS/Integrations/DelineaSS/DelineaSS.yml

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,14 @@ configuration:
2020
name: proxy
2121
required: false
2222
type: 8
23+
- display: Fetches Credentials
24+
name: isFetchCredentials
25+
required: false
26+
type: 8
27+
- display: Secret IDs (Provide multiple Id's by using ',' example- 1,2,3)
28+
name: secrets
29+
required: false
30+
type: 12
2331
description: Secret Server is the only fully featured Privileged Account Management (PAM) solution available both on premise and in the cloud. It empowers security and IT ops teams to secure and manage all types of privileged accounts and offers the fastest time to value of any PAM solution.
2432
display: DelineaSS
2533
name: DelineaSS
@@ -1086,7 +1094,7 @@ script:
10861094
- contextPath: Delinea.Secret.ChangePassword
10871095
description: Secret summary
10881096
type: String
1089-
dockerimage: demisto/python3:3.10.7.35188
1097+
dockerimage: demisto/python3:3.10.9.42008
10901098
feed: false
10911099
isfetch: false
10921100
longRunning: false

Packs/DelineaSS/Integrations/DelineaSS/DelineaSS_description.md

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,11 @@ Use check box **Trust any certificate (not secure)** for insecure connections.
1818

1919
Use check box **Use system proxy settings** for proxy.
2020

21+
If you want to use the function of synchronizing secrets stored in Delinea server, check the box **Fetches Credentials** and fill in the field with a list of the secret id(s) of the secrets separated by commas.
22+
23+
You can find the more deatil about Fetches Credentials and sync credentials from below link:
24+
https://docs.delinea.com/online-help/products/integrations/current/pan/xsoar-secret-server
25+
2126
Use the **TEST** button to check if the parameters for integration are correct. In case of successful authentication on the Delinea server and correct filling of all other parameters, you will receive a response **Success**.
2227

2328
This integration performs some REST API transfers to the Delinea server, the full description of which is given in the server documentation.
@@ -60,4 +65,4 @@ The following commands are implemented:
6065

6166
- delinea-user-search Search, filter, sort, and page users
6267

63-
- delinea-user-update Update a single user by ID
68+
- delinea-user-update Update a single user by ID

Packs/DelineaSS/Integrations/DelineaSS/DelineaSS_test.py

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -7,22 +7,25 @@
77
secret_delete_command, folder_create_command, \
88
folder_delete_command, folder_update_command, \
99
user_delete_command, secret_create_command, user_create_command, \
10-
user_update_command, secret_rpc_changepassword_command
10+
user_update_command, secret_rpc_changepassword_command, \
11+
fetch_credentials_command, secret_search_name_command
1112
from test_data.context import GET_PASSWORD_BY_ID_CONTEXT, \
1213
GET_USERNAME_BY_ID_CONTENT, SECRET_GET_CONTENT, \
1314
SECRET_PASSWORD_UPDATE_CONTEXT, SECRET_CHECKOUT_CONTEXT, \
1415
SECRET_CHECKIN_CONTEXT, SECRET_DELETE_CONTEXT, \
1516
FOLDER_CREATE_CONTEXT, FOLDER_DELETE_CONTEXT, FOLDER_UPDATE_CONTEXT, \
1617
USER_DELETE_CONTEXT, SECRET_CREATE_CONTEXT, USER_CREATE_CONTEXT, \
17-
USER_UPDATE_CONTEXT, SECRET_RPC_CHANGE_PASSWORD_CONTEXT
18+
USER_UPDATE_CONTEXT, SECRET_RPC_CHANGE_PASSWORD_CONTEXT, \
19+
SECRET_GET_CREDENTIALS_CONTEXT, SECRET_SEARCH_NAME_CONTEXT
1820
from test_data.http_responses import GET_PASSWORD_BY_ID_RAW_RESPONSE, \
19-
GET_USERNAME_BY_ID_RAW_RESPONSE, SECRET_CHECKOUT_RAW_RESPONSE,\
21+
GET_USERNAME_BY_ID_RAW_RESPONSE, SECRET_CHECKOUT_RAW_RESPONSE, \
2022
SECRET_GET_RAW_RESPONSE, SECRET_PASSWORD_UPDATE_RAW_RESPONSE, \
2123
SECRET_CHECKIN_RAW_RESPONSE, SECRET_DELETE_RAW_RESPONSE, \
2224
FOLDER_CREATE_RAW_RESPONSE, FOLDER_DELETE_RAW_RESPONSE, \
2325
FOLDER_UPDATE_RAW_RESPONSE, USER_DELETE_RAW_RESPONSE, \
2426
SECRET_CREATE_RAW_RESPONSE, SECRET_RPC_CHANGE_PASSWORD_RAW_RESPONSE, \
25-
USER_CREATE_RAW_RESPONSE, USER_UPDATE_RAW_RESPONSE
27+
USER_CREATE_RAW_RESPONSE, USER_UPDATE_RAW_RESPONSE, SECRET_GET_CREDENTIALS_RAW_RESPONSE, \
28+
SECRET_SEARCH_NAME_RAW_RESPONSE
2629

2730
GET_PASSWORD_BY_ID_ARGS = {"secret_id": "4"}
2831
GET_USERNAME_BY_ID_ARGS = {"secret_id": "4"}
@@ -35,16 +38,18 @@
3538
"parentFolderId": "3"}
3639
FOLDER_DELETE_ARGS = {"folder_id": "9"}
3740
FOLDER_UPDATE_ARGS = {"id": "12", "folderName": "xsoarTF3New"}
38-
USER_CREATE_ARGS = {"displayName": "xsoarUserTest1", "password": "1234567890",
41+
USER_CREATE_ARGS = {"displayName": "dispalyName", "password": "password",
3942
"userName": "XSOAR", "emailAddress": "[email protected]"}
4043
USER_DELETE_ARGS = {"id": "10"}
4144
SECRET_CREATE_ARGS = {"name": "xsoarSecret", "secrettemplateid": "6003",
4245
"siteid": "1", "checkoutenabled": "true",
4346
"folderid": "3", "machine_item": "my-machine",
4447
"username_item": "my-username",
45-
"password_item": "test123"}
48+
"password_item": "password_item"}
4649
USER_UPDATE_ARGS = {"id": "28", "userName": "UserOne"}
47-
SECRET_RPC_CHANGE_PASSWORD_ARGS = {"secret_id": "4", "newpassword": "Test000"}
50+
SECRET_RPC_CHANGE_PASSWORD_ARGS = {"secret_id": "4", "newpassword": "newPassword"}
51+
SECRET_GET_CREDENTIALS_ARGS = {"secretids": "4"}
52+
SECRET_SEARCH_NAME_ARGS = {"search_name": "Sayali"}
4853

4954

5055
@pytest.mark.parametrize('command, args, http_response, context', [
@@ -64,12 +69,15 @@
6469
(user_create_command, USER_CREATE_ARGS, USER_CREATE_RAW_RESPONSE, USER_CREATE_CONTEXT),
6570
(user_update_command, USER_UPDATE_ARGS, USER_UPDATE_RAW_RESPONSE, USER_UPDATE_CONTEXT),
6671
(secret_rpc_changepassword_command, SECRET_RPC_CHANGE_PASSWORD_ARGS,
67-
SECRET_RPC_CHANGE_PASSWORD_RAW_RESPONSE, SECRET_RPC_CHANGE_PASSWORD_CONTEXT)
72+
SECRET_RPC_CHANGE_PASSWORD_RAW_RESPONSE, SECRET_RPC_CHANGE_PASSWORD_CONTEXT),
73+
(fetch_credentials_command, SECRET_GET_CREDENTIALS_ARGS, SECRET_GET_CREDENTIALS_RAW_RESPONSE,
74+
SECRET_GET_CREDENTIALS_CONTEXT),
75+
(secret_search_name_command, SECRET_SEARCH_NAME_ARGS, SECRET_SEARCH_NAME_RAW_RESPONSE, SECRET_SEARCH_NAME_CONTEXT)
76+
6877
])
6978
def test_delinea_commands(command, args, http_response, context, mocker):
70-
7179
mocker.patch.object(Client, '_generate_token')
72-
client = Client(server_url="https://test.example.com", username="test", password="test123",
80+
client = Client(server_url="https://test.example.com", username="username", password="password",
7381
proxy=False, verify=False)
7482

7583
mocker.patch.object(Client, '_http_request', return_value=http_response)

Packs/DelineaSS/Integrations/DelineaSS/README.md

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1154,3 +1154,40 @@ Change a secret's password
11541154
}
11551155
```
11561156

1157+
### delinea-fetch-users
1158+
***
1159+
Fetch credentials from secret
1160+
1161+
1162+
#### Base Command
1163+
1164+
`delinea-fetch-users`
1165+
#### Input
1166+
NO input argumets
1167+
1168+
1169+
#### Context Output
1170+
1171+
| **Path** | **Type** | **Description** |
1172+
| --- | --- | --- |
1173+
| Delinea.User.Credentials | String | Secret credential objects |
1174+
1175+
1176+
#### Command Example
1177+
```!delinea-fetch-users```
1178+
1179+
#### Context Example
1180+
```json
1181+
[
1182+
{
1183+
"name": "4219",
1184+
"password": "test3",
1185+
"user": "test3"
1186+
},
1187+
{
1188+
"name": "4217",
1189+
"password": "dhPQhf1d@!E",
1190+
"user": "secret2"
1191+
}
1192+
]
1193+
```

Packs/DelineaSS/Integrations/DelineaSS/test_data/context.py

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
import collections
2+
3+
Credentials = collections.namedtuple('Credentials', ['name', 'user', 'password'])
14
GET_PASSWORD_BY_ID_CONTEXT = {
25
'Delinea.Secret.Password(val.secret_password && val.secret_password == obj.secret_password)': {
36
"Delinea": {
@@ -411,4 +414,23 @@
411414
"daysUntilExpiration": "null",
412415
"hasLauncher": "false"
413416
}
414-
}
417+
}
418+
419+
SECRET_GET_CREDENTIALS_CONTEXT = {
420+
'Delinea.Secret.Fetch.Credentials(val.credentials && val.credentials == obj.credentials)': [
421+
{
422+
'name': '4',
423+
'password': 'test00111',
424+
'user': 'andy'
425+
}
426+
]
427+
428+
}
429+
430+
SECRET_SEARCH_NAME_CONTEXT = {
431+
'Delinea.Secret.Id(val.search_id && val.search_id == obj.search_id)': [
432+
3564,
433+
3566,
434+
4241
435+
]
436+
}

0 commit comments

Comments
 (0)