fixed the 'status' method of the encrypted_webinterface module
added a method 'create_misc_config_file' to cryptobox.core.settings used this method to create the certificate file improved the description on how to set up an encrypted webinterface connection added description of the 'encrypted_webinterface' plugin to README.ssl moved 'coding_guidelines.txt' to the wiki
This commit is contained in:
parent
4e5b8e088f
commit
2ecc20e905
47
README.ssl
47
README.ssl
|
@ -4,7 +4,9 @@ This file describes how to encrypt your connection to the CryptoBox webserver.
|
||||||
This is highly recommended as the encryption password for your data could be
|
This is highly recommended as the encryption password for your data could be
|
||||||
exposed to intruders in your local network otherwise.
|
exposed to intruders in your local network otherwise.
|
||||||
|
|
||||||
There are several ways for setting up a SSL connection:
|
Below you will find detailed descriptions on how to set up an encrypted
|
||||||
|
connection to the webinterface:
|
||||||
|
- use the plugin "encrypted_webinterface"
|
||||||
- run the CryptoBox webserver behind an ssl-enabled webserver
|
- run the CryptoBox webserver behind an ssl-enabled webserver
|
||||||
- use stunnel to provide an SSL socket
|
- use stunnel to provide an SSL socket
|
||||||
- use the a proxy server (e.g. pound)
|
- use the a proxy server (e.g. pound)
|
||||||
|
@ -17,7 +19,27 @@ need encrypted http connections.
|
||||||
|
|
||||||
-------------------------------------------------------------------
|
-------------------------------------------------------------------
|
||||||
|
|
||||||
1) CryptoBox behind an ssl-enabled webserver
|
1) using the plugin 'encrypted_webinterface'
|
||||||
|
This plugin is disabled by default. You can enable it in your
|
||||||
|
cryptobox.conf file by removing it from the 'DisabledPlugins' setting.
|
||||||
|
|
||||||
|
The plugin does the following during startup of the CryptoBox:
|
||||||
|
- create a self-signed X.509 certificate if necessary
|
||||||
|
- run stunnel on port 443 (https) with this certificate
|
||||||
|
|
||||||
|
Now you just need to point your browser to the URL of the CryptoBox with
|
||||||
|
'https' instead of 'http' and to accept the certificate permanently
|
||||||
|
(the Internet Explorer is not capable of doing this - use Firefox,
|
||||||
|
Konqueror, Safari, ... instead, if you need this ability). That's it!
|
||||||
|
|
||||||
|
Of course, this will not work, if the port 443 is already in use by
|
||||||
|
another program - in this case, you should better choose one of the
|
||||||
|
other solutions described below.
|
||||||
|
|
||||||
|
|
||||||
|
-------------------------------------------------------------------
|
||||||
|
|
||||||
|
2) CryptoBox behind an ssl-enabled webserver
|
||||||
Read the documentation of your favourite webserver to learn how to enable
|
Read the documentation of your favourite webserver to learn how to enable
|
||||||
ssl encryption.
|
ssl encryption.
|
||||||
|
|
||||||
|
@ -38,16 +60,16 @@ need encrypted http connections.
|
||||||
|
|
||||||
-------------------------------------------------------------------
|
-------------------------------------------------------------------
|
||||||
|
|
||||||
2) CryptoBox behind stunnel
|
3) CryptoBox behind stunnel (configured manually)
|
||||||
You may want to tunnel the traffic between the cryptobox-server
|
You may want to tunnel the traffic between the cryptobox-server
|
||||||
and your browser. "stunnel" is an excellent candidate for this job.
|
and your browser. "stunnel" is an excellent candidate for this job.
|
||||||
|
|
||||||
If you do not have an ssl certificate yet, then you should create
|
If you do not have an ssl certificate yet, then you should create
|
||||||
one first. On Debian: "apt-get install ssl-cert" and run the following
|
one first. On Debian: "apt-get install ssl-cert" and run the following
|
||||||
command (replace the <NAMES>; a default CERT_CONF is shipped with the
|
command (the supplied example openssl.conf file resides in the doc
|
||||||
cryptobox-server package):
|
directory of the cryptobox-server package):
|
||||||
|
|
||||||
make-ssl-cert <CERT_CONF> <CERT_FILE_NAME>
|
make-ssl-cert conf-examples/openssl.conf <CERT_FILE_NAME>
|
||||||
|
|
||||||
In case, that you already have a certificate just run this command:
|
In case, that you already have a certificate just run this command:
|
||||||
|
|
||||||
|
@ -58,9 +80,10 @@ need encrypted http connections.
|
||||||
|
|
||||||
-------------------------------------------------------------------
|
-------------------------------------------------------------------
|
||||||
|
|
||||||
3) CryptoBox behind a proxy server
|
4) CryptoBox behind a proxy server
|
||||||
As there are many proxy servers around, we cannot describe all of them. As
|
As there are many proxy servers around, we cannot describe all of them. As
|
||||||
an example, we will explain the setup of the load-balancing proxy 'pound'.
|
an example, we will explain the setup of the load-balancing proxy 'pound'
|
||||||
|
(http://www.apsis.ch/pound/).
|
||||||
|
|
||||||
Just add the following lines to you /etc/pound/pound.cfg:
|
Just add the following lines to you /etc/pound/pound.cfg:
|
||||||
# Remove the X-SSL-Request header from incoming
|
# Remove the X-SSL-Request header from incoming
|
||||||
|
@ -77,13 +100,15 @@ need encrypted http connections.
|
||||||
|
|
||||||
-------------------------------------------------------------------
|
-------------------------------------------------------------------
|
||||||
|
|
||||||
4) Problems with SSL detection?
|
5) Problems with SSL detection?
|
||||||
If the CryptoBox continues to complain about the unencrypted connection, even
|
If the CryptoBox continues to complain about the unencrypted connection, even
|
||||||
if it runs behind an ssl-enabled webserver or behind stunnel, then you can do
|
if it runs behind an ssl-enabled webserver or behind stunnel, then you can do
|
||||||
one of the following things:
|
one of the following things:
|
||||||
|
- disable the plugin 'encypted_webinterface' in the cryptobox.conf file
|
||||||
|
if you do not need it
|
||||||
- set the request header value "X-SSL-Request" to "1" (the digit 'one')
|
- set the request header value "X-SSL-Request" to "1" (the digit 'one')
|
||||||
- set the environment setting "HTTPS" to a non-empty value during the
|
- set the environment setting "HTTPS" to a non-empty value during the
|
||||||
startup of the CryptoBox webserver. Maybe /etc/default/cryptobox-server
|
startup of the CryptoBox webserver. Maybe
|
||||||
would be the right place for this.
|
/etc/default/cryptobox-server would be the right place for this.
|
||||||
- let the CryptoBox webserver listen to port 443
|
- let the CryptoBox webserver listen to port 443
|
||||||
|
|
||||||
|
|
|
@ -1,18 +0,0 @@
|
||||||
Maybe we can add some notes here to get a consistent coding experience :)
|
|
||||||
|
|
||||||
-------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
comments:
|
|
||||||
- should be usable for pydoc
|
|
||||||
- ''' or """ at the beginning of every class/method
|
|
||||||
- ## for longterm comments, that are useful for understanding
|
|
||||||
- #blabla for codelines, that are out for experimenting and might be used later again
|
|
||||||
|
|
||||||
error handling:
|
|
||||||
- unspecific error handling is evil (try: "grep -r except: .")
|
|
||||||
|
|
||||||
unit testing:
|
|
||||||
- first write a unittest and then write the relating code until the unittest stops failing :)
|
|
||||||
- 'unittests.ClassName.py' should contain all tests for 'ClassName.py'
|
|
||||||
- commits with broken unit tests are evil (fix or disable the code (not the test ;) ))
|
|
||||||
|
|
|
@ -69,9 +69,12 @@ class encrypted_webinterface(cryptobox.plugins.base.CryptoBoxPlugin):
|
||||||
|
|
||||||
|
|
||||||
def get_status(self):
|
def get_status(self):
|
||||||
"""Retrieve the status of the feature.
|
"""Retrieve the current state of the webinterface connection
|
||||||
"""
|
"""
|
||||||
return "TODO"
|
if self.__is_encrypted():
|
||||||
|
return "1"
|
||||||
|
else:
|
||||||
|
return "0"
|
||||||
|
|
||||||
|
|
||||||
def get_warnings(self):
|
def get_warnings(self):
|
||||||
|
@ -85,21 +88,32 @@ class encrypted_webinterface(cryptobox.plugins.base.CryptoBoxPlugin):
|
||||||
warnings.append((45, "Plugins.%s.MissingModuleM2Crypto" % self.get_name()))
|
warnings.append((45, "Plugins.%s.MissingModuleM2Crypto" % self.get_name()))
|
||||||
if not os.path.isfile(self.root_action.STUNNEL_BIN):
|
if not os.path.isfile(self.root_action.STUNNEL_BIN):
|
||||||
warnings.append((44, "Plugins.%s.MissingProgramStunnel" % self.get_name()))
|
warnings.append((44, "Plugins.%s.MissingProgramStunnel" % self.get_name()))
|
||||||
## perform some checks for encrypted connections
|
if not self.__is_encrypted():
|
||||||
## check an environment setting - this is quite common behind proxies
|
|
||||||
## check if it is a local connection (or via stunnel)
|
|
||||||
## the arbitrarily chosen header is documented in README.proxy
|
|
||||||
if (cherrypy.request.scheme != "https") \
|
|
||||||
and (not os.environ.has_key("HTTPS")) \
|
|
||||||
and (not (cherrypy.request.headers.has_key("Remote-Host") \
|
|
||||||
and (cherrypy.request.headers["Remote-Host"] == "127.0.0.1"))) \
|
|
||||||
and (not (cherrypy.request.headers.has_key("X-SSL-Request") \
|
|
||||||
and (cherrypy.request.headers["X-SSL-Request"] == "1"))):
|
|
||||||
## plaintext connection -> "heavy security risk" (priority=20..39)
|
## plaintext connection -> "heavy security risk" (priority=20..39)
|
||||||
warnings.append((25, "Plugins.%s.NoSSL" % self.get_name()))
|
warnings.append((25, "Plugins.%s.NoSSL" % self.get_name()))
|
||||||
return warnings
|
return warnings
|
||||||
|
|
||||||
|
|
||||||
|
def __is_encrypted(self):
|
||||||
|
"""perform some checks for encrypted connections
|
||||||
|
"""
|
||||||
|
if cherrypy.request.scheme == "https":
|
||||||
|
return True
|
||||||
|
## check an environment setting - this is quite common behind proxies
|
||||||
|
if os.environ.has_key("HTTPS"):
|
||||||
|
return True
|
||||||
|
## check if it is a local connection (or via stunnel)
|
||||||
|
if cherrypy.request.headers.has_key("Remote-Host") \
|
||||||
|
and (cherrypy.request.headers["Remote-Host"] == "127.0.0.1"):
|
||||||
|
return True
|
||||||
|
## the arbitrarily chosen header is documented in README.proxy
|
||||||
|
if cherrypy.request.headers.has_key("X-SSL-Request") \
|
||||||
|
and (cherrypy.request.headers["X-SSL-Request"] == "1"):
|
||||||
|
return True
|
||||||
|
## it looks like a plain connection
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
def handle_event(self, event, event_info=None):
|
def handle_event(self, event, event_info=None):
|
||||||
"""Create a certificate during startup (if it does not exist) and run stunnel
|
"""Create a certificate during startup (if it does not exist) and run stunnel
|
||||||
"""
|
"""
|
||||||
|
@ -107,12 +121,14 @@ class encrypted_webinterface(cryptobox.plugins.base.CryptoBoxPlugin):
|
||||||
cert_abs_name = self.cbox.prefs.get_misc_config_filename(CERT_FILENAME)
|
cert_abs_name = self.cbox.prefs.get_misc_config_filename(CERT_FILENAME)
|
||||||
if not os.path.isfile(cert_abs_name):
|
if not os.path.isfile(cert_abs_name):
|
||||||
try:
|
try:
|
||||||
self.__create_certificate(cert_abs_name)
|
cert = self.__get_certificate()
|
||||||
self.cbox.log.info("Created new SSL certificate: %s" % cert_abs_name)
|
self.cbox.prefs.create_misc_config_file(CERT_FILENAME, cert)
|
||||||
|
self.cbox.log.info("Created new SSL certificate: %s" % \
|
||||||
|
cert_abs_name)
|
||||||
except IOError, err_msg:
|
except IOError, err_msg:
|
||||||
## do not run stunnel without a certificate
|
## do not run stunnel without a certificate
|
||||||
self.cbox.log.warn("Failed to create new SSL certificate (%s): %s" % \
|
self.cbox.log.warn("Failed to create new SSL certificate (%s): %s" \
|
||||||
(cert_abs_name, err_msg))
|
% (cert_abs_name, err_msg))
|
||||||
return
|
return
|
||||||
self.__run_stunnel(cert_abs_name)
|
self.__run_stunnel(cert_abs_name)
|
||||||
elif event == "shutdown":
|
elif event == "shutdown":
|
||||||
|
@ -181,8 +197,8 @@ class encrypted_webinterface(cryptobox.plugins.base.CryptoBoxPlugin):
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
def __create_certificate(self, filename):
|
def __get_certificate(self):
|
||||||
"""Create a self-signed certificate and store it in a file
|
"""Create a self-signed certificate and return its pem content
|
||||||
|
|
||||||
The code is mainly inspired by:
|
The code is mainly inspired by:
|
||||||
https://dev.tribler.org/browser/m2crypto/trunk/contrib/SimpleX509create.py
|
https://dev.tribler.org/browser/m2crypto/trunk/contrib/SimpleX509create.py
|
||||||
|
@ -226,17 +242,5 @@ class encrypted_webinterface(cryptobox.plugins.base.CryptoBoxPlugin):
|
||||||
result = ""
|
result = ""
|
||||||
result += cert.as_pem()
|
result += cert.as_pem()
|
||||||
result += pkey.as_pem(cipher=None)
|
result += pkey.as_pem(cipher=None)
|
||||||
if not os.path.exists(os.path.dirname(filename)):
|
return result
|
||||||
os.mkdir(os.path.dirname(filename))
|
|
||||||
try:
|
|
||||||
certfile = open(filename, "w")
|
|
||||||
except IOError:
|
|
||||||
raise
|
|
||||||
try:
|
|
||||||
certfile.write(result)
|
|
||||||
except IOError:
|
|
||||||
certfile.close()
|
|
||||||
raise
|
|
||||||
certfile.close()
|
|
||||||
os.chmod(filename, 0600)
|
|
||||||
|
|
||||||
|
|
|
@ -100,6 +100,28 @@ class CryptoBoxSettings:
|
||||||
'name' should not contain slashes (no directory part!)
|
'name' should not contain slashes (no directory part!)
|
||||||
"""
|
"""
|
||||||
return os.path.join(self.prefs["Locations"]["SettingsDir"], "misc", name)
|
return os.path.join(self.prefs["Locations"]["SettingsDir"], "misc", name)
|
||||||
|
|
||||||
|
|
||||||
|
def create_misc_config_file(self, name, content):
|
||||||
|
"""Create a new configuration file in the 'settings' directory
|
||||||
|
|
||||||
|
"name" should be the basename (without a directory)
|
||||||
|
"content" will be directly written to the file
|
||||||
|
this method may throw an IOException
|
||||||
|
"""
|
||||||
|
misc_conf_file = self.get_misc_config_filename(name)
|
||||||
|
misc_conf_dir = os.path.dirname(misc_conf_file)
|
||||||
|
if not os.path.isdir(misc_conf_dir):
|
||||||
|
os.mkdir(misc_conf_dir)
|
||||||
|
cfile = open(misc_conf_file, "w")
|
||||||
|
try:
|
||||||
|
cfile.write(content)
|
||||||
|
except IOError:
|
||||||
|
cfile.close()
|
||||||
|
raise
|
||||||
|
cfile.close()
|
||||||
|
## reread all misc files automatically - this should be ok
|
||||||
|
self.reload_misc_files()
|
||||||
|
|
||||||
|
|
||||||
def requires_partition(self):
|
def requires_partition(self):
|
||||||
|
|
Loading…
Reference in a new issue