-
Notifications
You must be signed in to change notification settings - Fork 103
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
allow user to supply a cerificate file for trusted SSL #254
Conversation
test/test_site.rb
Outdated
@@ -66,7 +66,7 @@ def session_id | |||
|
|||
# Monkey patch API behavior to give static responses. | |||
class Nexpose::APIRequest | |||
def self.execute(url, req, api_version='1.1') | |||
def self.execute(url, trust_store, req, api_version='1.1') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unused method argument - trust_store. If it's necessary, use _ or _trust_store as an argument name to indicate that it won't be used.
Unused method argument - req. If it's necessary, use _ or _req as an argument name to indicate that it won't be used.
Unused method argument - api_version. If it's necessary, use _ or _api_version as an argument name to indicate that it won't be used.
Surrounding space missing in default value assignment.
lib/nexpose/api_request.rb
Outdated
def self.execute(url, req, api_version='1.1', options = {}) | ||
obj = self.new(req.to_s, url, api_version) | ||
def self.execute(url, req, trust_store, api_version='1.1', options = {}) | ||
obj = self.new(req.to_s, url, trust_store, api_version) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Redundant self detected.
lib/nexpose/api_request.rb
Outdated
@@ -133,8 +140,8 @@ def attributes(*args) | |||
@res.root.attributes(*args) | |||
end | |||
|
|||
def self.execute(url, req, api_version='1.1', options = {}) | |||
obj = self.new(req.to_s, url, api_version) | |||
def self.execute(url, req, trust_store, api_version='1.1', options = {}) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Surrounding space missing in default value assignment.
1dd08d3
to
ea36ddd
Compare
lib/nexpose/connection.rb
Outdated
@@ -44,20 +44,29 @@ class Connection | |||
# The last XML response received by this object, useful for debugging. | |||
attr_reader :response_xml | |||
|
|||
# Enforcement of certificate validation to a CA | |||
attr_reader :allow_untrusted |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this used anywhere?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not yet, I would like to extend this to be usable but it starts to make this more of a breaking change, can remove or expand depending on how discussion goes.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We may be doing a 6.0 release soon anyway (other breaking changes) so it's not a big deal to me either way. You could even do separate branches for non-breaking and breaking changes if you are inclined to do so.
Example usage, normally would obtain and store then load cert for connection. require 'socket'
require 'openssl'
require 'nexpose'
host = 'r7dev'
port = 3780
user = 'nxadmin'
pass = 'nxadmin'
# get the cert from the host and hold as string
# certificate could also be loaded from file on disk with trust_store = File.load('/path/to/file.pem')
socket = TCPSocket.open(host,port)
ssl_context = OpenSSL::SSL::SSLContext.new()
ssl_context.ssl_version = :TLSv1
ssl_socket = OpenSSL::SSL::SSLSocket.new(socket, ssl_context)
ssl_socket.sync_close = true
ssl_socket.connect
cert = OpenSSL::X509::Certificate.new(ssl_socket.peer_cert)
ssl_socket.close
trust_cert = cert.to_pem
# use the loaded cert string to create a "trusted" connection
begin
puts("Connecting to Nexpose instance at #{host}:#{port} with username #{user}...")
nsc = Nexpose::Connection.new(host, user, pass, port, nil, nil, trust_cert)
nsc.login
# do some work
nsc.logout
rescue Nexpose::APIError => e
print_error("Connection failed: #{e.reason}")
return
end |
@jmartin-r7 @gschneider-r7 My suggestion would be we leave the signature in the same order, then add Agree/Disagree? We need to not alter the method arguments in such a way, that could cause a user to unknowingly invoke an unintended initialization. In this case, we have altered Also, any code that is specifying an |
@sgreen-r7, I am aware of the alteration to APIRequest constructor, I had some discussion with @gschneider-r7 on this as to if this should be considered a breaking change, my issue here is that trust_store is not an optional parameter, to place it as the last param will mean that all previous usages for it will break anyways as usage would require 4 params vs original 2 and optional third. Note that APIRequest is not expected to be used by any class but connection as APIRequest.execute which I also need to change in the same manner and is constructing the new APIRequests. This is called on a connection object as Connection.execute(xml, version = '1.1', options = {}). Looking at the patterns and usage here APIRequest is not expected to be an "public" class for consumption of the nexpose-client gem and so I decided the prioritization in order should be for required params to be forward in in the method signature. |
@sgreen-r7, revised per your request, can we land this and release a new gem version? |
lib/nexpose/connection.rb
Outdated
# A constructor to load a Connection object from a URI | ||
def self.from_uri(uri, user, pass, silo_id = nil, token = nil) | ||
uri = URI.parse(uri) | ||
new(uri.host, user, pass, uri.port, silo_id, token) | ||
new(uri.host, user, pass, uri.port, silo_id, token, nil) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not allowing trust cert to be specified with this method?
test/test_site.rb
Outdated
@@ -66,7 +66,7 @@ def session_id | |||
|
|||
# Monkey patch API behavior to give static responses. | |||
class Nexpose::APIRequest | |||
def self.execute(url, req, api_version='1.1') | |||
def self.execute(url, _trust_store, _req, _api_version = '1.1') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should probably put this in the correct order for consistency, even though it's just test code.
This suffers from #163 where SSL failures are not made clear to the user. I don't think that's a show-stopper for getting an initially usable version of this out. |
Also add parameter docs for the constructor.
def self.execute(url, req, api_version='1.1', options = {}) | ||
obj = self.new(req.to_s, url, api_version) | ||
def self.execute(url, req, api_version = '1.1', options = {}, trust_store = nil) | ||
obj = self.new(req.to_s, url, api_version, trust_store) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Redundant self detected.
@@ -93,7 +100,7 @@ def execute(options = {}) | |||
# 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 OpenSSL::SSL::SSLError | |||
rescue OpenSSL::SSL::SSLError => e |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Useless assignment to variable - e.
Allow validation of a known certificate when establishing a connection to the nexpose instance.
Description
Expand on the Connection object to support a known trusted certificate.
Current implementation allows for supply of certificate data in a trust_cert parameter on connection instantiation to be used for validation when supplied. Currently maintain backwards compatibility by using VERIFY_NONE when no specific certificate data to trust is supplied.
Validation requirements do require the certificate supplied to conform for hostname verification in addition to the specific certificate to trust the connection in the default VERIFY_PEER validation mode.
Motivation and Context
Allows module users to prevent MITM SSL attacks on the nexpose connection.
#246
How Has This Been Tested?
Connected this branch to another project currently consuming the nexpose gem 5.1.0 and obtained the certificate from a test nexpose instance with a self signed web certificate generated with a matching CN hostname value.
Tests:
Tested with PEM format self signed certificate with valid CN for host
Types of changes
Currently backward compatible (happy to consider version bump and making this a breaking change)
Checklist: