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.
- 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
|