Commit 827a0d8a by Sheng

Support https server

parent deef92fe
-----BEGIN CERTIFICATE-----
MIIDYDCCAkigAwIBAgIJAPPORA/o2Zd4MA0GCSqGSIb3DQEBCwUAMEUxCzAJBgNV
BAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBX
aWRnaXRzIFB0eSBMdGQwHhcNMTgxMDE0MDgwNTQzWhcNMjExMDEzMDgwNTQzWjBF
MQswCQYDVQQGEwJBVTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50
ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB
CgKCAQEAvSFaffq6ExFCPN4cApRopGEqVIipAYb6Ky3VHVu4pW0tOdrdKafGGYkN
GWQdsLV0AAzzxmCAPpXmmAx0m0mgtPaJp3iW8NUibkISxdEO/QJOA7y8O9iWhDdb
l9ghjwPI5AwURQkDkXbcBBBzQksYDaYseL2NGDGXkKCUQQoLzV0H+SV3vCPrbOXH
t50HKgKzEOGoT8LcI7BRCTXk1xTlK0b/4ylKUwKIsfNPH0a9RkukBjMFkpXG/2CV
VWb89+TkMzQwhcpIVn6rUCJQW5pHVRYLACP32Zki7xPUJb9OfF7XDK54v6Cwo3Fi
aZWxN6rYhnn8wRTufY3PYzv5f3XiZwIDAQABo1MwUTAdBgNVHQ4EFgQUq0kfpU/m
WQwNk3ymwm7fuVwYhJ0wHwYDVR0jBBgwFoAUq0kfpU/mWQwNk3ymwm7fuVwYhJ0w
DwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAf2xudhAeOTUpNpw+
XZWLBXBKZXINd7PrUDgEG4bB0/0kYZN+T7bMJEtmv6+9t57y6jSni9sQzpbvT2tJ
TrbZgwhDvyTm3mw5n5RpAB9ZK+lnMcasa5N4qSd6wmpXjkC+kcEs7oQ8PwgIf3xT
/aGdoswNTWCz0W8vs8yRynLB4MKx1d20IMlDkfGu5n7wXhNK0ymcT8pa6iqEYl6X
bhPVTlELl8bM/OKktFc42VXoRghLRnfl8yM/9t7HVHKfHXZrLpIdtEOvnKwtzX5r
fBMs4IPa0OIPHGCcbLGT4rIbSvSaI8yOPA93G1XXbMF1VKdKyzdGjMS6aFKfbrhV
lnaUOA==
-----END CERTIFICATE-----
-----BEGIN PRIVATE KEY-----
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC9IVp9+roTEUI8
3hwClGikYSpUiKkBhvorLdUdW7ilbS052t0pp8YZiQ0ZZB2wtXQADPPGYIA+leaY
DHSbSaC09omneJbw1SJuQhLF0Q79Ak4DvLw72JaEN1uX2CGPA8jkDBRFCQORdtwE
EHNCSxgNpix4vY0YMZeQoJRBCgvNXQf5JXe8I+ts5ce3nQcqArMQ4ahPwtwjsFEJ
NeTXFOUrRv/jKUpTAoix808fRr1GS6QGMwWSlcb/YJVVZvz35OQzNDCFykhWfqtQ
IlBbmkdVFgsAI/fZmSLvE9Qlv058XtcMrni/oLCjcWJplbE3qtiGefzBFO59jc9j
O/l/deJnAgMBAAECggEAZSwcblvbgiuvVUQzk6W0PIrFzCa20dxUoxiHcocIRWYb
1WEhAhF/xVUtLrIBt++5N/W1yh8BO3mQuzGehxth3qwrguzdQcOiAX1S8YMeE3ZS
KWmjABiim+PJGXdCrHCH3IYhqbRitkPw+jOalJH7MgH8tDIh8hlFTNa5t/kZyybW
uGFbqF6OFmyHSDIPvjPALzSlmd5po+EywnA5oa3sObj4n5xuaFB2l/IaF3ix38vT
geo517L15cCuAa7x42i1cAGn5H/hdeO/Dw+MGk+0sXRRPooCMBzKztxpsB+7kNhk
jbsVHmTkE5UG/T7Uc0PsthZNjFwouPOrQQVUFYTnwQKBgQDwBvpmc9vX4gnADa7p
L2lgMVo6KccPFeFr4DIAYmwS0Vl0sB2j6nPVEBg3PatGLKGNMCIlcj+A3z6KQ+4o
n7pnekRwX+2+m3OPX4Rbw8c/+E0CiRPtmYp9BISKNgPoSRGsI6s/L3wzagsDsQ3v
xhKCohvfyY8JwUEPX6Hosmu/UQKBgQDJt0/ihWn0g/2uOKnXlXthxvkXFoR45sO7
lY/yoyJB+Z4yGAjJlbyra+5xnReqYyBnf34/2AoddjT45dPCaFucMInQFINdMGF1
NeVNzC6xa/7jjbgwf4kGqHsLC85Mrq3wyK5hwhMmfEPmRs6w+CRzM/Q78Bsr5P/T
zEa13jFINwKBgQC50L0ieUjVDKD9s9oXnWOXWz19T4BRtl+nco1i7M67lqQJCJo5
njQD2ozUnwIrtjtuoLeeg56Ttr+krEf/3P+iQe4fjLPxXkiM0qYVoC9s311GvDXY
N4gVllzA3mYR+hcbSxW0OZ+N8ecK+ZNPbug/hx3LFi+MnrYuH5upGA7/sQKBgCRk
nlUQHP2wkqRMNNhgb9JEQ8yWk2/8snO1mDL+m7+reY8wJuW3zkJfRrXY0dw75izG
I9EA+VI3cXc2f+4jReP4HeUczlaR1AOBpc1TeVkpUuNbPlABsocw/oIPrzjGiztV
+aBJk4ruAJIbVE85ddoTFY161Gwm9MERqfBGFj4hAoGAN/ry0KC9/QkLkuPjs3uL
AU3xjBJt1SMB7KZq1yt8mBo8M4q/E3ulynBK7G3f+hS2aj7OAhU4IcPRPGqjsLO1
dZTIOMeVyOAr0TAaioCCIyvf8hEjA7cXddnWBJYi3WiUpOc6J0uINoSlrAX2UXtw
/Aq5PmJKn4D4a75f+ue2Sw8=
-----END PRIVATE KEY-----
import io import io
import ssl
import sys import sys
import os.path import os.path
import unittest import unittest
...@@ -8,7 +9,8 @@ import tornado.options as options ...@@ -8,7 +9,8 @@ import tornado.options as options
from tests.utils import make_tests_data_path from tests.utils import make_tests_data_path
from webssh.policy import load_host_keys from webssh.policy import load_host_keys
from webssh.settings import ( from webssh.settings import (
get_host_keys_settings, get_policy_setting, base_dir, print_version get_host_keys_settings, get_policy_setting, base_dir, print_version,
get_ssl_context
) )
from webssh.utils import UnicodeType from webssh.utils import UnicodeType
from webssh._version import __version__ from webssh._version import __version__
...@@ -78,3 +80,43 @@ class TestSettings(unittest.TestCase): ...@@ -78,3 +80,43 @@ class TestSettings(unittest.TestCase):
) )
else: else:
self.assertIsInstance(instance, paramiko.client.RejectPolicy) self.assertIsInstance(instance, paramiko.client.RejectPolicy)
def test_get_ssl_context(self):
options.certfile = ''
options.keyfile = ''
ssl_ctx = get_ssl_context(options)
self.assertIsNone(ssl_ctx)
options.certfile = 'provided'
options.keyfile = ''
with self.assertRaises(ValueError) as ctx:
ssl_ctx = get_ssl_context(options)
self.assertEqual('keyfile is not provided', str(ctx.exception))
options.certfile = ''
options.keyfile = 'provided'
with self.assertRaises(ValueError) as ctx:
ssl_ctx = get_ssl_context(options)
self.assertEqual('certfile is not provided', str(ctx.exception))
options.certfile = 'FileDoesNotExist'
options.keyfile = make_tests_data_path('cert.key')
with self.assertRaises(ValueError) as ctx:
ssl_ctx = get_ssl_context(options)
self.assertIn('does not exist', str(ctx.exception))
options.certfile = make_tests_data_path('cert.key')
options.keyfile = 'FileDoesNotExist'
with self.assertRaises(ValueError) as ctx:
ssl_ctx = get_ssl_context(options)
self.assertIn('does not exist', str(ctx.exception))
options.certfile = make_tests_data_path('cert.key')
options.keyfile = make_tests_data_path('cert.key')
with self.assertRaises(ssl.SSLError) as ctx:
ssl_ctx = get_ssl_context(options)
options.certfile = make_tests_data_path('cert.crt')
options.keyfile = make_tests_data_path('cert.key')
ssl_ctx = get_ssl_context(options)
self.assertIsNotNone(ssl_ctx)
...@@ -4,8 +4,10 @@ import tornado.ioloop ...@@ -4,8 +4,10 @@ import tornado.ioloop
from tornado.options import options from tornado.options import options
from webssh.handler import IndexHandler, WsockHandler from webssh.handler import IndexHandler, WsockHandler
from webssh.settings import (get_app_settings, get_host_keys_settings, from webssh.settings import (
get_policy_setting, max_body_size) get_app_settings, get_host_keys_settings, get_policy_setting,
get_ssl_context, max_body_size, xheaders
)
def make_handlers(loop, options): def make_handlers(loop, options):
...@@ -28,9 +30,15 @@ def main(): ...@@ -28,9 +30,15 @@ def main():
options.parse_command_line() options.parse_command_line()
loop = tornado.ioloop.IOLoop.current() loop = tornado.ioloop.IOLoop.current()
app = make_app(make_handlers(loop, options), get_app_settings(options)) app = make_app(make_handlers(loop, options), get_app_settings(options))
server_settings = dict(xheaders=True, max_body_size=max_body_size) ssl_ctx = get_ssl_context(options)
app.listen(options.port, options.address, **server_settings) kwargs = dict(xheaders=xheaders, max_body_size=max_body_size)
app.listen(options.port, options.address, **kwargs)
logging.info('Listening on {}:{}'.format(options.address, options.port)) logging.info('Listening on {}:{}'.format(options.address, options.port))
if ssl_ctx:
kwargs.update(ssl_options=ssl_ctx)
app.listen(options.sslPort, options.sslAddress, **kwargs)
logging.info('Listening on ssl {}:{}'.format(options.sslAddress,
options.sslPort))
loop.start() loop.start()
......
import logging import logging
import os.path import os.path
import ssl
import sys import sys
from tornado.options import define from tornado.options import define
...@@ -17,6 +18,10 @@ def print_version(flag): ...@@ -17,6 +18,10 @@ def print_version(flag):
define('address', default='127.0.0.1', help='Listen address') define('address', default='127.0.0.1', help='Listen address')
define('port', type=int, default=8888, help='Listen port') define('port', type=int, default=8888, help='Listen port')
define('sslAddress', default='0.0.0.0', help='SSL listen address')
define('sslPort', type=int, default=4433, help='SSL listen port')
define('certfile', default='', help='SSL certificate file')
define('keyfile', default='', help='SSL key file')
define('debug', type=bool, default=False, help='Debug mode') define('debug', type=bool, default=False, help='Debug mode')
define('policy', default='warning', define('policy', default='warning',
help='Missing host key policy, reject|autoadd|warning') help='Missing host key policy, reject|autoadd|warning')
...@@ -30,6 +35,7 @@ define('version', type=bool, help='Show version information', ...@@ -30,6 +35,7 @@ define('version', type=bool, help='Show version information',
base_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) base_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
max_body_size = 1 * 1024 * 1024 max_body_size = 1 * 1024 * 1024
swallow_http_errors = True swallow_http_errors = True
xheaders = True
def get_app_settings(options): def get_app_settings(options):
...@@ -69,3 +75,20 @@ def get_policy_setting(options, host_keys_settings): ...@@ -69,3 +75,20 @@ def get_policy_setting(options, host_keys_settings):
logging.info(policy_class.__name__) logging.info(policy_class.__name__)
check_policy_setting(policy_class, host_keys_settings) check_policy_setting(policy_class, host_keys_settings)
return policy_class() return policy_class()
def get_ssl_context(options):
if not options.certfile and not options.keyfile:
return None
elif not options.certfile:
raise ValueError('certfile is not provided')
elif not options.keyfile:
raise ValueError('keyfile is not provided')
elif not os.path.isfile(options.certfile):
raise ValueError('File {!r} does not exist'.format(options.certfile))
elif not os.path.isfile(options.keyfile):
raise ValueError('File {!r} does not exist'.format(options.keyfile))
else:
ssl_ctx = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH)
ssl_ctx.load_cert_chain(options.certfile, options.keyfile)
return ssl_ctx
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment