Skip to content

Commit

Permalink
Added feature - TenableAD Application Settings APIs
Browse files Browse the repository at this point in the history
Added feature - TenableAD Application Settings APIs

updated tests by removing obsolete fields

updated TenableAD base schema
  • Loading branch information
tushar-balwani committed Jan 10, 2022
1 parent 1ccab9f commit 4426a9a
Show file tree
Hide file tree
Showing 11 changed files with 238 additions and 3 deletions.
1 change: 1 addition & 0 deletions docs/api/ad/application_settings.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
.. automodule:: tenable.ad.application_settings.api
1 change: 1 addition & 0 deletions tenable/ad/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
about
api_keys
attack_types
application_settings
category
checker
checker_option
Expand Down
Empty file.
76 changes: 76 additions & 0 deletions tenable/ad/application_settings/api.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
'''
Application Settings
=============
Methods described in this section relate to the application settings API.
These methods can be accessed at ``TenableAD.application_settings``.
.. rst-class:: hide-signature
.. autoclass:: ApplicationSettingsAPI
:members:
'''
from typing import Dict
from tenable.ad.application_settings.schema import ApplicationSettingsSchema
from tenable.base.endpoint import APIEndpoint


class ApplicationSettingsAPI(APIEndpoint):
_path = 'application-settings'
_schema = ApplicationSettingsSchema()

def details(self) -> Dict:
'''
Get the application settings
Returns:
dict:
The application settings objects
Examples:
>>> tad.application_settings.get_settings()
'''
return self._schema.load(self._get())

def update(self,
**kwargs
) -> Dict:
'''
Update the application settings
Args:
smtp_server_address (optional, str):
The IP address of the SMTP server to use to send mails.
smtp_server_port (optional, int):
The port of SMTP server to use to send mails.
smtp_account (optional, str):
The login to use to authenticate against SMTP server.
smtp_account_password (optional, str):
The password to use to authenticate against SMTP server.
smtp_use_start_tls (optional, bool):
Whether the startTLS SMTP command should be used to secure
the connection to the SMTP server?
tls (optional, bool):
Whether the configured server should connect using TLS?
email_sender (optional, str):
The email address to display as the sender in the emails sent.
default_role_ids (optional, list[int]):
The default role identifiers.
default_profile_id (optional, int):
The default profile identifier.
internal_certificate (optional, str):
The certificate chain to use to verify certificates on TLS
connections.
Return:
dict:
The application settings objects
Example:
>>> tad.application_settings.update_settings(
... smtp_use_start_tls=True,
... tls=False,
... default_profile_id=1,
... )
'''
payload = self._schema.dump(self._schema.load(kwargs))
return self._schema.load(self._patch(json=payload))
23 changes: 23 additions & 0 deletions tenable/ad/application_settings/schema.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
from marshmallow import fields, pre_load
from tenable.ad.base.schema import CamelCaseSchema, convert_keys_to_camel
from tenable.ad.constants import SMTP_USE_START_TLS


class ApplicationSettingsSchema(CamelCaseSchema):
user_registration = fields.Bool()
keep_audit_log = fields.Bool()
log_retention_period = fields.Int()
smtp_server_address = fields.Str(allow_none=True)
smtp_server_port = fields.Int(allow_none=True)
smtp_account = fields.Str(allow_none=True)
smtp_account_password = fields.Str(allow_none=True)
smtp_use_start_tls = fields.Bool()
tls = fields.Bool()
email_sender = fields.Str()
default_role_ids = fields.List(fields.Int())
default_profile_id = fields.Int()
internal_certificate = fields.Str(allow_none=True)

@pre_load
def convert(self, data, **kwargs):
return convert_keys_to_camel(data, special=[SMTP_USE_START_TLS])
9 changes: 7 additions & 2 deletions tenable/ad/base/schema.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from typing import Optional, List
from marshmallow import Schema, fields, ValidationError
from marshmallow import Schema, fields
from tenable.ad.constants import SEARCH_USER_DN, SMTP_USE_START_TLS


def camelcase(s):
Expand Down Expand Up @@ -58,7 +59,10 @@ class CamelCaseSchema(Schema):
"""

def on_bind_field(self, field_name, field_obj):
last_word_uppercase_field_names = ['search_user_dn']
last_word_uppercase_field_names: List[str] = [
SEARCH_USER_DN, # ad-ldap-configuration
SMTP_USE_START_TLS, # ad-application-settings
]

if field_name in last_word_uppercase_field_names:
field_obj.data_key = last_word_uppercase(
Expand All @@ -69,5 +73,6 @@ def on_bind_field(self, field_name, field_obj):

class BoolInt(fields.Boolean):
'''Schema to return an integer value for given boolean value'''

def _serialize(self, value, attr, obj, **kwargs) -> int:
return int(value) if value else 0
8 changes: 8 additions & 0 deletions tenable/ad/constants.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
'''
Constants
'''

# field-names constants that are required to be converted to
# last word uppercase
SEARCH_USER_DN: str = 'search_user_dn' # ad-ldap-configuration
SMTP_USE_START_TLS = 'smtp_use_start_tls' # ad-application-settings
3 changes: 2 additions & 1 deletion tenable/ad/ldap_configuration/schema.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from marshmallow import fields, pre_load, validate as v
from tenable.ad.base.schema import CamelCaseSchema, convert_keys_to_camel
from tenable.ad.constants import SEARCH_USER_DN


class LDAPConfigurationAllowedGroupsSchema(CamelCaseSchema):
Expand All @@ -25,4 +26,4 @@ class LDAPConfigurationSchema(CamelCaseSchema):

@pre_load
def convert(self, data, **kwargs):
return convert_keys_to_camel(data, special=['search_user_dn'])
return convert_keys_to_camel(data, special=[SEARCH_USER_DN])
9 changes: 9 additions & 0 deletions tenable/ad/session.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

from .about import AboutAPI
from .api_keys import APIKeyAPI
from .application_settings.api import ApplicationSettingsAPI
from .attack_types.api import AttackTypesAPI
from .category.api import CategoryAPI
from .checker.api import CheckerAPI
Expand Down Expand Up @@ -66,6 +67,14 @@ def api_keys(self):
'''
return APIKeyAPI(self)

@property
def application_settings(self):
'''
The interface object for the
:doc:`Tenable.ad Application Settings APIs <application_settings>`.
'''
return ApplicationSettingsAPI(self)

@property
def attack_types(self):
'''
Expand Down
58 changes: 58 additions & 0 deletions tests/ad/application_settings/test_application_setting_api.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import responses

from tests.ad.conftest import RE_BASE


@responses.activate
def test_application_settings_details(api):
responses.add(responses.GET,
f'{RE_BASE}/application-settings',
json={
'default_profile_id': 1,
'default_role_ids': [2],
'email_sender': 'default@tenable.ad',
'internal_certificate': None,
'keep_audit_log': True,
'log_retention_period': 365,
'smtp_account': None,
'smtp_account_password': None,
'smtp_server_address': None,
'smtp_server_port': None,
'smtp_use_start_tls': True,
'tls': False,
'user_registration': False
}
)
resp = api.application_settings.details()
assert isinstance(resp, dict)
assert resp['default_profile_id'] == 1
assert resp['log_retention_period'] == 365
assert resp['smtp_use_start_tls'] is True


@responses.activate
def test_application_settings_update(api):
responses.add(responses.PATCH,
f'{RE_BASE}/application-settings',
json={
'default_profile_id': 1,
'default_role_ids': [2],
'email_sender': 'default@tenable.ad',
'internal_certificate': None,
'keep_audit_log': True,
'log_retention_period': 300,
'smtp_account': None,
'smtp_account_password': None,
'smtp_server_address': None,
'smtp_server_port': None,
'smtp_use_start_tls': False,
'tls': False,
'user_registration': False
}
)
resp = api.application_settings.update(
smtp_use_start_tls=False,
)
assert isinstance(resp, dict)
assert resp['default_profile_id'] == 1
assert resp['smtp_use_start_tls'] is False
53 changes: 53 additions & 0 deletions tests/ad/application_settings/test_application_setting_schema.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
'''
Testing the application setting schema
'''
import pytest
from marshmallow import ValidationError
from tenable.ad.application_settings.schema import ApplicationSettingsSchema


@pytest.fixture()
def application_setting_schema():
return {
'default_profile_id': 1,
'default_role_ids': [2],
'email_sender': 'default@tenable.ad',
'internal_certificate': None,
'smtp_account': None,
'smtp_account_password': None,
'smtp_server_address': None,
'smtp_server_port': None,
'smtp_use_start_tls': False,
'tls': False
}


def test_application_setting_schema(application_setting_schema):
'''
test application setting schema
'''
test_resp = {
'defaultProfileId': 1,
'defaultRoleIds': [2],
'emailSender': 'default@tenable.ad',
'internalCertificate': None,
'keepAuditLog': True,
'logRetentionPeriod': 300,
'smtpAccount': None,
'smtpAccountPassword': None,
'smtpServerAddress': None,
'smtpServerPort': None,
'smtpUseStartTLS': False,
'tls': False,
'userRegistration': False
}

schema = ApplicationSettingsSchema()
req = schema.dump(schema.load(application_setting_schema))
assert test_resp['defaultProfileId'] == req['defaultProfileId']
assert test_resp['emailSender'] == req['emailSender']
assert test_resp['smtpUseStartTLS'] == req['smtpUseStartTLS']

with pytest.raises(ValidationError):
application_setting_schema['some_val'] = 'something'
schema.load(application_setting_schema)

0 comments on commit 4426a9a

Please sign in to comment.