Added SSL (Secure Sockets Layer) support, inspired by patch by rcaskey (issue 79). The automatic certificate creation does not work well; so the system instead instructs and gives example on how to create your own using third-party tools. I can connect to the server using a twisted-client instance, but not that many regular mud clients seem to support SSL at all (and if they do I don't know to configure them ...)

This commit is contained in:
Griatch 2011-05-28 15:48:50 +00:00
parent 7c56c69cea
commit a8a70e9f5e
3 changed files with 103 additions and 12 deletions

View file

@ -1,11 +1,11 @@
"""
This module implements the main Evennia server process, the core of
the game engine. Don't import this module! If you need to access the
server processes from code, instead import sessionhandler.SESSIONS
and use its 'server' property.
the game engine. Don't import this module directly! If you need to
access the server processes from code, instead go via the session-
handler: src.sessionhandler.SESSIONS.server
This module should be started with the 'twistd' executable since it
sets up all the networking features. (this is done by automatically
sets up all the networking features. (this is done automatically
by game/evennia.py).
"""
@ -39,10 +39,12 @@ SERVERNAME = settings.SERVERNAME
VERSION = get_evennia_version()
TELNET_PORTS = settings.TELNET_PORTS
SSL_PORTS = settings.SSL_PORTS
SSH_PORTS = settings.SSH_PORTS
WEBSERVER_PORTS = settings.WEBSERVER_PORTS
TELNET_ENABLED = settings.TELNET_ENABLED and TELNET_PORTS
SSL_ENABLED = settings.SSL_ENABLED and SSL_PORTS
SSH_ENABLED = settings.SSH_ENABLED and SSH_PORTS
WEBSERVER_ENABLED = settings.WEBSERVER_ENABLED and WEBSERVER_PORTS
WEBCLIENT_ENABLED = settings.WEBCLIENT_ENABLED
@ -101,7 +103,7 @@ class Evennia(object):
# set a callback if the server is killed abruptly,
# by Ctrl-C, reboot etc.
reactor.addSystemEventTrigger('before', 'shutdown',self.shutdown, _abrupt=True)
reactor.addSystemEventTrigger('before', 'shutdown', self.shutdown, _abrupt=True)
self.game_running = True
@ -153,6 +155,8 @@ class Evennia(object):
print " telnet: " + ", ".join([str(port) for port in TELNET_PORTS])
if SSH_ENABLED:
print " ssh: " + ", ".join([str(port) for port in SSH_PORTS])
if SSL_ENABLED:
print " ssl: " + ", ".join([str(port) for port in SSL_PORTS])
if WEBSERVER_ENABLED:
clientstring = ""
if WEBCLIENT_ENABLED:
@ -196,32 +200,46 @@ EVENNIA = Evennia(application)
if TELNET_ENABLED:
# start telnet game connections
# Start telnet game connections
from src.server import telnet
for port in TELNET_PORTS:
for port in TELNET_PORTS:
factory = protocol.ServerFactory()
factory.protocol = telnet.TelnetProtocol
telnet_service = internet.TCPServer(port, factory)
telnet_service.setName('EvenniaTelnet%s' % port)
EVENNIA.services.addService(telnet_service)
if SSL_ENABLED:
# Start SSL game connection (requires PyOpenSSL).
from src.server import ssl
for port in SSL_PORTS:
factory = protocol.ServerFactory()
factory.protocol = ssl.SSLProtocol
ssl_service = internet.SSLServer(port, factory, ssl.getSSLContext())
ssl_service.setName('EvenniaSSL%s' % port)
EVENNIA.services.addService(ssl_service)
if SSH_ENABLED:
# Start SSH game connections. Will create a keypair in evennia/game if necessary.
from src.server import ssh
for port in SSH_PORTS:
factory = ssh.makeFactory({'protocolFactory':ssh.SshProtocol,
'protocolArgs':()})
'protocolArgs':()})
ssh_service = internet.TCPServer(port, factory)
ssh_service.setName('EvenniaSSH%s' % port)
EVENNIA.services.addService(ssh_service)
if WEBSERVER_ENABLED:
# a django-compatible webserver.
# Start a django-compatible webserver.
from twisted.python import threadpool
from src.server.webserver import DjangoWebRoot, WSGIWebServer

69
src/server/ssl.py Normal file
View file

@ -0,0 +1,69 @@
"""
This is a simple context factory for auto-creating
SSL keys and certificates.
"""
import os, sys
from twisted.internet import ssl as twisted_ssl
try:
import OpenSSL
except ImportError:
print " SSL_ENABLED requires PyOpenSSL."
sys.exit()
from src.server.telnet import TelnetProtocol
class SSLProtocol(TelnetProtocol):
"""
Communication is the same as telnet, except data transfer
is done with encryption.
"""
pass
def verify_SSL_key_and_cert(keyfile, certfile):
"""
This function looks for RSA key and certificate in the current
directory. If files ssl.key and ssl.cert does not exist, they
are created.
"""
if not (os.path.exists(keyfile) and os.path.exists(certfile)):
# key/cert does not exist. Create.
import subprocess
from Crypto.PublicKey import RSA
from twisted.conch.ssh.keys import Key
print " Creating SSL key and certificate (this need only be done once)."
# create the RSA key and store it.
KEY_LENGTH = 1024
rsaKey = Key(RSA.generate(KEY_LENGTH))
keyString = rsaKey.toString(type="OPENSSH")
file(keyfile, 'w+b').write(keyString)
# try to create the certificate
CERT_EXPIRE = 365 * 20 # twenty years validity
# default:
#openssl req -new -x509 -key ssl.key -out ssl.cert -days 7300
exestring = "openssl req -new -x509 -key %s -out %s -days %s" % (keyfile, certfile, CERT_EXPIRE)
#print "exestring:", exestring
try:
err = subprocess.call(exestring)#, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
except OSError, e:
print " %s\n" % e
print " Evennia's SSL context factory could not automatically create an SSL certificate game/%s." % certfile
print " A private key 'ssl.key' was already created. Please create %s manually using the commands valid " % certfile
print " for your operating system."
print " Example (linux, using the openssl program): "
print " %s" % exestring
sys.exit()
def getSSLContext():
"""
Returns an SSL context (key and certificate). This function
verifies that key/cert exists before obtaining the context, and if
not, creates them.
"""
keyfile, certfile = "ssl.key", "ssl.cert"
verify_SSL_key_and_cert(keyfile, certfile)
return twisted_ssl.DefaultOpenSSLContextFactory(keyfile, certfile)

View file

@ -36,10 +36,14 @@ WEBSERVER_PORTS = [8000]
# Start the evennia ajax client on /webclient
# (the webserver must also be running)
WEBCLIENT_ENABLED = True
# Activate SSH protocol
# Activate SSH protocol (SecureShell)
SSH_ENABLED = False
# Ports to use for SSH
# Ports to use for SSH
SSH_PORTS = [8022]
# Actiave SSL protocol (SecureSocketLibrary)
SSL_ENABLED = False
# Ports to use for SSL
SSL_PORTS = [4001]
# Activate full persistence if you want everything in-game to be
# stored to the database. With it set, you can do typeclass.attr=value
# and value will be saved to the database under the name 'attr'.