Class: Nexpose::APIRequest

Inherits:
Object
  • Object
show all
Includes:
XMLUtils
Defined in:
lib/nexpose.rb

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from XMLUtils

#parse_xml

Constructor Details

#initialize(req, url, api_version) ⇒ APIRequest

Returns a new instance of APIRequest.



116
117
118
119
120
121
# File 'lib/nexpose.rb', line 116

def initialize(req, url, api_version)
	@url = url
	@req = req
	@api_version = api_version
	prepare_http_client
end

Instance Attribute Details

#errorObject (readonly)

Returns the value of attribute error.



110
111
112
# File 'lib/nexpose.rb', line 110

def error
  @error
end

#headersObject (readonly)

Returns the value of attribute headers.



100
101
102
# File 'lib/nexpose.rb', line 100

def headers
  @headers
end

#httpObject (readonly)

Returns the value of attribute http.



98
99
100
# File 'lib/nexpose.rb', line 98

def http
  @http
end

#pauseObject (readonly)

Returns the value of attribute pause.



103
104
105
# File 'lib/nexpose.rb', line 103

def pause
  @pause
end

#raw_responseObject (readonly)

Returns the value of attribute raw_response.



113
114
115
# File 'lib/nexpose.rb', line 113

def raw_response
  @raw_response
end

#raw_response_dataObject (readonly)

Returns the value of attribute raw_response_data.



114
115
116
# File 'lib/nexpose.rb', line 114

def raw_response_data
  @raw_response_data
end

#reqObject (readonly)

Returns the value of attribute req.



105
106
107
# File 'lib/nexpose.rb', line 105

def req
  @req
end

#resObject (readonly)

Returns the value of attribute res.



106
107
108
# File 'lib/nexpose.rb', line 106

def res
  @res
end

#retry_countObject (readonly)

Returns the value of attribute retry_count.



101
102
103
# File 'lib/nexpose.rb', line 101

def retry_count
  @retry_count
end

#sidObject (readonly)

Returns the value of attribute sid.



107
108
109
# File 'lib/nexpose.rb', line 107

def sid
  @sid
end

#successObject (readonly)

Returns the value of attribute success.



108
109
110
# File 'lib/nexpose.rb', line 108

def success
  @success
end

#time_outObject (readonly)

Returns the value of attribute time_out.



102
103
104
# File 'lib/nexpose.rb', line 102

def time_out
  @time_out
end

#traceObject (readonly)

Returns the value of attribute trace.



111
112
113
# File 'lib/nexpose.rb', line 111

def trace
  @trace
end

#uriObject (readonly)

Returns the value of attribute uri.



99
100
101
# File 'lib/nexpose.rb', line 99

def uri
  @uri
end

Class Method Details

.execute(url, req, api_version) ⇒ Object



210
211
212
213
214
215
216
217
# File 'lib/nexpose.rb', line 210

def self.execute(url, req, api_version)
	obj = self.new(req, url, api_version)
	obj.execute
	if(not obj.success)
		raise APIError.new(obj, "Action failed: #{obj.error}")
	end
	obj
end

Instance Method Details

#attributes(*args) ⇒ Object



205
206
207
208
# File 'lib/nexpose.rb', line 205

def attributes(*args)
	return if not @res.root
	@res.root.attributes(*args)
end

#executeObject



142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
# File 'lib/nexpose.rb', line 142

def execute
	@conn_tries = 0

	begin
	prepare_http_client
	@raw_response, @raw_response_data = @http.post(@uri.path, @req, @headers)
	@res = parse_xml(@raw_response_data)

	if(not @res.root)
		@error = "NeXpose service returned invalid XML"
		return @sid
	end

	@sid = attributes['session-id']

	if(attributes['success'] and attributes['success'].to_i == 1)
		@success = true
	elsif @api_version =~ /1.2/  and @res and 	(@res.get_elements '//Exception').count < 1
		@success = true
	else
		@success = false
		@res.elements.each('//Failure/Exception') do |s|
			s.elements.each('message') do |m|
				@error = m.text
			end
			s.elements.each('stacktrace') do |m|
				@trace = m.text
			end
		end
	end
	# This is a hack to handle corner cases where a heavily loaded NeXpose instance
	# drops our HTTP connection before processing. We try 5 times to establish a
	# connection in these situations. The actual exception occurs in the Ruby
	# http library, which is why we use such generic error classes.
	rescue ::ArgumentError, ::NoMethodError
		if @conn_tries < 5
			@conn_tries += 1
			retry
		end
	rescue ::Timeout::Error
		if @conn_tries < 5
			@conn_tries += 1
			retry
		end
		@error = "NeXpose host did not respond"
	rescue ::Errno::EHOSTUNREACH,::Errno::ENETDOWN,::Errno::ENETUNREACH,::Errno::ENETRESET,::Errno::EHOSTDOWN,::Errno::EACCES,::Errno::EINVAL,::Errno::EADDRNOTAVAIL
		@error = "NeXpose host is unreachable"
	# Handle console-level interrupts
	rescue ::Interrupt
		@error = "received a user interrupt"
	rescue ::Errno::ECONNRESET,::Errno::ECONNREFUSED,::Errno::ENOTCONN,::Errno::ECONNABORTED
		@error = "NeXpose service is not available"
	rescue ::REXML::ParseException
		@error = "NeXpose has not been properly licensed"
	end

	if ! (@success or @error)
		@error = "NeXpose service returned an unrecognized response: #{@raw_response_data.inspect}"
	end

	@sid
end

#prepare_http_clientObject



123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
# File 'lib/nexpose.rb', line 123

def prepare_http_client
	@retry_count = 0
	@retry_count_max = 10
	@time_out = 30
	@pause = 2
	@uri = URI.parse(@url)
	@http = Net::HTTP.new(@uri.host, @uri.port)
	@http.use_ssl = true
	#
	# XXX: This is obviously a security issue, however, we handle this at the client level by forcing
	#      a confirmation when the nexpose host is not localhost. In a perfect world, we would present
	#      the server signature before accepting it, but this requires either a direct callback inside
	#      of this module back to whatever UI, or opens a race condition between accept and attempt.
	#
	@http.verify_mode = OpenSSL::SSL::VERIFY_NONE
	@headers = {'Content-Type' => 'text/xml'}
	@success = false
end