Skip to content

Commit

Permalink
Feat: Update admin settings (#82)
Browse files Browse the repository at this point in the history
  • Loading branch information
mamullen13316 authored Sep 19, 2024
1 parent 5e389fa commit 3924d9e
Show file tree
Hide file tree
Showing 4 changed files with 307 additions and 4 deletions.
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ name = "sophosfirewall-python"
packages = [
{ include = "sophosfirewall_python" },
]
version = "0.1.52"
version = "0.1.53"
description = "Python SDK for Sophos Firewall"
authors = ["Matt Mullen <matt.mullen@sophos.com>"]
readme = "README.md"
Expand Down
198 changes: 198 additions & 0 deletions sophosfirewall_python/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -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."""
Expand Down Expand Up @@ -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 = """
<AdminSettings>
<HostnameSettings>
<HostName>{{ hostname }}</HostName>
<HostNameDesc>{{ description }}</HostNameDesc>
</HostnameSettings>
</AdminSettings>
"""
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 = """
<AdminSettings>
<WebAdminSettings>
<Certificate>{{ certificate }}</Certificate>
<HTTPSport>{{ https_port }}</HTTPSport>
<UserPortalHTTPSPort>{{ userportal_https_port }}</UserPortalHTTPSPort>
<VPNPortalHTTPSPort>{{ vpnportal_https_port }}</VPNPortalHTTPSPort>
<PortalRedirectMode>{{ portal_redirect_mode }}</PortalRedirectMode>
<PortalCustomHostname>{{ port_custom_hostname }}</PortalCustomHostname>
</WebAdminSettings>
</AdminSettings>
"""
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 = """
<AdminSettings>
<LoginSecurity>
<LogoutSession>{{ logout_session }}</LogoutSession>
<BlockLogin>{{ block_login }}</BlockLogin>
{% if block_login == 'Enable' %}
<BlockLoginSettings>
<UnsucccessfulAttempt>{{ unsuccessful_attempt }}</UnsucccessfulAttempt>
<Duration>{{ duration }}</Duration>
<ForMinutes>{{ minutes }}</ForMinutes>
</BlockLoginSettings>
{% endif %}
</LoginSecurity>
</AdminSettings>
"""
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 = """
<AdminSettings>
<PasswordComplexitySettings>
<PasswordComplexityCheck>{{ complexity_check }}</PasswordComplexityCheck>
<PasswordComplexity>
<MinimumPasswordLength>{{ enforce_min_length }}</MinimumPasswordLength>
<IncludeAlphabeticCharacters>{{ include_alpha }}</IncludeAlphabeticCharacters>
<IncludeNumericCharacter>{{ include_special }}</IncludeNumericCharacter>
<IncludeSpecialCharacter>{{ include_special }}</IncludeSpecialCharacter>
<MinimumPasswordLengthValue>{{ min_length }}</MinimumPasswordLengthValue>
</PasswordComplexity>
</PasswordComplexitySettings>
</AdminSettings>
"""

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 = """
<AdminSettings>
<LoginDisclaimer>{{ setting }}</LoginDisclaimer>
</AdminSettings>
"""
template_vars = {"setting": setting}

return self.client.submit_xml(template_data=template_data, template_vars=template_vars, set_operation="update", debug=debug)
3 changes: 2 additions & 1 deletion sophosfirewall_python/api_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
108 changes: 106 additions & 2 deletions sophosfirewall_python/firewallapi.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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__ = [
Expand Down

0 comments on commit 3924d9e

Please sign in to comment.