https.py 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153
  1. # Copyright (C) 2010-2013 Sebastian Rahlf and others (see AUTHORS).
  2. #
  3. # This program is release under the MIT license. You can find the full text of
  4. # the license in the LICENSE file.
  5. import os.path
  6. from pytest_localserver.http import ContentServer
  7. #: default server certificate
  8. DEFAULT_CERTIFICATE = os.path.join(os.getcwd(), 'server.pem')
  9. class SecureContentServer (ContentServer):
  10. """
  11. Small test server which works just like :class:`http.Server` over HTTP::
  12. server = SecureContentServer(
  13. port=8080, key='/srv/my.key', cert='my.certificate')
  14. server.start()
  15. print 'Test server running at %s' % server.url
  16. server.serve_content(open('/path/to/some.file').read())
  17. # any call to https://localhost:8080 will get the contents of
  18. # /path/to/some.file as a response.
  19. To avoid *ssl handshake failures* you can import the `pytest-localserver
  20. CA`_ into your browser of choice.
  21. How to create a self-signed certificate
  22. ---------------------------------------
  23. If you want to create your own server certificate, you need `OpenSSL`_
  24. installed on your machine. A self-signed certificate consists of a
  25. certificate and a private key for your server. It can be created with
  26. a command like this, using OpenSSL 1.1.1::
  27. openssl req \
  28. -x509 \
  29. -newkey rsa:4096 \
  30. -sha256 \
  31. -days 3650 \
  32. -nodes \
  33. -keyout server.pem \
  34. -out server.pem \
  35. -subj "/CN=127.0.0.1/O=pytest-localserver/OU=Testing Dept." \
  36. -addext "subjectAltName=DNS:localhost"
  37. Note that both key and certificate are in a single file now named
  38. ``server.pem``.
  39. How to create your own Certificate Authority
  40. --------------------------------------------
  41. Generate a server key and request for signing (csr). Make sure that the
  42. common name (CN) is your IP address/domain name (e.g. ``localhost``). ::
  43. openssl genpkey \
  44. -algorithm RSA \
  45. -pkeyopt rsa_keygen_bits:4096 \
  46. -out server.key
  47. openssl req \
  48. -new \
  49. -addext "subjectAltName=DNS:localhost" \
  50. -key server.key \
  51. -out server.csr
  52. Generate your own CA. Make sure that this time the CN is *not* your IP
  53. address/domain name (e.g. ``localhost CA``). ::
  54. openssl genpkey \
  55. -algorithm RSA \
  56. -pkeyopt rsa_keygen_bits:4096 \
  57. -aes256 \
  58. -out ca.key
  59. openssl req \
  60. -new \
  61. -x509 \
  62. -key ca.key \
  63. -out ca.crt
  64. Sign the certificate signing request (csr) with the self-created CA that
  65. you made earlier. Note that OpenSSL does not copy the subjectAltName field
  66. from the request (csr), so you have to provide it again as a file. If you
  67. issue subsequent certificates and your browser already knows about previous
  68. ones simply increment the serial number. ::
  69. echo "subjectAltName=DNS:localhost" >server-extensions.txt
  70. openssl x509 -req -in server.csr -CA ca.crt -CAkey ca.key \
  71. -set_serial 01 -extfile server-extensions.txt -out server.crt
  72. Create a single file for both key and certificate::
  73. cat server.key server.crt > server.pem
  74. Now you only need to import ``ca.crt`` as a CA in your browser.
  75. Want to know more?
  76. ------------------
  77. This information was compiled from the following sources, which you might
  78. find helpful if you want to dig deeper into `pyOpenSSH`_, certificates and
  79. CAs:
  80. - http://code.activestate.com/recipes/442473/
  81. - http://www.tc.umn.edu/~brams006/selfsign.html
  82. -
  83. A more advanced tutorial can be found `here`_.
  84. .. _pytest-localserver CA: https://raw.githubusercontent.com/pytest-dev/pytest-localserver/master/pytest_localserver/ca.crt
  85. .. _pyOpenSSH: https://launchpad.net/pyopenssl
  86. """
  87. def __init__(self, host='localhost', port=0,
  88. key=DEFAULT_CERTIFICATE, cert=DEFAULT_CERTIFICATE):
  89. """
  90. :param key: location of file containing the server private key.
  91. :param cert: location of file containing server certificate.
  92. """
  93. super(SecureContentServer, self).__init__(host, port, ssl_context=(key, cert))
  94. if __name__ == '__main__': # pragma: no cover
  95. import sys
  96. import time
  97. print('Using certificate %s.' % DEFAULT_CERTIFICATE)
  98. server = SecureContentServer()
  99. server.start()
  100. server.logging = True
  101. print('HTTPS server is running at %s' % server.url)
  102. print('Type <Ctrl-C> to stop')
  103. try:
  104. path = sys.argv[1]
  105. except IndexError:
  106. path = os.path.join(
  107. os.path.dirname(os.path.abspath(__file__)), '..', 'README.rst')
  108. server.serve_content(open(path).read(), 302)
  109. try:
  110. while True:
  111. time.sleep(1)
  112. except KeyboardInterrupt:
  113. print('\rstopping...')
  114. server.stop()