diff options
| -rw-r--r-- | src/leap/base/auth.py | 14 | ||||
| -rw-r--r-- | src/leap/base/specs.py | 16 | ||||
| -rw-r--r-- | src/leap/base/tests/test_providers.py | 6 | ||||
| -rw-r--r-- | src/leap/baseapp/eip.py | 2 | ||||
| -rw-r--r-- | src/leap/baseapp/network.py | 8 | ||||
| -rw-r--r-- | src/leap/crypto/certs.py | 42 | ||||
| -rw-r--r-- | src/leap/crypto/tests/__init__.py | 0 | ||||
| -rw-r--r-- | src/leap/crypto/tests/test_certs.py | 11 | ||||
| -rw-r--r-- | src/leap/eip/checks.py | 29 | ||||
| -rw-r--r-- | src/leap/eip/config.py | 27 | ||||
| -rw-r--r-- | src/leap/eip/specs.py | 37 | ||||
| -rw-r--r-- | src/leap/eip/tests/data.py | 33 | ||||
| -rw-r--r-- | src/leap/eip/tests/test_config.py | 64 | ||||
| -rw-r--r-- | src/leap/gui/firstrun/regvalidation.py | 14 | 
14 files changed, 212 insertions, 91 deletions
| diff --git a/src/leap/base/auth.py b/src/leap/base/auth.py index 73856bb0..c6bd3518 100644 --- a/src/leap/base/auth.py +++ b/src/leap/base/auth.py @@ -43,7 +43,7 @@ class LeapSRPRegister(object):      def __init__(self,                   schema="https",                   provider=None, -                 port=None, +                 #port=None,                   verify=True,                   register_path="1/users.json",                   method="POST", @@ -57,8 +57,8 @@ class LeapSRPRegister(object):          self.schema = schema          # XXX FIXME -        self.provider = provider -        self.port = port +        #self.provider = provider +        #self.port = port          # XXX splitting server,port          # deprecate port call.          domain, port = get_https_domain_and_port(provider) @@ -255,6 +255,7 @@ class SRPAuth(requests.auth.AuthBase):          try:              assert self.srp_usr.authenticated()              logger.debug('user is authenticated!') +            print 'user is authenticated!'          except (AssertionError):              raise SRPAuthenticationError(                  "Auth verification failed.") @@ -355,8 +356,11 @@ if __name__ == "__main__":              req.raise_for_status              return req -        req = test_srp_protected_get('https://localhost:8443/1/cert') -        print 'cert :', req.content[:200] + "..." +        #req = test_srp_protected_get('https://localhost:8443/1/cert') +        req = test_srp_protected_get('%s/1/cert' % SERVER) +        import ipdb;ipdb.set_trace() +        #print 'cert :', req.content[:200] + "..." +        print 'cert :', req.content          sys.exit(0)      if action == "add": diff --git a/src/leap/base/specs.py b/src/leap/base/specs.py index b4bb8dcf..962aa07d 100644 --- a/src/leap/base/specs.py +++ b/src/leap/base/specs.py @@ -2,22 +2,26 @@ leap_provider_spec = {      'description': 'provider definition',      'type': 'object',      'properties': { -        'serial': { -            'type': int, -            'default': 1, -            'required': True, -        }, +        #'serial': { +            #'type': int, +            #'default': 1, +            #'required': True, +        #},          'version': {              'type': unicode,              'default': '0.1.0'              #'required': True          }, +        "default_language": { +            'type': unicode, +            'default': 'en' +        },          'domain': {              'type': unicode,  # XXX define uri type              'default': 'testprovider.example.org'              #'required': True,          }, -        'display_name': { +        'name': {              'type': dict,  # XXX multilingual object?              'default': {u'en': u'Test Provider'}              #'required': True diff --git a/src/leap/base/tests/test_providers.py b/src/leap/base/tests/test_providers.py index d9604fab..8801a3eb 100644 --- a/src/leap/base/tests/test_providers.py +++ b/src/leap/base/tests/test_providers.py @@ -16,10 +16,12 @@ from leap.base import providers  EXPECTED_DEFAULT_CONFIG = {      u"api_version": u"0.1.0",      u"description": {u'en': u"Test provider"}, -    u"display_name": {u'en': u"Test Provider"}, +    u"default_language": u"en", +    #u"display_name": {u'en': u"Test Provider"},      u"domain": u"testprovider.example.org", +    u'name': {u'en': u'Test Provider'},      u"enrollment_policy": u"open", -    u"serial": 1, +    #u"serial": 1,      u"services": [          u"eip"      ], diff --git a/src/leap/baseapp/eip.py b/src/leap/baseapp/eip.py index 54acbc0e..0d7506b3 100644 --- a/src/leap/baseapp/eip.py +++ b/src/leap/baseapp/eip.py @@ -203,6 +203,8 @@ class EIPConductorAppMixin(object):                  # we could bring Timer Init to this Mixin                  # or to its own Mixin.                  self.timer.start(constants.TIMER_MILLISECONDS) +                # XXX EMIT SIGNAL INSTEAD (when first run, +                # network checker does not exist...)                  self.network_checker.start()              return diff --git a/src/leap/baseapp/network.py b/src/leap/baseapp/network.py index 3e57490d..7363cfaa 100644 --- a/src/leap/baseapp/network.py +++ b/src/leap/baseapp/network.py @@ -18,13 +18,17 @@ class NetworkCheckerAppMixin(object):      def __init__(self, *args, **kwargs):          provider = kwargs.pop('provider', None) +        if provider: +            self.init_network_checker(provider) + +    def init_network_checker(self, provider):          self.network_checker = NetworkCheckerThread(              error_cb=self.networkError.emit,              debug=self.debugmode,              provider=provider) -        # XXX move run_checks to slot -- this definitely -        # cannot start on init!!! +    @QtCore.pyqtSlot(object) +    def runNetworkChecks(self):          self.network_checker.run_checks()      @QtCore.pyqtSlot(object) diff --git a/src/leap/crypto/certs.py b/src/leap/crypto/certs.py index 8908865d..45d7326d 100644 --- a/src/leap/crypto/certs.py +++ b/src/leap/crypto/certs.py @@ -1,10 +1,14 @@  import ctypes +from StringIO import StringIO +import re  import socket  import gnutls.connection  import gnutls.crypto  import gnutls.library +from leap.util.misc import null_check +  def get_https_cert_from_domain(domain):      """ @@ -20,12 +24,44 @@ def get_https_cert_from_domain(domain):      return cert -def get_cert_from_file(filepath): -    with open(filepath) as f: -        cert = gnutls.crypto.X509Certificate(f.read()) +def get_cert_from_file(_file): +    getcert = lambda f: gnutls.crypto.X509Certificate(f.read()) +    if isinstance(_file, str): +        with open(_file) as f: +            cert = getcert(f) +    else: +        cert = getcert(_file)      return cert +def get_pkey_from_file(_file): +    getkey = lambda f: gnutls.crypto.X509PrivateKey(f.read()) +    if isinstance(_file, str): +        with open(_file) as f: +            key = getkey(f) +    else: +        key = getkey(_file) +    return key + + +def can_load_cert_and_pkey(string): +    try: +        f = StringIO(string) +        cert = get_cert_from_file(f) + +        f = StringIO(string) +        key = get_pkey_from_file(f) + +        null_check(cert, 'certificate') +        null_check(key, 'private key') +    except: +        # XXX catch GNUTLSError +        raise +        return False +    else: +        return True + +  def get_cert_fingerprint(domain=None, filepath=None,                           hash_type="SHA256", sep=":"):      """ diff --git a/src/leap/crypto/tests/__init__.py b/src/leap/crypto/tests/__init__.py new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/src/leap/crypto/tests/__init__.py diff --git a/src/leap/crypto/tests/test_certs.py b/src/leap/crypto/tests/test_certs.py new file mode 100644 index 00000000..4d167c51 --- /dev/null +++ b/src/leap/crypto/tests/test_certs.py @@ -0,0 +1,11 @@ +import unittest + + +class CertTestCase(unittest.TestCase): + +    def test_load_client_and_pkey(self): +        self.fail('not implemented') + + +if __name__ == "__main__": +    unittest.main() diff --git a/src/leap/eip/checks.py b/src/leap/eip/checks.py index 8d615b94..d7f4402b 100644 --- a/src/leap/eip/checks.py +++ b/src/leap/eip/checks.py @@ -160,7 +160,6 @@ class ProviderCertChecker(object):          if autocacert and verify is True and self.cacert is not None:              logger.debug('verify cert: %s', self.cacert)              verify = self.cacert -        #import pdb4qt; pdb4qt.set_trace()          logger.debug('is https working?')          logger.debug('uri: %s (verify:%s)', uri, verify)          try: @@ -242,7 +241,9 @@ class ProviderCertChecker(object):              raise          try:              pemfile_content = req.content -            self.is_valid_pemfile(pemfile_content) +            valid = self.is_valid_pemfile(pemfile_content) +            if not valid: +                return False              cert_path = self._get_client_cert_path()              self.write_cert(pemfile_content, to=cert_path)          except: @@ -276,7 +277,10 @@ class ProviderCertChecker(object):          cert = gnutls.crypto.X509Certificate(cert_s)          from_ = time.gmtime(cert.activation_time)          to_ = time.gmtime(cert.expiration_time) -        return from_ < now() < to_ +        # FIXME BUG ON LEAP_CLI, certs are not valid on gmtime +        # See #1153 +        #return from_ < now() < to_ +        return now() < to_      def is_valid_pemfile(self, cert_s=None):          """ @@ -290,23 +294,8 @@ class ProviderCertChecker(object):              certfile = self._get_client_cert_path()              with open(certfile) as cf:                  cert_s = cf.read() -        try: -            # XXX get a real cert validation -            # so far this is only checking begin/end -            # delimiters :) -            # XXX use gnutls for get proper -            # validation. -            # crypto.X509Certificate(cert_s) -            sep = "-" * 5 + "BEGIN CERTIFICATE" + "-" * 5 -            # we might have private key and cert in the same file -            certparts = cert_s.split(sep) -            if len(certparts) > 1: -                cert_s = sep + certparts[1] -            ssl.PEM_cert_to_DER_cert(cert_s) -        except: -            # XXX raise proper exception -            raise -        return True +        valid = certs.can_load_cert_and_pkey(cert_s) +        return valid      @property      def ca_cert_path(self): diff --git a/src/leap/eip/config.py b/src/leap/eip/config.py index e40d2785..48e6e9a7 100644 --- a/src/leap/eip/config.py +++ b/src/leap/eip/config.py @@ -65,9 +65,12 @@ def get_eip_gateway(eipconfig=None, eipserviceconfig=None):      that matches the name defined in the eip.json config      file.      """ +    # XXX eventually we should move to a more clever +    # gateway selection. maybe we could return +    # all gateways that match our cluster. +      null_check(eipconfig, "eipconfig")      null_check(eipserviceconfig, "eipserviceconfig") -      PLACEHOLDER = "testprovider.example.org"      conf = eipconfig.config @@ -78,26 +81,26 @@ def get_eip_gateway(eipconfig=None, eipserviceconfig=None):          return PLACEHOLDER      gateways = eipsconf.get('gateways', None) -      if not gateways:          logger.error('missing gateways in eip service config')          return PLACEHOLDER      if len(gateways) > 0:          for gw in gateways: -            name = gw.get('name', None) -            if not name: +            clustername = gw.get('cluster', None) +            if not clustername: +                logger.error('no cluster name')                  return -            if name == primary_gateway: -                hosts = gw.get('hosts', None) -                if not hosts: -                    logger.error('no hosts') +            if clustername == primary_gateway: +                # XXX at some moment, we must +                # make this a more generic function, +                # and return ports, protocols... +                ipaddress = gw.get('ip_address', None) +                if not ipaddress: +                    logger.error('no ip_address')                      return -                if len(hosts) > 0: -                    return hosts[0] -                else: -                    logger.error('no hosts') +                return ipaddress      logger.error('could not find primary gateway in provider'                   'gateway list') diff --git a/src/leap/eip/specs.py b/src/leap/eip/specs.py index cf5d5359..c41fd29b 100644 --- a/src/leap/eip/specs.py +++ b/src/leap/eip/specs.py @@ -77,12 +77,12 @@ eipconfig_spec = {          },          'primary_gateway': {              'type': unicode, -            'default': u"turkey", +            'default': u"location_unknown",              #'required': True          },          'secondary_gateway': {              'type': unicode, -            'default': u"france" +            'default': u"location_unknown2"          },          'management_password': {              'type': unicode @@ -100,25 +100,30 @@ eipservice_config_spec = {              'default': 1          },          'version': { -            'type': unicode, +            'type': int,              'required': True, -            'default': "0.1.0" +            'default': 1          }, -        'capabilities': { -            'type': dict, -            'default': { -                "transport": ["openvpn"], -                "ports": ["80", "53"], -                "protocols": ["udp", "tcp"], -                "static_ips": True, -                "adblock": True} +        'clusters': { +            'type': list, +            'default': [ +                {"label": { +                    "en": "Location Unknown"}, +                    "name": "location_unknown"}]          },          'gateways': {              'type': list, -            'default': [{"country_code": "us", -                        "label": {"en":"west"}, -                        "capabilities": {}, -                        "hosts": ["1.2.3.4", "1.2.3.5"]}] +            'default': [ +                {"capabilities": { +                    "adblock": True, +                    "filter_dns": True, +                    "ports": ["80", "53", "443", "1194"], +                    "protocols": ["udp", "tcp"], +                    "transport": ["openvpn"], +                    "user_ips": False}, +                 "cluster": "location_unknown", +                 "host": "location.example.org", +                 "ip_address": "127.0.0.1"}]          },          'openvpn_configuration': {              'type': dict, diff --git a/src/leap/eip/tests/data.py b/src/leap/eip/tests/data.py index cadf720e..a7fe1853 100644 --- a/src/leap/eip/tests/data.py +++ b/src/leap/eip/tests/data.py @@ -23,26 +23,29 @@ EIP_SAMPLE_CONFIG = {          "keys/client/openvpn.pem" % PROVIDER),      "connect_on_login": True,      "block_cleartext_traffic": True, -    "primary_gateway": "turkey", -    "secondary_gateway": "france", +    "primary_gateway": "location_unknown", +    "secondary_gateway": "location_unknown2",      #"management_password": "oph7Que1othahwiech6J"  }  EIP_SAMPLE_SERVICE = {      "serial": 1, -    "version": "0.1.0", -    "capabilities": { -        "transport": ["openvpn"], -        "ports": ["80", "53"], -        "protocols": ["udp", "tcp"], -        "static_ips": True, -        "adblock": True -    }, +    "version": 1, +    "clusters": [ +        {"label": { +            "en": "Location Unknown"}, +            "name": "location_unknown"} +    ],      "gateways": [ -    {"country_code": "tr", -     "name": "turkey", -     "label": {"en":"Ankara, Turkey"}, -     "capabilities": {}, -     "hosts": ["192.0.43.10"]} +        {"capabilities": { +            "adblock": True, +            "filter_dns": True, +            "ports": ["80", "53", "443", "1194"], +            "protocols": ["udp", "tcp"], +            "transport": ["openvpn"], +            "user_ips": False}, +         "cluster": "location_unknown", +         "host": "location.example.org", +         "ip_address": "192.0.43.10"}      ]  } diff --git a/src/leap/eip/tests/test_config.py b/src/leap/eip/tests/test_config.py index 404d543f..5977ef3c 100644 --- a/src/leap/eip/tests/test_config.py +++ b/src/leap/eip/tests/test_config.py @@ -15,7 +15,7 @@ except ImportError:  from leap.eip import config as eipconfig  from leap.eip.tests.data import EIP_SAMPLE_CONFIG, EIP_SAMPLE_SERVICE  from leap.testing.basetest import BaseLeapTest -from leap.util.fileutil import mkdir_p +from leap.util.fileutil import mkdir_p, mkdir_f  _system = platform.system() @@ -48,11 +48,12 @@ class EIPConfigTest(BaseLeapTest):          open(tfile, 'wb').close()          os.chmod(tfile, stat.S_IRUSR | stat.S_IWUSR | stat.S_IXUSR) -    def write_sample_eipservice(self, vpnciphers=False, extra_vpnopts=None): +    def write_sample_eipservice(self, vpnciphers=False, extra_vpnopts=None, +                                gateways=None):          conf = eipconfig.EIPServiceConfig() -        folder, f = os.path.split(conf.filename) -        if not os.path.isdir(folder): -            mkdir_p(folder) +        mkdir_f(conf.filename) +        if gateways: +            EIP_SAMPLE_SERVICE['gateways'] = gateways          if vpnciphers:              openvpnconfig = OrderedDict({                  "auth": "SHA1", @@ -75,6 +76,10 @@ class EIPConfigTest(BaseLeapTest):              fd.write(json.dumps(EIP_SAMPLE_CONFIG))      def get_expected_openvpn_args(self, with_openvpn_ciphers=False): +        """ +        yeah, this is almost as duplicating the +        code for building the command +        """          args = []          eipconf = eipconfig.EIPConfig(domain=self.provider)          eipconf.load() @@ -156,6 +161,55 @@ class EIPConfigTest(BaseLeapTest):      # params in the function call, to disable      # some checks. +    def test_get_eip_gateway(self): +        self.write_sample_eipconfig() +        eipconf = eipconfig.EIPConfig(domain=self.provider) + +        # default eipservice +        self.write_sample_eipservice() +        eipsconf = eipconfig.EIPServiceConfig(domain=self.provider) + +        gateway = eipconfig.get_eip_gateway( +            eipconfig=eipconf, +            eipserviceconfig=eipsconf) + +        # in spec is local gateway by default +        self.assertEqual(gateway, '127.0.0.1') + +        # change eipservice +        # right now we only check that cluster == selected primary gw in +        # eip.json, and pick first matching ip +        eipconf._config.config['primary_gateway'] = "foo_provider" +        newgateways = [{"cluster": "foo_provider", +                        "ip_address": "127.0.0.99"}] +        self.write_sample_eipservice(gateways=newgateways) +        eipsconf = eipconfig.EIPServiceConfig(domain=self.provider) +        # load from disk file +        eipsconf.load() + +        gateway = eipconfig.get_eip_gateway( +            eipconfig=eipconf, +            eipserviceconfig=eipsconf) +        self.assertEqual(gateway, '127.0.0.99') + +        # change eipservice, several gateways +        # right now we only check that cluster == selected primary gw in +        # eip.json, and pick first matching ip +        eipconf._config.config['primary_gateway'] = "bar_provider" +        newgateways = [{"cluster": "foo_provider", +                        "ip_address": "127.0.0.99"}, +                       {'cluster': "bar_provider", +                        "ip_address": "127.0.0.88"}] +        self.write_sample_eipservice(gateways=newgateways) +        eipsconf = eipconfig.EIPServiceConfig(domain=self.provider) +        # load from disk file +        eipsconf.load() + +        gateway = eipconfig.get_eip_gateway( +            eipconfig=eipconf, +            eipserviceconfig=eipsconf) +        self.assertEqual(gateway, '127.0.0.88') +      def test_build_ovpn_command_empty_config(self):          self.touch_exec()          self.write_sample_eipservice() diff --git a/src/leap/gui/firstrun/regvalidation.py b/src/leap/gui/firstrun/regvalidation.py index 0e67834b..aeb98204 100644 --- a/src/leap/gui/firstrun/regvalidation.py +++ b/src/leap/gui/firstrun/regvalidation.py @@ -100,9 +100,12 @@ class RegisterUserValidationPage(ValidationPage):          def fetcheipcert():              try: -                pCertChecker.download_new_client_cert( +                downloaded = pCertChecker.download_new_client_cert(                      credentials=credentials,                      verify=verify) +                if not downloaded: +                    logger.error('Could not download client cert.') +                    return False              except auth.SRPAuthenticationError as exc:                  return self.fail(self.tr( @@ -126,10 +129,11 @@ class RegisterUserValidationPage(ValidationPage):          """          # this should be called CONNECT PAGE AGAIN.          # here we go! :) -        full_domain = self.field('provider_domain') -        domain, port = get_https_domain_and_port(full_domain) -        _domain = u"%s:%s" % (domain, port) if port != 443 else unicode(domain) -        self.run_eip_checks_for_provider_and_connect(_domain) +        if self.is_done(): +            full_domain = self.field('provider_domain') +            domain, port = get_https_domain_and_port(full_domain) +            _domain = u"%s:%s" % (domain, port) if port != 443 else unicode(domain) +            self.run_eip_checks_for_provider_and_connect(_domain)      def run_eip_checks_for_provider_and_connect(self, domain):          wizard = self.wizard() | 
