Class: RemedyHelper
- Inherits:
-
Object
- Object
- RemedyHelper
- Defined in:
- lib/nexpose_ticketing/helpers/remedy_helper.rb
Overview
Serves as the Remedy interface for creating/updating issues from vulnelrabilities found in Nexpose.
Instance Attribute Summary collapse
-
#client ⇒ Object
Returns the value of attribute client.
-
#log ⇒ Object
Returns the value of attribute log.
-
#options ⇒ Object
Returns the value of attribute options.
-
#remedy_data ⇒ Object
Returns the value of attribute remedy_data.
Instance Method Summary collapse
-
#close_tickets(tickets) ⇒ Object
Sends ticket closure (in SOAP format) to Remedy individually (each ticket in the list as a separate web service call).
-
#create_tickets(tickets) ⇒ Object
Sends a list of tickets (in SOAP format) to Remedy individually (each ticket in the list as a separate web service call).
-
#extract_queried_incident(queried_incident, notes_header) ⇒ Object
Extracts from a queried Remedy incident the relevant data required for an update to be made to said incident.
-
#generate_new_ticket(extra_fields = nil) ⇒ Object
Generates a savon-based ticket object.
-
#get_client(wdsl, endpoint) ⇒ Object
Sends a list of tickets (in SOAP format) to Remedy individually (each ticket in the list as a separate web service call).
-
#initialize(remedy_data, options) ⇒ RemedyHelper
constructor
A new instance of RemedyHelper.
-
#prepare_close_tickets(vulnerability_list, nexpose_identifier_id) ⇒ Object
Prepare ticket closures from the CSV of vulnerabilities exported from Nexpose.
-
#prepare_create_tickets(vulnerability_list, nexpose_identifier_id) ⇒ Object
Prepare tickets from the CSV of vulnerabilities exported from Nexpose.
-
#prepare_tickets(vulnerability_list, nexpose_identifier_id, matching_fields) ⇒ Object
Prepares a list of vulnerabilities into a list of savon-formatted tickets (incidents) for Remedy.
-
#prepare_update_tickets(vulnerability_list, nexpose_identifier_id) ⇒ Object
Prepare to update tickets from the CSV of vulnerabilities exported from Nexpose.
-
#query_for_ticket(unique_id) ⇒ Object
Sends a query (in SOAP format) to Remedy to return back a single ticket based on the criteria.
-
#send_tickets(client, service, tickets) ⇒ Object
Sends a list of tickets (in SOAP format) to Remedy individually (each ticket in the list as a separate web service call).
-
#ticket_from_queried_incident(queried_incident, notes_header, status) ⇒ Object
Creates a ticket with the extracted data from a queried Remedy incident.
-
#update_tickets(tickets) ⇒ Object
Sends ticket updates (in SOAP format) to Remedy individually (each ticket in the list as a separate web service call).
Constructor Details
#initialize(remedy_data, options) ⇒ RemedyHelper
Returns a new instance of RemedyHelper.
15 16 17 18 19 20 |
# File 'lib/nexpose_ticketing/helpers/remedy_helper.rb', line 15 def initialize(remedy_data, ) @remedy_data = remedy_data @options = @log = NexposeTicketing::NxLogger.instance @common_helper = NexposeTicketing::CommonHelper.new(@options) end |
Instance Attribute Details
#client ⇒ Object
Returns the value of attribute client.
14 15 16 |
# File 'lib/nexpose_ticketing/helpers/remedy_helper.rb', line 14 def client @client end |
#log ⇒ Object
Returns the value of attribute log.
14 15 16 |
# File 'lib/nexpose_ticketing/helpers/remedy_helper.rb', line 14 def log @log end |
#options ⇒ Object
Returns the value of attribute options.
14 15 16 |
# File 'lib/nexpose_ticketing/helpers/remedy_helper.rb', line 14 def @options end |
#remedy_data ⇒ Object
Returns the value of attribute remedy_data.
14 15 16 |
# File 'lib/nexpose_ticketing/helpers/remedy_helper.rb', line 14 def remedy_data @remedy_data end |
Instance Method Details
#close_tickets(tickets) ⇒ Object
Sends ticket closure (in SOAP format) to Remedy individually (each ticket in the list as a separate web service call).
-
Args :
-
tickets- List of savon-formatted (hash) ticket closures.
-
123 124 125 126 127 128 129 130 |
# File 'lib/nexpose_ticketing/helpers/remedy_helper.rb', line 123 def close_tickets(tickets) if tickets.nil? || tickets.empty? @log.("No tickets to close.") return end client = get_client('HPD_IncidentInterface_WS.xml', :query_modify_soap_endpoint) send_tickets(client, :help_desk_modify_service, tickets) end |
#create_tickets(tickets) ⇒ Object
Sends a list of tickets (in SOAP format) to Remedy individually (each ticket in the list as a separate web service call).
-
Args :
-
tickets- List of savon-formatted (hash) ticket creates (new tickets).
-
96 97 98 99 100 |
# File 'lib/nexpose_ticketing/helpers/remedy_helper.rb', line 96 def create_tickets(tickets) fail 'Ticket(s) cannot be empty' if tickets.nil? || tickets.empty? client = get_client('HPD_IncidentInterface_Create_WS.xml', :create_soap_endpoint) send_tickets(client, :help_desk_submit_service, tickets) end |
#extract_queried_incident(queried_incident, notes_header) ⇒ Object
Extracts from a queried Remedy incident the relevant data required for an update to be made to said incident. Creates a ticket with the extracted data.
- +queried_incident+ - The queried incident from Remedy
- +notes_header+ - The texted to be placed at the top of the Remedy 'Notes' field.
-
Returns :
-
A single savon-formated (hash) ticket for updating within Remedy.
-
349 350 351 352 353 354 355 356 |
# File 'lib/nexpose_ticketing/helpers/remedy_helper.rb', line 349 def extract_queried_incident(queried_incident, notes_header) unless queried_incident.first.is_a?(Hash) return ticket_from_queried_incident(queried_incident, notes_header, nil) end fail "Multiple tickets returned for same NXID" if queried_incidents.count > 1 ticket_from_queried_incident(queried_incident.first, notes_header, nil) end |
#generate_new_ticket(extra_fields = nil) ⇒ Object
Generates a savon-based ticket object.
-
Args :
-
extra_fields- List of mode-specific fields (hash) to be added to the ticket.
-
27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 |
# File 'lib/nexpose_ticketing/helpers/remedy_helper.rb', line 27 def generate_new_ticket(extra_fields=nil) base_ticket = { 'First_Name' => "#{@remedy_data[:first_name]}", 'Impact' => '1-Extensive/Widespread', 'Last_Name' => "#{@remedy_data[:last_name]}", 'Reported_Source' => 'Other', 'Service_Type' => 'Infrastructure Event', 'Status' => 'New', 'Action' => 'CREATE', "Summary"=>"", "Notes"=>"", 'Urgency' => '1-Critical', } extra_fields.each { |k, v| base_ticket[k.to_s] = v } if extra_fields base_ticket end |
#get_client(wdsl, endpoint) ⇒ Object
Sends a list of tickets (in SOAP format) to Remedy individually (each ticket in the list as a separate web service call).
-
Args :
-
wdsl- XML file which describes the network service. -
endpoint- Endpoint to which the data will be submitted.
-
51 52 53 54 55 56 57 58 59 60 61 62 63 64 |
# File 'lib/nexpose_ticketing/helpers/remedy_helper.rb', line 51 def get_client(wdsl, endpoint) Savon.client(wsdl: File.join(File.dirname(__FILE__), "../config/remedy_wsdl/#{wdsl}"), adapter: :net_http, ssl_verify_mode: :none, open_timeout: @remedy_data[:open_timeout], read_timeout: @remedy_data[:read_timeout], endpoint: @remedy_data[endpoint.intern], soap_header: { 'AuthenticationInfo' => { 'userName' => "#{@remedy_data[:username]}", 'password' => "#{@remedy_data[:password]}", 'authentication' => "#{@remedy_data[:authentication]}" } }) end |
#prepare_close_tickets(vulnerability_list, nexpose_identifier_id) ⇒ Object
Prepare ticket closures from the CSV of vulnerabilities exported from Nexpose.
-
Args :
-
vulnerability_list- CSV of vulnerabilities within Nexpose.
-
-
Returns :
-
List of savon-formated (hash) tickets for closing within Remedy.
-
366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 |
# File 'lib/nexpose_ticketing/helpers/remedy_helper.rb', line 366 def prepare_close_tickets(vulnerability_list, nexpose_identifier_id) @log.("Preparing ticket closures for mode #{@options[:ticket_mode]}.") @nxid = nil tickets = [] CSV.parse(vulnerability_list.chomp, headers: :first_row) do |row| @nxid = @common_helper.generate_nxid(nexpose_identifier_id, row) # Query Remedy for the incident by unique id (generated NXID) queried_incident = query_for_ticket("NXID: #{@nxid}") if queried_incident.nil? || queried_incident.empty? @log.("No incident found for NXID: #{@nxid}") else # Remedy incident updates require populating all fields. ticket = ticket_from_queried_incident(queried_incident, nil, 'Closed') tickets.push(ticket) end end tickets end |
#prepare_create_tickets(vulnerability_list, nexpose_identifier_id) ⇒ Object
Prepare tickets from the CSV of vulnerabilities exported from Nexpose. This method determines how to prepare the tickets (by default, by IP address or by vulnerability) based on config options.
-
Args :
-
vulnerability_list- CSV of vulnerabilities within Nexpose.
-
-
Returns :
-
List of savon-formated (hash) tickets for creating within Remedy.
-
166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 |
# File 'lib/nexpose_ticketing/helpers/remedy_helper.rb', line 166 def prepare_create_tickets(vulnerability_list, nexpose_identifier_id) @log.('Preparing ticket requests...') case @options[:ticket_mode] # 'D' Default IP *-* Vulnerability when 'D' then matching_fields = ['ip_address', 'vulnerability_id'] # 'I' IP address -* Vulnerability when 'I' then matching_fields = ['ip_address'] # 'V' Vulnerability -* Assets when 'V' then matching_fields = ['vulnerability_id'] else fail 'Unsupported ticketing mode selected.' end prepare_tickets(vulnerability_list, nexpose_identifier_id, matching_fields) end |
#prepare_tickets(vulnerability_list, nexpose_identifier_id, matching_fields) ⇒ Object
Prepares a list of vulnerabilities into a list of savon-formatted tickets (incidents) for Remedy.
-
Args :
-
vulnerability_list- CSV of vulnerabilities within Nexpose.
-
-
Returns :
-
List of savon-formated (hash) tickets for creating within Remedy.
-
215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 |
# File 'lib/nexpose_ticketing/helpers/remedy_helper.rb', line 215 def prepare_tickets(vulnerability_list, nexpose_identifier_id, matching_fields) @ticket = Hash.new(-1) @log.("Preparing tickets for #{@options[:ticket_mode]} mode.") tickets = [] previous_row = nil description = nil CSV.parse(vulnerability_list.chomp, headers: :first_row) do |row| if previous_row.nil? previous_row = row.dup description = @common_helper.get_description(nexpose_identifier_id, row) @ticket = generate_new_ticket({'Summary' => "#{@common_helper.get_title(row, 100)}", 'Notes' => ""}) #Skip querying for ticket if it's the initial scan next if row['comparison'].nil? # Query Remedy for the incident by unique id (generated NXID) queried_incident = query_for_ticket("NXID: #{@common_helper.generate_nxid(nexpose_identifier_id, row)}") if !queried_incident.nil? && queried_incident.first.is_a?(Hash) queried_incident.select! { |t| !['Closed', 'Resolved', 'Cancelled'].include?(t[:status]) } end if queried_incident.nil? || queried_incident.empty? @log.("No incident found for NXID: #{@common_helper.generate_nxid(nexpose_identifier_id, row)}. Creating...") new_ticket_csv = vulnerability_list.split("\n").first new_ticket_csv += "\n#{row.to_s}" #delete the comparison row data = CSV::Table.new(CSV.parse(new_ticket_csv, headers: true)) data.delete("comparison") new_ticket = prepare_create_tickets(data.to_s, nexpose_identifier_id) @log.('Created ticket. Sending to Remedy...') create_tickets(new_ticket) @log.('Ticket sent. Performing update for ticket...') #Now that there is a ticket for this NXID update it as if it existed this whole time... previous_row = nil redo else info = @common_helper.get_field_info(matching_fields, previous_row) @log.("Creating ticket update with #{info} for Nexpose Identifier with ID: #{nexpose_identifier_id}") @log.("Ticket status #{row['comparison']}") # Remedy incident updates require populating all fields. @ticket = extract_queried_incident(queried_incident, "") end elsif matching_fields.any? { |x| previous_row[x].nil? || previous_row[x] != row[x] } info = @common_helper.get_field_info(matching_fields, previous_row) @log.("Generated ticket with #{info}") @ticket['Notes'] = @common_helper.print_description(description) tickets.push(@ticket) previous_row = nil description = nil redo else description = @common_helper.update_description(description, row) end end unless @ticket.nil? || @ticket.empty? @ticket['Notes'] = @common_helper.print_description(description) tickets.push(@ticket) end @log.("Generated <#{tickets.count.to_s}> tickets.") tickets end |
#prepare_update_tickets(vulnerability_list, nexpose_identifier_id) ⇒ Object
Prepare to update tickets from the CSV of vulnerabilities exported from Nexpose. This method determines how to prepare the tickets for update (by IP address or by vulnerability) based on config options.
-
Args :
-
vulnerability_list- CSV of vulnerabilities within Nexpose.
-
-
Returns :
-
List of savon-formated (hash) tickets for creating within Remedy.
-
191 192 193 194 195 196 197 198 199 200 201 202 203 204 |
# File 'lib/nexpose_ticketing/helpers/remedy_helper.rb', line 191 def prepare_update_tickets(vulnerability_list, nexpose_identifier_id) case @options[:ticket_mode] # 'D' Default IP *-* Vulnerability when 'D' then fail 'Ticket updates are not supported in Default mode.' # 'I' IP address -* Vulnerability when 'I' then matching_fields = ['ip_address'] # 'V' Vulnerability -* Assets when 'V' then matching_fields = ['vulnerability_id'] else fail 'Unsupported ticketing mode selected.' end prepare_tickets(vulnerability_list, nexpose_identifier_id, matching_fields) end |
#query_for_ticket(unique_id) ⇒ Object
Sends a query (in SOAP format) to Remedy to return back a single ticket based on the criteria.
-
Args :
-
unique_id- Unique identifier generated by the helper.
-
-
Returns :
-
Remedy incident information in hash format or nil if no results are found.
-
140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 |
# File 'lib/nexpose_ticketing/helpers/remedy_helper.rb', line 140 def query_for_ticket(unique_id) client = get_client('HPD_IncidentInterface_WS.xml', :query_modify_soap_endpoint) begin response = client.call(:help_desk_query_list_service, message: {'Qualification' => "'Status' < \"Closed\" AND 'Detailed Decription' LIKE \"%#{unique_id}%\""}) rescue Savon::SOAPFault => e @log.("SOAP exception in query ticket: #{e.}") return if e.to_hash[:fault][:faultstring].index("ERROR (302)") == 0 raise rescue Savon::HTTPError => e @log.("HTTP error in query ticket: #{e.}") raise end response.body[:help_desk_query_list_service_response][:get_list_values] end |
#send_tickets(client, service, tickets) ⇒ Object
Sends a list of tickets (in SOAP format) to Remedy individually (each ticket in the list as a separate web service call).
-
Args :
-
service- The helpdesk service to which the tickets should be submitted. -
tickets- List of savon-formatted (hash) ticket creates (new tickets).
-
73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 |
# File 'lib/nexpose_ticketing/helpers/remedy_helper.rb', line 73 def send_tickets(client, service, tickets) service_name = service.to_s.match(/desk_([a-z]*)_/) service_name = service_name.captures.first unless service_name.nil? tickets.each do |ticket| begin @log.(ticket) response = client.call(service, message: ticket) rescue Savon::SOAPFault => e @log.("SOAP exception in #{service_name} ticket: #{e.}") raise rescue Savon::HTTPError => e @log.("HTTP error in #{service_name} ticket: #{e.}") raise end end end |
#ticket_from_queried_incident(queried_incident, notes_header, status) ⇒ Object
Creates a ticket with the extracted data from a queried Remedy incident.
- +queried_incident+ - The queried incident from Remedy
- +notes_header+ - The texted to be placed at the top of the Remedy 'Notes' field.
- +status+ - The status to which the ticket will be set.
-
Returns :
-
A single savon-formated (hash) ticket for updating within Remedy.
-
291 292 293 294 295 296 297 298 299 300 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 327 328 329 330 331 332 333 334 335 336 337 338 |
# File 'lib/nexpose_ticketing/helpers/remedy_helper.rb', line 291 def ticket_from_queried_incident(queried_incident, notes_header, status) { 'Categorization_Tier_1' => queried_incident[:categorization_tier_1], 'Categorization_Tier_2' => queried_incident[:categorization_tier_2], 'Categorization_Tier_3' => queried_incident[:categorization_tier_3], 'Closure_Manufacturer' => queried_incident[:closure_manufacturer], 'Closure_Product_Category_Tier1' => queried_incident[:closure_product_category_tier1], 'Closure_Product_Category_Tier2' => queried_incident[:closure_product_category_tier2], 'Closure_Product_Category_Tier3' => queried_incident[:closure_product_category_tier3], 'Closure_Product_Model_Version' => queried_incident[:closure_product_model_version], 'Closure_Product_Name' => queried_incident[:closure_product_name], 'Company' => queried_incident[:company], 'Summary' => queried_incident[:summary], 'Notes' => notes_header || queried_incident[:notes], 'Impact' => queried_incident[:impact], 'Manufacturer' => queried_incident[:manufacturer], 'Product_Categorization_Tier_1' => queried_incident[:product_categorization_tier_1], 'Product_Categorization_Tier_2' => queried_incident[:product_categorization_tier_2], 'Product_Categorization_Tier_3' => queried_incident[:product_categorization_tier_3], 'Product_Model_Version' => queried_incident[:product_model_version], 'Product_Name' => queried_incident[:product_name], 'Reported_Source' => queried_incident[:reported_source], 'Resolution' => queried_incident[:resolution], 'Resolution_Category' => queried_incident[:resolution_category], 'Resolution_Category_Tier_2' => queried_incident[:resolution_category_tier_2], 'Resolution_Category_Tier_3' => queried_incident[:resolution_category_tier_3], 'Resolution_Method' => queried_incident[:resolution_method], 'Service_Type' => queried_incident[:service_type], 'Status' => status || queried_incident[:status], 'Urgency' => queried_incident[:urgency], 'Action' => 'MODIFY', 'Work_Info_Summary' => queried_incident[:work_info_summary], 'Work_Info_Notes' => queried_incident[:work_info_notes], 'Work_Info_Type' => queried_incident[:work_info_type], 'Work_Info_Date' => queried_incident[:work_info_date], 'Work_Info_Source' => queried_incident[:work_info_source], 'Work_Info_Locked' => queried_incident[:work_info_locked], 'Work_Info_View_Access' => queried_incident[:work_info_view_access], 'Incident_Number' => queried_incident[:incident_number], 'Status_Reason' => queried_incident[:status_reason], 'ServiceCI' => queried_incident[:service_ci], 'ServiceCI_ReconID' => queried_incident[:service_ci_recon_id], 'HPD_CI' => queried_incident[:hpd_ci], 'HPD_CI_ReconID' => queried_incident[:hpd_ci_recon_id], 'HPD_CI_FormName' => queried_incident[:hpd_ci_form_name], 'z1D_CI_FormName' => queried_incident[:z1d_ci_form_name] } end |
#update_tickets(tickets) ⇒ Object
Sends ticket updates (in SOAP format) to Remedy individually (each ticket in the list as a separate web service call).
-
Args :
-
tickets- List of savon-formatted (hash) ticket updates.
-
108 109 110 111 112 113 114 115 |
# File 'lib/nexpose_ticketing/helpers/remedy_helper.rb', line 108 def update_tickets(tickets) if tickets.nil? || tickets.empty? @log.("No tickets to update.") return end client = get_client('HPD_IncidentInterface_WS.xml', :query_modify_soap_endpoint) send_tickets(client, :help_desk_modify_service, tickets) end |