-
Notifications
You must be signed in to change notification settings - Fork 173
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Showing
12 changed files
with
1,131 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
.. automodule:: tenable.sc.nnmscanner |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,248 @@ | ||
''' | ||
NNM | ||
======== | ||
The following methods allow for interaction into the Tenable.sc | ||
:sc-api:`NNM <Passive-Scanner.html>` API. These items are typically seen under the | ||
**Passive Scanner** section of Tenable.sc. | ||
Methods available on ``sc.nnm``: | ||
.. rst-class:: hide-signature | ||
.. autoclass:: NNMAPI | ||
:members: | ||
''' | ||
from .base import SCEndpoint | ||
from tenable.utils import dict_merge | ||
|
||
|
||
class NNMAPI(SCEndpoint): | ||
def _constructor(self, **kw): | ||
''' | ||
Handles parsing the keywords and returns an NNM definition document | ||
''' | ||
if 'name' in kw: | ||
# Validate that the name parameter is a string. | ||
self._check('name', kw['name'], str) | ||
|
||
if 'description' in kw: | ||
# Validate that the description parameter is a string. | ||
self._check('description', kw['description'], str) | ||
|
||
# Make sure that the appropriate authentication type is set. | ||
if 'username' in kw: | ||
kw['authType'] = 'password' | ||
elif 'cert' in kw: | ||
kw['authType'] = 'certificate' | ||
|
||
if 'cert' in kw: | ||
# Validate that the cert parameter is a string. | ||
self._check('cert', kw['cert'], str) | ||
|
||
if 'username' in kw: | ||
# Validate that the username parameter is a string. | ||
self._check('username', kw['username'], str) | ||
|
||
if 'password' in kw: | ||
# Validate that the password parameter is a string. | ||
self._check('password', kw['password'], str) | ||
|
||
if 'address' in kw: | ||
# Validate that the address parameter is a string and store it | ||
# within the ip parameter | ||
kw['ip'] = self._check('address', kw['address'], str) | ||
del(kw['address']) | ||
|
||
if 'port' in kw: | ||
# Validate that the port parameter is a integer. | ||
self._check('port', kw['port'], int) | ||
|
||
if 'proxy' in kw: | ||
# Validate that the proxy parameter is a boolean flag and store it | ||
# as a lowercased string in useProxy. | ||
kw['useProxy'] = str(self._check( | ||
'proxy', kw['proxy'], bool)).lower() | ||
del(kw['proxy']) | ||
|
||
if 'verify' in kw: | ||
# Validate that the verify parameter is a boolean flag and store it | ||
# as a lowercased string in verifyHost. | ||
kw['verifyHost'] = str(self._check( | ||
'verify', kw['verify'], bool)).lower() | ||
del(kw['verify']) | ||
|
||
if 'enabled' in kw: | ||
# Validate that the enabled parameter is a boolean flag and store it | ||
# as a lowercased string. | ||
kw['enabled'] = str(self._check( | ||
'enabled', kw['enabled'], bool)).lower() | ||
|
||
return kw | ||
|
||
def create(self, name, address, **kw): | ||
''' | ||
Creates a NNM in SC. | ||
:sc-api:`NNM: create <Passive-Passive-Scanner.html#passivescanner_POST>` | ||
Args: | ||
address (str): The address of the nnm | ||
name (str): The name of the nnm | ||
description (str, optional): | ||
The description of the nnm. | ||
enabled (bool, optional): | ||
Is this NNM enabled? If left unspecified, the default is | ||
``True``. | ||
port (int, optional): | ||
What is the port that the NNM service is running on. If left | ||
unspecified, then the default is ``8835``. | ||
proxy (bool, optional): | ||
Is this NNM behind a proxy? If left unspecified then the | ||
default is ``False``. | ||
repository_ids (list, optional): | ||
Lists repository ID. | ||
username (str) | ||
Define username of NNM user. | ||
password (str) | ||
Define password of NNM user. | ||
Returns: | ||
:obj:`dict`: | ||
The newly created NNM. | ||
Examples: | ||
>>> nnm = sc.nnm.create('Example NNM', '192.168.0.1', username='admin', password='userpasswordhere') | ||
''' | ||
payload = { | ||
'port': 8835, | ||
'proxy': False, | ||
'verify': False, | ||
'name': name, | ||
'address': address, | ||
} | ||
payload = self._constructor(**dict_merge(payload, kw)) | ||
return self._api.post('passivescanner', json=payload).json()['response'] | ||
|
||
def details(self, id, fields=None): | ||
''' | ||
Returns the details for a specific NNM. | ||
:sc-api:`NNM: details <Passive-Scanner.html#passivescanner_POST>` | ||
Args: | ||
id (int): The identifier for the NNM. | ||
fields (list, optional): A list of attributes to return. | ||
Returns: | ||
:obj:`dict`: | ||
The NNM resource record. | ||
Examples: | ||
>>> nnm = sc.nnm.details(1) | ||
>>> pprint(nnm) | ||
''' | ||
params = dict() | ||
if fields: | ||
params['fields'] = ','.join([self._check('field', f, str) for f in fields]) | ||
|
||
return self._api.get('passivescanner/{}'.format(self._check('id', id, int)), | ||
params=params).json()['response'] | ||
|
||
def edit(self, id, **kw): | ||
''' | ||
Edits a NNM. | ||
:sc-api:`NNM: edit <Passive-Scanner.html#passivescanner_id_PATCH>` | ||
Args: | ||
id (int): The numeric identifier for the NNM. | ||
address (str, optional): The address of the NNM | ||
description (str, optional): | ||
The description of the NNM. | ||
enabled (bool, optional): | ||
Is this NNM enabled? If left unspecified, the default is | ||
``True``. | ||
name (str, optional): The name of the NNM. | ||
port (int, optional): | ||
What is the port that the NNM service is running on. If left | ||
unspecified, then the default is ``8835``. | ||
proxy (bool, optional): | ||
Is this scanner behind a proxy? If left unspecified then the | ||
default is ``False``. | ||
repository_ids (list, optional): | ||
Lists repository ID. | ||
Returns: | ||
:obj:`dict`: | ||
The newly updated NNM. | ||
Examples: | ||
>>> nnm = sc.nnm.edit(1, enabled=True) | ||
''' | ||
payload = self._constructor(**kw) | ||
return self._api.patch('passivescanner/{}'.format(id), | ||
json=payload).json()['response'] | ||
|
||
def delete(self, id): | ||
''' | ||
Removes the specified NNM. | ||
:sc-api:`NNM: delete <Passive-Scanner.html#passivescanner_id_DELETE>` | ||
Args: | ||
id (int): The numeric identifier for the NNM to remove. | ||
Returns: | ||
:obj:`str`: | ||
An empty response. | ||
Examples: | ||
>>> sc.nnm.delete(1) | ||
''' | ||
return self._api.delete('passivescanner/{}'.format( | ||
self._check('id', id, int))).json()['response'] | ||
|
||
def list(self, fields=None): | ||
''' | ||
Retrieves the list of NNM definitions. | ||
:sc-api:`NNM: list <Passive-Scanner.html#passivescanner_GET>` | ||
Args: | ||
fields (list, optional): | ||
A list of attributes to return for each NNM. | ||
Returns: | ||
:obj:`list`: | ||
A list of NNM resources. | ||
Examples: | ||
>>> for nnm in sc.nnm.list(): | ||
... pprint(nnm) | ||
''' | ||
params = dict() | ||
if fields: | ||
params['fields'] = ','.join([self._check('field', f, str) | ||
for f in fields]) | ||
|
||
return self._api.get('passivescanner', params=params).json()['response'] | ||
''' | ||
Returns: | ||
:obj:`list`: | ||
The list of scans that match the search criteria. | ||
''' | ||
def update_status(self): | ||
''' | ||
Starts an on-demand NNM status update. | ||
:sc-api:`NNM: update-status <Passive-Scanner.html#passiveScannerRESTReference-/passivescanner/updateStatus>` | ||
Returns: | ||
:obj:`list`: | ||
The updated NNM status for all NNM instances. | ||
Examples: | ||
>>> status = sc.nnm.update_status() | ||
''' | ||
return self._api.post('passivescanner/updateStatus', | ||
json={}).json()['response']['status'] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
interactions: | ||
- request: | ||
body: '{"port": 8835, "name": "Example", "username": "admin", "password": "password", | ||
"authType": "password", "ip": "127.0.0.1", "useProxy": "false", "verifyHost": | ||
"false"}' | ||
headers: | ||
Accept: | ||
- '*/*' | ||
Accept-Encoding: | ||
- gzip, deflate | ||
Connection: | ||
- keep-alive | ||
Content-Length: | ||
- '165' | ||
Content-Type: | ||
- application/json | ||
Cookie: | ||
- TNS_SESSIONID=SESSIONID | ||
TNS_SESSIONID: | ||
- cd4d086a6fee6fce62aa510acf845657 | ||
User-Agent: | ||
- Integration/1.0 (pytest; pytenable-automated-testing; Build/unknown) pyTenable/1.4.3 | ||
(Restfly/1.4.5; Python/3.8.2; Darwin/x86_64) | ||
X-SecurityCenter: | ||
- '0000000000' | ||
method: POST | ||
uri: https://127.0.0.1/rest/passivescanner | ||
response: | ||
body: | ||
string: '{"type":"regular","response":{"id":"10","name":"Example","description":"","ip":"127.0.0.1","port":"8835","useProxy":"false","enabled":"true","verifyHost":"false","authType":"password","cert":null,"username":"admin","password":"SET","version":null,"webVersion":null,"admin":"false","uptime":-1,"status":"8192","pluginSet":null,"loadedPluginSet":null,"lastReportTime":"1647270051","createdTime":"1647273651","modifiedTime":"1647273651","repositories":[]},"error_code":0,"error_msg":"","warnings":[],"timestamp":1647273651} | ||
' | ||
headers: | ||
Cache-Control: | ||
- no-cache, no-store | ||
Connection: | ||
- Keep-Alive | ||
Content-Length: | ||
- '521' | ||
Content-Security-Policy: | ||
- 'default-src ''self''; script-src ''self'' pendo-io-static.storage.googleapis.com | ||
app.pendo.io cdn.pendo.io pendo-static-6165929460760576.storage.googleapis.com | ||
data.pendo.io cdn.metarouter.io e.metarouter.io api.amplitude.com cdn.amplitude.com | ||
*.cloudfront.net; connect-src ''self'' app.pendo.io data.pendo.io pendo-static-6165929460760576.storage.googleapis.com | ||
cdn.metarouter.io e.metarouter.io api.amplitude.com cdn.amplitude.com *.cloudfront.net; | ||
img-src ''self'' data: cdn.pendo.io app.pendo.io pendo-static-6165929460760576.storage.googleapis.com | ||
data.pendo.io; style-src ''self'' app.pendo.io cdn.pendo.io pendo-static-6165929460760576.storage.googleapis.com; | ||
frame-ancestors ''self'' app.pendo.io; form-action ''self''; block-all-mixed-content; | ||
Upgrade-Insecure-Requests; object-src ''none''' | ||
Content-Type: | ||
- application/json | ||
Date: | ||
- Mon, 14 Mar 2022 16:00:51 GMT | ||
Expect-CT: | ||
- max-age=31536000 | ||
Expires: | ||
- Thu, 19 Nov 1981 08:52:00 GMT | ||
Keep-Alive: | ||
- timeout=15, max=100 | ||
Pragma: | ||
- no-cache | ||
Server: | ||
- Apache | ||
Strict-Transport-Security: | ||
- max-age=31536000; includeSubDomains | ||
Vary: | ||
- x-apikey | ||
X-Content-Type-Options: | ||
- nosniff | ||
X-Frame-Options: | ||
- DENY | ||
X-XSS-Protection: | ||
- 1; mode=block | ||
status: | ||
code: 200 | ||
message: OK | ||
version: 1 |
Oops, something went wrong.