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.
- checksums.yaml +5 -5
- data/CHANGELOG.md +184 -13
- data/COPYING +1 -1
- data/Gemfile.lock +72 -61
- data/README.markdown +10 -1
- data/Rakefile +2 -0
- data/lib/eso.rb +23 -0
- data/lib/eso/conductor.rb +227 -0
- data/lib/eso/configuration/configuration.rb +124 -0
- data/lib/eso/configuration/configuration_manager.rb +145 -0
- data/lib/eso/filter.rb +137 -0
- data/lib/eso/integration_option.rb +88 -0
- data/lib/eso/integration_options_manager.rb +178 -0
- data/lib/eso/nexpose.rb +212 -0
- data/lib/eso/service.rb +83 -0
- data/lib/eso/step.rb +166 -0
- data/lib/eso/step_configuration.rb +73 -0
- data/lib/eso/workflow.rb +149 -0
- data/lib/nexpose/ajax.rb +1 -0
- data/lib/nexpose/connection.rb +8 -4
- data/lib/nexpose/group.rb +1 -1
- data/lib/nexpose/maint.rb +23 -2
- data/lib/nexpose/report.rb +10 -0
- data/lib/nexpose/role.rb +3 -2
- data/lib/nexpose/scan.rb +4 -2
- data/lib/nexpose/site.rb +4 -2
- data/lib/nexpose/util.rb +2 -1
- data/lib/nexpose/version.rb +1 -1
- data/lib/nexpose/vuln_exception.rb +6 -6
- metadata +20 -9
@@ -0,0 +1,178 @@
|
|
1
|
+
require 'nexpose'
|
2
|
+
|
3
|
+
module Eso
|
4
|
+
##
|
5
|
+
# This class is a manager for the integration options api. Integration options match epo/dxl/etc steps
|
6
|
+
# (ie discover-epo-assets) to nexpose steps (ie import-external-assets).
|
7
|
+
|
8
|
+
class IntegrationOptionsManager
|
9
|
+
|
10
|
+
##
|
11
|
+
# Constructor for IntegrationOptionsManager.
|
12
|
+
#
|
13
|
+
# @param [Nexpose::Connection] nsc A logged-in Nexpose::Connection object with a valid session used to authenticate.
|
14
|
+
# @return [Eso::IntegrationOptionsManager] The newly created IntegrationOptionManager object
|
15
|
+
#
|
16
|
+
def initialize(nsc)
|
17
|
+
@nexpose_console = nsc
|
18
|
+
@url = "https://#{nsc.host}:#{nsc.port}/eso/integration-manager-service/api/integration-options/"
|
19
|
+
end
|
20
|
+
|
21
|
+
##
|
22
|
+
# Create a new or Update existing integration option.
|
23
|
+
#
|
24
|
+
# @param [String] payload The JSON representation of an integration option.
|
25
|
+
# @return [String] The integrationOptionID (a UUID) of the newly created configuration. Raises error on failure.
|
26
|
+
#
|
27
|
+
def create(payload)
|
28
|
+
# TODO retry if the post fails on timeout
|
29
|
+
response_body = ::Nexpose::AJAX.post(@nexpose_console, "#{@url}", payload, ::Nexpose::AJAX::CONTENT_TYPE::JSON)
|
30
|
+
JSON.parse(response_body)['data']['id']
|
31
|
+
end
|
32
|
+
alias_method :update, :create
|
33
|
+
|
34
|
+
# Deleting and stopping are the same thing
|
35
|
+
def delete(integration_option_id)
|
36
|
+
::Nexpose::AJAX.delete(@nexpose_console, "#{@url}#{integration_option_id}/state")
|
37
|
+
end
|
38
|
+
alias_method :stop, :delete
|
39
|
+
|
40
|
+
##
|
41
|
+
# Get an existing integration option.
|
42
|
+
#
|
43
|
+
# @param [String] integration_option_id The integration_option_id of the integration option.
|
44
|
+
# @return IntegrationOption for that id, or nil
|
45
|
+
#
|
46
|
+
def get(integration_option_id)
|
47
|
+
# Gets all integration options
|
48
|
+
response_body = ::Nexpose::AJAX.get(@nexpose_console, "#{@url}", ::Nexpose::AJAX::CONTENT_TYPE::JSON)
|
49
|
+
response = JSON.parse(response_body, symbolize_names: true)
|
50
|
+
|
51
|
+
# Find the desired one
|
52
|
+
raw_integration_option = response.find{|raw| raw[:id] == integration_option_id}
|
53
|
+
raise "No IntegrationOption with ID #{integration_option_id}" if raw_integration_option.nil?
|
54
|
+
|
55
|
+
# Load it to an object
|
56
|
+
IntegrationOption.load(raw_integration_option)
|
57
|
+
end
|
58
|
+
|
59
|
+
##
|
60
|
+
# Get the status of an integration option.
|
61
|
+
#
|
62
|
+
# @param [String] integration_option_id The integration_option_id of the integration option.
|
63
|
+
# @return the state (READY, STOPPED, etc)
|
64
|
+
#
|
65
|
+
def status(integration_option_id)
|
66
|
+
response_body = ::Nexpose::AJAX.get(@nexpose_console, "#{@url}#{integration_option_id}/status", ::Nexpose::AJAX::CONTENT_TYPE::JSON)
|
67
|
+
response = JSON.parse(response_body)
|
68
|
+
response['state']
|
69
|
+
end
|
70
|
+
|
71
|
+
def start(integration_option_id)
|
72
|
+
response_body = ::Nexpose::AJAX.post(@nexpose_console, "#{@url}#{integration_option_id}/state", ::Nexpose::AJAX::CONTENT_TYPE::JSON)
|
73
|
+
JSON.parse(response_body)
|
74
|
+
end
|
75
|
+
|
76
|
+
# TODO: These build_* methods must die.
|
77
|
+
def self.build_import_epo_assets_option(name:, discovery_conn_id:, site_id: nil)
|
78
|
+
step1 = Step.new(service_name: ServiceNames::EPO, type_name: StepNames::DISCOVER_EPO)
|
79
|
+
.add_property(StepConfiguration::ConfigParamProperties::DISCOVERY_CONFIG_ID, discovery_conn_id)
|
80
|
+
step2 = Step.new(service_name: ServiceNames::NEXPOSE, type_name: StepNames::IMPORT_EXTERNAL, previous_type_name: step1.type_name)
|
81
|
+
|
82
|
+
#This isn't always known immediately, which is why we have IntegrationOption.site_id=
|
83
|
+
step2.add_property(StepConfiguration::ConfigParamProperties::SITE_ID, site_id) if site_id
|
84
|
+
IntegrationOption.new(name: name, steps: [step1, step2])
|
85
|
+
end
|
86
|
+
|
87
|
+
def self.build_import_ad_assets_option(name:, discovery_conn_id:, site_id: nil)
|
88
|
+
step1 = Step.new(service_name: ServiceNames::ACTIVE_DIRECTORY, type_name: StepNames::DISCOVER_ACTIVE_DIRECTORY)
|
89
|
+
.add_property(StepConfiguration::ConfigParamProperties::DISCOVERY_CONFIG_ID, discovery_conn_id)
|
90
|
+
step2 = Step.new(service_name: ServiceNames::NEXPOSE, type_name: StepNames::IMPORT_EXTERNAL, previous_type_name: step1.type_name)
|
91
|
+
|
92
|
+
#This isn't always known immediately, which is why we have IntegrationOption.site_id=
|
93
|
+
step2.add_property(StepConfiguration::ConfigParamProperties::SITE_ID, site_id) if site_id
|
94
|
+
IntegrationOption.new(name: name, steps: [step1, step2])
|
95
|
+
end
|
96
|
+
|
97
|
+
def self.build_sync_aws_assets_option(name:, discovery_conn_id:, site_id: nil)
|
98
|
+
step1 = Step.new(service_name: ServiceNames::AWS, type_name: StepNames::DISCOVER_AWS_ASSETS)
|
99
|
+
.add_property(StepConfiguration::ConfigParamProperties::DISCOVERY_CONFIG_ID, discovery_conn_id)
|
100
|
+
step2 = Step.new(service_name: ServiceNames::NEXPOSE, type_name: StepNames::SYNC_EXTERNAL, previous_type_name: step1.type_name)
|
101
|
+
|
102
|
+
#This isn't always known immediately, which is why we have IntegrationOption.site_id=
|
103
|
+
step2.add_property(StepConfiguration::ConfigParamProperties::SITE_ID, site_id) if site_id
|
104
|
+
IntegrationOption.new(name: name, steps: [step1, step2])
|
105
|
+
end
|
106
|
+
|
107
|
+
def self.build_verify_aws_targets_option(name:, discovery_conn_id:)
|
108
|
+
step1 = Step.new(service_name: ServiceNames::AWS, type_name: StepNames::VERIFY_AWS_ASSETS)
|
109
|
+
.add_property(StepConfiguration::ConfigParamProperties::DISCOVERY_CONFIG_ID, discovery_conn_id)
|
110
|
+
step2 = Step.new(service_name: ServiceNames::NEXPOSE, type_name: StepNames::VERIFY_EXTERNAL_TARGETS,
|
111
|
+
previous_type_name: step1.type_name)
|
112
|
+
step3 = Step.new(service_name: ServiceNames::AWS, type_name: StepNames::VERIFY_AWS_ASSETS,
|
113
|
+
previous_type_name: step2.type_name)
|
114
|
+
.add_property(StepConfiguration::ConfigParamProperties::DISCOVERY_CONFIG_ID, discovery_conn_id)
|
115
|
+
|
116
|
+
IntegrationOption.new(name: name, steps: [step1, step2, step3])
|
117
|
+
end
|
118
|
+
|
119
|
+
def self.build_sync_azure_assets_option(name:, discovery_conn_id:, site_id: nil)
|
120
|
+
step1 = Step.new(service_name: ServiceNames::AZURE, type_name: StepNames::DISCOVER_AZURE_ASSETS)
|
121
|
+
.add_property(StepConfiguration::ConfigParamProperties::DISCOVERY_CONFIG_ID, discovery_conn_id)
|
122
|
+
step2 = Step.new(service_name: ServiceNames::NEXPOSE, type_name: StepNames::SYNC_EXTERNAL, previous_type_name: step1.type_name)
|
123
|
+
|
124
|
+
#This isn't always known immediately, which is why we have IntegrationOption.site_id=
|
125
|
+
step2.add_property(StepConfiguration::ConfigParamProperties::SITE_ID, site_id) if site_id
|
126
|
+
IntegrationOption.new(name: name, steps: [step1, step2])
|
127
|
+
end
|
128
|
+
|
129
|
+
def self.build_sync_aws_assets_with_tags_option(name:, discovery_conn_id:, site_id: nil, tags: '')
|
130
|
+
step1 = Step.new(service_name: ServiceNames::AWS, type_name: StepNames::DISCOVER_AWS_ASSETS)
|
131
|
+
.add_property(StepConfiguration::ConfigParamProperties::DISCOVERY_CONFIG_ID, discovery_conn_id)
|
132
|
+
.add_property(StepConfiguration::ConfigParamProperties::IMPORT_TAGS, true)
|
133
|
+
.add_property(StepConfiguration::ConfigParamProperties::EXCLUDE_ASSETS_WITH_TAGS, "")
|
134
|
+
.add_property(StepConfiguration::ConfigParamProperties::ONLY_IMPORT_THESE_TAGS, tags)
|
135
|
+
step2 = Step.new(service_name: ServiceNames::NEXPOSE, type_name: StepNames::SYNC_EXTERNAL, previous_type_name: step1.type_name)
|
136
|
+
|
137
|
+
#This isn't always known immediately, which is why we have IntegrationOption.site_id=
|
138
|
+
step2.add_property(StepConfiguration::ConfigParamProperties::SITE_ID, site_id) if site_id
|
139
|
+
IntegrationOption.new(name: name, steps: [step1, step2])
|
140
|
+
end
|
141
|
+
|
142
|
+
def self.build_sync_azure_assets_with_tags_option(name:, discovery_conn_id:, site_id: nil, only_tags: '', exclude_tags: '')
|
143
|
+
step1 = Step.new(service_name: ServiceNames::AZURE, type_name: StepNames::DISCOVER_AZURE_ASSETS)
|
144
|
+
.add_property(StepConfiguration::ConfigParamProperties::DISCOVERY_CONFIG_ID, discovery_conn_id)
|
145
|
+
.add_property(StepConfiguration::ConfigParamProperties::IMPORT_TAGS, true)
|
146
|
+
.add_property(StepConfiguration::ConfigParamProperties::EXCLUDE_ASSETS_WITH_TAGS, exclude_tags)
|
147
|
+
.add_property(StepConfiguration::ConfigParamProperties::ONLY_IMPORT_THESE_TAGS, only_tags)
|
148
|
+
step2 = Step.new(service_name: ServiceNames::NEXPOSE, type_name: StepNames::SYNC_EXTERNAL, previous_type_name: step1.type_name)
|
149
|
+
|
150
|
+
#This isn't always known immediately, which is why we have IntegrationOption.site_id=
|
151
|
+
step2.add_property(StepConfiguration::ConfigParamProperties::SITE_ID, site_id) if site_id
|
152
|
+
IntegrationOption.new(name: name, steps: [step1, step2])
|
153
|
+
end
|
154
|
+
|
155
|
+
def self.build_export_risk_scores_option(name:, discovery_conn_id:)
|
156
|
+
step1 = Step.new(service_name: ServiceNames::NEXPOSE, type_name: StepNames::RISK_SCORE_UPDATED)
|
157
|
+
step2 = Step.new(service_name: ServiceNames::EPO, type_name: StepNames::PUSH_RISK_SCORE, previous_type_name: step1.type_name)
|
158
|
+
.add_property(StepConfiguration::ConfigParamProperties::DISCOVERY_CONFIG_ID, discovery_conn_id)
|
159
|
+
IntegrationOption.new(name: name, steps: [step1, step2])
|
160
|
+
end
|
161
|
+
|
162
|
+
def self.build_find_vuln_details_option(name:, discovery_conn_id:)
|
163
|
+
step1 = Step.new(service_name: ServiceNames::DXL, type_name: StepNames::VULN_DETAILS_REQUEST)
|
164
|
+
.add_property(StepConfiguration::ConfigParamProperties::DISCOVERY_CONFIG_ID, discovery_conn_id)
|
165
|
+
step2 = Step.new(service_name: ServiceNames::NEXPOSE, type_name: StepNames::VULN_DETAILS, previous_type_name: step1.type_name)
|
166
|
+
step3 = Step.new(service_name: ServiceNames::DXL, type_name: StepNames::VULN_DETAILS_REQUEST, previous_type_name: step2.type_name)
|
167
|
+
.add_property(StepConfiguration::ConfigParamProperties::DISCOVERY_CONFIG_ID, discovery_conn_id)
|
168
|
+
IntegrationOption.new(name: name, steps: [step1, step2, step3])
|
169
|
+
end
|
170
|
+
|
171
|
+
def self.build_publish_vulnerabilities_option(name:, discovery_conn_id:)
|
172
|
+
step1 = Step.new(service_name: ServiceNames::NEXPOSE, type_name: StepNames::NEW_ASSET_VULN)
|
173
|
+
step2 = Step.new(service_name: ServiceNames::DXL, type_name: StepNames::PUBLISH_VULN_INT_TYPE, previous_type_name: step1.type_name)
|
174
|
+
.add_property(StepConfiguration::ConfigParamProperties::DISCOVERY_CONFIG_ID, discovery_conn_id)
|
175
|
+
IntegrationOption.new(name: name, steps: [step1, step2])
|
176
|
+
end
|
177
|
+
end
|
178
|
+
end
|
data/lib/eso/nexpose.rb
ADDED
@@ -0,0 +1,212 @@
|
|
1
|
+
require 'nexpose'
|
2
|
+
|
3
|
+
module Eso
|
4
|
+
module ServiceNames
|
5
|
+
ACTIVE_DIRECTORY = 'active-directory'
|
6
|
+
AWS = 'amazon-web-services'
|
7
|
+
AZURE = 'azure'
|
8
|
+
DXL = 'dxl'
|
9
|
+
EPO = 'epo'
|
10
|
+
NEXPOSE = 'nexpose'
|
11
|
+
end
|
12
|
+
|
13
|
+
module StepNames
|
14
|
+
ADD_TO_SITE = 'add-to-site'
|
15
|
+
ADD_VULN_AND_SCAN = 'add-vulnerabilities-to-site-and-scan'
|
16
|
+
DISCOVER_ACTIVE_DIRECTORY = 'discover-ad-assets'
|
17
|
+
DISCOVER_AWS_ASSETS = 'discover-aws-assets'
|
18
|
+
DISCOVER_AZURE_ASSETS = 'discover-azure-assets'
|
19
|
+
DISCOVER_EPO = 'discover-epo-assets'
|
20
|
+
DISCOVER_KNOWN = 'discover-known-assets'
|
21
|
+
DISCOVER_NEW = 'discover-new-assets'
|
22
|
+
DISCOVERY_CONFIG_METADATA = 'discoveryConfigMetadata'
|
23
|
+
EMPTY = ''
|
24
|
+
FILE_REPUTATION_TRIGGER = 'tie-file-reputation-trigger'
|
25
|
+
IMPORT_EXTERNAL = 'import-external-assets'
|
26
|
+
NEW_ASSET_VULN = 'new-asset-vulnerability'
|
27
|
+
NEW_VULN = 'new-vulnerabilities'
|
28
|
+
PUBLISH_VULN_INT_TYPE = 'publish-vulnerability-integration-type'
|
29
|
+
PUSH_RISK_SCORE = 'push-risk-score'
|
30
|
+
RISK_SCORE_UPDATED = 'risk-score-updated'
|
31
|
+
SCAN = 'scan'
|
32
|
+
SCAN_IN_SITE = 'scan-in-site'
|
33
|
+
SYNC_EXTERNAL = 'sync-external-assets'
|
34
|
+
TAG = 'tag'
|
35
|
+
VERIFY_AWS_ASSETS = 'verify-aws-targets'
|
36
|
+
VERIFY_EXTERNAL_TARGETS = 'verify-external-targets'
|
37
|
+
VULN_DETAILS = 'vulnerability-details'
|
38
|
+
VULN_DETAILS_REQUEST = 'vulnerability-details-request'
|
39
|
+
end
|
40
|
+
|
41
|
+
module Values
|
42
|
+
ARRAY = 'Array'
|
43
|
+
BOOLEAN = 'Boolean'
|
44
|
+
INTEGER = 'Integer'
|
45
|
+
OBJECT = 'Object'
|
46
|
+
STRING = 'String'
|
47
|
+
end
|
48
|
+
|
49
|
+
module StepConfigTypes
|
50
|
+
DISCOVERY_CONFIG = [StepNames::DISCOVER_ACTIVE_DIRECTORY,
|
51
|
+
StepNames::DISCOVER_AWS_ASSETS,
|
52
|
+
StepNames::DISCOVER_AZURE_ASSETS,
|
53
|
+
StepNames::DISCOVER_EPO,
|
54
|
+
StepNames::DISCOVER_KNOWN,
|
55
|
+
StepNames::DISCOVER_NEW,
|
56
|
+
StepNames::FILE_REPUTATION_TRIGGER,
|
57
|
+
StepNames::PUBLISH_VULN_INT_TYPE,
|
58
|
+
StepNames::PUSH_RISK_SCORE,
|
59
|
+
StepNames::VULN_DETAILS_REQUEST]
|
60
|
+
EMPTY = [StepNames::NEW_ASSET_VULN,
|
61
|
+
StepNames::NEW_VULN,
|
62
|
+
StepNames::RISK_SCORE_UPDATED,
|
63
|
+
StepNames::VULN_DETAILS]
|
64
|
+
SITE = [StepNames::ADD_TO_SITE,
|
65
|
+
StepNames::ADD_VULN_AND_SCAN,
|
66
|
+
StepNames::IMPORT_EXTERNAL,
|
67
|
+
StepNames::SCAN,
|
68
|
+
StepNames::SCAN_IN_SITE,
|
69
|
+
StepNames::SYNC_EXTERNAL]
|
70
|
+
TAG = [StepNames::TAG]
|
71
|
+
VERIFY = [StepNames::DISCOVER_AWS_ASSETS]
|
72
|
+
end
|
73
|
+
|
74
|
+
module Filters
|
75
|
+
CVSS_SCORE = 'CVSS_SCORE'
|
76
|
+
DHCP_HOST_NAME = 'DHCP_HOST_NAME'
|
77
|
+
HOURS_SINCE_LAST_SCAN= 'HOURS_SINCE_LAST_SCAN'
|
78
|
+
HOURS_SINCE_LAST_SCAN_ITEM = 'HOURS_SINCE_LAST_SCAN_ITEM'
|
79
|
+
IP_ADDRESS = 'IP_ADDRESS'
|
80
|
+
IP_RANGE = 'IP_RANGE'
|
81
|
+
MAC_ADDRESS = 'MAC_ADDRESS'
|
82
|
+
OPEN_PORT = 'OPEN_PORT'
|
83
|
+
RISK_SCORE = 'RISK_SCORE'
|
84
|
+
SERVICE_NAME = 'SERVICE_NAME'
|
85
|
+
end
|
86
|
+
|
87
|
+
module Nexpose
|
88
|
+
def self.create_discovery_workflow(conductor:, name:, step1_type:, step1_param: nil, step2_type:, step2_param:)
|
89
|
+
step1 = self.send("create_#{step1_type.to_s.gsub(/-/, "_")}_step", id: step1_param)
|
90
|
+
step2 = self.send("create_#{step2_type.to_s.gsub(/-/, "_")}_step", id: step2_param)
|
91
|
+
step2.previous_type_name = step1.type_name
|
92
|
+
conductor.create_workflow(name: name, steps: [step1, step2])
|
93
|
+
end
|
94
|
+
|
95
|
+
def self.create_scan_new_vuln_workflow(conductor:, name:, filters:, site_id:)
|
96
|
+
step1 = self.create_new_vuln_step(workflow: nil, filters: filters, previous_type_name: StepNames::EMPTY)
|
97
|
+
step2 = self.create_add_vuln_and_scan_step(id: site_id)
|
98
|
+
step2.previous_type_name = step1.type_name
|
99
|
+
conductor.create_workflow(name: name, steps: [step1, step2])
|
100
|
+
end
|
101
|
+
|
102
|
+
def self.create_file_trigger_workflow(conductor:, name:, step1_param:, step2_param:)
|
103
|
+
step1 = self.create_file_reputation_step(workflow: nil, id: step1_param)
|
104
|
+
step2 = self.create_tag_step(workflow: nil, id: step2_param)
|
105
|
+
step2.previous_type_name = step1.type_name
|
106
|
+
conductor.create_workflow(name: name, steps: [step1, step2])
|
107
|
+
end
|
108
|
+
|
109
|
+
def self.create_scan_in_site_step(workflow: nil, id:, previous_type_name: StepNames::EMPTY)
|
110
|
+
Step.new(workflow: workflow,
|
111
|
+
service_name: ServiceNames::NEXPOSE,
|
112
|
+
type_name: StepNames::SCAN_IN_SITE,
|
113
|
+
previous_type_name: previous_type_name)
|
114
|
+
.add_property(StepConfiguration::ConfigParamProperties::SITE_ID, id)
|
115
|
+
end
|
116
|
+
|
117
|
+
def self.create_file_reputation_step(workflow: nil, id:)
|
118
|
+
Step.new(workflow: workflow,
|
119
|
+
service_name: ServiceNames::DXL,
|
120
|
+
type_name: StepNames::FILE_REPUTATION_TRIGGER,
|
121
|
+
previous_type_name: nil)
|
122
|
+
.add_property(StepConfiguration::ConfigParamProperties::DISCOVERY_CONFIG_ID, id)
|
123
|
+
end
|
124
|
+
|
125
|
+
def self.create_discover_new_assets_step(workflow: nil, id:, previous_type_name: StepNames::EMPTY)
|
126
|
+
Step.new(workflow: workflow,
|
127
|
+
service_name: ServiceNames::NEXPOSE,
|
128
|
+
type_name: StepNames::DISCOVER_NEW,
|
129
|
+
previous_type_name: previous_type_name)
|
130
|
+
.add_property(StepConfiguration::ConfigParamProperties::DISCOVERY_CONFIG_ID, id)
|
131
|
+
end
|
132
|
+
|
133
|
+
def self.create_discover_known_assets_step(workflow: nil, id:, previous_type_name: StepNames::EMPTY)
|
134
|
+
step = Step.new(workflow: workflow,
|
135
|
+
service_name: ServiceNames::NEXPOSE,
|
136
|
+
type_name: StepNames::DISCOVER_KNOWN,
|
137
|
+
previous_type_name: previous_type_name)
|
138
|
+
.add_property(StepConfiguration::ConfigParamProperties::DISCOVERY_CONFIG_ID, id)
|
139
|
+
config_params = step.configuration_params
|
140
|
+
config_params[:HOURS_SINCE_LAST_SCAN] = {
|
141
|
+
:valueClass => Values::ARRAY,
|
142
|
+
:items => [
|
143
|
+
{
|
144
|
+
:valueClass => Values::OBJECT,
|
145
|
+
:objectType => Filters::HOURS_SINCE_LAST_SCAN_ITEM,
|
146
|
+
:properties => {
|
147
|
+
:operator => {
|
148
|
+
:valueClass => Values::STRING,
|
149
|
+
:value => ::Nexpose::Search::Operator::GREATER_THAN
|
150
|
+
},
|
151
|
+
:operand1 => {
|
152
|
+
:valueClass => Values::STRING,
|
153
|
+
:value => '1'
|
154
|
+
}
|
155
|
+
}
|
156
|
+
}
|
157
|
+
]
|
158
|
+
}
|
159
|
+
step.configuration_params = config_params
|
160
|
+
step
|
161
|
+
end
|
162
|
+
|
163
|
+
def self.create_new_vuln_step(workflow: nil, filters:, previous_type_name: StepNames::EMPTY)
|
164
|
+
# The filter definitions on the server are not standard at this point so that is why it is necessary to hard code this
|
165
|
+
# Opening a defect to fix the consistency on these on the backend so we can use the add_filter function in the automation
|
166
|
+
step = Step.new(workflow: workflow,
|
167
|
+
service_name: ServiceNames::NEXPOSE,
|
168
|
+
type_name: StepNames::NEW_VULN,
|
169
|
+
previous_type_name: previous_type_name)
|
170
|
+
|
171
|
+
filters.each { |filter| step.add_filter(filter) }
|
172
|
+
step
|
173
|
+
end
|
174
|
+
|
175
|
+
def self.create_add_vuln_and_scan_step(workflow: nil, id:, previous_type_name: StepNames::EMPTY)
|
176
|
+
Step.new(workflow: workflow,
|
177
|
+
service_name: ServiceNames::NEXPOSE,
|
178
|
+
type_name: StepNames::ADD_VULN_AND_SCAN,
|
179
|
+
previous_type_name: previous_type_name)
|
180
|
+
.add_property(StepConfiguration::ConfigParamProperties::SITE_ID, id)
|
181
|
+
end
|
182
|
+
|
183
|
+
def self.create_add_to_site_step(workflow: nil, id:, previous_type_name: StepNames::EMPTY)
|
184
|
+
Step.new(workflow: workflow,
|
185
|
+
service_name: ServiceNames::NEXPOSE,
|
186
|
+
type_name: StepNames::ADD_TO_SITE,
|
187
|
+
previous_type_name: previous_type_name)
|
188
|
+
.add_property(StepConfiguration::ConfigParamProperties::SITE_ID, id)
|
189
|
+
end
|
190
|
+
|
191
|
+
def self.create_scan_step(workflow: nil, id:, previous_type_name: StepNames::EMPTY)
|
192
|
+
Step.new(workflow: workflow,
|
193
|
+
service_name: ServiceNames::NEXPOSE,
|
194
|
+
type_name: StepNames::SCAN,
|
195
|
+
previous_type_name: previous_type_name)
|
196
|
+
.add_property(StepConfiguration::ConfigParamProperties::SITE_ID, id)
|
197
|
+
end
|
198
|
+
|
199
|
+
def self.create_tag_step(workflow: nil, id:, previous_type_name: StepNames::EMPTY)
|
200
|
+
Step.new(workflow: workflow,
|
201
|
+
service_name: ServiceNames::NEXPOSE,
|
202
|
+
type_name: StepNames::TAG,
|
203
|
+
previous_type_name: previous_type_name)
|
204
|
+
.add_property(StepConfiguration::ConfigParamProperties::TAG_ID, id)
|
205
|
+
end
|
206
|
+
|
207
|
+
def self.get_discover_step(workflow: )
|
208
|
+
workflow.get_step(StepNames::DISCOVER_NEW) || workflow.get_step(StepNames::DISCOVER_KNOWN)
|
209
|
+
end
|
210
|
+
end
|
211
|
+
end
|
212
|
+
|
data/lib/eso/service.rb
ADDED
@@ -0,0 +1,83 @@
|
|
1
|
+
module Eso
|
2
|
+
class Service
|
3
|
+
attr_accessor :host
|
4
|
+
|
5
|
+
attr_accessor :port
|
6
|
+
|
7
|
+
attr_accessor :url
|
8
|
+
|
9
|
+
CONTENT_TYPE_JSON = 'application/json; charset-utf-8'
|
10
|
+
|
11
|
+
def initialize(host:, port: 3780, nsc:)
|
12
|
+
@host = host
|
13
|
+
@port = port
|
14
|
+
@nexpose_console = nsc
|
15
|
+
end
|
16
|
+
|
17
|
+
def get(url:, content_type: CONTENT_TYPE_JSON)
|
18
|
+
get = Net::HTTP::Get.new(url)
|
19
|
+
get.set_content_type(content_type)
|
20
|
+
request(request: get)
|
21
|
+
end
|
22
|
+
|
23
|
+
def put(url:, payload:, content_type: CONTENT_TYPE_JSON)
|
24
|
+
put = Net::HTTP::Put.new(url)
|
25
|
+
put.set_content_type(content_type)
|
26
|
+
put.body = payload.to_s if payload
|
27
|
+
request(request: put)
|
28
|
+
end
|
29
|
+
|
30
|
+
def post(url:, payload: nil, content_type: CONTENT_TYPE_JSON)
|
31
|
+
post = Net::HTTP::Post.new(url)
|
32
|
+
post.set_content_type(content_type)
|
33
|
+
post.body = payload.to_s if payload
|
34
|
+
request(request: post)
|
35
|
+
end
|
36
|
+
|
37
|
+
def delete(url:, content_type: CONTENT_TYPE_JSON)
|
38
|
+
delete = Net::HTTP::Delete.new(url)
|
39
|
+
delete.set_content_type(content_type)
|
40
|
+
request(request: delete)
|
41
|
+
end
|
42
|
+
|
43
|
+
def http(timeout:)
|
44
|
+
http = Net::HTTP.new(@host, @port)
|
45
|
+
http.read_timeout = timeout if timeout
|
46
|
+
http.use_ssl = false
|
47
|
+
http
|
48
|
+
end
|
49
|
+
|
50
|
+
def https(timeout:)
|
51
|
+
http = Net::HTTP.new(@host, @port)
|
52
|
+
http.read_timeout = timeout if timeout
|
53
|
+
http.use_ssl = true
|
54
|
+
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
55
|
+
http
|
56
|
+
end
|
57
|
+
|
58
|
+
def add_nexpose_session(request:)
|
59
|
+
request.add_field('nexposeCCSessionID', @nexpose_console.session_id)
|
60
|
+
request.add_field('Cookie', "nexposeCCSessionID=#{@nexpose_console.session_id}")
|
61
|
+
request.add_field('X-Requested-With', 'XMLHttpRequest')
|
62
|
+
end
|
63
|
+
|
64
|
+
def request(request:, timeout: nil)
|
65
|
+
http = https(timeout: timeout)
|
66
|
+
add_nexpose_session(request: request)
|
67
|
+
response = http.request(request)
|
68
|
+
case response
|
69
|
+
when Net::HTTPOK, Net::HTTPCreated
|
70
|
+
rv = nil
|
71
|
+
if response.content_type == "application/json" && !response.body.empty?
|
72
|
+
json_data = JSON.parse(response.body, symbolize_names: true)
|
73
|
+
json_data[:data].nil? ? rv = json_data : rv = json_data[:data]
|
74
|
+
end
|
75
|
+
rv
|
76
|
+
when Net::HTTPForbidden
|
77
|
+
raise "Access denied. Response was #{response.body}"
|
78
|
+
else
|
79
|
+
raise "There was an error sending the request. Response was #{response.body}"
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|