Skip to content

Commit

Permalink
Merge pull request #11 from authomatic/pyramid_ssl
Browse files Browse the repository at this point in the history
Add SSL support for pyramid.
  • Loading branch information
mrichar1 authored Feb 7, 2020
2 parents ab6561e + 7c3a6eb commit 1aa1f99
Show file tree
Hide file tree
Showing 8 changed files with 86 additions and 6 deletions.
6 changes: 5 additions & 1 deletion README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,10 @@ Pyramid (wsgiref.simple_server)
By ``wsgiref.simple_server`` you must wrap the **WSGI application** in
``liveandletdie.WsgirefSimpleServer.wrap(app)``.

If you set the ``ssl`` keyword argument to ``True``, the app will be run with
a self-signed certificate, and the schema of the ``self.check_url``
will be ``"https"``.

.. code-block:: python
# pyramid/app/main.py
Expand Down Expand Up @@ -213,4 +217,4 @@ Or bootstrap and run tests in one step:

$ sh bootstrap-and-test.sh

Enjoy!
Enjoy!
59 changes: 57 additions & 2 deletions liveandletdie/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,12 @@
import os
import re
import signal
import ssl
import subprocess
import sys
import tempfile
import time
from werkzeug.serving import make_ssl_devcert
# pylint: disable=wrong-import-order
try:
from urllib.parse import urlsplit, splitport
Expand Down Expand Up @@ -419,11 +422,10 @@ def wrap(cls, app):
"""

host, port = cls.parse_args()
ssl = cls._argument_parser.parse_args().ssl
ssl_context = None

if host:
if ssl:
if cls._argument_parser.parse_args().ssl:
try:
import OpenSSL # pylint: disable=unused-variable
except ImportError:
Expand Down Expand Up @@ -483,13 +485,66 @@ def create_command(self):


class WsgirefSimpleServer(WrapperBase):
def __init__(self, *args, **kwargs):
"""
:param bool ssl:
If true, the app will be run with ssl enabled and the
scheme of the ``self.check_url`` will be ``"https"``.
"""
self.ssl = kwargs.pop('ssl', None)
super(WsgirefSimpleServer, self).__init__(*args, **kwargs)
if self.ssl:
self.scheme = 'https'

def create_command(self):
command = super(WsgirefSimpleServer, self).create_command()
if self.ssl is True:
command += ['--ssl=1']
return command

def check(self, check_url=None):
url = self.check_url if check_url is None else \
self._normalize_check_url(check_url)

if self.ssl:
url = url.replace('http://', 'https://')

super(WsgirefSimpleServer, self).check(url)

@classmethod
def _add_args(cls):
super(WsgirefSimpleServer, cls)._add_args()
cls._argument_parser.add_argument('--ssl',
help='Run with ssl enabled.',
type=bool,
nargs='?',
default=False)

@classmethod
def wrap(cls, app):
host, port = cls.parse_args()
if host:
from wsgiref.simple_server import make_server

server = make_server(host, port, app)
if cls._argument_parser.parse_args().ssl:
# Set HTTPS='1' makes wsgiref set wsgi.url_scheme='https'
# This in turn makes pyramid set request.scheme='https'
server.base_environ['HTTPS'] = '1'

with tempfile.TemporaryDirectory() as td:
# Generate temporary self-signed cert/key pair
# using the library used by Flask for 'adhoc' ssl_context
certpath = '{}/liveandletdie'.format(td)
make_ssl_devcert(certpath)

server.socket = ssl.wrap_socket(
server.socket,
server_side=True,
certfile='{}.crt'.format(certpath),
keyfile='{}.key'.format(certpath),
)

server.serve_forever()
server.server_close()
sys.exit()
Expand Down
8 changes: 6 additions & 2 deletions sample_apps/pyramid/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,11 @@


def home(request):
return Response('Home Pyramid')
content = 'Home Pyramid'
if request.scheme == 'https':
content += ' SSL'

return Response(content)


if __name__ == '__main__':
Expand All @@ -22,4 +26,4 @@ def home(request):

server = make_server('127.0.0.1', 8080, app)

server.serve_forever()
server.serve_forever()
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
name=NAME,
version='0.0.6',
packages=find_packages(),
install_requires=['requests'],
install_requires=['requests', 'werkzeug'],
package_data={'': ['*.txt', '*.rst']},
author='Peter Hudec',
author_email='[email protected]',
Expand Down
5 changes: 5 additions & 0 deletions test_examples/pytest_example/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,11 @@ def abspath(pth):
abspath('sample_apps/pyramid/main.py'),
port=PORT
),
'Pyramid SSL': liveandletdie.WsgirefSimpleServer(
abspath('sample_apps/pyramid/main.py'),
port=PORT,
ssl=True
),
'Flask': liveandletdie.Flask(
abspath('sample_apps/flask/main.py'),
port=PORT
Expand Down
7 changes: 7 additions & 0 deletions test_examples/unittest_example/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,13 @@ class TestPyramid(unittest.TestCase):
app = liveandletdie.WsgirefSimpleServer(abspath('sample_apps/pyramid/main.py'), port=PORT)


@test_decorator
class TestPyramidSSL(unittest.TestCase):
EXPECTED_TEXT = 'Home Pyramid SSL'
app = liveandletdie.WsgirefSimpleServer(abspath('sample_apps/pyramid/main.py'), port=PORT,
ssl=True)


@test_decorator
class TestDjango(unittest.TestCase):
EXPECTED_TEXT = 'Home Django'
Expand Down
4 changes: 4 additions & 0 deletions tests/test_all.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,3 +86,7 @@ def test__normalize_check_url(self):
class TestFlask(SSLBase):
app_path = os.path.join(SAMPLE_APPS_DIR, 'flask', 'main.py')
class_ = liveandletdie.Flask

class TestPyramid(SSLBase):
app_path = os.path.join(SAMPLE_APPS_DIR, 'pyramid', 'main.py')
class_ = liveandletdie.Pyramid
1 change: 1 addition & 0 deletions tox.ini
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ deps=
pytest
pyopenssl
requests
werkzeug
setenv =
PYTHONPATH={toxinidir}
PYTHONWARNINGS=ignore
Expand Down

0 comments on commit 1aa1f99

Please sign in to comment.