Skip to content
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

Fixes #280: Migrated HTTP communication to use requests #2023

Merged
merged 1 commit into from
Dec 28, 2019

Conversation

andy-maier
Copy link
Contributor

@andy-maier andy-maier commented Dec 11, 2019

Ready for review and manual tests (see below for hints).

In addition to issue #280, it also addresses these issues:

Note: If you want to test this PR with pywbemtools, it requires using PR pywbem/pywbemtools#467.

  • Particular review points:

    • Changes to ca_cert parameter of WBEMConnection
    • Removal of communication via UNIX sockets
    • Removal of local authentication schemes
    • The new pywbem.PYWBEM_USES_REQUESTS attribute for indicating requests support to users
  • Manual tests against real WBEM servers, including error behavior:

    • Different client envs:
      • Python 2 on Linux
      • Python 3 on Linux
      • Python 2 on native Windows
      • Python 3 on native Windows
    • tests for ca_certs:
      • No server certificate verification
      • Verification of self-signed server certificate with specified path to PEM file
      • Verification of self-signed server certificate with specified path to directory
    • tests for 2-way auth (x509 parm):
      • client certificate in PEM file, client private key in PEM file
      • client certificate and client private key in single PEM file (specified as 'cert_file')
  • Tests that have been moved to new issue Tests with CA-chain server certificates #2038:

    • Verification of CA-chain server certificate with specified path to PEM file
    • Verification of CA-chain server certificate with specified path to directory
    • Verification of CA-chain server certificate with certifi-provided root certificates

@andy-maier andy-maier self-assigned this Dec 11, 2019
@andy-maier andy-maier added this to the 1.0.0 milestone Dec 11, 2019
@andy-maier andy-maier changed the title [WIP] Migrated from httplib to requests [WIP] Fixes #280: Migrated from httplib to requests Dec 11, 2019
@andy-maier andy-maier changed the title [WIP] Fixes #280: Migrated from httplib to requests [WIP] Fixes #280: Migrated HTTP communication to use requests Dec 11, 2019
@andy-maier andy-maier force-pushed the andy/use-requests branch 2 times, most recently from 8885ac5 to 0e9776e Compare December 13, 2019 12:35
@andy-maier andy-maier force-pushed the andy/use-requests branch 2 times, most recently from ac3d52e to ade2c7b Compare December 13, 2019 14:21
@andy-maier andy-maier force-pushed the andy/use-requests branch 2 times, most recently from aec1139 to 875b527 Compare December 13, 2019 15:11
@coveralls
Copy link

coveralls commented Dec 13, 2019

Coverage Status

Coverage increased (+1.0%) to 86.866% when pulling 67a76e8 on andy/use-requests into 6800b15 on master.

@andy-maier andy-maier force-pushed the andy/use-requests branch 8 times, most recently from 2d37bee to e93d08f Compare December 14, 2019 00:02
Copy link
Collaborator

@KSchopmeyer KSchopmeyer left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We were not passing the scheme or port on to requests Since we are no longer calling parse_url for each operation which properly sets up the port with defaults if not supplied. I did a temp fix on about line 246 of cim_http.py

if cimxml_headers is None:
    cimxml_headers = []

target = '/cimom'
host, port, ssl = parse_url(conn.url)               <----------------brokout host, port ssl
scheme = 'https' if ssl else 'http'
target_url = '{}://{}:{}{}'.format(scheme, host, port, target)   <---------------reassembled with host and p

# Make sure the data parameter is converted to a UTF-8 encoded byte string.
# This is important because according to RFC2616, the Content-Length HTTP
# header must be measured in Bytes (and the Content-Type header will
# indicate UTF-8).
req_body = _ensure_bytes(req_data)

But that is not the correct place to be doing this since it should be done once per connection. I noted that"

a. in old code the http lib required host and port separate. So parse_url separted them for every wbem_connection call.

b. We were also separating them for some of the pull operations using parse_url in cim_operations.py which means that this code was called for every pull.

c. We were also separating scheme, etc. in individual properties within cim_operations.py (see the scheme property.

Why not do this once per connection during construction and maintain the scheme, host parameters to be used where we are using parse_url in cim_operations.

Also, since it is no longer required to separate host and port for the requests call should we redefine the cim_operations url to include the port and use parse_url once on each connection in WBEMConnection init to sort out the port including the default port.

In fact, should we redo parse_url and get it out of cim_http.py????

NOTE: This is not a complete review since I am working primarily just to get through tests now.

Update by Andy: I have changed the approach for normalizing and defaulting the URL components in PR #2048. This should address these comments.

Copy link
Collaborator

@KSchopmeyer KSchopmeyer left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed the whole set. See comments below. Since I have not gotten through all tests, This is still incomplete but removed the review needed to flag you

docs/mof_compiler.help.txt Show resolved Hide resolved
pywbem/_features.py Outdated Show resolved Hide resolved
pywbem/_features.py Outdated Show resolved Hide resolved
pywbem/cim_http.py Show resolved Hide resolved
pywbem_os_setup.bat Show resolved Hide resolved
@KSchopmeyer
Copy link
Collaborator

NOTE: I also found the following code to log actual requests at the HTTPConnection level and inserted it for these tests with conn.debug around it. (Not the whole context but the debug_requests_on. Just a question but would it be logical to get it into our code with the debug, or some other flag.

def debug_requests_on():
'''Switches on logging of the requests module.'''
HTTPConnection.debuglevel = 1

logging.basicConfig()
logging.getLogger().setLevel(logging.DEBUG)
requests_log = logging.getLogger("requests.packages.urllib3")
requests_log.setLevel(logging.DEBUG)
requests_log.propagate = True

def debug_requests_off():
'''Switches off logging of the requests module, might be some side-effects'''
HTTPConnection.debuglevel = 0

root_logger = logging.getLogger()
root_logger.setLevel(logging.WARNING)
root_logger.handlers = []
requests_log = logging.getLogger("requests.packages.urllib3")
requests_log.setLevel(logging.WARNING)
requests_log.propagate = False

@contextlib.contextmanager
def debug_requests():
'''Use with 'with'!'''
debug_requests_on()
yield
debug_requests_off()

@KSchopmeyer
Copy link
Collaborator

Finally for Christmas day. I also ran with Python 2 locally and passed the tests with these fixes. The remaining test is with windows.

@KSchopmeyer
Copy link
Collaborator

KSchopmeyer commented Dec 25, 2019

We are getting OpenSSL information on errors with requests that are http based and should not involve SSL.

(pywbem3) C:\Users\kscho\dev\pywbem\examples>enuminstances.py
Usage: C:\Users\kscho\dev\pywbem\examples\enuminstances.py server_url username password namespace' ' classname
Using internal defaults
Requesting url=http://localhost, ns=root/cimv2, class=CIM_ComputerSystem
TARGET_URL http://localhost:5988/cimom
Operation failed: Failed to establish a new connection: [WinError 10061] No connection could be made because the target machine actively refused it; OpenSSL version used: OpenSSL 1.0.2o 27 Mar 2018

Update by Andy: The "OpenSSL version used ..." text is inserted by pywbem. This could be improved by only inserting it for scheme='https'. Will do that in a separate PR #2049.

@KSchopmeyer
Copy link
Collaborator

KSchopmeyer commented Dec 25, 2019

Testing status: Wed 26 Dec. With temp patches per earlier comments

platform http https/no-verify https/ca-certfile https/ca-certdir mutual
python 3 OK OK OK OK OK
python 2 OK OK OK OK OK
windows OK OK OK

TODO:

  1. ca cert by directory in windows
  2. mutual auth, windows. Need to install tools for c_rehash for windows
    3 try to test certifi
  3. Test errors like bad certs

@andy-maier
Copy link
Contributor Author

andy-maier commented Dec 27, 2019

The latest update to this PR along with PR #2048 and the to be created one for the ssl messages for http connections should address all comments by Karl so far. Setting to review needed again, to get the changes verified.

This change migrates the HTTP communication of the pywbem client to use
the Python 'requests' package. This unifies the HTTP communication
again between Python 2 (where M2Crypto was used) and Python 3 (where
Python's ssl module was used).

Details:

* The coding changes are mainly in cim_http.py where the internal
  function wbem_requests() has mostly been re-written, and in
  cim_operations.py where wbem_requests() is called and the
  WBEMConnection object got a new 'session' attribute for the
  requests.Session object.

* Changed the way the 'ca_certs' parameter of 'WBEMConnection' can
  be used to select the CA certificates used to validate the
  server certificate, as follows:
  - Removed the set of hard coded certificate directories.
  - The default 'None' now causes the certificates from the certifi
    package to be used.
  - A string is interpreted as a path of a certificate file
    or certificate directory. Upon creation of the WBEMConnection
    object, the specified path name is checked for existance, and
    IOError is raised if it does not exist.

* Added concept of features in pywbem and a first PYWBEM_USES_REQUESTS
  feature which indicates a version of pywbem that uses the 'requests'
  package. This is useful for users of pywbem to write code that works
  with multiple versions of pywbem.

* Added a check for existance of the client certificate files
  specified with the 'x509' parameter of 'WBEMConnection', raising
  IOError if any of them is specified but does not exist.

* Added a 'scheme' read-only attribute to WBEMConnection that provides
  the scheme of the input URL.

* Removed support for the 'OWLocal' authentication scheme that was supported
  for the OpenWBEM server, and the 'Local' authentication scheme that was
  supported for the OpenPegasus server. Pywbem now supports only the 'Basic'
  authentication scheme.

* Removed support for communicating with WBEM servers using UNIX domain
  sockets by specifying a file-based URL. Use the standard http and https
  protocols instead.

* Changed the function tests to use requests_mock for their HTTP
  level mocking. This required adjusting the format of the CIMObject
  headers to no longer use percent-escapes.

* Removed use of x509 parameter from testcases in test_recorder.py,
  because the files are now checked for existence, and the subject of
  these tests does not justify the effort of mocking that.

* Changed the pywbem_os_setup.* scripts to no longer be used for
  installation of pywbem. They are still used for development of
  pywbem. Updated the docs accordingly.

* Note that the documentation of pywbem versions before 1.0.0 downloads
  the pywbem_os_setup.* scripts from the master branch of the pywbem repo.
  Therefore, the scripts still need to work for such earlier versions of
  pywbem. Added a bold information display explaining that the script
  no longer needs to be invoked when installing pywbem 1.0.0.

* Removed troubleshooting items that were specific to M2Crypto and
  Swig.

* Reduced the docs section about prerequisite OS packages to say
  there are no such prereqs anymore starting with 1.0.0.

* Re-established pypy support in Travis. It had to be removed because
  M2Crypto did not install on pypy. It is commented out in this change,
  but will be activated in the manual-ci-run branch.

* Clarified in the description of the ca_certs parameter of WBEMConnection
  that path names may be any type of string (byte string or unicode string).

* Made OpenSSL version info in exceptions that are raised to be conditional
  on using https, in order to avoid confusion.

Signed-off-by: Andreas Maier <andreas.r.maier@gmx.de>
@KSchopmeyer
Copy link
Collaborator

Testing done using url-normalize branch

@andy-maier andy-maier merged commit 93fefa5 into master Dec 28, 2019
@andy-maier andy-maier deleted the andy/use-requests branch December 28, 2019 17:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants