summaryrefslogtreecommitdiff
path: root/src/leap
diff options
context:
space:
mode:
authorkali <kali@leap.se>2012-09-18 22:55:45 +0900
committerkali <kali@leap.se>2012-09-18 22:55:45 +0900
commit89735a5fd3c81e8aba3cb7b1d4836c1bf1e8c098 (patch)
treea8a00856a7ee856cb08f263d613ac038f82043fd /src/leap
parent0d35f2a82bf15504ace2135af3e0c66ae1c16874 (diff)
cert verification and malformed json checks
Diffstat (limited to 'src/leap')
-rw-r--r--src/leap/base/config.py20
-rw-r--r--src/leap/base/constants.py2
-rw-r--r--src/leap/base/exceptions.py2
-rw-r--r--src/leap/baseapp/eip.py2
-rw-r--r--src/leap/eip/checks.py65
-rw-r--r--src/leap/eip/eipconnection.py26
-rw-r--r--src/leap/eip/exceptions.py15
7 files changed, 104 insertions, 28 deletions
diff --git a/src/leap/base/config.py b/src/leap/base/config.py
index e896ffd2..eb9bf88a 100644
--- a/src/leap/base/config.py
+++ b/src/leap/base/config.py
@@ -18,6 +18,9 @@ from leap.base import exceptions
from leap.base import constants
from leap.util.fileutil import (mkdir_p)
+# move to base!
+from leap.eip import exceptions as eipexceptions
+
class BaseLeapConfig(object):
slug = None
@@ -145,9 +148,9 @@ class JSONLeapConfig(BaseLeapConfig):
config[k] = v()
self._config.serialize(to)
- def load(self, fromfile=None, from_uri=None, fetcher=None):
+ def load(self, fromfile=None, from_uri=None, fetcher=None, verify=False):
if from_uri is not None:
- fetched = self.fetch(from_uri, fetcher=fetcher)
+ fetched = self.fetch(from_uri, fetcher=fetcher, verify=verify)
if fetched:
return
if fromfile is None:
@@ -156,12 +159,21 @@ class JSONLeapConfig(BaseLeapConfig):
# XXX check for no errors, etc
self._config.config = newconfig
- def fetch(self, uri, fetcher=None):
+ def fetch(self, uri, fetcher=None, verify=True):
if not fetcher:
fetcher = self.fetcher
- request = fetcher.get(uri)
+ logger.debug('verify: %s', verify)
+ request = fetcher.get(uri, verify=verify)
+
+ # XXX get 404, ...
+ # and raise a UnableToFetch...
request.raise_for_status()
fd, fname = tempfile.mkstemp(suffix=".json")
+ if not request.json:
+ try:
+ json.loads(request.content)
+ except ValueError:
+ raise eipexceptions.LeapBadConfigFetchedError
with open(fname, 'w') as tmp:
tmp.write(json.dumps(request.json))
self._loadtemp(fname)
diff --git a/src/leap/base/constants.py b/src/leap/base/constants.py
index f3e24715..7a1415fb 100644
--- a/src/leap/base/constants.py
+++ b/src/leap/base/constants.py
@@ -11,7 +11,7 @@ DEFAULT_PROVIDER = __branding.get(
"provider_domain",
"testprovider.example.org")
-DEFINITION_EXPECTED_PATH = "definition.json"
+DEFINITION_EXPECTED_PATH = "provider.json"
DEFAULT_PROVIDER_DEFINITION = {
u'api_uri': u'https://api.%s/' % DEFAULT_PROVIDER,
diff --git a/src/leap/base/exceptions.py b/src/leap/base/exceptions.py
index 9c4aa77b..caaa3be6 100644
--- a/src/leap/base/exceptions.py
+++ b/src/leap/base/exceptions.py
@@ -4,3 +4,5 @@ class MissingConfigFileError(Exception):
class ImproperlyConfigured(Exception):
pass
+
+
diff --git a/src/leap/baseapp/eip.py b/src/leap/baseapp/eip.py
index ff6a79ac..8ebd84ae 100644
--- a/src/leap/baseapp/eip.py
+++ b/src/leap/baseapp/eip.py
@@ -131,6 +131,8 @@ class EIPConductorAppMixin(object):
ErrorDialog(errtype="critical",
msg=message,
label="critical error")
+ elif error.warning:
+ logger.warning(error.message)
else:
dialog = ErrorDialog()
diff --git a/src/leap/eip/checks.py b/src/leap/eip/checks.py
index aea5a5d7..b55f5827 100644
--- a/src/leap/eip/checks.py
+++ b/src/leap/eip/checks.py
@@ -9,6 +9,8 @@ import netifaces
import ping
import requests
+from leap import __branding as BRANDING
+from leap import certs
from leap.base import constants as baseconstants
from leap.base import providers
from leap.eip import config as eipconfig
@@ -20,6 +22,11 @@ from leap.util.fileutil import mkdir_p
logger = logging.getLogger(name=__name__)
"""
+ProviderCertChecker
+-------------------
+Checks on certificates. To be moved to base.
+docs TBD
+
EIPConfigChecker
----------
It is used from the eip conductor (a instance of EIPConnection that is
@@ -36,14 +43,15 @@ LeapNetworkChecker
------------------
Network checks. To be moved to base.
docs TBD
-
-ProviderCertChecker
--------------------
-Checks on certificates.
-docs TBD
"""
+def get_ca_cert():
+ ca_file = BRANDING.get('provider_ca_file')
+ if ca_file:
+ return certs.where(ca_file)
+
+
class LeapNetworkChecker(object):
"""
all network related checks
@@ -67,6 +75,7 @@ class LeapNetworkChecker(object):
# XXX we probably should raise an exception here?
# unless we use this as smoke test
try:
+ # XXX remove this hardcoded random ip
requests.get('http://216.172.161.165')
except (requests.HTTPError, requests.RequestException) as e:
self.error = e.message
@@ -124,7 +133,7 @@ class ProviderCertChecker(object):
"""
def __init__(self, fetcher=requests):
self.fetcher = fetcher
- self.cacert = None
+ self.cacert = get_ca_cert()
def run_all(self, checker=None, skip_download=False):
if not checker:
@@ -159,25 +168,34 @@ class ProviderCertChecker(object):
raise NotImplementedError
def is_there_provider_ca(self):
- # XXX fake it till you make it! :P
+ from leap import certs
+ logger.debug('do we have provider_ca?')
+ cacert_path = BRANDING.get('provider_ca_file', None)
+ if not cacert_path:
+ logger.debug('False')
+ return False
+ self.cacert = certs.where(cacert_path)
+ logger.debug('True')
return True
- # enable this when we have
- # a custom "branded" bundle
- # certs package.
- try:
- from leap.custom import certs
- except ImportError:
- raise
- self.cacert = certs.where('cacert.pem')
-
def is_https_working(self, uri=None, verify=True):
+ if uri is None:
+ uri = self._get_root_uri()
# XXX raise InsecureURI or something better
+ logger.debug('is https working?')
+ logger.debug('uri: %s', uri)
+ #import ipdb;ipdb.set_trace()
assert uri.startswith('https')
if verify is True and self.cacert is not None:
+ logger.debug('verify cert: %s', self.cacert)
verify = self.cacert
- self.fetcher.get(uri, verify=verify)
- return True
+ try:
+ self.fetcher.get(uri, verify=verify)
+ except requests.exceptions.SSLError:
+ raise eipexceptions.EIPBadCertError
+ else:
+ logger.debug('True')
+ return True
def check_new_cert_needed(self, skip_download=False):
if not self.is_cert_valid(do_raise=False):
@@ -256,7 +274,11 @@ class ProviderCertChecker(object):
raise
return True
+ def _get_root_uri(self):
+ return u"https://%s/" % baseconstants.DEFAULT_PROVIDER
+
def _get_client_cert_uri(self):
+ # XXX get the whole thing from constants
return "https://%s/cert/get" % (baseconstants.DEFAULT_PROVIDER)
def _get_client_cert_path(self):
@@ -370,7 +392,12 @@ class EIPConfigChecker(object):
domain = config.get('provider', None)
uri = self._get_provider_definition_uri(domain=domain)
- self.defaultprovider.load(from_uri=uri, fetcher=self.fetcher)
+ # FIXME! Pass ca path verify!!!
+ self.defaultprovider.load(
+ from_uri=uri,
+ fetcher=self.fetcher,
+ verify=False)
+ #import ipdb;ipdb.set_trace()
self.defaultprovider.save()
def fetch_eip_service_config(self, skip_download=False,
diff --git a/src/leap/eip/eipconnection.py b/src/leap/eip/eipconnection.py
index d1c84b2a..4e240f16 100644
--- a/src/leap/eip/eipconnection.py
+++ b/src/leap/eip/eipconnection.py
@@ -6,6 +6,7 @@ import logging
import Queue
import sys
+from leap.eip.checks import ProviderCertChecker
from leap.eip.checks import EIPConfigChecker
from leap.eip import config as eipconfig
from leap.eip import exceptions as eip_exceptions
@@ -22,7 +23,10 @@ class EIPConnection(OpenVPNConnection):
Status updates (connected, bandwidth, etc) are signaled to the GUI.
"""
- def __init__(self, config_checker=EIPConfigChecker, *args, **kwargs):
+ def __init__(self,
+ provider_cert_checker=ProviderCertChecker,
+ config_checker=EIPConfigChecker,
+ *args, **kwargs):
self.settingsfile = kwargs.get('settingsfile', None)
self.logfile = kwargs.get('logfile', None)
@@ -30,6 +34,8 @@ class EIPConnection(OpenVPNConnection):
status_signals = kwargs.pop('status_signals', None)
self.status = EIPConnectionStatus(callbacks=status_signals)
+
+ self.provider_cert_checker = provider_cert_checker()
self.config_checker = config_checker()
host = eipconfig.get_socket_path()
@@ -45,12 +51,25 @@ class EIPConnection(OpenVPNConnection):
run all eip checks previous to attempting a connection
"""
logger.debug('running conductor checks')
+
+ def push_err(exc):
+ # keep the original traceback!
+ exc_traceback = sys.exc_info()[2]
+ self.error_queue.put((exc, exc_traceback))
+
+ try:
+ # network (1)
+ self.provider_cert_checker.run_all()
+ except Exception as exc:
+ push_err(exc)
try:
self.config_checker.run_all(skip_download=skip_download)
+ except Exception as exc:
+ push_err(exc)
+ try:
self.run_openvpn_checks()
except Exception as exc:
- exc_traceback = sys.exc_info()[2]
- self.error_queue.put((exc, exc_traceback))
+ push_err(exc)
def connect(self):
"""
@@ -84,6 +103,7 @@ class EIPConnection(OpenVPNConnection):
# XXX this separation does not
# make sense anymore after having
# merged Connection and Manager classes.
+ # XXX GET RID OF THIS FUNCTION HERE!
try:
state = self.get_connection_state()
except eip_exceptions.ConnectionRefusedError:
diff --git a/src/leap/eip/exceptions.py b/src/leap/eip/exceptions.py
index 467be7fe..f048621f 100644
--- a/src/leap/eip/exceptions.py
+++ b/src/leap/eip/exceptions.py
@@ -40,6 +40,8 @@ class EIPClientError(Exception):
base EIPClient exception
"""
critical = False
+ failfirst = False
+ warning = False
class CriticalError(EIPClientError):
@@ -54,7 +56,7 @@ class Warning(EIPClientError):
"""
just that, warnings
"""
- pass
+ warning = True
class EIPNoPolkitAuthAgentAvailable(CriticalError):
@@ -81,10 +83,21 @@ class EIPNoCommandError(EIPClientError):
"<br/>(Might be a permissions problem)")
+class EIPBadCertError(Warning):
+ # XXX this should be critical and fail close
+ message = "cert verification failed"
+ usermessage = "there is a problem with provider certificate"
+
+
+class LeapBadConfigFetchedError(Warning):
+ message = "provider sent a malformed json file"
+ usermessage = "an error occurred during configuratio of leap services"
+
#
# errors still needing some love
#
+
class EIPInitNoKeyFileError(CriticalError):
message = "No vpn keys found in the expected path"
usermessage = "We could not find your eip certs in the expected path"