nexpose 7.0.1 → 7.3.0

Sign up to get free protection for your applications and to get access to all the features.
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