Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added feature for Widgets API under Tenable.ad #466

Merged
merged 3 commits into from
Dec 1, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/api/ad/about.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
.. automodule:: tenable.ad.about
1 change: 1 addition & 0 deletions docs/api/ad/api_keys.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
.. automodule:: tenable.ad.api_keys
1 change: 1 addition & 0 deletions docs/api/ad/directories.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
.. automodule:: tenable.ad.directories.api
1 change: 1 addition & 0 deletions docs/api/ad/index.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
.. automodule:: tenable.ad
1 change: 1 addition & 0 deletions docs/api/ad/widget.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
.. automodule:: tenable.ad.widget.api
Empty file added docs/api/index.rst
Empty file.
1 change: 1 addition & 0 deletions docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
api/sc/index
api/ot/index
api/dl/index
api/ad/index
api/nessus/index
api/reports/index
api/base/index
Expand Down
20 changes: 20 additions & 0 deletions tenable/ad/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
'''
Tenable.ad
==========

This package covers the Tenable.ad interface.

.. autoclass:: TenableAD
:members:


.. toctree::
:hidden:
:glob:

about
api_keys
directories
widget
'''
from .session import TenableAD # noqa: F401
26 changes: 26 additions & 0 deletions tenable/ad/about.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
'''
About
=====

Methods described in this section relate to the the about API.
These methods can be accessed at ``TenableAD.about``.

.. rst-class:: hide-signature
.. autoclass:: AboutAPI
:members:
'''
from tenable.base.endpoint import APIEndpoint


class AboutAPI(APIEndpoint):
_path = 'about'

def version(self) -> str:
'''
Returns the version of the connected Tenable.ad instance.

Examples:

>>> tad.about.version()
'''
return self._get(box=True).version
SteveMcGrath marked this conversation as resolved.
Show resolved Hide resolved
39 changes: 39 additions & 0 deletions tenable/ad/api_keys.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
'''
APIKeys
=======

Methods described in this section relate to the the APIKeys API.
These methods can be accessed at ``TenableAD.api_keys``.

.. rst-class:: hide-signature
.. autoclass:: APIKeyAPI
:members:
'''
from tenable.base.endpoint import APIEndpoint


class APIKeyAPI(APIEndpoint):
_path = 'api-key'

def get(self) -> str:
'''
Gets the API Key of the current user.

Examples:

>>> tad.api_keys.get()
'''
return self._get(box=True).key
SteveMcGrath marked this conversation as resolved.
Show resolved Hide resolved

def refresh(self) -> str:
'''
Creates or renews an API for the current user. Will also refresh the
API Key used in the current TenableAD session.

Examples:

>>> tad.api_keys.refresh()
'''
key = self._post(json={}, box=True).key
self._api._key_auth(key)
return key
SteveMcGrath marked this conversation as resolved.
Show resolved Hide resolved
15 changes: 15 additions & 0 deletions tenable/ad/base/schema.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
from marshmallow import Schema


def camelcase(s):
parts = iter(s.split("_"))
return next(parts) + "".join(i.title() for i in parts)


class CamelCaseSchema(Schema):
"""Schema that uses camel-case for its external representation
and snake-case for its internal representation.
"""

def on_bind_field(self, field_name, field_obj):
field_obj.data_key = camelcase(field_obj.data_key or field_name)
203 changes: 203 additions & 0 deletions tenable/ad/directories/api.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,203 @@
'''
Directory
=========

Methods described in this section relate to the the directory API.
These methods can be accessed at ``TenableAD.directories``.

.. rst-class:: hide-signature
.. autoclass:: DirectoriesAPI

.. automethod:: create
.. automethod:: delete
.. automethod:: details
.. automethod:: update
.. automethod:: list
'''
from typing import List, Dict

from marshmallow import INCLUDE
from restfly.utils import dict_clean

from tenable.base.endpoint import APIEndpoint
from .schema import DirectorySchema


class DirectoriesAPI(APIEndpoint):
_path = 'directories'

def list(self) -> List[Dict]:
'''
Retrieve all directory instances

Returns:
list:
The list of directory objects

Examples:

>>> tad.directories.list()
'''
schema = DirectorySchema(unknown=INCLUDE)
return schema.load(self._get(), many=True)

def create(self,
infrastructure_id: int,
name: str,
ip: str,
dns: str,
**kwargs
) -> List[Dict]:
'''
Create a new directory instance

Args:
infrastructure_id (int):
The infrastructure object to bind this directory to.
name (str):
Name of the directory instance.
ip (str):
The IP Address of the directory server.
dns (str):
The DNS domain that this directory is tied to.
directory_type (optional, str):
???
ldap_port (optional, str):
The port number associated to the LDAP service on the
directory server.
global_catalog_port (optional, str):
The port number associated to the Global Catalog service
running on the directory server.
smb_port (optional, str):
The port number associated to the Server Messaging
Block (SMB) service running on the directory server.

Returns:
dict:
The created directory instance.

Examples:

>>> tad.directories.create(
... infrastructure_id=1,
... name='ExampleServer',
... ip='172.16.0.1',
... directory_type='????',
... dns='company.tld',
... )
'''
schema = DirectorySchema(unknown=INCLUDE)
payload = [schema.dump(schema.load(
dict_clean({
'infrastructureId': infrastructure_id,
'name': name,
'ip': ip,
'type': kwargs.get('directory_type'),
'dns': dns,
'ldapPort': kwargs.get('ldap_port'),
'globalCatalogPort': kwargs.get('global_catalog_port'),
'smbPort': kwargs.get('smb_port')
})
))]
return schema.load(self._post(json=payload), many=True)

def details(self, directory_id: str) -> Dict:
'''
Retrieves the details for a specific directory instance.

Args:
directory_id (str): The directory instance identifier.

Returns:
dict:
the directory object.

Examples:

>>> tad.directories.details(1)
'''
schema = DirectorySchema(unknown=INCLUDE)
return schema.load(self._get(directory_id))

def update(self,
infrastructure_id: int,
directory_id: int,
**kwargs
) -> Dict:
'''
Updates the directory instance based on infrastrcture_id and
directory_id.

Args:
infrastructure_id (int):
The infrastructure instance identifier.
directory_id (int):
The directory instance identifier.
name (optional, str):
Name of the directory instance.
ip (optional, str):
The IP Address of the directory server.
directory_type (optional, str):
???
dns (optional, str):
The DNS domain that this directory is tied to.
ldap_port (optional, int):
The port number associated to the LDAP service on the
directory server.
global_catalog_port (optional, str):
The port number associated to the Global Catalog service
running on the directory server.
smb_port (optional, str):
The port number associated to the Server Messaging
Block (SMB) service running on the directory server.

Returns:
dict:
The updated directory object.

Examples:

>>> tad.directories.update(infrastructure_id=2,
... directory_id=9,
... name='updated_new_name')

>>> tad.directories.update(infrastructure_id=2,
... directory_id=9,
... name='updated_new_name',
... ldap_port=390)

'''
schema = DirectorySchema(unknown=INCLUDE)
payload = schema.dump(schema.load(kwargs))
return schema.load(
self._api.patch((f'infrastructures/{infrastructure_id}'
f'/directories/{directory_id}'),
json=payload))

def delete(self, infrastructure_id: int, directory_id: int) -> None:
'''
Deletes the directory instance.

Args:
infrastructure_id (int):
The infrastructure instance identifier.
directory_id (int):
The directory instance identifier.

Returns:
None:

Examples:

>>> tad.directories.delete(infrastructure_id=2,
... directory_id='12')

'''
self._api.delete((f'infrastructures/{infrastructure_id}'
f'/directories/{directory_id}'))

# NOTE: Get All Directories for a Given Infrastructure is located within
# the infrastructures module.
#
# NOTE: Get Directory instance by id is located within the infrastructures
# module.
14 changes: 14 additions & 0 deletions tenable/ad/directories/schema.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
from marshmallow import fields
from tenable.ad.base.schema import CamelCaseSchema


class DirectorySchema(CamelCaseSchema):
infrastructure_id = fields.Int()
id = fields.Int()
name = fields.Str()
ip = fields.Str()
dns = fields.Str()
type = fields.Str()
ldap_port = fields.Int()
global_catalog_port = fields.Int()
smb_port = fields.Int()
Loading