class Nexpose::Site
Configuration object representing a Nexpose
site.
For a basic walk-through, see {github.com/rapid7/nexpose-client/wiki/Using-Sites}
Attributes
- Array
-
Collection of real-time alerts.
@see Alert
@see SMTPAlert
@see SNMPAlert
@see SyslogAlert
Scan
the assets with last scanned engine or not.
- Array
-
Blackout
starting dates, times and duration for blackout periods.
Configuration version. Default: 3
Description of the site.
discovery config of the discovery connection associated with this site if it is dynamic.
Excluded scan targets. May be IPv4, IPv6, DNS names, IPRanges or assetgroup ids.
The site ID. An ID of -1 is used to designate a site that has not been saved to a Nexpose
console.
Included scan targets. May be IPv4, IPv6, DNS names, IPRanges or assetgroup ids.
Unique name of the site. Required.
Information about the organization that this site belongs to. Used by some reports.
The risk factor associated with this site. Default: 1.0
Scan
template to use when starting a scan job. Default: full-audit-without-web-spider
Friendly name of scan template to use when starting a scan job. Value is populated when a site is saved or loaded from a console.
- Array
-
Schedule
starting dates and times for scans, and set their frequency.
Asset
filter criteria if this site is dynamic.
- Array
-
Collection of credentials associated with this site. Does not
include shared credentials.
- Array
-
List of user IDs for users who have access to the site.
- Array
-
Collection of web credentials associated with the site.
Public Class Methods
Copy an existing configuration from a Nexpose
instance. Returned object will reset the site ID and append “Copy” to the existing name.
@param [Connection] connection Connection
to the security console. @param [Fixnum] id Site
ID of an existing site. @return [Site] Site
configuration loaded from a Nexpose
console.
# File lib/nexpose/site.rb, line 496 def self.copy(connection, id) site = self.load(connection, id) site.id = -1 site.name = "#{site.name} Copy" site end
# File lib/nexpose/site.rb, line 390 def self.from_hash(hash) site = new(hash[:name], hash[:scan_template_id]) hash.each do |k, v| site.instance_variable_set("@#{k}", v) end # Convert each string address to either a HostName or IPRange object included_scan_targets = { addresses: [], asset_groups: [] } site.included_scan_targets[:addresses].each { |asset| included_scan_targets[:addresses] << HostOrIP.convert(asset) } included_scan_targets[:asset_groups] = site.included_scan_targets[:asset_groups] site.included_scan_targets = included_scan_targets excluded_scan_targets = { addresses: [], asset_groups: [] } site.excluded_scan_targets[:addresses].each { |asset| excluded_scan_targets[:addresses] << HostOrIP.convert(asset) } excluded_scan_targets[:asset_groups] = site.excluded_scan_targets[:asset_groups] site.excluded_scan_targets = excluded_scan_targets site end
# File lib/nexpose/site.rb, line 484 def self.json_initializer(data) new(data[:name], data[:scan_template_id]) end
Load an site from the provided console.
@param [Connection] nsc Active connection to a Nexpose
console. @param [String] id Unique identifier of a site. @return [Site] The requested site, if found.
# File lib/nexpose/site.rb, line 452 def self.load(nsc, id) uri = "/api/2.1/site_configurations/#{id}" resp = AJAX.get(nsc, uri, AJAX::CONTENT_TYPE::JSON) hash = JSON.parse(resp, symbolize_names: true) site = self.json_initializer(hash).deserialize(hash) # Convert each string address to either a HostName or IPRange object included_addresses = hash[:included_scan_targets][:addresses] site.included_scan_targets[:addresses] = [] included_addresses.each { |asset| site.include_asset(asset) } excluded_addresses = hash[:excluded_scan_targets][:addresses] site.excluded_scan_targets[:addresses] = [] excluded_addresses.each { |asset| site.exclude_asset(asset) } site.organization = Organization.create(site.organization) site.schedules = (hash[:schedules] || []).map { |schedule| Nexpose::Schedule.from_hash(schedule) } site.blackouts = (hash[:blackouts] || []).map { |blackout| Nexpose::Blackout.from_hash(blackout) } site.site_credentials = hash[:site_credentials].map { |cred| Nexpose::SiteCredentials.new.object_from_hash(nsc, cred) } site.shared_credentials = hash[:shared_credentials].map { |cred| Nexpose::SiteCredentials.new.object_from_hash(nsc, cred) } site.discovery_config = Nexpose::DiscoveryConnection.new.object_from_hash(nsc, hash[:discovery_config]) unless hash[:discovery_config].nil? site.search_criteria = Nexpose::DiscoveryConnection::Criteria.parseHash(hash[:search_criteria]) unless hash[:search_criteria].nil? site.alerts = Alert.load_alerts(hash[:alerts]) site.tags = Tag.load_tags(hash[:tags]) site.web_credentials = hash[:web_credentials].map { |web_cred| ( web_cred[:service] == Nexpose::WebCredentials::WebAppAuthType::HTTP_HEADER ? Nexpose::WebCredentials::Headers.new(web_cred[:name], web_cred[:baseURL], web_cred[:soft403Pattern], web_cred[:id]).object_from_hash(nsc, web_cred) : Nexpose::WebCredentials::HTMLForms.new(web_cred[:name], web_cred[:baseURL], web_cred[:loginURL], web_cred[:soft403Pattern], web_cred[:id]).object_from_hash(nsc, web_cred)) } site end
Site
constructor. Both arguments are optional.
@param [String] name Unique name of the site. @param [String] scan_template_id
ID of the scan template to use.
# File lib/nexpose/site.rb, line 160 def initialize(name = nil, scan_template_id = 'full-audit-without-web-spider') @name = name @scan_template_id = scan_template_id @id = -1 @risk_factor = 1.0 @config_version = 3 @schedules = [] @blackouts = [] @included_scan_targets = { addresses: [], asset_groups: [] } @excluded_scan_targets = { addresses: [], asset_groups: [] } @site_credentials = [] @shared_credentials = [] @web_credentials = [] @alerts = [] @users = [] @tags = [] end
Public Instance Methods
# File lib/nexpose/site.rb, line 374 def add_user(user_id) unless user_id.is_a?(Numeric) && user_id > 0 raise 'Invalid user id. A user id must be a positive number and refer to an existing system user.' end @users << { id: user_id } end
Delete this site from a Nexpose
console.
@param [Connection] connection Connection
to console where this site will be saved. @return [Boolean] Whether or not the site was successfully deleted.
# File lib/nexpose/site.rb, line 534 def delete(connection) r = connection.execute(%(<SiteDeleteRequest session-id="#{connection.session_id}" site-id="#{@id}"/>)) r.success end
Adds an asset to this site excluded scan targets, resolving whether an IP or hostname is provided.
@param [String] asset Identifier of an asset, either IP or host name.
# File lib/nexpose/site.rb, line 315 def exclude_asset(asset) @excluded_scan_targets[:addresses] << HostOrIP.convert(asset) end
Adds an asset group ID to this site excluded scan targets.
@param [Integer] asset_group_id Identifier of an assetGroupID.
# File lib/nexpose/site.rb, line 350 def exclude_asset_group(asset_group_id) validate_asset_group(asset_group_id) @excluded_scan_targets[:asset_groups] << asset_group_id.to_i end
Adds assets to this site excluded scan targets by IP address range.
@param [String] from Beginning IP address of a range. @param [String] to Ending IP address of a range.
# File lib/nexpose/site.rb, line 286 def exclude_ip_range(from, to) from_ip = IPAddr.new(from) to_ip = IPAddr.new(to) (from_ip..to_ip) raise 'Invalid IP range specified' if (from_ip..to_ip).to_a.size.zero? @excluded_scan_targets[:addresses] << IPRange.new(from, to) rescue ArgumentError => e raise "#{e.message} in given IP range" end
Returns the array of excluded scan target addresses. @return [Array] Array of excluded addresses.
# File lib/nexpose/site.rb, line 206 def excluded_addresses @excluded_scan_targets[:addresses] end
Sets the array of excluded scan target addresses. @param [Array] new_addresses The new array of scan target addresses. @return [Array] Array of updated scan target addresses.
# File lib/nexpose/site.rb, line 213 def excluded_addresses=(new_addresses) @excluded_scan_targets[:addresses] = new_addresses end
Returns the array of IDs for excluded scan target asset groups. @return [Array] Array of IDs for excluded asset groups.
# File lib/nexpose/site.rb, line 219 def excluded_asset_groups @excluded_scan_targets[:asset_groups] end
Sets the array IDs for excluded scan target asset groups. @param [Array] new_asset_groups The new array of IDs for scan target asset groups. @return [Array] Array of IDs of the updated scan target asset groups.
# File lib/nexpose/site.rb, line 226 def excluded_asset_groups=(new_asset_groups) @excluded_scan_targets[:asset_groups] = new_asset_groups end
Adds an asset to this site included scan targets, resolving whether an IP or hostname is provided.
@param [String] asset Identifier of an asset, either IP or host name.
# File lib/nexpose/site.rb, line 269 def include_asset(asset) @included_scan_targets[:addresses] << HostOrIP.convert(asset) end
Adds an asset group ID to this site included scan targets.
@param [Integer] asset_group_id Identifier of an assetGroupID.
# File lib/nexpose/site.rb, line 332 def include_asset_group(asset_group_id) validate_asset_group(asset_group_id) @included_scan_targets[:asset_groups] << asset_group_id.to_i end
Adds assets to this site by IP address range.
@param [String] from Beginning IP address of a range. @param [String] to Ending IP address of a range.
# File lib/nexpose/site.rb, line 240 def include_ip_range(from, to) from_ip = IPAddr.new(from) to_ip = IPAddr.new(to) (from_ip..to_ip) raise 'Invalid IP range specified' if (from_ip..to_ip).to_a.size.zero? @included_scan_targets[:addresses] << IPRange.new(from, to) rescue ArgumentError => e raise "#{e.message} in given IP range" end
Returns the array of included scan target addresses. @return [Array] Array of included addresses.
# File lib/nexpose/site.rb, line 180 def included_addresses @included_scan_targets[:addresses] end
Sets the array of included scan target addresses. @param [Array] new_addresses The new array of scan target addresses. @return [Array] Array of updated scan target addresses.
# File lib/nexpose/site.rb, line 187 def included_addresses=(new_addresses) @included_scan_targets[:addresses] = new_addresses end
Returns the array of IDs for included scan target asset groups. @return [Array] Array of included asset groups.
# File lib/nexpose/site.rb, line 193 def included_asset_groups @included_scan_targets[:asset_groups] end
Sets the array of IDs for included scan target asset groups. @param [Array new_asset_groups The new array of IDs for scan target asset groups. @return [Array Array of IDs of the updated scan target asset groups.
# File lib/nexpose/site.rb, line 200 def included_asset_groups=(new_asset_groups) @included_scan_targets[:asset_groups] = new_asset_groups end
Returns true when the site is dynamic.
# File lib/nexpose/site.rb, line 231 def is_dynamic? !@discovery_config.nil? end
Removes an asset to this site excluded scan targets, resolving whether an IP or hostname is provided.
@param [String] asset Identifier of an asset, either IP or host name.
# File lib/nexpose/site.rb, line 324 def remove_excluded_asset(asset) @excluded_scan_targets[:addresses].reject! { |existing_asset| existing_asset == HostOrIP.convert(asset) } end
Adds an asset group ID to this site excluded scan targets.
@param [Integer] asset_group_id Identifier of an assetGroupID.
# File lib/nexpose/site.rb, line 359 def remove_excluded_asset_group(asset_group_id) validate_asset_group(asset_group_id) @excluded_scan_targets[:asset_groups].reject! { |t| t.eql? asset_group_id.to_i } end
Remove assets from this site excluded scan targets by IP address range.
@param [String] from Beginning IP address of a range. @param [String] to Ending IP address of a range.
# File lib/nexpose/site.rb, line 300 def remove_excluded_ip_range(from, to) from_ip = IPAddr.new(from) to_ip = IPAddr.new(to) (from_ip..to_ip) raise 'Invalid IP range specified' if (from_ip..to_ip).to_a.size.zero? @excluded_scan_targets[:addresses].reject! { |t| t.eql? IPRange.new(from, to) } rescue ArgumentError => e raise "#{e.message} in given IP range" end
Remove an asset to this site included scan targets, resolving whether an IP or hostname is provided.
@param [String] asset Identifier of an asset, either IP or host name.
# File lib/nexpose/site.rb, line 278 def remove_included_asset(asset) @included_scan_targets[:addresses].reject! { |existing_asset| existing_asset == HostOrIP.convert(asset) } end
Adds an asset group ID to this site included scan targets.
@param [Integer] asset_group_id Identifier of an assetGroupID.
# File lib/nexpose/site.rb, line 341 def remove_included_asset_group(asset_group_id) validate_asset_group(asset_group_id) @included_scan_targets[:asset_groups].reject! { |t| t.eql? asset_group_id.to_i } end
Remove assets to this site by IP address range.
@param [String] from Beginning IP address of a range. @param [String] to Ending IP address of a range.
# File lib/nexpose/site.rb, line 254 def remove_included_ip_range(from, to) from_ip = IPAddr.new(from) to_ip = IPAddr.new(to) (from_ip..to_ip) raise 'Invalid IP range specified' if (from_ip..to_ip).to_a.size.zero? @included_scan_targets[:addresses].reject! { |t| t.eql? IPRange.new(from, to) } rescue ArgumentError => e raise "#{e.message} in given IP range" end
# File lib/nexpose/site.rb, line 382 def remove_user(user_id) unless user_id.is_a?(Numeric) && user_id > 0 raise 'Invalid user id. A user id must be a positive number and refer to an existing system user.' end @users.delete_if { |h| h[:id] == user_id } end
Saves this site to a Nexpose
console. If the site is dynamic, connection and asset filter changes must be saved through the DiscoveryConnection#update_site call.
@param [Connection] connection Connection
to console where this site will be saved. @return [Fixnum] Site
ID assigned to this configuration, if successful.
# File lib/nexpose/site.rb, line 510 def save(connection) new_site = @id == -1 if new_site resp = AJAX.post(connection, '/api/2.1/site_configurations/', to_json, AJAX::CONTENT_TYPE::JSON) @id = resp.to_i else AJAX.put(connection, "/api/2.1/site_configurations/#{@id}", to_json, AJAX::CONTENT_TYPE::JSON) end # Retrieve the scan engine and shared credentials and add them to the site configuration site_config = Site.load(connection, @id) @engine_id = site_config.engine_id @shared_credentials = site_config.shared_credentials @alerts = site_config.alerts @id end
Scan
this site.
@param [Connection] connection Connection
to console where scan will be launched. @param [String] sync_id Optional synchronization token. @param [Boolean] blackout_override Optional. Given suffencent permissions, force bypass blackout and start scan. @return [Scan] Scan
launch information.
# File lib/nexpose/site.rb, line 546 def scan(connection, sync_id = nil, blackout_override = false) xml = REXML::Element.new('SiteScanRequest') xml.add_attributes({ 'session-id' => connection.session_id, 'site-id' => @id, 'sync-id' => sync_id }) xml.add_attributes({ 'force' => true }) if blackout_override response = connection.execute(xml, '1.1', timeout: connection.timeout) Scan.parse(response.res) if response.success end
# File lib/nexpose/site.rb, line 414 def to_h included_scan_targets = { addresses: @included_scan_targets[:addresses].compact, asset_groups: @included_scan_targets[:asset_groups].compact } excluded_scan_targets = { addresses: @excluded_scan_targets[:addresses].compact, asset_groups: @excluded_scan_targets[:asset_groups].compact } hash = { id: @id, name: @name, description: @description, auto_engine_selection_enabled: @auto_engine_selection_enabled, included_scan_targets: included_scan_targets, excluded_scan_targets: excluded_scan_targets, engine_id: @engine_id, scan_template_id: @scan_template_id, risk_factor: @risk_factor, schedules: (@schedules || []).map(&:to_h), shared_credentials: (@shared_credentials || []).map(&:to_h), site_credentials: (@site_credentials || []).map(&:to_h), web_credentials: (@web_credentials || []).map(&:to_h), discovery_config: @discovery_config.to_h, search_criteria: @search_criteria.to_h, tags: (@tags || []).map(&:to_h), alerts: (@alerts || []).map(&:to_h), organization: @organization.to_h, users: users } # @TODO: Revisit this for 2.0.0 update # Only pass in blackouts if they were actually specified (for backwards compatibility) hash[:blackouts] = @blackouts.map(&:to_h) if @blackouts && @blackouts.any? hash end
# File lib/nexpose/site.rb, line 410 def to_json JSON.generate(to_h) end
# File lib/nexpose/site.rb, line 364 def validate_asset_group(asset_group_id) begin Integer(asset_group_id) rescue ArgumentError => e raise "Invalid asset_group id. #{e.message}" end raise 'Invalid asset_group id. Must be positive number.' if asset_group_id.to_i < 1 end