Class: Contrast::Agent::Patching::Policy::TriggerNode

Inherits:
PolicyNode show all
Defined in:
lib/contrast/agent/patching/policy/trigger_node.rb

Overview

This class functions to translate our policy.json into an actionable Ruby object, allowing for dynamic patching over hardcoded patching, specifically for those methods which result in the trigger of an attack (indicate points in the application where uncontrolled user input attempted to or did do damage).

Constant Summary collapse

JSON_NAME =
'name'
JSON_APPLICATOR =
'applicator'
JSON_APPLICATOR_METHOD =
'applicator_method'
JSON_REQUIRED_PROPS =
'required_properties'
JSON_OPTIONAL_PROPS =
'optional_properties'
JSON_ON_EXCEPTION =
'on_exception'
NODE =
'Trigger'

Constants inherited from PolicyNode

PolicyNode::JSON_CLASS_NAME, PolicyNode::JSON_INSTANCE_METHOD, PolicyNode::JSON_METHOD_NAME, PolicyNode::JSON_METHOD_SCOPE, PolicyNode::JSON_METHOD_VISIBILITY, PolicyNode::JSON_PROPERTIES

Instance Attribute Summary collapse

Attributes inherited from PolicyNode

#class_name, #instance_method, #method_name, #method_scope, #method_visibility, #properties

Instance Method Summary collapse

Methods inherited from PolicyNode

#feature, #id, #instance_method?

Methods included from Components::Scope::InstanceMethods

#contrast_enter_method_scopes!, #contrast_exit_method_scopes!, #with_app_scope, #with_contrast_scope, #with_deserialization_scope, #with_split_scope

Constructor Details

#initialize(trigger_hash = {}, rule_hash = {}) ⇒ TriggerNode

Returns a new instance of TriggerNode.



28
29
30
31
32
33
34
35
36
37
38
# File 'lib/contrast/agent/patching/policy/trigger_node.rb', line 28

def initialize trigger_hash = {}, rule_hash = {}
  super(trigger_hash)
  @rule_id = rule_hash[JSON_NAME]
  @on_exception = rule_hash[JSON_ON_EXCEPTION] # returns nil in most cases
  @required_properties = rule_hash[JSON_REQUIRED_PROPS]
  @optional_properties = rule_hash[JSON_OPTIONAL_PROPS]
  @applicator = class_from_string(rule_hash[JSON_APPLICATOR])
  # if a unique applicator method is defined for this method (rare case), preference getting that one.
  # otherwise, fall back to the normal applicator method for this rule
  @applicator_method = (trigger_hash[JSON_APPLICATOR_METHOD] || rule_hash[JSON_APPLICATOR_METHOD]).to_sym
end

Instance Attribute Details

#applicatorObject (readonly)

Returns the value of attribute applicator.



24
25
26
# File 'lib/contrast/agent/patching/policy/trigger_node.rb', line 24

def applicator
  @applicator
end

#applicator_methodObject (readonly)

Returns the value of attribute applicator_method.



24
25
26
# File 'lib/contrast/agent/patching/policy/trigger_node.rb', line 24

def applicator_method
  @applicator_method
end

#on_exceptionObject (readonly)

Returns the value of attribute on_exception.



24
25
26
# File 'lib/contrast/agent/patching/policy/trigger_node.rb', line 24

def on_exception
  @on_exception
end

#optional_propertiesObject (readonly)

Returns the value of attribute optional_properties.



24
25
26
# File 'lib/contrast/agent/patching/policy/trigger_node.rb', line 24

def optional_properties
  @optional_properties
end

#required_propertiesObject (readonly)

Returns the value of attribute required_properties.



24
25
26
# File 'lib/contrast/agent/patching/policy/trigger_node.rb', line 24

def required_properties
  @required_properties
end

#rule_idObject (readonly)

Returns the value of attribute rule_id.



24
25
26
# File 'lib/contrast/agent/patching/policy/trigger_node.rb', line 24

def rule_id
  @rule_id
end

Instance Method Details

#node_classObject



40
41
42
# File 'lib/contrast/agent/patching/policy/trigger_node.rb', line 40

def node_class
  NODE
end

#validateObject

Raises:

  • (ArgumentError)

    Validates if the created nodes have everything that we’ll need now or later on.



45
46
47
48
49
50
51
52
53
54
# File 'lib/contrast/agent/patching/policy/trigger_node.rb', line 45

def validate
  super
  unless applicator.public_methods(false).any?(applicator_method)
    raise(ArgumentError,
          "#{ id } did not have a proper applicator method: " \
          "#{ applicator } does not respond to #{ applicator_method }. Unable to create.")
  end
  validate_properties
  validate_rule
end

#validate_propertiesObject

Raises:

  • (ArgumentError)

    Validates if the created nodes have everything that we’ll need now or later on.



57
58
59
60
61
62
63
64
65
66
67
68
69
# File 'lib/contrast/agent/patching/policy/trigger_node.rb', line 57

def validate_properties
  if (required_properties & optional_properties).any?
    raise(ArgumentError,
          "#{ rule_id } had overlapping elements between required and optional properties. Unable to create.")
  end
  if (properties.keys - (required_properties | optional_properties)).any?
    raise(ArgumentError, "#{ id } had an unexpected property. Unable to create.")
  end

  return unless (required_properties - properties.keys).any?

  raise(ArgumentError, "#{ id } did not have a required property. Unable to create.")
end

#validate_ruleObject

Raises:

  • (ArgumentError)

    Validates if the created nodes have everything that we’ll need now or later on.



72
73
74
75
76
77
78
79
80
81
82
83
84
85
# File 'lib/contrast/agent/patching/policy/trigger_node.rb', line 72

def validate_rule
  raise(ArgumentError, 'Unknown rule did not have a proper name. Unable to create.') unless rule_id
  raise(ArgumentError, "#{ id } did not have a proper applicator. Unable to create.") unless applicator

  unless applicator_method
    raise(ArgumentError, "#{ id } did not have a proper applicator method. Unable to create.")
  end
  unless required_properties
    raise(ArgumentError, "#{ id } did not have a proper set of required properties. Unable to create.")
  end
  return if optional_properties

  raise(ArgumentError, "#{ id } did not have a proper set of optional properties. Unable to create.")
end