nexpose_ticketing 0.8.3 → 1.0.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 +4 -4
- data/bin/nexpose_jira +7 -0
- data/bin/nexpose_remedy +6 -0
- data/bin/nexpose_servicedesk +6 -0
- data/bin/nexpose_servicenow +6 -0
- data/lib/nexpose_ticketing/common_helper.rb +344 -0
- data/lib/nexpose_ticketing/config/servicedesk.config +3 -3
- data/lib/nexpose_ticketing/config/ticket_service.config +2 -0
- data/lib/nexpose_ticketing/helpers/jira_helper.rb +53 -107
- data/lib/nexpose_ticketing/helpers/remedy_helper.rb +208 -594
- data/lib/nexpose_ticketing/helpers/servicedesk_helper.rb +302 -289
- data/lib/nexpose_ticketing/helpers/servicenow_helper.rb +74 -165
- data/lib/nexpose_ticketing/nx_logger.rb +139 -30
- data/lib/nexpose_ticketing/queries.rb +148 -59
- data/lib/nexpose_ticketing/ticket_repository.rb +6 -0
- data/lib/nexpose_ticketing/ticket_service.rb +28 -16
- data/lib/nexpose_ticketing/version.rb +3 -0
- metadata +14 -6
- data/Gemfile.lock +0 -67
@@ -1,118 +1,184 @@
|
|
1
1
|
require 'net/http'
|
2
2
|
require 'nokogiri'
|
3
3
|
require 'dbm'
|
4
|
+
require 'nexpose_ticketing/common_helper'
|
5
|
+
require 'nexpose_ticketing/nx_logger'
|
6
|
+
require 'nexpose_ticketing/version'
|
4
7
|
|
5
8
|
class ServiceDeskHelper
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
9
|
+
attr_accessor :servicedesk_data, :options, :log
|
10
|
+
|
11
|
+
def initialize(servicedesk_data, options)
|
12
|
+
@servicedesk_data = servicedesk_data
|
13
|
+
@options = options
|
14
|
+
@log = NexposeTicketing::NxLogger.instance
|
15
|
+
|
16
|
+
@rest_uri = servicedesk_data[:rest_uri]
|
17
|
+
@api_key = servicedesk_data[:api_key]
|
18
|
+
@ticket_db_path = servicedesk_data[:ticket_db_path]
|
19
|
+
@common_helper = NexposeTicketing::CommonHelper.new(@options)
|
20
|
+
end
|
21
|
+
|
22
|
+
|
23
|
+
def open_database()
|
24
|
+
DBM.open(@ticket_db_path, 0600, DBM::WRCREAT)
|
25
|
+
end
|
26
|
+
|
27
|
+
|
28
|
+
def add_ticket_to_database(workorderid, nxid)
|
29
|
+
@log.log_message("Adding ticket <#{workorderid}> for NXID <#{nxid}> to local db.")
|
30
|
+
db = open_database()
|
31
|
+
db[nxid] = workorderid
|
32
|
+
db.close()
|
33
|
+
end
|
34
|
+
|
35
|
+
|
36
|
+
def find_ticket_in_database(nxid)
|
37
|
+
@log.log_message("Finding workorder id for NXID <#{nxid}> from local db.")
|
38
|
+
db = open_database()
|
39
|
+
begin
|
40
|
+
workorderid = db[nxid]
|
41
|
+
@log.log_message("Lookup found incident <#{workorderid}> in the db.")
|
42
|
+
rescue Exception => e
|
43
|
+
@log.log_message("Threw an exception accessing the dbm <#{e.class} #{e} #{e.message}>.")
|
44
|
+
raise e
|
16
45
|
end
|
46
|
+
db.close()
|
17
47
|
|
18
|
-
|
19
|
-
|
20
|
-
DBM.open(@ticket_db_path, 0600, DBM::WRCREAT)
|
21
|
-
end
|
48
|
+
workorderid
|
49
|
+
end
|
22
50
|
|
23
51
|
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
52
|
+
def remove_tickets_from_database(tickets)
|
53
|
+
db = open_database()
|
54
|
+
tickets.each do |t|
|
55
|
+
nxid = t[:nxid]
|
56
|
+
@log.log_message("Removing workorder id from database for NXID <#{nxid}>")
|
57
|
+
db.delete(nxid) unless db[nxid].nil?
|
58
|
+
end
|
59
|
+
db.close()
|
60
|
+
end
|
61
|
+
|
62
|
+
|
63
|
+
def prepare_create_tickets(vulnerability_list, nexpose_identifier_id)
|
64
|
+
@log.log_message('Preparing ticket creation...')
|
65
|
+
case @options[:ticket_mode]
|
66
|
+
# 'D' Default IP *-* Vulnerability
|
67
|
+
when 'D' then matching_fields = ['ip_address', 'vulnerability_id']
|
68
|
+
# 'I' IP address -* Vulnerability
|
69
|
+
when 'I' then matching_fields = ['ip_address']
|
70
|
+
# 'V' Vulnerability -* Assets
|
71
|
+
when 'V' then matching_fields = ['vulnerability_id']
|
72
|
+
else
|
73
|
+
fail 'Unsupported ticketing mode selected.'
|
29
74
|
end
|
30
75
|
|
76
|
+
tickets = prepare_tickets(vulnerability_list, nexpose_identifier_id, matching_fields)
|
31
77
|
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
begin
|
36
|
-
workorderid = db[nxid]
|
37
|
-
@log.log_message("Lookup found incident <#{workorderid}> in the db.")
|
38
|
-
rescue Exception => e
|
39
|
-
@log.log_message("Threw an exception accessing the dbm <#{e.class} #{e} #{e.message}>.")
|
40
|
-
raise e
|
41
|
-
end
|
42
|
-
db.close()
|
78
|
+
tickets.each { |ticket| @log.log_message("Prepared ticket: #{ticket}")}
|
79
|
+
tickets
|
80
|
+
end
|
43
81
|
|
44
|
-
return workorderid
|
45
|
-
end
|
46
82
|
|
83
|
+
def prepare_tickets(vulnerability_list, nexpose_identifier_id, matching_fields)
|
84
|
+
@log.log_message("Preparing ticket for #{@options[:ticket_mode]} mode.")
|
85
|
+
tickets = []
|
86
|
+
host_vulns={}
|
87
|
+
previous_row = nil
|
88
|
+
description = nil
|
89
|
+
nxid = nil
|
47
90
|
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
91
|
+
initial_scan = false
|
92
|
+
|
93
|
+
CSV.parse( vulnerability_list.chomp, headers: :first_row ) do |row|
|
94
|
+
initial_scan = initial_scan || row['comparison'].nil?
|
95
|
+
|
96
|
+
if previous_row.nil?
|
97
|
+
nxid = @common_helper.generate_nxid(nexpose_identifier_id, row)
|
98
|
+
previous_row = row.dup
|
99
|
+
description = @common_helper.get_description(nexpose_identifier_id, row)
|
100
|
+
|
101
|
+
host_vulns[nxid] = { :ip => row['ip_address'],
|
102
|
+
:description => "",
|
103
|
+
:title => @common_helper.get_title(row) }
|
104
|
+
elsif matching_fields.any? { |x| previous_row[x].nil? || previous_row[x] != row[x] }
|
105
|
+
nxid = @common_helper.generate_nxid(nexpose_identifier_id, previous_row)
|
106
|
+
info = @common_helper.get_field_info(matching_fields, previous_row)
|
107
|
+
@log.log_message("Generated ticket with #{info}")
|
108
|
+
|
109
|
+
host_vulns[nxid][:description] = @common_helper.print_description(description)
|
110
|
+
previous_row = nil
|
111
|
+
description = nil
|
112
|
+
redo
|
113
|
+
else
|
114
|
+
description = @common_helper.update_description(description, row)
|
115
|
+
end
|
53
116
|
end
|
54
117
|
|
55
|
-
|
56
|
-
|
57
|
-
case @options[:ticket_mode]
|
58
|
-
# 'D' Default mode: IP *-* Vulnerability
|
59
|
-
when 'D'
|
60
|
-
tickets = create_tickets_by_default(vulnerability_list, nexpose_identifier_id)
|
61
|
-
# 'I' IP address mode: IP address -* Vulnerability
|
62
|
-
when 'I'
|
63
|
-
tickets = create_tickets_by_ip(vulnerability_list, nexpose_identifier_id)
|
64
|
-
else
|
65
|
-
fail 'No ticketing mode selected.'
|
66
|
-
end
|
67
|
-
|
68
|
-
tickets.each { |ticket| @log.log_message("Prepared ticket: #{ticket}")}
|
69
|
-
return tickets
|
118
|
+
unless host_vulns[nxid].nil? || host_vulns[nxid].empty?
|
119
|
+
host_vulns[nxid][:description] = @common_helper.print_description(description)
|
70
120
|
end
|
71
121
|
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
}
|
97
|
-
xml.value {
|
98
|
-
xml.text subject
|
99
|
-
}
|
100
|
-
}
|
101
|
-
xml.parameter {
|
102
|
-
xml.name {
|
103
|
-
xml.text 'description'
|
104
|
-
}
|
105
|
-
xml.value {
|
106
|
-
xml.cdata description
|
107
|
-
}
|
108
|
-
}
|
109
|
-
}
|
122
|
+
host_vulns.each do |nxid, vuln_info|
|
123
|
+
workorderid = initial_scan ? nil : find_ticket_in_database(nxid)
|
124
|
+
if workorderid.nil? || workorderid.empty?
|
125
|
+
@log.log_message("Creating new incident for assetid #{nxid}")
|
126
|
+
tickets << { :action => :create, :nxid => nxid,
|
127
|
+
:description => create_ticket_request(vuln_info[:title], vuln_info[:description]) }
|
128
|
+
else
|
129
|
+
@log.log_message("Updating incident for assetid #{nxid}")
|
130
|
+
tickets << { :action => :modify, :nxid => nxid,
|
131
|
+
:workorderid => workorderid,
|
132
|
+
:description => modify_ticket_request(vuln_info[:description]) }
|
133
|
+
end
|
134
|
+
end
|
135
|
+
tickets
|
136
|
+
end
|
137
|
+
|
138
|
+
## Uses the configured or default options to set up a ticket creation request
|
139
|
+
def create_ticket_request(subject, description)
|
140
|
+
request = Nokogiri::XML::Builder.new do |xml|
|
141
|
+
xml.Operation {
|
142
|
+
xml.Details {
|
143
|
+
xml.parameter {
|
144
|
+
xml.name {
|
145
|
+
xml.text 'requester'
|
110
146
|
}
|
111
|
-
|
112
|
-
|
147
|
+
xml.value {
|
148
|
+
xml.text @servicedesk_data[:requester]
|
149
|
+
}
|
150
|
+
}
|
151
|
+
xml.parameter {
|
152
|
+
xml.name {
|
153
|
+
xml.text 'Group'
|
154
|
+
}
|
155
|
+
xml.value {
|
156
|
+
xml.text @servicedesk_data[:group]
|
157
|
+
}
|
158
|
+
}
|
159
|
+
xml.parameter {
|
160
|
+
xml.name {
|
161
|
+
xml.text 'subject'
|
162
|
+
}
|
163
|
+
xml.value {
|
164
|
+
xml.text subject
|
165
|
+
}
|
166
|
+
}
|
167
|
+
xml.parameter {
|
168
|
+
xml.name {
|
169
|
+
xml.text 'description'
|
170
|
+
}
|
171
|
+
xml.value {
|
172
|
+
xml.cdata description
|
173
|
+
}
|
174
|
+
}
|
175
|
+
}
|
176
|
+
}
|
113
177
|
end
|
178
|
+
request.to_xml
|
179
|
+
end
|
114
180
|
|
115
|
-
|
181
|
+
def modify_ticket_request(description)
|
116
182
|
# modifyRequest = """
|
117
183
|
# <Operation>
|
118
184
|
# <Details>
|
@@ -123,224 +189,171 @@ class ServiceDeskHelper
|
|
123
189
|
# </Details>
|
124
190
|
# </Operation>
|
125
191
|
# """
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
}
|
133
|
-
xml.value {
|
134
|
-
xml.cdata description
|
135
|
-
}
|
136
|
-
}
|
192
|
+
doc = Nokogiri::XML::Builder.new() do |xml|
|
193
|
+
xml.Operation {
|
194
|
+
xml.Details {
|
195
|
+
xml.parameter {
|
196
|
+
xml.name {
|
197
|
+
xml.text 'requester'
|
137
198
|
}
|
138
|
-
|
199
|
+
xml.value {
|
200
|
+
xml.text @servicedesk_data[:requester]
|
201
|
+
}
|
202
|
+
}
|
203
|
+
xml.parameter {
|
204
|
+
xml.name {
|
205
|
+
xml.text 'description'
|
206
|
+
}
|
207
|
+
xml.value {
|
208
|
+
xml.cdata description
|
209
|
+
}
|
210
|
+
}
|
139
211
|
}
|
140
|
-
|
141
|
-
|
142
|
-
return doc.to_xml
|
212
|
+
}
|
143
213
|
end
|
214
|
+
doc.to_xml
|
215
|
+
end
|
216
|
+
|
217
|
+
def submit_ticket(ticket)
|
218
|
+
@log.log_message("Connecting to #{@rest_uri}.")
|
219
|
+
uri = URI( @rest_uri )
|
220
|
+
res = Net::HTTP::post_form(uri,
|
221
|
+
'OPERATION_NAME' => 'ADD_REQUEST',
|
222
|
+
'TECHNICIAN_KEY' => @api_key,
|
223
|
+
'INPUT_DATA' => ticket[:description])
|
224
|
+
|
225
|
+
response = Nokogiri::XML.parse(res.read_body)
|
226
|
+
begin
|
227
|
+
status = response.xpath('//statuscode').text
|
228
|
+
status_code = status.empty? ? -1 : Integer(status)
|
229
|
+
|
230
|
+
if status_code != 200
|
231
|
+
@log.log_message("Unable to create ticket #{ticket}, got response #{response.to_xml}")
|
232
|
+
return
|
233
|
+
end
|
144
234
|
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
CSV.parse( vulnerability_list.chomp, headers: :first_row ) do |vuln|
|
150
|
-
subject = "#{vuln['ip_address']}: #{vuln['summary']}"
|
151
|
-
description = "Host: #{ip_address}\nSummary: #{vuln['summary']}\nFix: #{vuln['fix']}\nURL: #{vuln['url']}"
|
152
|
-
|
153
|
-
tickets << { :action => :create, :nxid => "#{nexpose_identifier_id}#{vuln['asset_id']}#{vuln['vulnerability_id']}#{vuln['solution_id']}",
|
154
|
-
:description => create_ticket_request( subject, description ) }
|
155
|
-
end
|
156
|
-
return tickets
|
235
|
+
workorderid = Integer(response.xpath('//workorderid').text)
|
236
|
+
rescue ArgumentError => ae
|
237
|
+
@log.log_message("Failed to parse response from servicedesk #{response}")
|
238
|
+
raise ae
|
157
239
|
end
|
158
240
|
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
241
|
+
@log.log_message( "created ticket #{workorderid}")
|
242
|
+
add_ticket_to_database( workorderid, ticket[:nxid] )
|
243
|
+
end
|
244
|
+
|
245
|
+
|
246
|
+
def modify_ticket(ticket)
|
247
|
+
@log.log_message("Connecting to #{@rest_uri}/#{ticket[:workorderid]}")
|
248
|
+
uri = URI( "#{@rest_uri}/#{ticket[:workorderid]}")
|
249
|
+
res = Net::HTTP::post_form(uri,
|
250
|
+
'OPERATION_NAME' => 'EDIT_REQUEST',
|
251
|
+
'TECHNICIAN_KEY' => @api_key,
|
252
|
+
'INPUT_DATA' => ticket[:description])
|
253
|
+
|
254
|
+
response = Nokogiri::XML.parse(res.read_body)
|
255
|
+
begin
|
256
|
+
status = Integer(response.xpath('//statuscode').text)
|
257
|
+
rescue Exception => e
|
258
|
+
@log.log_message("XML request was #{ticket[:description]} response is #{response.to_xml}")
|
259
|
+
raise e
|
174
260
|
end
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
@log.log_message("Connecting to #{@rest_uri}.")
|
179
|
-
uri = URI( @rest_uri )
|
180
|
-
res = Net::HTTP::post_form( uri,
|
181
|
-
'OPERATION_NAME' => 'ADD_REQUEST',
|
182
|
-
'TECHNICIAN_KEY' => @api_key,
|
183
|
-
'INPUT_DATA' => ticket[:description] )
|
184
|
-
|
185
|
-
response = Nokogiri::XML.parse( res.read_body )
|
186
|
-
begin
|
187
|
-
status = response.xpath('//statuscode').text
|
188
|
-
if status.empty?
|
189
|
-
status_code = -1
|
190
|
-
else
|
191
|
-
status_code = Integer( status )
|
192
|
-
end
|
193
|
-
|
194
|
-
if status_code != 200
|
195
|
-
@log.log_message("Unable to create ticket #{ticket}, got response #{response.to_xml}")
|
196
|
-
return
|
197
|
-
end
|
198
|
-
|
199
|
-
workorderid = Integer(response.xpath('//workorderid').text)
|
200
|
-
rescue ArgumentError => ae
|
201
|
-
@log.log_message("Failed to parse response from servicedesk #{response}")
|
202
|
-
raise ae
|
203
|
-
end
|
204
|
-
|
205
|
-
@log.log_message( "created ticket #{workorderid}")
|
206
|
-
add_ticket_to_database( workorderid, ticket[:nxid] )
|
261
|
+
|
262
|
+
unless status == 200
|
263
|
+
@log.log_message("Unable to modify ticket #{ticket}, got response #{response.to_xml}")
|
207
264
|
end
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
end
|
225
|
-
|
226
|
-
if status != 200
|
227
|
-
@log.log_message("Unable to modify ticket #{ticket}, got response #{response.to_xml}")
|
228
|
-
return
|
229
|
-
end
|
265
|
+
end
|
266
|
+
|
267
|
+
|
268
|
+
def close_ticket(ticket)
|
269
|
+
@log.log_message("Connecting to #{@rest_uri}/#{ticket[:workorderid]}")
|
270
|
+
uri = URI( "#{@rest_uri}/#{ticket[:workorderid]}" )
|
271
|
+
res = Net::HTTP::post_form(uri,
|
272
|
+
'OPERATION_NAME' => 'CLOSE_REQUEST',
|
273
|
+
'TECHNICIAN_KEY' => @api_key)
|
274
|
+
|
275
|
+
response = Nokogiri::XML.parse(res.read_body)
|
276
|
+
begin
|
277
|
+
status = Integer(response.xpath('//statuscode').text)
|
278
|
+
rescue Exception => e
|
279
|
+
@log.log_message("XML request was #{ticket[:description]} response is #{response.to_xml}")
|
280
|
+
raise e
|
230
281
|
end
|
231
282
|
|
283
|
+
unless status == 200
|
284
|
+
@log.log_message("Unable to close ticket #{ticket}, got response #{response.to_xml}")
|
285
|
+
end
|
286
|
+
end
|
232
287
|
|
233
|
-
def close_ticket(ticket)
|
234
|
-
@log.log_message("Connecting to #{@rest_uri}/#{ticket[:workorderid]}")
|
235
|
-
uri = URI( "#{@rest_uri}/#{ticket[:workorderid]}" )
|
236
|
-
res = Net::HTTP::post_form( uri,
|
237
|
-
'OPERATION_NAME' => 'CLOSE_REQUEST',
|
238
|
-
'TECHNICIAN_KEY' => @api_key )
|
239
|
-
|
240
|
-
response = Nokogiri::XML.parse( res.read_body )
|
241
|
-
begin
|
242
|
-
status = Integer(response.xpath('//statuscode').text)
|
243
|
-
rescue Exception => e
|
244
|
-
@log.log_message("XML request was #{ticket[:description]} response is #{response.to_xml}")
|
245
|
-
raise e
|
246
|
-
end
|
247
|
-
|
248
|
-
if status != 200
|
249
|
-
@log.log_message("Unable to close ticket #{ticket}, got response #{response.to_xml}")
|
250
|
-
return
|
251
|
-
end
|
252
288
|
|
253
|
-
|
289
|
+
def create_tickets(tickets)
|
290
|
+
@log.log_message("Creating tickets on server at #{@rest_uri}")
|
254
291
|
|
292
|
+
tickets.each { |ticket| submit_ticket(ticket) }
|
293
|
+
end
|
255
294
|
|
256
|
-
def create_tickets(tickets)
|
257
|
-
@log.log_message("Creating tickets on server at #{@rest_uri}")
|
258
295
|
|
259
|
-
|
296
|
+
def prepare_update_tickets(vulnerability_list, nexpose_identifier_id)
|
297
|
+
@log.log_message('Preparing ticket updates...')
|
298
|
+
case @options[:ticket_mode]
|
299
|
+
# 'D' Default IP *-* Vulnerability
|
300
|
+
when 'D' then fail 'Ticket updates are not supported in Default mode.'
|
301
|
+
# 'I' IP address -* Vulnerability
|
302
|
+
when 'I' then matching_fields = ['ip_address']
|
303
|
+
# 'V' Vulnerability -* Assets
|
304
|
+
when 'V' then matching_fields = ['vulnerability_id']
|
305
|
+
else
|
306
|
+
fail 'Unsupported ticketing mode selected.'
|
260
307
|
end
|
261
308
|
|
262
|
-
|
263
|
-
|
264
|
-
fail 'Ticket updates are only supported in IP-address mode.' if @options[:ticket_mode] != 'I'
|
265
|
-
|
266
|
-
@log.log_message('Preparing ticket updates by IP address.')
|
267
|
-
tickets = []
|
268
|
-
hostVulns={}
|
269
|
-
CSV.parse( vulnerability_list.chomp, headers: :first_row ) do |vuln|
|
270
|
-
hostVulns["#{nexpose_identifier_id}#{vuln['ip_address']}"] = { :ip => vuln['ip_address'], :description => "" } if not hostVulns.has_key?(vuln['asset_id'])
|
271
|
-
hostVulns["#{nexpose_identifier_id}#{vuln['ip_address']}"][:description] += "Summary: #{vuln['summary']}\nFix: #{vuln['fix']}\nURL: #{vuln['url']}\n\n"
|
272
|
-
end
|
273
|
-
|
274
|
-
hostVulns.each do |nxid, vulnInfo|
|
275
|
-
workorderid = find_ticket_in_database(nxid)
|
276
|
-
if workorderid.nil? || workorderid.empty?
|
277
|
-
@log.log_message("No incident found for assetid #{nxid}, using defaults")
|
278
|
-
tickets << { :action => :create, :nxid => nxid,
|
279
|
-
:description => create_ticket_request("Vulnerabilities on #{vulnInfo[:ip]}", vulnInfo[:description]) }
|
280
|
-
else
|
281
|
-
tickets << { :action => :modifty, :nxid => nxid, :workorderid => workorderid,
|
282
|
-
:description => modify_ticket_request( vulnInfo[:description] ) }
|
283
|
-
end
|
284
|
-
end
|
285
|
-
return tickets
|
286
|
-
end
|
309
|
+
prepare_tickets(vulnerability_list, nexpose_identifier_id, matching_fields)
|
310
|
+
end
|
287
311
|
|
288
312
|
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
end
|
313
|
+
def update_tickets(tickets)
|
314
|
+
@log.log_message('Updating tickets')
|
315
|
+
tickets.each do |ticket|
|
316
|
+
if ticket[:action] == :create
|
317
|
+
@log.log_message('Creating ticket')
|
318
|
+
submit_ticket(ticket)
|
319
|
+
else
|
320
|
+
@log.log_message("Updating ticket #{ticket[:workorderid]}")
|
321
|
+
modify_ticket(ticket)
|
322
|
+
end
|
300
323
|
end
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
# @NXID = "#{nexpose_identifier_id}#{row['current_asset_id']}#{row['current_vuln_id']}"
|
327
|
-
else
|
328
|
-
fail 'Could not close tickets - do not understand the ticketing mode!'
|
329
|
-
end
|
330
|
-
workorderid = find_ticket_in_database(@nxid)
|
331
|
-
# Query ServiceDesk for the incident by unique id (generated NXID)
|
332
|
-
if workorderid.nil? || workorderid.empty?
|
333
|
-
@log.log_message("No workorderid found for NXID #{@nxid}")
|
334
|
-
else
|
335
|
-
tickets << { :action => :close, :nxid => @nxid, :workorderid => workorderid,
|
336
|
-
:description => closeTicketRequest() }
|
337
|
-
end
|
324
|
+
end
|
325
|
+
|
326
|
+
# Prepare ticket closures from the CSV of vulnerabilities exported from Nexpose.
|
327
|
+
#
|
328
|
+
# * *Args* :
|
329
|
+
# - +vulnerability_list+ - CSV of vulnerabilities within Nexpose.
|
330
|
+
#
|
331
|
+
# * *Returns* :
|
332
|
+
# - List of savon-formated (hash) tickets for closing within ServiceDesk.
|
333
|
+
#
|
334
|
+
def prepare_close_tickets(vulnerability_list, nexpose_identifier_id)
|
335
|
+
@log.log_message("Preparing ticket closures for mode #{@options[:ticket_mode]}.")
|
336
|
+
@nxid = nil
|
337
|
+
tickets = []
|
338
|
+
CSV.parse(vulnerability_list.chomp, headers: :first_row) do |row|
|
339
|
+
@nxid = @common_helper.generate_nxid(nexpose_identifier_id, row)
|
340
|
+
|
341
|
+
workorderid = find_ticket_in_database(@nxid)
|
342
|
+
# Query ServiceDesk for the incident by unique id (generated NXID)
|
343
|
+
if workorderid.nil? || workorderid.empty?
|
344
|
+
@log.log_message("No workorderid found for NXID #{@nxid}")
|
345
|
+
else
|
346
|
+
tickets << { :action => :close, :nxid => @nxid,
|
347
|
+
:workorderid => workorderid,
|
348
|
+
:description => 'Automatically closing ticket.' }
|
338
349
|
end
|
339
|
-
return tickets
|
340
350
|
end
|
351
|
+
tickets
|
352
|
+
end
|
341
353
|
|
342
354
|
|
343
|
-
|
344
|
-
|
345
|
-
|
355
|
+
def close_tickets( tickets )
|
356
|
+
tickets.each { |ticket| close_ticket(ticket) if ticket[:action] == :close && !ticket[:workorderid].nil?}
|
357
|
+
remove_tickets_from_database(tickets)
|
358
|
+
end
|
346
359
|
end
|