nexpose 7.0.1 → 7.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,124 @@
1
+ module Eso
2
+ # This class represents the Configuration that is sent to the server for new
3
+ # style Discovery Connections.
4
+ class Configuration
5
+ attr_accessor :service_name, :config_name, :config_id, :properties
6
+
7
+ def initialize(service_name:, config_name:, properties:[], config_id:)
8
+ @service_name = service_name
9
+ @config_name = config_name
10
+ @properties = properties
11
+ @config_id = config_id
12
+ end
13
+
14
+ # Convert the Configuration to a JSON string for sending to Nexpose
15
+ #
16
+ # @return [String] A JSON String representation of the Configuration
17
+ def to_json
18
+ self.to_hash.to_json
19
+ end
20
+
21
+ # Convert the Configuration to a Hash
22
+ #
23
+ # @return [Hash] A Hash representation of the Configuration
24
+ def to_hash
25
+ hash = {:configId => @config_id,
26
+ :serviceName => @service_name,
27
+ :configName => @config_name,
28
+ :configurationAttributes => {:valueClass => Eso::Values::OBJECT,
29
+ :objectType => 'service_configuration',
30
+ :properties => []}}
31
+ properties.each {|prop| hash[:configurationAttributes][:properties] << prop.to_hash}
32
+ end
33
+
34
+ # Retrieve a Configuration attribute property value given the name of the property
35
+ #
36
+ # @param [String] name The name of the property to retrieve
37
+ # @return [String] The value of the property
38
+ def property(name)
39
+ prop = properties.find{|attr| attr.property == name}
40
+ prop.value unless prop.nil?
41
+ end
42
+
43
+ # Update a Configuration attribute property value given the name of the property
44
+ #
45
+ # @param [String] name The name of the property to update
46
+ # @param [String] value The value of the property to update
47
+ # @return [String] The value of the property
48
+ def update_property(name, value)
49
+ properties.find{|attr| attr.property == name}.value = value
50
+ end
51
+
52
+ # Delete a Configuration attribute property value given the name of the property
53
+ #
54
+ # @param [String] name The name of the property to update
55
+ def delete_property(name)
56
+ properties.delete_if{|attr| attr.property == name}
57
+ end
58
+
59
+ # Load a Configuration object from a Hash
60
+ #
61
+ # @param [Hash] hash The Hash containing the Configuration object
62
+ # @return [Configuration] The Configuration object which was in the Hash
63
+ def self.load(hash)
64
+ configuration = self.new(service_name: hash[:serviceName],
65
+ config_name: hash[:configName],
66
+ config_id: hash[:configID])
67
+ hash[:configurationAttributes][:properties].each do |prop|
68
+ configuration.properties << ConfigurationAttribute.load(prop)
69
+ end
70
+ configuration
71
+ end
72
+ end
73
+
74
+ # The ConfigurationAttribute is a property of the Configuration
75
+ class ConfigurationAttribute
76
+ attr_accessor :property, :value_class, :value
77
+
78
+ def initialize(property, value_class, value)
79
+ @property = property
80
+ @value_class = value_class
81
+ @value = value
82
+ end
83
+
84
+ # Convert the ConfigurationAttribute to a JSON string for sending to Nexpose
85
+ #
86
+ # @return [String] A JSON String representation of the ConfigurationAttribute
87
+ def to_json
88
+ self.to_hash.to_json
89
+ end
90
+
91
+ # Convert the ConfigurationAttribute to a Hash
92
+ #
93
+ # @return [Hash] A Hash representation of the ConfigurationAttribute
94
+ def to_hash
95
+ prop = @property.to_sym
96
+ hash = {prop => {}}
97
+ hash[prop]['valueClass'] = @value_class
98
+ if @value_class == Eso::Values::ARRAY
99
+ items = []
100
+ @value.each{|v| items<< {'value' => v, 'valueClass' => Eso::Values::STRING}}
101
+ hash[prop]['items'] = items
102
+ else
103
+ hash[prop]['value'] = @value
104
+ end
105
+ hash
106
+ end
107
+
108
+ # Load a ConfigurationAttribute object from an Array
109
+ #
110
+ # @param [Array] array The Array containing the ConfigurationAttribute object
111
+ # @return [ConfigurationAttribute] The ConfigurationAttribute object which was in the Array
112
+ def self.load(array)
113
+ property = array.first
114
+ value_class = array.last['valueClass']
115
+ value =
116
+ if value_class == Eso::Values::ARRAY
117
+ array.last['items'].map{|item| item['value']}
118
+ else
119
+ array.last['value']
120
+ end
121
+ self.new(property, value_class, value)
122
+ end
123
+ end
124
+ end
@@ -0,0 +1,145 @@
1
+ module Eso
2
+ ##
3
+ # This class represents a configuration manager service, which manages a number of configurations (ie a hostname,
4
+ # port, username, and password) used to connect to services, and the services they connect to (ie, ePO, dxl, palo-alto).
5
+ #
6
+ class ConfigurationManager
7
+ attr_accessor :url, :nexpose_console
8
+
9
+ ##
10
+ # Constructor for ConfigurationManager.
11
+ #
12
+ # @param [Nexpose::Connection] nsc A logged-in Nexpose::Connection object with a valid session used to authenticate.
13
+ # @return [Eso::ConfigurationManager] The newly created configurationManager object
14
+ #
15
+ def initialize(nsc)
16
+ @nexpose_console = nsc
17
+ @url = "https://#{nsc.host}:#{nsc.port}/eso/configuration-manager/api/"
18
+ end
19
+
20
+ ##
21
+ # Return all of the services that are currently supported by this configuration manager.
22
+ #
23
+ # @return [Array] An array containing all of services in the configuration manager in String object form.
24
+ # Returns an empty array if no services have been configured.
25
+ #
26
+ def services
27
+ json_data = ::Nexpose::AJAX.get(@nexpose_console, "#{@url}service/", ::Nexpose::AJAX::CONTENT_TYPE::JSON)
28
+ JSON.parse(json_data)
29
+ end
30
+
31
+ ##
32
+ # Return all of the configurations of a particular service type.
33
+ #
34
+ # @param [String] service_name The name of a service to find configurations of.
35
+ # @return [Array] An array containing all the configurations of the given service type.
36
+ #
37
+ def service_configurations(service_name)
38
+ json_data = ::Nexpose::AJAX.get(@nexpose_console,
39
+ "#{@url}service/configuration/#{service_name}/",
40
+ ::Nexpose::AJAX::CONTENT_TYPE::JSON)
41
+ JSON.parse(json_data, :symbolize_names => true)
42
+ end
43
+
44
+ ##
45
+ # Return the configuration of a particular service type with a particular name.
46
+ #
47
+ # @param [String] service_name The name of a service to find configurations of.
48
+ # @param [String] config_name The name of the Configuration.
49
+ # @return [Eso::Configuration] A Configuration object which matches the service name and config name requested.
50
+ def configuration_by_name(service_name, config_name)
51
+ service_configs_by_type = service_configurations(service_name)
52
+ config_hash = service_configs_by_type.find { |config| config[:configName] == config_name }
53
+ Eso::Configuration.load(config_hash)
54
+ end
55
+
56
+ def configuration_type(service_name:)
57
+ json_data = ::Nexpose::AJAX.get(@nexpose_console,
58
+ "#{@url}service/configurationType/#{service_name.downcase}",
59
+ ::Nexpose::AJAX::CONTENT_TYPE::JSON)
60
+ JSON.parse(json_data)
61
+ end
62
+
63
+ ##
64
+ # Get a configuration by id. Runs a GET call against the eso/configuration-manager/api/service/configuration/CONFIGURATION_ID endpoint
65
+ # @param [String] configuration_id The id of the configuration to get
66
+ # return [JSON] A json object representing a configuration
67
+ # TODO : Update to use an Eso::Configuration
68
+ def get_configuration(configuration_id)
69
+ json_data = ::Nexpose::AJAX.get(@nexpose_console, "#{@url}/service/configuration/id/#{configuration_id}", ::Nexpose::AJAX::CONTENT_TYPE::JSON)
70
+ JSON.parse(json_data, :symbolize_names => true)
71
+ end
72
+
73
+ ##
74
+ # Create a new configuration.
75
+ #
76
+ # @param [String] payload The JSON representation of a configuration.
77
+ # @return [Integer] The configID (>= 1) of the newly created configuration. Raises error on failure.
78
+ # TODO: Update to use an Eso::Configuration
79
+ def post_service_configuration(payload)
80
+ # TODO retry if the post fails on timeout
81
+ response_body = ::Nexpose::AJAX.post(@nexpose_console, "#{@url}service/configuration", payload, ::Nexpose::AJAX::CONTENT_TYPE::JSON)
82
+ config_id = Integer(JSON.parse(response_body)['data'])
83
+ raise Exception.new("API returned invalid configID (#{config_id}) while attempting to create configuration.") unless config_id >= 1
84
+ config_id
85
+ end
86
+
87
+ ##
88
+ # Test a configuration.
89
+ #
90
+ # @param [String] payload The JSON representation of a configuration.
91
+ # @return [String] The response from the call or an APIError
92
+ # TODO: Update to use an Eso::Configuration
93
+ def test_service_configuration(payload)
94
+ ::Nexpose::AJAX.post(@nexpose_console,
95
+ "#{@url}service/configuration/test",
96
+ payload,
97
+ ::Nexpose::AJAX::CONTENT_TYPE::JSON)
98
+ end
99
+
100
+ ##
101
+ # Delete a configuration. Runs a DELETE call against the eso/configuration-manager/api/service/configuration/CONFIGURATION_ID endpoint
102
+ #
103
+ # @param [String] configuration_id The id of the configuration to delete
104
+ # return [Boolean] Return true if the api reports a successful delete. Raises an error on failure.
105
+ def delete(configuration_id)
106
+ response_body = ::Nexpose::AJAX.delete(@nexpose_console, "#{@url}service/configuration/#{configuration_id}")
107
+ raise Exception.new("Failed to delete configuration with ID: #{configuration_id}") unless 'success' == response_body
108
+ true
109
+ end
110
+
111
+ ##
112
+ # Preview assets for a configuration. Calls a POST to the eso/configuration-manager/api/service/configuration/preview endpoint
113
+ #
114
+ # @param configuration The configuration to preview
115
+ # return [Array] previewed assets
116
+ # TODO: Update to use an Eso::Configuration
117
+ def preview_assets(configuration)
118
+ response_body = ::Nexpose::AJAX.post(@nexpose_console,
119
+ "#{@url}service/configuration/preview",
120
+ configuration,
121
+ ::Nexpose::AJAX::CONTENT_TYPE::JSON)
122
+ @preview_assets = JSON.parse(response_body)["previewAssets"]
123
+ end
124
+ end
125
+
126
+ module ConfigManagerMessages
127
+ module TestConfig
128
+ AUTH_FAILED_AWS = 'Could not authenticate to Amazon Web Services.'
129
+ # Actual message will list out the bad ARNs
130
+ AUTH_FAILED_AWS_ARN = /Could not authenticate to Amazon Web Services with the following ARNs/
131
+
132
+ CONNECTION_SUCCESSFUL = 'The connection to the external service was successful.'
133
+ # Applies to invalid user, password, wrong protocol, can't reach server, bad base or search query
134
+ CONNECTION_FAILED = 'The connection to the external service failed.'
135
+
136
+ INVALID_FIELDS = 'The configuration had invalid fields.'
137
+
138
+ RETRY_AD = 'Failed to reach out to the Active Directory service, will try again.'
139
+ RETRY_AWS = 'Failed to reach out to Amazon Web Services, will try again.'
140
+ RETRY_AZURE = 'Failed to reach out to the Azure service, will try again.'
141
+ RETRY_DXL = 'The DXL connection is currently down and the connection is in retry status.'
142
+ RETRY_EPO = 'Failed to reach out to the ePO service, will try again.'
143
+ end
144
+ end
145
+ end
data/lib/eso/filter.rb ADDED
@@ -0,0 +1,137 @@
1
+ module Eso
2
+ class Filter
3
+ # These are defined in Eso::Filters which reside in the respective service they are related to.
4
+ attr_accessor :type
5
+
6
+ # These are the individual filter items
7
+ attr_accessor :filter_items
8
+
9
+ # Constructor for Filter.
10
+ #
11
+ # @param [String] type The type of filter this is. They are based on the service this filter exists in. These are defined in Eso::Filters which reside in the respective service they are related to.
12
+ # @param [Array] items Array of filters of this type
13
+ # @return [Eso::Filter] The newly created filter object
14
+ #
15
+ def initialize(type:, items: [])
16
+ @type = type
17
+ @filter_items = items
18
+ end
19
+
20
+ # Append a filter_item later
21
+ def <<(filter_item)
22
+ @filter_items << filter_item
23
+ end
24
+
25
+ def to_json
26
+ self.to_hash.to_json
27
+ end
28
+
29
+ def to_hash
30
+ hash = {}
31
+ hash[@type.to_sym] = {
32
+ valueClass: 'Array',
33
+ items: @filter_items.map{|item| item.to_hash}
34
+ }
35
+ hash
36
+ end
37
+ alias_method :to_h, :to_hash
38
+
39
+ class FilterItem
40
+ attr_accessor :type
41
+ # Examples are "OR", "IN", "CONTAINS". These should probably be constantized somewhere.
42
+ attr_accessor :operator
43
+
44
+ # Array containing the values to filter on
45
+ attr_accessor :operands
46
+
47
+ def initialize(type:, operator:, operands:)
48
+ @type = "#{type}_ITEM"
49
+ @operator = operator
50
+ process_operands(operands)
51
+ end
52
+
53
+ def process_operands(operands)
54
+ @operands =
55
+ if ["IS_EMPTY", "IS_NOT_EMPTY"].include? @operator
56
+ nil
57
+ elsif @type == "#{Eso::Filters::IP_ADDRESS}_ITEM" ||
58
+ @type == "#{Eso::Filters::IP_RANGE}_ITEM" ||
59
+ @type == "#{Eso::Filters::OPEN_PORT}_ITEM" ||
60
+ @type == "#{Eso::Filters::RISK_SCORE}_ITEM" ||
61
+ @type == "#{Eso::Filters::CVSS_SCORE}_ITEM"
62
+ operands.first.split('-')
63
+ else
64
+ operands
65
+ end
66
+
67
+ if @operands == nil
68
+ return
69
+ end
70
+ @operands.map! do |value|
71
+ # This regex is used to determine if the string is actually a float.
72
+ # http://stackoverflow.com/questions/1034418/determine-if-a-string-is-a-valid-float-value
73
+ if value =~ /^\s*[+-]?((\d+_?)*\d+(\.(\d+_?)*\d+)?|\.(\d+_?)*\d+)(\s*|([eE][+-]?(\d+_?)*\d+)\s*)$/
74
+ if (@type == "#{Eso::Filters::OPEN_PORT}_ITEM")
75
+ value.to_i
76
+ else
77
+ value.to_f
78
+ end
79
+ # If it's not a float, let's see if it's an integer.
80
+ elsif value.to_i.to_s == value
81
+ value.to_i
82
+ # Guess not, so lets keep the original value.
83
+ else
84
+ value
85
+ end
86
+ end
87
+ end
88
+
89
+ def to_hash
90
+ hash = {
91
+ valueClass: "Object",
92
+ objectType: @type,
93
+ properties: {
94
+ operator: {
95
+ valueClass: "String",
96
+ value: @operator
97
+ }
98
+ }
99
+ }
100
+ # Currently there are no standards that say how many operands a filter can have
101
+ operand_hash = {}
102
+ operand_counter = 1
103
+ unless @operands.nil?
104
+ @operands.each do |operand|
105
+ label = "operand#{operand_counter}".to_sym
106
+
107
+ # A correct value class is required because Jackson expects it.
108
+ # A Jackson processor for Ruby would probably make this much nicer
109
+ # Also, defaulting to Number is probably a bad idea, but based on current possible values in ESO this works.
110
+ case operand.class.to_s
111
+
112
+ when "String"
113
+ value_class = "String"
114
+ when "Array"
115
+ value_class = "Array"
116
+ when "Fixnum"
117
+ value_class = "Integer"
118
+ else
119
+ value_class = "Number"
120
+ end
121
+
122
+ operand_hash[label] = {
123
+ valueClass: value_class,
124
+ value: operand
125
+ }
126
+ operand_counter += 1
127
+ end
128
+
129
+ hash[:properties].merge! operand_hash
130
+ end
131
+
132
+ hash
133
+ end
134
+ end
135
+ end
136
+ end
137
+
@@ -0,0 +1,88 @@
1
+ module Eso
2
+
3
+ module IntegrationOptionNames
4
+ IMPORT_AD_ASSETS = 'import_ad_assets'
5
+ IMPORT_EPO_ASSETS = 'import_epo_assets'
6
+ SYNC_AZURE_ASSETS = 'sync_azure_assets'
7
+ SYNC_AZURE_ASSETS_WITH_TAGS = 'sync_azure_assets_with_tags'
8
+ end
9
+
10
+ # IntegrationOptionTypes is a way to categorize what various Integration Options do.
11
+ module IntegrationOptionTypes
12
+ # The IMPORT_TO_SITE Array tracks Integration Options which load Assets into a Site.
13
+ IMPORT_TO_SITE = [
14
+ IntegrationOptionNames::IMPORT_AD_ASSETS,
15
+ IntegrationOptionNames::IMPORT_EPO_ASSETS,
16
+ IntegrationOptionNames::SYNC_AZURE_ASSETS,
17
+ IntegrationOptionNames::SYNC_AZURE_ASSETS_WITH_TAGS
18
+ ]
19
+ end
20
+
21
+ class IntegrationOption
22
+ attr_accessor :name
23
+ attr_accessor :steps
24
+ attr_accessor :id
25
+
26
+ def initialize(id: nil, name:, steps: [])
27
+ @id = id
28
+ @name = name
29
+ @steps = steps
30
+ end
31
+
32
+ def site_id=(site_id)
33
+ # As of now, the site is always in the last Step of the IntegrationOption. Might change.
34
+ @steps.last.add_property(StepConfiguration::ConfigParamProperties::SITE_ID, site_id)
35
+ end
36
+
37
+ def site_id
38
+ # As of now, the site is always in the last Step of the IntegrationOption. Might change.
39
+ @steps.last.site_id
40
+ end
41
+
42
+ # Return this object and the associated steps in a digestible JSON format.
43
+ #
44
+ # @return [String] JSON interpretation of this workflow.
45
+ #
46
+ def to_json
47
+ # Convert Object to Hash
48
+ hash = self.to_hash
49
+
50
+ # Grab the Step objects and convert to Hashes
51
+ steps = hash['steps']
52
+ hashified_steps = []
53
+ steps.each {|step| hashified_steps << step.to_hash}
54
+ hash['steps'] = hashified_steps
55
+
56
+ # Convert Hash to JSON
57
+ hash.to_json
58
+ end
59
+
60
+ # Return this object as a Hash. The corresponding Steps will still be objects.
61
+ #
62
+ # @return [Hash] Hash interpretation of this IntegrationOption.
63
+ def to_hash
64
+ hash = {}
65
+ instance_variables.each {|var| hash[var.to_s.delete("@")] = instance_variable_get(var)}
66
+ hash
67
+ end
68
+
69
+ # Load a Hash of an IntegrationOption into an actual IntegrationOption. Probably didn't need to
70
+ # break out separately, but might be useful
71
+ #
72
+ # @param [Hash] raw_integration_option is a Hash representation of an IntegrationOption
73
+ # @return [IntegrationOption] The IntegrationOption version of the Hash
74
+ def self.load(raw_integration_option)
75
+ integration_option = IntegrationOption.new(id: raw_integration_option[:id], name: raw_integration_option[:name])
76
+ steps = raw_integration_option[:steps]
77
+ steps.each do |step|
78
+ step_config = step[:stepConfiguration]
79
+ integration_option.steps << Step.new(uuid: step[:uuid],
80
+ service_name: step[:serviceName],
81
+ type_name: step_config[:typeName],
82
+ previous_type_name: step_config[:previousTypeName],
83
+ configuration_params: step_config[:configurationParams])
84
+ end
85
+ integration_option
86
+ end
87
+ end
88
+ end