nexpose 7.0.1 → 7.3.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.
data/lib/eso/step.rb ADDED
@@ -0,0 +1,166 @@
1
+ module Eso
2
+ # Object representation of a step, which are attributes of Workflows and Integration Options
3
+ #
4
+ class Step
5
+ # UUID of this step. This is generated on creation on the server.
6
+ attr_accessor :uuid
7
+
8
+ # Type of this step. Should be one of Eso::ServiceNames
9
+ attr_accessor :serviceName
10
+
11
+ # The configuration for this step.
12
+ attr_accessor :stepConfiguration
13
+
14
+ # Constructor for Step.
15
+ #
16
+ # @param [String] uuid UUID of this Step. This is created on the server side upon creation through the API.
17
+ # @param [String] service_name The name of step this is.
18
+ # @param [Workflow] workflow The workflow this step belongs to.
19
+ # @param [Hash] configuration_params Hash of the parameters for this step.
20
+ #
21
+ def initialize(uuid: nil, service_name:, workflow: nil, type_name:, previous_type_name: StepNames::EMPTY, configuration_params: nil)
22
+ @uuid = uuid if uuid
23
+ @serviceName = service_name
24
+ @stepConfiguration = StepConfiguration.new(type_name, previous_type_name)
25
+ @stepConfiguration.configurationParams = configuration_params if configuration_params
26
+ @stepConfiguration.workflowID = workflow.id if workflow
27
+ end
28
+
29
+ # Return the configuration parameters for this step.
30
+ #
31
+ # @return [Hash] Hash of the configuration parameters for this step.
32
+ #
33
+ def configuration_params
34
+ @stepConfiguration.configurationParams
35
+ end
36
+
37
+ # Set the the configuration parameters for this step.
38
+ #
39
+ # @param [Hash] config_params of the new configuration parameters you would like to set.
40
+ # @return [Hash] Hash of the updated configuration parameters for this step.
41
+ #
42
+ def configuration_params=(config_params)
43
+ @stepConfiguration.configurationParams = config_params
44
+ end
45
+
46
+ # Return the type name for this step.
47
+ #
48
+ # @return [String] The currently configured type name.
49
+ #
50
+ def type_name
51
+ @stepConfiguration.typeName
52
+ end
53
+
54
+ # Set the type name for this step.
55
+ #
56
+ # @param [String] The new type_name that you would like to set this to. See Eso::StepNames for valid names.
57
+ # @return [String] The newly set type name.
58
+ #
59
+ def type_name=(wf_action_name)
60
+ @stepConfiguration.typeName = wf_action_name
61
+ end
62
+
63
+ # Return the previous type name for this step.
64
+ #
65
+ # @return [String] The previous type name for this step.
66
+ #
67
+ def previous_type_name
68
+ @stepConfiguration.previousTypeName
69
+ end
70
+
71
+ # Set the previous type name for this step.
72
+ #
73
+ # @param [String] The new previous type name that you would like to set. See Eso::StepNames for valid names.
74
+ # @return [String] Hash of the configuration parameters for this step.
75
+ #
76
+ def previous_type_name=(action_name)
77
+ @stepConfiguration.previousTypeName = action_name
78
+ end
79
+
80
+ # Return the properties of this step.
81
+ #
82
+ # @return [Hash{}] Hash of the properties for this step.
83
+ #
84
+ def properties
85
+ @stepConfiguration.configurationParams[:properties]
86
+ end
87
+
88
+ # Set the properties of this step.
89
+ #
90
+ # @param [Hash] The new properties to set for this step.
91
+ # @return [Hash] Hash of the newly configured properties for this step.
92
+ #
93
+ def properties=(new_properties)
94
+ @stepConfiguration.configurationParams[:properties] = new_properties
95
+ end
96
+
97
+ # Determine the siteID of this step, if it exists
98
+ #
99
+ # @return [String|nil] The String siteID value or nil if no siteID
100
+ def site_id
101
+ if @stepConfiguration.configurationParams[:properties][:siteID]
102
+ @stepConfiguration.configurationParams[:properties][:siteID][:value]
103
+ end
104
+ end
105
+
106
+ # Returns all configured filters for this step.
107
+ #
108
+ # @return [Array] An array of the currently configured filters for this step, each represented as a hash.
109
+ #
110
+ def filters
111
+ rv = {}
112
+ self.properties.each_pair do |key, value|
113
+ if value[:properties]
114
+ rv[key] = value if value[:properties].has_key?(:operators)
115
+ end
116
+ end
117
+ rv
118
+ end
119
+
120
+ # Convenience method which calls the #add_property method of the @stepConfiguration, but returns the Step
121
+ #
122
+ # @return [Step] Returns this Step for chaining
123
+ def add_property(name, value)
124
+ @stepConfiguration.add_property(name, value)
125
+ self
126
+ end
127
+
128
+ # Convenience method which calls the #add_property method of the @stepConfiguration, but returns the Step
129
+ #
130
+ # @return [Step] Returns this Step for chaining
131
+ def update_property(name, value)
132
+ @stepConfiguration.add_property(name, value)
133
+ self
134
+ end
135
+
136
+ # Add the specified filter to this step. The filter is converted to a hash and saved as such instead of being saved as a ESO::Filter object.
137
+ #
138
+ # @param [Filter] filter The filter to add to this step.
139
+ #
140
+ def add_filter(filter)
141
+ @stepConfiguration.configurationParams[:properties].merge! filter.to_hash
142
+ end
143
+
144
+ # Return this step in a JSON digestible format.
145
+ #
146
+ # @return [String] JSON interpretation of this step.
147
+ #
148
+ def to_json
149
+ self.to_hash.to_json
150
+ end
151
+
152
+ # Return this step as a hash.
153
+ #
154
+ # @return [Hash] Hash interpretation of this step.
155
+ #
156
+ def to_hash
157
+ hash = {}
158
+ instance_variables.each do |var|
159
+ value = instance_variable_get(var)
160
+ value = value.to_h if value.respond_to?('to_h')
161
+ hash[var.to_s.delete('@')] = value
162
+ end
163
+ hash
164
+ end
165
+ end
166
+ end
@@ -0,0 +1,73 @@
1
+ module Eso
2
+ class StepConfiguration
3
+ attr_accessor :typeName, :previousTypeName, :configurationParams, :workflowID
4
+
5
+ module ConfigParamProperties
6
+ DISCOVERY_CONFIG_ID = 'discoveryConfigID'
7
+ EXCLUDE_ASSETS_WITH_TAGS= 'excludeAssetsWithTags'
8
+ IMPORT_TAGS = 'importTags'
9
+ ONLY_IMPORT_THESE_TAGS = 'onlyImportTheseTags'
10
+ SITE_ID = 'siteID'
11
+ TAG_ID = 'tagID'
12
+ end
13
+
14
+ module ConfigParamPropertyTypes
15
+ BOOLEAN = [ConfigParamProperties::IMPORT_TAGS]
16
+ INTEGER = [ConfigParamProperties::DISCOVERY_CONFIG_ID,
17
+ ConfigParamProperties::SITE_ID,
18
+ ConfigParamProperties::TAG_ID]
19
+ STRING = [ConfigParamProperties::EXCLUDE_ASSETS_WITH_TAGS,
20
+ ConfigParamProperties::ONLY_IMPORT_THESE_TAGS]
21
+ end
22
+
23
+ def initialize (typeName, previousTypeName, configurationParams=nil, workflowID=nil)
24
+ @typeName = typeName
25
+ @previousTypeName = previousTypeName
26
+ @configurationParams = configurationParams ? configurationParams : {
27
+ :valueClass => Values::OBJECT,
28
+ :objectType => 'params',
29
+ :properties => {}}
30
+ @workflowID = workflowID if workflowID
31
+ end
32
+
33
+ # This adds the specified property to this StepConfiguration.configurationParams.properties Hash
34
+ #
35
+ # @param [String] name The name of the property to add, which should be one of ConfigParamProperties
36
+ # @param [Object] value The value of the property to add, which should already be in the appropriate format (Eso::Values)
37
+ # @return [StepConfiguration] Returns this object for chaining.
38
+ def add_property(name, value)
39
+ @configurationParams[:properties][name] =
40
+ case name
41
+ when *ConfigParamPropertyTypes::BOOLEAN
42
+ {
43
+ valueClass: Values::BOOLEAN,
44
+ value: value
45
+ }
46
+ when *ConfigParamPropertyTypes::INTEGER
47
+ {
48
+ valueClass: Values::INTEGER,
49
+ value: value
50
+ }
51
+ when *ConfigParamPropertyTypes::STRING
52
+ {
53
+ valueClass: Values::STRING,
54
+ value: value
55
+ }
56
+ else
57
+ raise ArgumentError, "Invalid StepConfiguration ConfigurationParameter Property name: #{name}. " +
58
+ 'Should be one of StepConfiguration::ConfigParamProperties'
59
+ end
60
+ self
61
+ end
62
+
63
+ def to_h
64
+ hash = {
65
+ :typeName => @typeName,
66
+ :previousTypeName => @previousTypeName,
67
+ :configurationParams => @configurationParams
68
+ }
69
+ hash['workflowID'] = @workflowID if @workflowID
70
+ hash
71
+ end
72
+ end
73
+ end
@@ -0,0 +1,149 @@
1
+ module Eso
2
+
3
+ # The following classes have mixed casing (snake and camel) to accommodate for the API.
4
+ # I guess a TODO would be to write a helper to automatically convert them.
5
+ class Workflow
6
+ # The id of the workflow. This will be created upon saving to the server upon creation.
7
+ attr_accessor :id
8
+
9
+ # The name of the workflow. This is required.
10
+ attr_accessor :name
11
+
12
+ # An array of the steps this workflow takes action on.
13
+ attr_accessor :steps
14
+
15
+ # The time the workflow was created in milliseconds since epoch
16
+ attr_accessor :timeCreated
17
+
18
+ # Constructor for the workflow
19
+ #
20
+ # @param [String] id ID of the workflow.
21
+ # @param [String] name Name of the workflow.
22
+ # @param [Array] steps Array of the steps that this workflow takes.
23
+ # @param [Fixnum] time_created The time the workflow was created in millis since epoch
24
+ #
25
+ def initialize(id: nil, name:, steps: [], time_created: (Time.now.strftime('%s').to_i * 1000))
26
+ @id = id
27
+ @name = name
28
+ @steps = steps
29
+ @timeCreated = time_created
30
+ end
31
+
32
+ # Load an existing workflow from the API.
33
+ #
34
+ # @param [Conductor] conductor The Conductor object governing the workflows
35
+ # @param [String] id ID of the workflow to load
36
+ # @return [Workflow] Workflow object that was loaded.
37
+ #
38
+ def self.load(conductor, id)
39
+ uri = "#{conductor.url}workflows/#{id}"
40
+ resp = conductor.get(url: uri)
41
+ workflow = self.new(id: resp[:id], name: resp[:name])
42
+ steps = resp[:steps]
43
+ steps.each do |step|
44
+ workflow_step = Step.new(uuid: step[:uuid],
45
+ service_name: step[:serviceName],
46
+ workflow: workflow,
47
+ type_name: step[:stepConfiguration][:typeName],
48
+ previous_type_name: step[:stepConfiguration][:previousTypeName],
49
+ configuration_params: step[:stepConfiguration][:configurationParams])
50
+ workflow.steps << workflow_step
51
+ end
52
+ workflow
53
+ end
54
+
55
+ # Return the relevant step based on the given service name.
56
+ # For example, if you want the step related to the scan service you would pass 'nexpose-scan-service'.
57
+ #
58
+ # @param [String] service_name Service name to be returned.
59
+ # @return [Step] Step object corresponding to the given service.
60
+ #
61
+ def get_step(type_name)
62
+ @steps.find do |step|
63
+ step.type_name == type_name
64
+ end
65
+ end
66
+
67
+ # Return the trigger step of a workflow. The trigger step is defined as a step that monitors for events
68
+ # that will cause the action to fire.
69
+ #
70
+ # Currently triggers do not have a previous-action so that is what this is returning. This behavior could change in ESO's future.
71
+ #
72
+ # @return [Step] Step object representation of the trigger step.
73
+ #
74
+ def trigger
75
+ @steps.find do |step|
76
+ step.stepConfiguration.previousTypeName.nil?
77
+ end
78
+ end
79
+
80
+ # Return this object and the associated steps in a digestible JSON format.
81
+ #
82
+ # @return [String] JSON interpretation of this workflow.
83
+ #
84
+ def to_json
85
+ hash = self.to_hash
86
+ steps = hash['steps']
87
+ hashified_steps = []
88
+ steps.each { |step| hashified_steps << step.to_hash }
89
+ hash['steps'] = hashified_steps
90
+ hash.to_json
91
+ end
92
+
93
+ # Return this object as a hash.
94
+ # The corresponding steps will still be objects.
95
+ #
96
+ # @return [Hash{}] Hash interpretation of this workflow.
97
+ def to_hash
98
+ hash = {}
99
+ instance_variables.each { |var| hash[var.to_s.delete('@')] = instance_variable_get(var) }
100
+ hash
101
+ end
102
+
103
+ # Representation of state of a workflow or integration option. Taken from service-orchestration State.java
104
+ module State
105
+ # Workflow or an integration option is configured and ready to accept events
106
+ READY = 'ready'
107
+
108
+ # Workflow or an integration option is processing or has processed events
109
+ RUNNING = 'running'
110
+
111
+ # The workflow or an integration option is running, but is temporarily unsuccessful processing events
112
+ RETRY = 'retry'
113
+
114
+ # Workflow or an integration option is stopped by the user
115
+ STOPPED = 'stopped'
116
+
117
+ # Workflow or an integration option has experienced an error that caused it to stop
118
+ ERROR = 'error'
119
+ end
120
+
121
+ StateHistory = Struct.new(:message, :state, :startTime)
122
+
123
+ class History < Workflow
124
+ # The current state of the workflow
125
+ attr_accessor :state
126
+
127
+ # The most recent message
128
+ attr_accessor :message
129
+
130
+ # An array of Eso::Workflow::StateHistory
131
+ attr_accessor :state_histories
132
+
133
+ # Constructor for the WorkflowHistory
134
+ #
135
+ # @param [String] id ID of the workflow.
136
+ # @param [String] name Name of the workflow.
137
+ # @param [Array] steps Array of the steps that this workflow takes.
138
+ # @param [Fixnum] time_created The time the workflow was created in millis since epoch
139
+ # @param [Eso::Workflow::State] state The current state of the workflow
140
+ # @param [String] message The most recent message
141
+ def initialize(id:, name:, time_created:, steps:, state:, message:, history:)
142
+ super(id: id, name: name, timeCreated: time_created, steps: steps)
143
+ @state = state
144
+ @message = message
145
+ @state_histories = history
146
+ end
147
+ end
148
+ end
149
+ end
data/lib/nexpose/ajax.rb CHANGED
@@ -149,6 +149,7 @@ module Nexpose
149
149
  def headers(nsc, request)
150
150
  request.add_field('nexposeCCSessionID', nsc.session_id)
151
151
  request.add_field('Cookie', "nexposeCCSessionID=#{nsc.session_id}")
152
+ request.add_field('X-Requested-With', 'XMLHttpRequest')
152
153
  end
153
154
 
154
155
  def request(nsc, request, timeout = nil)
@@ -57,11 +57,11 @@ module Nexpose
57
57
  attr_reader :response_xml
58
58
  # The trust store to validate connections against if any
59
59
  attr_reader :trust_store
60
- # The main HTTP read_timeout value
60
+ # The main HTTP read_timeout value, in seconds
61
61
  # For more information visit the link below:
62
62
  # https://ruby-doc.org/stdlib/libdoc/net/http/rdoc/Net/HTTP.html#read_timeout-attribute-method
63
63
  attr_accessor :timeout
64
- # The optional HTTP open_timeout value
64
+ # The optional HTTP open_timeout value, in seconds
65
65
  # For more information visit the link below:
66
66
  # http://ruby-doc.org/stdlib/libdoc/net/http/rdoc/Net/HTTP.html#open_timeout-attribute-method
67
67
  attr_accessor :open_timeout
@@ -143,11 +143,15 @@ module Nexpose
143
143
  http.cert_store = @trust_store
144
144
  end
145
145
  headers = { 'Cookie' => "nexposeCCSessionID=#{@session_id}" }
146
- resp = http.get(uri.to_s, headers)
147
146
 
148
147
  if file_name
149
- ::File.open(file_name, 'wb') { |file| file.write(resp.body) }
148
+ http.request_get(uri.to_s, headers) do |resp|
149
+ ::File.open(file_name, 'wb') do |file|
150
+ resp.read_body { |chunk| file.write(chunk) }
151
+ end
152
+ end
150
153
  else
154
+ resp = http.get(uri.to_s, headers)
151
155
  resp.body
152
156
  end
153
157
  end
data/lib/nexpose/group.rb CHANGED
@@ -159,7 +159,7 @@ module Nexpose
159
159
  #
160
160
  def self.load(connection, id)
161
161
  xml = %(<AssetGroupConfigRequest session-id="#{connection.session_id}" group-id="#{id}"/>)
162
- r = APIRequest.execute(connection.url, xml)
162
+ r = APIRequest.execute(connection.url, xml, '1.1', { timeout: connection.timeout, open_timeout: connection.open_timeout })
163
163
  parse(r.res)
164
164
  end
165
165
 
data/lib/nexpose/maint.rb CHANGED
@@ -96,12 +96,15 @@ module Nexpose
96
96
  # It will restart the console after acknowledging receiving the request.
97
97
  #
98
98
  # @param [Connection] nsc An active connection to a Nexpose console.
99
+ # @param [String] (Optional) The password to use when restoring the backup.
99
100
  # @return [Boolean] Whether the request was received.
100
101
  #
101
- def restore(nsc)
102
+ def restore(nsc, password = nil)
103
+ raise 'Supplied Password is incorrect for restoring this Backup.' if invalid_backup_password?(nsc, password)
102
104
  parameters = { 'backupid' => @name,
103
105
  'cmd' => 'restore',
104
- 'targetTask' => 'backupRestore' }
106
+ 'targetTask' => 'backupRestore',
107
+ 'password' => password }
105
108
  xml = AJAX.form_post(nsc, '/admin/global/maintenance/maintCmd.txml', parameters)
106
109
  if !!(xml =~ /succeded="true"/)
107
110
  nsc._maintenance_restart
@@ -129,5 +132,23 @@ module Nexpose
129
132
  hash['Platform-Independent'],
130
133
  hash['Size'])
131
134
  end
135
+
136
+ private
137
+
138
+ def invalid_backup_password?(nsc, password)
139
+ !correct_backup_password?(nsc, password) if backup_need_password?(nsc)
140
+ end
141
+
142
+ def backup_need_password?(nsc)
143
+ resp = Nexpose::AJAX.get(nsc, '/data/admin/backups/password', Nexpose::AJAX::CONTENT_TYPE::JSON, 'backupID' => name)
144
+ resp == 'true'
145
+ end
146
+
147
+ def correct_backup_password?(nsc, password)
148
+ raise 'This Backup file requires a Password. Please include a password during the restore command.' if password.nil?
149
+ resp = Nexpose::AJAX.post(nsc, "/data/admin/backups/password?backupID=#{name}&password=#{password}", nil, Nexpose::AJAX::CONTENT_TYPE::JSON)
150
+ resp == 'true'
151
+ end
152
+
132
153
  end
133
154
  end