nexpose_ticketing 0.8.3 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
- attr_accessor :servicedesk_data, :options, :log
7
-
8
- def initialize(servicedesk_data, options)
9
- @servicedesk_data = servicedesk_data
10
- @options = options
11
- @log = NexposeTicketing::NXLogger.new
12
-
13
- @rest_uri = servicedesk_data[:rest_uri]
14
- @api_key = servicedesk_data[:api_key]
15
- @ticket_db_path = servicedesk_data[:ticket_db_path]
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
- def open_database()
20
- DBM.open(@ticket_db_path, 0600, DBM::WRCREAT)
21
- end
48
+ workorderid
49
+ end
22
50
 
23
51
 
24
- def add_ticket_to_database(workorderid, nxid)
25
- @log.log_message("Adding ticket <#{workorderid}> for NXID <#{nxid}> to local db.")
26
- db = open_database()
27
- db[nxid] = workorderid
28
- db.close()
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
- def find_ticket_in_database(nxid)
33
- @log.log_message("Finding workorder id for NXID <#{nxid}> from local db.")
34
- db = open_database()
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
- def remove_ticket_from_database(nxid)
49
- @log.log_message("Removing workorder id from database for NXID <#{nxid}>")
50
- db = open_database()
51
- db.delete(nxid)
52
- db.close()
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
- def prepare_create_tickets(vulnerability_list, nexpose_identifier_id)
56
- @log.log_message('Preparing ticket requests...')
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
- ## Uses the configured or default options to set up a ticket creation request
73
- def create_ticket_request(subject, description)
74
- request = Nokogiri::XML::Builder.new do |xml|
75
- xml.Operation {
76
- xml.Details {
77
- xml.parameter {
78
- xml.name {
79
- xml.text 'requester'
80
- }
81
- xml.value {
82
- xml.text @servicedesk_data[:requestor]
83
- }
84
- }
85
- xml.parameter {
86
- xml.name {
87
- xml.text 'Group'
88
- }
89
- xml.value {
90
- xml.text @servicedesk_data[:group]
91
- }
92
- }
93
- xml.parameter {
94
- xml.name {
95
- xml.text 'subject'
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
- end
112
- return request.to_xml
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
- def modify_ticket_request(description)
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
- doc = Nokogiri::XML::Builder.new() do |xml|
127
- xml.Operation {
128
- xml.Details {
129
- xml.parameter {
130
- xml.name {
131
- xml.text 'Description'
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
- end
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
- ## Given a bunch of vulnerabilities that passed the filters, make tickets for each one
146
- def create_tickets_by_default(vulnerability_list, nexpose_identifier_id)
147
- @log.log_message('Preparing tickets by vulnerability...')
148
- tickets = []
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
- def create_tickets_by_ip(vulnerability_list, nexpose_identifier_id)
161
- @log.log_message('Preparing tickets by ip')
162
- tickets = []
163
- hostVulns = {}
164
- CSV.parse( vulnerability_list.chomp, headers: :first_row ) do |vuln|
165
- hostVulns["#{nexpose_identifier_id}#{vuln['ip_address']}"] = { :ip => vuln['ip_address'], :description => "" } if not hostVulns.has_key?("#{nexpose_identifier_id}#{vuln['ip_address']}")
166
- hostVulns["#{nexpose_identifier_id}#{vuln['ip_address']}"][:description] += "Summary: #{vuln['summary']}\nFix: #{vuln['fix']}\nURL: #{vuln['url']}\n\n"
167
- end
168
-
169
- hostVulns.each do |nxid, vulnInfo|
170
- tickets << { :action => :create, :nxid => nxid,
171
- :description => create_ticket_request( "Vulnerabilities on #{vulnInfo[:ip]}", vulnInfo[:description] ) }
172
- end
173
- return tickets
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
- def submit_ticket(ticket)
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
- def modify_ticket(ticket)
211
- @log.log_message("Connecting to #{@rest_uri}/#{ticket[:workorderid]}")
212
- uri = URI( "#{@rest_uri}/#{ticket[:workorderid]}" )
213
- res = Net::HTTP::post_form( uri,
214
- 'OPERATION_NAME' => 'EDIT_REQUEST',
215
- 'TECHNICIAN_KEY' => @api_key,
216
- 'INPUT_DATA' => ticket[:description] )
217
-
218
- response = Nokogiri::XML.parse( res.read_body )
219
- begin
220
- status = Integer(response.xpath('//statuscode').text)
221
- rescue Exception => e
222
- @log.log_message("XML request was #{ticket[:description]} response is #{response.to_xml}")
223
- raise e
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
- end
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
- tickets.each { |ticket| submit_ticket(ticket) }
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
- def prepare_update_tickets(vulnerability_list, nexpose_identifier_id)
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
- def update_tickets(tickets)
290
- @log.log_message('Updating tickets')
291
- tickets.each do |ticket|
292
- if ticket[:action] == :create
293
- @log.log_message('Creating ticket')
294
- submit_ticket(ticket)
295
- else
296
- @log.log_message("Updating ticket #{ticket[:workorderid]}")
297
- modify_ticket(ticket)
298
- end
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
- # Prepare ticket closures from the CSV of vulnerabilities exported from Nexpose.
304
- #
305
- # * *Args* :
306
- # - +vulnerability_list+ - CSV of vulnerabilities within Nexpose.
307
- #
308
- # * *Returns* :
309
- # - List of savon-formated (hash) tickets for closing within ServiceDesk.
310
- #
311
- def prepare_close_tickets(vulnerability_list, nexpose_identifier_id)
312
- fail 'Ticket closures are only supported in default mode.' if @options[:ticket_mode] == 'I'
313
- @log.log_message('Preparing ticket closures by default method.')
314
- @nxid = nil
315
- tickets = []
316
- CSV.parse(vulnerability_list.chomp, headers: :first_row) do |row|
317
- case @options[:ticket_mode]
318
- # 'D' Default mode: IP *-* Vulnerability
319
- when 'D'
320
- @nxid = "#{nexpose_identifier_id}#{row['asset_id']}#{row['vulnerability_id']}#{row['solution_id']}"
321
- # 'I' IP address mode: IP address -* Vulnerability
322
- when 'I'
323
- @nxid = "#{nexpose_identifier_id}#{row['current_ip']}"
324
- # 'V' Vulnerability mode: Vulnerability -* IP address
325
- # when 'V'
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
- def close_tickets( tickets )
344
- tickets.each { |ticket| close_ticket(ticket) if ticket[:action] == close && !ticket[:workorderid].nil?}
345
- end
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