From 63ca883c0863d990f8c4677212d084aa5bb51569 Mon Sep 17 00:00:00 2001 From: Matt Mullen Date: Wed, 18 Sep 2024 15:21:11 -0400 Subject: [PATCH] feat: add update methods for admin settings --- sophosfirewall_python/admin.py | 198 +++++++++++++++++++++++++++ sophosfirewall_python/api_client.py | 3 +- sophosfirewall_python/firewallapi.py | 108 ++++++++++++++- 3 files changed, 306 insertions(+), 3 deletions(-) diff --git a/sophosfirewall_python/admin.py b/sophosfirewall_python/admin.py index fd531af..ca15a16 100644 --- a/sophosfirewall_python/admin.py +++ b/sophosfirewall_python/admin.py @@ -7,6 +7,7 @@ permissions and limitations under the License. """ from sophosfirewall_python.utils import Utils +from xmltodict import unparse class AclRule: """Class for working with Local Service ACL Exception Rules.""" @@ -179,3 +180,200 @@ def get(self, name): xml_tag="Notification", key="Name", value=name ) return self.client.get_tag(xml_tag="Notification") + +class AdminSettings: + """Class for working with Admin and user settings (System > Administration).""" + + def __init__(self, api_client): + self.client = api_client + + def get(self): + """Get Admin and user settings + + Returns: + dict: XML response converted to Python dictionary + """ + return self.client.get_tag(xml_tag="AdminSettings") + + def update_hostname_settings(self, hostname=None, description=None, debug=False): + """Update hostname admin settings. + + Args: + hostname (str, optional): Hostname. Defaults to None. + description (str, optional): Hostname description. Defaults to None. + + Returns: + dict: XML response converted to Python dictionary + """ + exist_settings = self.get()["Response"]["AdminSettings"]["HostnameSettings"] + + template_data = """ + + + {{ hostname }} + {{ description }} + + + """ + template_vars = { + "hostname": hostname if hostname else exist_settings["HostName"], + "description": description if description else exist_settings["HostNameDesc"] + } + + return self.client.submit_xml(template_data=template_data, template_vars=template_vars, set_operation="update", debug=debug) + + def update_webadmin_settings(self, certificate=None, + https_port=None, + userportal_https_port=None, + vpnportal_https_port=None, + portal_redirect_mode=None, + portal_custom_hostname=None, + debug=False): + """Update webadmin settings. System > Administration > Admin and user settings. + + Args: + certificate (str, optional): SSL Certificate name. Defaults to None. + https_port (str, optional): HTTPS port for admin interface. Defaults to None. + userportal_https_port (str, optional): HTTPS port for User portal. Defaults to None. + vpnportal_https_port (str, optional): HTTPS port for VPN portal. Defaults to None. + portal_redirect_mode (str, optional): Portal redirect mode. Defaults to None. + portal_custom_hostname (str, optional): Portal custom hostname. Defaults to None. + + Returns: + dict: XML response converted to Python dictionary + """ + exist_settings = self.get()["Response"]["AdminSettings"]["WebAdminSettings"] + + template_data = """ + + + {{ certificate }} + {{ https_port }} + {{ userportal_https_port }} + {{ vpnportal_https_port }} + {{ portal_redirect_mode }} + {{ port_custom_hostname }} + + + """ + template_vars = { + "certificate": certificate if certificate else exist_settings["Certificate"], + "https_port": https_port if https_port else exist_settings["HTTPSport"], + "userportal_https_port": userportal_https_port if userportal_https_port else exist_settings["UserPortalHTTPSPort"], + "vpnportal_https_port": vpnportal_https_port if vpnportal_https_port else exist_settings["VPNPortalHTTPSPort"], + "portal_redirect_mode": portal_redirect_mode if portal_redirect_mode else exist_settings["PortalRedirectMode"], + "portal_custom_hostname": portal_custom_hostname if portal_custom_hostname else exist_settings["PortalCustomHostname"] + } + + return self.client.submit_xml(template_data=template_data, template_vars=template_vars, set_operation="update", debug=debug) + + def update_loginsecurity_settings(self, logout_session=None, block_login=None, unsuccessful_attempt=None, duration=None, minutes=None, debug=False): + """Update login security admin settings. System > Administration > Admin and user settings. + + Args: + logout_session (str, optional): Enable/disable logout session. Specify number of minutes to enable. Defaults to None. + block_login (str, optional): Enable/disable block login. Defaults to None. + unsuccessful_attempt (str, optional): Set number of unsuccessful attempts. Defaults to None. + duration (str, optional): Set block login duration. Defaults to None. + minutes (str, optional): Set number of minutes for block login. Defaults to None. + + Returns: + dict: XML response converted to Python dictionary + """ + exist_settings = self.get()["Response"]["AdminSettings"]["LoginSecurity"] + + template_data = """ + + + {{ logout_session }} + {{ block_login }} + {% if block_login == 'Enable' %} + + {{ unsuccessful_attempt }} + {{ duration }} + {{ minutes }} + + {% endif %} + + + """ + if not unsuccessful_attempt and "BlockLoginSettings" in exist_settings: + unsuccessful_attempt = exist_settings["BlockLoginSettings"]["UnsucccessfulAttempt"] + if not duration and "BlockLoginSettings" in exist_settings: + duration = exist_settings["BlockLoginSettings"]["Duration"] + if not minutes and "BlockLoginSettings" in exist_settings: + minutes = exist_settings["BlockLoginSettings"]["ForMinutes"] + template_vars = { + "logout_session": logout_session if logout_session else exist_settings["LogoutSession"], + "block_login": block_login if block_login else exist_settings["BlockLogin"], + "unsuccessful_attempt": unsuccessful_attempt if unsuccessful_attempt else "5", + "duration": duration if duration else "5", + "minutes": minutes if minutes else "60" + } + + return self.client.submit_xml(template_data=template_data, template_vars=template_vars, set_operation="update", debug=debug) + + def update_passwordcomplexity_settings(self, complexity_check=None, enforce_min_length=None, include_alpha=None, include_numeric=None, include_special=None, min_length=None, debug=False): + """Update password complexity settings. System > Administration > Admin and user settings. + + Args: + complexity_check (str, optional): Enable/disable password complexity check. Defaults to None. + enforce_min_length (str, optional): Enforce minimum required password length. Defaults to None. + include_alpha (str, optional): Enforce inclusion of alphanumeric characters. Defaults to None. + include_numeric (str, optional): Enforce inclusion numeric characters. Defaults to None. + include_special (str, optional): Enforce inclusion of special characters. Defaults to None. + min_length (str, optional): Minimul required password length. Defaults to None. + + Returns: + dict: XML response converted to Python dictionary + """ + exist_settings = self.get()["Response"]["AdminSettings"]["PasswordComplexitySettings"] + + template_data = """ + + + {{ complexity_check }} + + {{ enforce_min_length }} + {{ include_alpha }} + {{ include_special }} + {{ include_special }} + {{ min_length }} + + + + """ + + template_vars = { + "complexity_check": complexity_check if complexity_check else exist_settings["PasswordComplexityCheck"], + "enforce_min_length": enforce_min_length if enforce_min_length else exist_settings["PasswordComplexity"]["MinimumPasswordLength"], + "include_alpha": include_alpha if include_alpha else exist_settings["PasswordComplexity"]["IncludeAlphabeticCharacters"], + "include_numeric": include_numeric if include_numeric else exist_settings["PasswordComplexity"]["IncludeNumericCharacter"], + "include_special": include_special if include_special else exist_settings["PasswordComplexity"]["IncludeSpecialCharacter"], + "min_length": min_length if min_length else exist_settings["PasswordComplexity"]["MinimumPasswordLengthValue"] + } + + return self.client.submit_xml(template_data=template_data, template_vars=template_vars, set_operation="update", debug=debug) + + def update_login_disclaimer(self, enabled: bool = False, debug: bool = False): + """Update login disclaimer. System > Administration > Admin and user settings. + + Args: + enabled (bool, optional): Enable or disable Login Disclaimer. Defaults to True. + + Returns: + dict: XML response converted to Python dictionary + """ + if enabled: + setting = "Enable" + else: + setting = "Disable" + + template_data = """ + + {{ setting }} + + """ + template_vars = {"setting": setting} + + return self.client.submit_xml(template_data=template_data, template_vars=template_vars, set_operation="update", debug=debug) diff --git a/sophosfirewall_python/api_client.py b/sophosfirewall_python/api_client.py index 51d082a..0542640 100644 --- a/sophosfirewall_python/api_client.py +++ b/sophosfirewall_python/api_client.py @@ -190,7 +190,8 @@ def submit_xml( set_operation: str = "add", debug: bool = False, ) -> dict: - """Submits XML payload as a string to the API. + """Submits XML payload as a string to the API. + Args: template_data (str): A string containing the XML payload. Variables can be optionally passed in the string using Jinja2 (ex. {{ some_var }}) template_vars (dict, optional): Dictionary of variables to inject into the XML string. diff --git a/sophosfirewall_python/firewallapi.py b/sophosfirewall_python/firewallapi.py index 79fb5fa..cf4b479 100644 --- a/sophosfirewall_python/firewallapi.py +++ b/sophosfirewall_python/firewallapi.py @@ -30,7 +30,7 @@ ) from sophosfirewall_python.service import Service, ServiceGroup from sophosfirewall_python.network import Interface, Vlan, Zone -from sophosfirewall_python.admin import AclRule, Notification +from sophosfirewall_python.admin import AclRule, Notification, AdminSettings from sophosfirewall_python.authen import User, AdminAuthen from sophosfirewall_python.profile import AdminProfile from sophosfirewall_python.ips import IPS @@ -376,7 +376,7 @@ def get_admin_settings(self): Returns: dict: XML response converted to Python dictionary """ - return self.client.get_tag(xml_tag="AdminSettings") + return AdminSettings(self.client).get() def get_dns_forwarders(self): """Get DNS forwarders. @@ -937,6 +937,110 @@ def update_rule(self, name: str, rule_params: dict, debug: bool = False): dict: XML response converted to Python dictionary """ return FirewallRule(self.client).update(name, rule_params, debug) + + def update_hostname_settings(self, hostname: str = None, description: str = None, debug: bool = False): + """Update hostname admin settings. System > Administration > Admin and user settings. + + Args: + hostname (str, optional): Hostname. Defaults to None. + description (str, optional): Hostname description. Defaults to None. + + Returns: + dict: XML response converted to Python dictionary + """ + return AdminSettings(self.client).update_hostname_settings(hostname, description, debug) + + def update_webadmin_settings(self, certificate: str = None, + https_port: str = None, + userportal_https_port: str = None, + vpnportal_https_port: str = None, + portal_redirect_mode: str = None, + portal_custom_hostname: str = None, + debug: bool = False): + """Update webadmin settings. System > Administration > Admin and user settings. + + Args: + certificate (str, optional): SSL Certificate name. Defaults to None. + https_port (str, optional): HTTPS port for admin interface. Defaults to None. + userportal_https_port (str, optional): HTTPS port for User portal. Defaults to None. + vpnportal_https_port (str, optional): HTTPS port for VPN portal. Defaults to None. + portal_redirect_mode (str, optional): Portal redirect mode. Defaults to None. + portal_custom_hostname (str, optional): Portal custom hostname. Defaults to None. + + Returns: + dict: XML response converted to Python dictionary + """ + return AdminSettings(self.client).update_webadmin_settings(certificate, + https_port, + userportal_https_port, + vpnportal_https_port, + portal_redirect_mode, + portal_custom_hostname, + debug) + + def update_loginsecurity_settings(self, logout_session: str = None, + block_login: str = None, + unsuccessful_attempt: str = None, + duration: str = None, + minutes: str = None, + debug: bool = False): + """Update login security settings. System > Administration > Admin and user settings. + + Args: + logout_session (str, optional): Enable to logout Admin Session after configured timeout. Specify number of minutes to enable (1-120). Defaults to None. + block_login (str, optional): Enable to block Admin login after configured number of failed attempts within configured time span. Defaults to None. + unsuccessful_attempt (str, optional): Allowed number of failed Admin login attempts from the same IP address (1-5). Defaults to None. + duration (str, optional): Time span within which if Admin Login attempts exceed configured Unsuccessful Attempts, then Admin Login gets blocked. (1-120). Defaults to None. + minutes (str, optional): Time interval for which Admin Login is blocked (1-60). Defaults to None. + + Returns: + dict: XML response converted to Python dictionary + """ + return AdminSettings(self.client).update_loginsecurity_settings(logout_session, + block_login, + unsuccessful_attempt, + duration, + minutes, + debug) + + def update_passwordcomplexity_settings(self, complexity_check: str = None, + enforce_min_length: str = None, + include_alpha: str = None, + include_numeric: str = None, + include_special: str = None, + min_length: str = None, + debug: bool = False): + """Update hostname admin settings. System > Administration > Admin and user settings. + + Args: + complexity_check (str, optional): Enable/disable password complexity check. Defaults to None. + enforce_min_length (str, optional): Enforce minimum required password length. Defaults to None. + include_alpha (str, optional): Enforce inclusion of alphanumeric characters. Defaults to None. + include_numeric (str, optional): Enforce inclusion numeric characters. Defaults to None. + include_special (str, optional): Enforce inclusion of special characters. Defaults to None. + min_length (str, optional): Minimul required password length. Defaults to None. + + Returns: + dict: XML response converted to Python dictionary + """ + return AdminSettings(self.client).update_passwordcomplexity_settings(complexity_check, + enforce_min_length, + include_alpha, + include_numeric, + include_special, + min_length, + debug) + + def update_login_disclaimer(self, enabled: bool = False, debug: bool = False): + """Update login disclaimer. System > Administration > Admin and user settings. + + Args: + enabled (bool, optional): Enable or disable Login Disclaimer. Defaults to True. + + Returns: + dict: XML response converted to Python dictionary + """ + return AdminSettings(self.client).update_login_disclaimer(enabled, debug) # Export the error classes for backward compatibility __all__ = [