mirror of https://github.com/huashengdun/webssh
				
				
				
			Support https server
							parent
							
								
									deef92fe66
								
							
						
					
					
						commit
						827a0d8a9d
					
				| 
						 | 
				
			
			@ -0,0 +1,21 @@
 | 
			
		|||
-----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-----
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,28 @@
 | 
			
		|||
-----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-----
 | 
			
		||||
| 
						 | 
				
			
			@ -1,4 +1,5 @@
 | 
			
		|||
import io
 | 
			
		||||
import ssl
 | 
			
		||||
import sys
 | 
			
		||||
import os.path
 | 
			
		||||
import unittest
 | 
			
		||||
| 
						 | 
				
			
			@ -8,7 +9,8 @@ import tornado.options as options
 | 
			
		|||
from tests.utils import make_tests_data_path
 | 
			
		||||
from webssh.policy import load_host_keys
 | 
			
		||||
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._version import __version__
 | 
			
		||||
| 
						 | 
				
			
			@ -78,3 +80,43 @@ class TestSettings(unittest.TestCase):
 | 
			
		|||
            )
 | 
			
		||||
        else:
 | 
			
		||||
            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
 | 
			
		|||
 | 
			
		||||
from tornado.options import options
 | 
			
		||||
from webssh.handler import IndexHandler, WsockHandler
 | 
			
		||||
from webssh.settings import (get_app_settings, get_host_keys_settings,
 | 
			
		||||
                             get_policy_setting, max_body_size)
 | 
			
		||||
from webssh.settings import (
 | 
			
		||||
    get_app_settings,  get_host_keys_settings, get_policy_setting,
 | 
			
		||||
    get_ssl_context, max_body_size, xheaders
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def make_handlers(loop, options):
 | 
			
		||||
| 
						 | 
				
			
			@ -28,9 +30,15 @@ def main():
 | 
			
		|||
    options.parse_command_line()
 | 
			
		||||
    loop = tornado.ioloop.IOLoop.current()
 | 
			
		||||
    app = make_app(make_handlers(loop, options), get_app_settings(options))
 | 
			
		||||
    server_settings = dict(xheaders=True, max_body_size=max_body_size)
 | 
			
		||||
    app.listen(options.port, options.address, **server_settings)
 | 
			
		||||
    ssl_ctx = get_ssl_context(options)
 | 
			
		||||
    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))
 | 
			
		||||
    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()
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,5 +1,6 @@
 | 
			
		|||
import logging
 | 
			
		||||
import os.path
 | 
			
		||||
import ssl
 | 
			
		||||
import sys
 | 
			
		||||
 | 
			
		||||
from tornado.options import define
 | 
			
		||||
| 
						 | 
				
			
			@ -17,6 +18,10 @@ def print_version(flag):
 | 
			
		|||
 | 
			
		||||
define('address', default='127.0.0.1', help='Listen address')
 | 
			
		||||
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('policy', default='warning',
 | 
			
		||||
       help='Missing host key policy, reject|autoadd|warning')
 | 
			
		||||
| 
						 | 
				
			
			@ -30,6 +35,7 @@ define('version', type=bool, help='Show version information',
 | 
			
		|||
base_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
 | 
			
		||||
max_body_size = 1 * 1024 * 1024
 | 
			
		||||
swallow_http_errors = True
 | 
			
		||||
xheaders = True
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def get_app_settings(options):
 | 
			
		||||
| 
						 | 
				
			
			@ -69,3 +75,20 @@ def get_policy_setting(options, host_keys_settings):
 | 
			
		|||
    logging.info(policy_class.__name__)
 | 
			
		||||
    check_policy_setting(policy_class, host_keys_settings)
 | 
			
		||||
    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
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue