# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
"""
Alert element types that can be used as a matching criteria in the rules of an Alert Policy.
"""
from smc.api.exceptions import AlertChainError, UnsupportedAlertChannel, AlertPolicyError
from smc.base.model import Element, ElementCreator, SubElement
from smc.base.util import element_resolver
from smc.compat import is_api_version_more_than_or_equal, is_smc_version_more_than_or_equal
from smc.api.exceptions import CreateRuleFailed
from smc.base.collection import rule_collection
class AlertElement(Element):
"""
Base alert element.
"""
class CustomAlert(AlertElement):
"""
This represents a custom Alert.
It gives the name and description to an Alert Event. The Alert element can be used
as a matching criteria in the rules of an Alert Policy.
Create an alert::
CustomAlert.create('myalert')
"""
typeof = "alert"
@classmethod
def create(cls, name, comment=None):
"""
Create the custom alert
:param str name: name of custom alert
:param str comment: optional comment
:raises CreateElementFailed: failed creating element with reason
:return: instance with meta
:rtype: CustomAlert
"""
json = {"name": name, "comment": comment}
return ElementCreator(cls, json)
class FwAlert(AlertElement):
"""
This represents a predefined Firewall Alert.
It gives the name and description to an Alert Event. The Alert element can be used
as a matching criteria in the rules of an Alert Policy.
"""
typeof = "fw_alert"
class IdsAlert(AlertElement):
"""
This represents a predefined IDS Alert.
It gives the name and description to an Alert Event. The Alert element can be used
as a matching criteria in the rules of an Alert Policy.
"""
typeof = "ids_alert"
[docs]
class AlertChain(Element):
"""
This represents an Alert Chain.
"""
typeof = "alert_chain"
[docs]
@classmethod
def create(cls, name, final_action=None, alert_chain_ref=None, comment=None):
"""
Create the custom alert
:param str name: name of alert chain
:param str comment: optional comment
:param str final_action: optional final_action
possible values:
1)none: stop policy processing without acknowledging.
2)acknowledge: stop policy processing and acknowledge.
3)redirect: redirect to another alert chain.
4)return: return to the next policy rule.
:param obj alert_chain_ref: The redirect alert chain. object of AlertChain.
:raises CreateElementFailed: failed creating element with reason
:return: instance with meta of alert chain
:rtype: AlertChain
"""
json = {"name": name, "final_action": final_action, "comment": comment}
if final_action == 'redirect':
json.update(alert_chain_ref=alert_chain_ref)
return ElementCreator(cls, json)
@property
def final_action(self):
return self.data.get("final_action", None)
@property
def open(self):
self.make_request(href=self.get_relation("open"), method="create")
@property
def save(self):
self.make_request(href=self.get_relation("save"), method="create")
@property
def alert_chain_rules(self):
return [AlertChainRule(**rule) for rule in self.make_request(resource="alert_chain_rules")]
def add_rule_section(self, name, add_pos=None,
after=None, before=None, background_color=None):
return AlertChainRule.create_rule_section(self, self.get_relation("alert_chain_rules"),
name, add_pos, after,
before, background_color)
def add_alert_chain_rule(self, name, alert_channel=None, destination=None, delay=0,
admin_name=[], amount=None, notify_first_block=0, period=0,
comment=None, add_pos=None, after=None, before=None, validate=False):
return AlertChainRule.create(self, name, alert_channel, destination, delay, admin_name,
amount, notify_first_block, period, comment, add_pos,
after, before, validate)
class AlertRuleCommon(object):
"""
Functionality common to all alert rules
"""
@property
def background_color(self):
"""
Background color in hexadecimal format (#RRGGBB).
Applicable for rule section and insert point.
"""
return self.data.get("background_color", None)
def is_locked(self):
"""
Locked flag for this rule.
"""
return self.data.get("locked", None)
def lock(self, reason_for=None):
"""
.. Requires SMC version >= 6.10.10 or >= 7.0.2 or >= 7.1.0
Locks this rule with an optional reason.
:raises ResourceNotFound: If not running on supported SMC version
"""
if reason_for:
return self.make_request(method="update",
resource="lock",
params={"reason_for": reason_for})
else:
return self.make_request(method="update", resource="lock")
def unlock(self):
"""
.. Requires SMC version >= 6.10.10 or >= 7.0.2 or >= 7.1.0
Unlocks this rule.
:raises ResourceNotFound: If not running on supported SMC version
"""
return self.make_request(method="update", resource="unlock")
[docs]
class AlertChainRule(AlertRuleCommon, SubElement):
"""
This represents a Alert Chain Rule for Alert Chain Policy.
"""
typeof = "alert_chain_rule"
[docs]
@staticmethod
def create_rule_section(self, rules_href, name, add_pos=None,
after=None, before=None, background_color=None):
"""
Create an alert rule section in an Alert Chain or Alert Policy.
To specify a specific numbering position for the rule section, use the `add_pos` field.
If no position or before/after is specified, the rule section will be placed
at the top which will encapsulate all rules below.
Create a rule section for the relavant policy::
policy = AlertPolicy('mypolicy')
policy.alert_rules.create_rule_section(name='attop')
:param str name: create a rule section by name
:param int add_pos: position to insert the rule, starting with position 1.
If the position value is greater than the number of rules, the rule is
inserted at the bottom. If add_pos is not provided, rule is inserted in
position 1. Mutually exclusive with ``after`` and ``before`` params.
:param str after: Rule tag to add this rule after. Mutually exclusive with
``add_pos`` and ``before`` params.
:param str before: Rule tag to add this rule before. Mutually exclusive with
``add_pos`` and ``after`` params.
:param str background_color: the background color of the rule section.
in hexadecimal format (#RRGGBB)
:raises MissingRequiredInput: when options are specified the need additional
setting, i.e. use_vpn action requires a vpn policy be specified.
:raises CreateRuleFailed: rule creation failure
:return: the created ipv4 rule
:rtype: IPv4Rule
"""
params = {}
href = AlertChainRule.set_up_positions(self, params, rules_href, add_pos, after, before)
json = {"comment": name, "alert_channel": None}
if (is_api_version_more_than_or_equal("7.1") and
is_smc_version_more_than_or_equal("7.1.7") and
background_color):
json.update(background_color=background_color)
return ElementCreator(
self.__class__,
exception=CreateRuleFailed,
href=href,
params=params,
json=json,
)
[docs]
@staticmethod
def create(self, name, alert_channel=None, destination=None, delay=0, admin_name=[],
amount=None, notify_first_block=0, period=0, comment=None, add_pos=None,
after=None, before=None, validate=False):
"""
:param object self: object of AlertChain.
:param str name: name of alert chain rule.
:param str alert_channel: The alert channel, default is Delay channel.Valid values are below
smtp: SMTP channel.
sms: SMS channel.
snmp: SNMP channel.
custom_script: Custom script channel.
delay: Delay channel.
user_notification: User notification channel.
:param str destination: destination address
:param int delay: The delay before the next notification, in minutes.
:param list admin_name: List of admin users. Used in the case of User notification channel.
:param int amount: The maximum number of notifications to be sent before activating
moderation.
:param int notify_first_block: Indicates whether we shall notify the first blocked
notification upon moderation activation.
:param int period: The period during which notifications are tracked before activating
moderation. period need to be mentioned in minutes.
:param str comment: descript of element.
:param int add_pos: position to insert the rule, starting with position 1. If
the position value is greater than the number of rules, the rule is inserted at
the bottom. If add_pos is not provided, rule is inserted in position 1. Mutually
exclusive with ``after`` and ``before`` params.
:param str after: Rule tag to add this rule after. Mutually exclusive with ``add_pos``
and ``before`` params.
:param str before: Rule tag to add this rule before. Mutually exclusive with ``add_pos``
and ``after`` params.
:param bool validate: validate the rule creation. Default: False
:raises CreateElementFailed: failed creating element with reason
:return: instance with meta of alert chain rule
:rtype: AlertChainRule
"""
if alert_channel not in ['smtp', 'sms', 'snmp', 'custom_script', 'user_notification',
'delay'] and alert_channel:
raise UnsupportedAlertChannel(
"Failed to create an alert chain rule due to an unsupported alert channel {}".
format(alert_channel))
json = {
"name": name,
"alert_channel": alert_channel,
"delay": delay,
"period": period,
"notify_first_block": notify_first_block,
"admin_name": admin_name,
"comment": comment
}
if amount:
json.update(amount=amount)
if destination:
json.update(destination=destination)
params = {"validate": False} if not validate else {}
href = AlertChainRule.set_up_positions(self, params,
self.get_relation("alert_chain_rules"),
add_pos, after, before)
return ElementCreator(
AlertChainRule,
exception=AlertChainError,
href=href,
params=params,
json=json,
)
@staticmethod
def set_up_positions(self, params, href, add_pos, after, before):
if add_pos is not None and is_smc_version_more_than_or_equal("7.1.9"):
if add_pos <= 0:
add_pos = 1
rules = self.make_request(href=href)
if rules:
if len(rules) >= add_pos: # Position somewhere in the list
for position, entry in enumerate(rules):
if position + 1 == add_pos:
href = self.__class__(**entry).get_relation("add_before")
break
else: # Put at the end
last_rule = rules.pop()
href = self.__class__(**last_rule).get_relation("add_after")
elif after:
params.update(after=after)
elif before:
params.update(before=before)
return href
[docs]
class AlertPolicy(Element):
"""
This represents an Alert Policy.
"""
typeof = "alert_policy"
[docs]
@classmethod
def create(cls, name, comment=None):
"""
Create the custom alert
:param str name: name of alert policy
:param str comment: optional comment
:raises CreateElementFailed: failed creating element with reason
:return: instance with meta of alert policy
:rtype: AlertPolicy
"""
json = {"name": name, "comment": comment}
return ElementCreator(cls, json)
@property
def alert_rules(self):
return [AlertRule(**rule) for rule in self.make_request(resource="alert_rules")]
def add_rule_section(self, name, add_pos=None,
after=None, before=None, background_color=None):
return AlertRule.create_rule_section(self, self.get_relation("alert_rules"), name,
add_pos, after, before, background_color)
[docs]
def add_alert_rule(self, name, alert_chain_ref=None, match_sender_ref=[],
alert_and_situation_ref=[], min_severity=1, max_severity=10,
rule_validity_times=[], comment=None, add_pos=None,
after=None, before=None, validate=False):
"""
creation of the element of type alert_rule.
:param object self: object of AlertPolicy.
:param str name: name of alert rule.
:param str(AlertChain) alert_chain_ref: The Alert Chain.
:param str match_sender_ref: The senders. If empty, it is considered as ANY.
:param list alert_and_situation_ref: The alerts and situations. If empty, it is considered
as ANY.
:param int min_severity: The minimum value for the severity (value between 1 and 10)
:param int max_severity: The maximum value for the severity (value between 1 and 10)
:param list rule_validity_times: The rule's validity to a specific time period. During the
specified time period, the rule matches. Outside the specified time period, the rule
does not match and the matching continues to the next rule.
:param str comment: descript of element.
:param int add_pos: position to insert the rule, starting with position 1. If
the position value is greater than the number of rules, the rule is inserted at
the bottom. If add_pos is not provided, rule is inserted in position 1. Mutually
exclusive with ``after`` and ``before`` params.
:param str after: Rule tag to add this rule after. Mutually exclusive with ``add_pos``
and ``before`` params.
:param str before: Rule tag to add this rule before. Mutually exclusive with ``add_pos``
and ``after`` params.
:param bool validate: validate the rule creation. Default: False
:raises CreateElementFailed: failed creating element with reason
:return: instance with meta of alert rule
:rtype: AlertRule
"""
return AlertRule.create(self, name, alert_chain_ref, match_sender_ref,
alert_and_situation_ref,
min_severity, max_severity, rule_validity_times, comment,
add_pos, after, before, validate)
[docs]
class AlertRule(AlertRuleCommon, SubElement):
"""
This represents Alert Rule for Alert Policy.
"""
typeof = "alert_rule"
[docs]
@staticmethod
def create_rule_section(self, rules_href, name, add_pos=None,
after=None, before=None, background_color=None):
"""
Create an alert rule section in an Alert Chain or Alert Policy.
To specify a specific numbering position for the rule section, use the `add_pos` field.
If no position or before/after is specified, the rule section will be placed
at the top which will encapsulate all rules below.
Create a rule section for the relavant policy::
policy = AlertPolicy('mypolicy')
policy.alert_rules.create_rule_section(name='attop')
:param str name: create a rule section by name
:param int add_pos: position to insert the rule, starting with position 1.
If the position value is greater than the number of rules, the rule is
inserted at the bottom. If add_pos is not provided, rule is inserted in
position 1. Mutually exclusive with ``after`` and ``before`` params.
:param str after: Rule tag to add this rule after. Mutually exclusive with
``add_pos`` and ``before`` params.
:param str before: Rule tag to add this rule before. Mutually exclusive with
``add_pos`` and ``after`` params.
:param str background_color: the background color of the rule section.
in hexadecimal format (#RRGGBB)
:raises MissingRequiredInput: when options are specified the need additional
setting, i.e. use_vpn action requires a vpn policy be specified.
:raises CreateRuleFailed: rule creation failure
:return: the created ipv4 rule
:rtype: IPv4Rule
"""
params = {}
href = AlertChainRule.set_up_positions(self, params, rules_href, add_pos, after, before)
json = {"comment": name}
if (is_api_version_more_than_or_equal("7.1") and
is_smc_version_more_than_or_equal("7.1.7") and
background_color):
json.update(background_color=background_color)
return ElementCreator(
self.__class__,
exception=CreateRuleFailed,
href=href,
params=params,
json=json,
)
[docs]
@staticmethod
def create(self, name, alert_chain_ref=None, match_sender_ref=[], alert_and_situation_ref=[],
min_severity=1, max_severity=10, rule_validity_times=[], comment=None, add_pos=None,
after=None, before=None, validate=False):
"""
creation of the element of type alert_rule.
:param object self: object of AlertPolicy.
:param str name: name of alert rule.
:param str(AlertChain) alert_chain_ref: The Alert Chain.
:param list match_sender_ref: The senders. If empty, it is considered as ANY.
:param list alert_and_situation_ref: The alerts and situations. If empty, it is considered
as ANY.
:param int min_severity: The minimum value for the severity (value between 1 and 10):Matches
the rule to only Situations with the specified Severity value(s). For example, if your
rule is general and matches a wide range of Situations, you may want to create two
similar rules: one for less severe Situations and one for more Severe situations. Useful
in rules that contain Tags in the Situation cell.
:param int max_severity: The maximum value for the severity (value between 1 and 10):Matches
the rule to only Situations with the specified Severity value(s). For example if your
rule is general and matches a wide range of Situations, you may want to create two
similar rules: one for less severe Situations and one for more Severe situations. Useful
in rules that contain Tags in the Situation cell.
:param list rule_validity_times: The rule's validity to a specific time period. During the
specified time period, the rule matches. Outside the specified time period, the rule
does not match and the matching continues to the next rule.
:param str comment: descript of element.
:param int add_pos: position to insert the rule, starting with position 1. If
the position value is greater than the number of rules, the rule is inserted at
the bottom. If add_pos is not provided, rule is inserted in position 1. Mutually
exclusive with ``after`` and ``before`` params.
:param str after: Rule tag to add this rule after. Mutually exclusive with ``add_pos``
and ``before`` params.
:param str before: Rule tag to add this rule before. Mutually exclusive with ``add_pos``
and ``after`` params.
:param bool validate: validate the rule creation. Default: False
:raises CreateElementFailed: failed creating element with reason
:return: instance with meta of alert rule
:rtype: AlertRule
"""
json = {
"name": name,
"match_sender_ref": element_resolver(match_sender_ref),
"alert_and_situation_ref": element_resolver(alert_and_situation_ref),
"rule_validity_times": element_resolver(rule_validity_times),
"min_severity": min_severity,
"max_severity": max_severity,
"comment": comment
}
if alert_chain_ref:
json.update(alert_chain_ref=element_resolver(alert_chain_ref))
params = {"validate": False} if not validate else {}
href = AlertRule.set_up_positions(self, params,
self.get_relation("alert_rules"),
add_pos, after, before)
return ElementCreator(
AlertRule,
exception=AlertPolicyError,
href=href,
params=params,
json=json,
)
@staticmethod
def set_up_positions(self, params, href, add_pos, after, before):
if add_pos is not None and is_smc_version_more_than_or_equal("7.1.9"):
if add_pos <= 0:
add_pos = 1
rules = self.make_request(href=href)
if rules:
if len(rules) >= add_pos: # Position somewhere in the list
for position, entry in enumerate(rules):
if position + 1 == add_pos:
href = self.__class__(**entry).get_relation("add_before")
break
else: # Put at the end
last_rule = rules.pop()
href = self.__class__(**last_rule).get_relation("add_after")
elif after:
params.update(after=after)
elif before:
params.update(before=before)
return href