# Copyright (c) 2022 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details. # frozen_string_literal: true require 'contrast/utils/object_share' require 'contrast/agent/reporting/settings/bot_blocker' require 'contrast/agent/reporting/settings/ip_filter' require 'contrast/agent/reporting/settings/log_enhancer' require 'contrast/agent/reporting/settings/rule_definition' require 'contrast/agent/reporting/settings/syslog' require 'contrast/agent/reporting/settings/helpers' module Contrast module Agent module Reporting # This module will hold all the settings from the TS responce module Settings # Application level settings for the Protect featureset. # Used for the FeatureSet TS response class ProtectServerFeature PROTECT_RULES_KEYS = %i[ cmd_injection method_tampering nosql_injection path_traversal redos reflected_xss sql_injection ssrf unsafe_file_upload untrusted_deserialization xxe ].cs__freeze # Indicate if the protect feature set is enabled for this server or not. # # @return enabled [Boolean] def enabled? @_enabled end # Set the enabled # # @param enabled [Boolean] # @return enabled [Boolean] def enabled= enabled @_enabled = enabled end # When false, the agent should not track observations. # when true, the agent should track observed usage of protect URLs # { enable: true } # # @return observability [Boolean] def observability @_observability end # @param enable [Boolean] # @return observability [Boolean] def observability= enable @_observability = enable end # Indicate if the bot protection feature set is enabled for this server or not. # # @return bot_blocker [Contrast::Agent::Reporting::Settings::BotBlocker] def bot_blocker @_bot_blocker ||= Contrast::Agent::Reporting::Settings::BotBlocker.new end # The IP addresses for which to disable protection. # # @return ip_allowlist [Array, []] # expires [Integer] The time after which the filter is no longer valid. # ip [String] The IP or range of IPs to which this message pertains. # name [String] The user defined name of the filter. # uuid [String] The identifier of the filter as defined by TeamServer. def ip_allowlist @_ip_allowlist ||= [] end # set ip_allowlist # # @param allowlist [array] of IpFilter: { # expires [Integer] The time after which the filter is no longer valid. # ip [String] The IP or range of IPs to which this message pertains. # name [String] The user defined name of the filter. # uuid [String] The identifier of the filter as defined by TeamServer. # } # @return ip_allowlist [Array] def ip_allowlist= allowlist Contrast::Agent::Reporting::Settings::Helpers.array_to_iv(Contrast::Agent::Reporting::Settings::IpFilter, ip_allowlist, allowlist) end # The IP addresses for which to disable protection. # # @return ip_denylist [Array, []] # expires [Integer] The time after which the filter is no longer valid. # ip [String] The IP or range of IPs to which this message pertains. # name [String] The user defined name of the filter. # uuid [String] The identifier of the filter as defined by TeamServer. def ip_denylist @_ip_denylist ||= [] end # set ip_denylist # # @param denylist [array] of IpFilter: { # expires [Integer] The time after which the filter is no longer valid. # ip [String] The IP or range of IPs to which this message pertains. # name [String] The user defined name of the filter. # uuid [String] The identifier of the filter as defined by TeamServer. # } # @return ip_denylist [Array] def ip_denylist= denylist Contrast::Agent::Reporting::Settings::Helpers.array_to_iv(Contrast::Agent::Reporting::Settings::IpFilter, ip_denylist, denylist) end # All of the apis to add new logging calls to the application at runtime. # # @return log_enhancers [Array, []] def log_enhancers @_log_enhancers ||= [] end # All of the apis to add new logging calls to the application at runtime. # # @param log_enhancers_array [Array] of LogEnhancers: { # api [String] The method signature to instrument, as understood by the agent. # format [String] The format of the message to log. # id [Integer] The identifier of the enhancer as defined by TeamServer. # level [String] The level at which to log this message. Trace as 0 and Error as 4. # [ TRACE, DEBUG, INFO, WARN, ERROR ] # name [String] The user defined name of the enhancer. # type [String] The type of log message to generate. Audit as 0, Security as 2. # [ AUDIT, ERROR, SECURITY ] # } # @return log_enhancers [Array] def log_enhancers= log_enhancers_array Contrast::Agent::Reporting::Settings::Helpers.array_to_iv(Contrast::Agent::Reporting::Settings::LogEnhancer, log_enhancers, log_enhancers_array) end # The keywords and patterns required for the input analysis of each rule with that capability. # # @return rule_definition_list [Array] def rule_definition_list @_rule_definition_list ||= [] end # The keywords and patterns required for the input analysis of each rule with that capability. # # @param list [Array] Array of RuleDefinition: { # keywords [Array] The words to search for in input that indicate an attack.{ # caseSensitive [Boolean] # id [String] # score [Integer] The impact of matching this entry; higher meaning more # likely to be an attack # value [String] } # name [String] AssessRuleID # patterns [Array] A word or pattern whose presence in an input represents an attack { # caseSensitive [Boolean] # id [String] # score [Integer] The impact of matching this entry; higher meaning more # likely to be an attack # value [String] } # } # @return rule_definition_list [Array] def ng_rule_definition_list list Contrast::Agent::Reporting::Settings::Helpers.array_to_iv( Contrast::Agent::Reporting::Settings::RuleDefinition, rule_definition_list, list) end # Transforms ServerSettings hash rules to definition_list # # @param rules [Hash] def rules_to_definition_list rules return unless rules&.cs__is_a?(Hash) definition_list = [] rules.slice(*PROTECT_RULES_KEYS).each_pair do |key, rule| new_entry = Contrast::Agent::Reporting::Settings::RuleDefinition.new new_entry.name = Contrast::Agent::Reporting::Settings::Helpers.to_rule_id(key) new_entry.patterns = rule[:patterns] new_entry.keywords = rule[:keywords] definition_list << new_entry end @_rule_definition_list = definition_list end # Controls for the syslogging feature in the agent. # # @return syslog [Contrast::Agent::Reporting::Settings::Syslog] def syslog @_syslog ||= Contrast::Agent::Reporting::Settings::Syslog.new end # The protect response should be structured like this: # protect{ enable, observability, rules, log_enhancers } # instead we receive all the data under the protect: # the rules array is merged under protect and the ruleDefinition # list is separate: # "defend" : { # "botBlockers" : [], # "enabled" : true, # "logEnhancers" : [], # "ipDenylist" : [], # "ipAllowlist" : [], # "syslog" : {}, # "ruleDefinitionList" : [{...}], # "bot-blocker" : false # }, def to_controlled_hash { botBlockers: bot_blocker.bots.map(&:to_controlled_hash), enabled: enabled?, observability: observability, # used with ServerSettings only logEnhancers: log_enhancers.map(&:to_controlled_hash), ipDenylist: ip_denylist.map(&:to_controlled_hash), ipAllowlist: ip_allowlist.map(&:to_controlled_hash), syslog: syslog.settings_blank? ? nil : syslog.to_controlled_hash, # used with ServerSettings only ruleDefinitionList: rule_definition_list.map(&:to_controlled_hash), 'bot-blocker': bot_blocker.to_controlled_hash }.compact end end end end end end