Exemplo n.º 1
0
def connect(host=C.MANAGER_HOST, port=None, tls_mode=C.MANAGER_TLS,
            username=None, password=None, headless=False):
    """Connect to LabRAD and return a deferred that fires the protocol object.

    Args:
        host (str): The hostname of the manager.
        port (int): The tcp port of the manager. If None, use the appropriate
            default value based on the TLS mode.
        tls_mode (str): The tls mode to use for this connection. See:
            `labrad.constants.check_tls_mode`.
        username (str | None): The username to use when authenticating.
        password (str | None): The password to use when authenticating.
        headless (bool): Whether to use headless OAuth flow if no username or
            password is configured.

    Returns:
        twisted.internet.defer.Deferred(LabradProtocol): A deferred that will
        fire with the protocol once the connection is established.
    """
    spawn_kw = dict(host=host, port=port, tls_mode=tls_mode,
                    username=username, password=password, headless=headless)

    tls_mode = C.check_tls_mode(tls_mode)
    if port is None:
        port = C.MANAGER_PORT_TLS if tls_mode == 'on' else C.MANAGER_PORT

    @inlineCallbacks
    def authenticate(p):
        yield p.authenticate(username, password, headless)

    if tls_mode == 'on':
        tls_options = crypto.tls_options(host)
        p = yield _factory.connectSSL(host, port, tls_options, timeout=C.TIMEOUT)
        p.set_address(host, port)
        p.spawn_kw = spawn_kw
        yield authenticate(p)
        returnValue(p)

    @inlineCallbacks
    def do_connect():
        p = yield _factory.connectTCP(host, port, timeout=C.TIMEOUT)
        p.set_address(host, port)
        p.spawn_kw = spawn_kw
        returnValue(p)

    @inlineCallbacks
    def start_tls(p, cert_string=None):
        try:
            cert = yield p._sendManagerRequest(1, ('STARTTLS', host))
        except Exception:
            raise Exception(
                'Failed sending STARTTLS command to server. You should update '
                'the manager and configure it to support encryption or else '
                'disable encryption for clients. See '
                'https://github.com/labrad/pylabrad/blob/master/CONFIG.md')
        p.transport.startTLS(crypto.tls_options(host, cert_string=cert_string))
        returnValue(cert)

    @inlineCallbacks
    def ping(p):
        resp = yield p._sendManagerRequest(2, 'PING')
        if isinstance(resp, tuple):
            manager_features = set(resp[1])
        else:
            manager_features = set()
        returnValue(manager_features)

    p = yield do_connect()
    is_local_connection = util.is_local_connection(p.transport)
    if ((tls_mode == 'starttls-force') or
        (tls_mode == 'starttls' and not is_local_connection)):
        try:
            cert = yield start_tls(p)
        except Exception:
            # TODO: remove this retry. This is a temporary fix to support
            # compatibility until TLS is fully deployed.
            print('STARTTLS failed; will retry without encryption in case we '
                  'are connecting to a legacy manager.')
            p = yield connect(host, port, tls_mode='off')
            print('Connected without encryption.')
            p.manager_features = set()
            yield authenticate(p)
            returnValue(p)
        try:
            manager_features = yield ping(p)
        except Exception:
            print('STARTTLS failed due to untrusted server certificate:')
            print('SHA1 Fingerprint={}'.format(crypto.fingerprint(cert)))
            print()
            while True:
                ans = input(
                        'Accept server certificate for host "{}"? (accept just '
                        'this [O]nce; [S]ave and always accept this cert; '
                        '[R]eject) '.format(host))
                ans = ans.lower()
                if ans in ['o', 's', 'r']:
                    break
                else:
                    print('Invalid input:', ans)
            if ans == 'r':
                raise
            p = yield do_connect()
            yield start_tls(p, cert)
            manager_features = yield ping(p)
            if ans == 's':
                # save now that we know TLS succeeded,
                # including hostname verification.
                crypto.save_cert(host, cert)
    else:
        manager_features = yield ping(p)
    p.manager_features = manager_features

    yield authenticate(p)
    returnValue(p)
Exemplo n.º 2
0
def connect(host=C.MANAGER_HOST, port=None, tls_mode=C.MANAGER_TLS):
    """Connect to LabRAD and return a deferred that fires the protocol object.

    Args:
        host (str): The hostname of the manager.
        port (int): The tcp port of the manager. If None, use the appropriate
            default value based on the TLS mode.
        tls_mode (str): The tls mode to use for this connection. See:
            `labrad.constants.check_tls_mode`.

    Returns:
        twisted.internet.defer.Deferred(LabradProtocol): A deferred that will
        fire with the protocol once the connection is established.
    """
    tls_mode = C.check_tls_mode(tls_mode)
    if port is None:
        port = C.MANAGER_PORT_TLS if tls_mode == 'on' else C.MANAGER_PORT

    if tls_mode == 'on':
        tls_options = crypto.tls_options(host)
        p = yield _factory.connectSSL(host, port, tls_options, timeout=C.TIMEOUT)
        returnValue(p)

    def do_connect():
        return _factory.connectTCP(host, port, timeout=C.TIMEOUT)

    @inlineCallbacks
    def start_tls(p, cert_string=None):
        try:
            resp = yield p.sendRequest(C.MANAGER_ID, [(1L, ('STARTTLS', host))])
        except Exception:
            raise Exception(
                'Failed sending STARTTLS command to server. You should update '
                'the manager and configure it to support encryption or else '
                'disable encryption for clients. See '
                'https://github.com/labrad/pylabrad/blob/master/CONFIG.md')
        cert = resp[0][1]
        p.transport.startTLS(crypto.tls_options(host, cert_string=cert_string))
        returnValue(cert)

    def ping(p):
        return p.sendRequest(C.MANAGER_ID, [(2L, 'PING')])

    p = yield do_connect()
    is_local_connection = util.is_local_connection(p.transport)
    if ((tls_mode == 'starttls-force') or
        (tls_mode == 'starttls' and not is_local_connection)):
        try:
            cert = yield start_tls(p)
        except Exception:
            # TODO: remove this retry. This is a temporary fix to support
            # compatibility until TLS is fully deployed.
            print ('STARTTLS failed; will retry without encryption in case we '
                   'are connecting to a legacy manager.')
            p = yield connect(host, port, tls_mode='off')
            print 'Connected without encryption.'
            returnValue(p)
        try:
            yield ping(p)
        except Exception:
            print 'STARTTLS failed due to untrusted server certificate:'
            print 'SHA1 Fingerprint={}'.format(crypto.fingerprint(cert))
            print
            while True:
                ans = raw_input(
                        'Accept server certificate for host "{}"? (accept just '
                        'this [O]nce; [S]ave and always accept this cert; '
                        '[R]eject) '.format(host))
                ans = ans.lower()
                if ans in ['o', 's', 'r']:
                    break
                else:
                    print 'Invalid input:', ans
            if ans == 'r':
                raise
            p = yield do_connect()
            yield start_tls(p, cert)
            yield ping(p)
            if ans == 's':
                # save now that we know TLS succeeded,
                # including hostname verification.
                crypto.save_cert(host, cert)
    returnValue(p)
Exemplo n.º 3
0
def getConnection(host=C.MANAGER_HOST, port=None, name="Python Client",
                  password=None, tls=C.MANAGER_TLS):
    """Connect to LabRAD and return a deferred that fires the protocol object."""
    tls = C.check_tls_mode(tls)
    if port is None:
        port = C.MANAGER_PORT_TLS if tls == 'on' else C.MANAGER_PORT

    if tls == 'on':
        tls_options = crypto.tls_options(host)
        p = yield protocol.factory.connectSSL(host, port, tls_options,
                                              timeout=C.TIMEOUT)
    else:
        def connect():
            return protocol.factory.connectTCP(host, port, timeout=C.TIMEOUT)

        @inlineCallbacks
        def start_tls(p, cert_string=None):
            try:
                resp = yield p.sendRequest(C.MANAGER_ID, [(1L, ('STARTTLS', host))])
            except Exception, e:
                raise Exception(
                    'Failed sending STARTTLS command to server. You should '
                    'update the manager and configure it to support encryption '
                    'or else disable encryption for clients. See '
                    'https://github.com/labrad/pylabrad/blob/master/CONFIG.md')
            cert = resp[0][1]
            p.transport.startTLS(crypto.tls_options(host, cert_string=cert_string))
            returnValue(cert)

        def ping(p):
            return p.sendRequest(C.MANAGER_ID, [(2L, 'PING')])

        p = yield connect()
        is_local_connection = util.is_local_connection(p.transport)
        if ((tls == 'starttls-force') or
            (tls == 'starttls' and not is_local_connection)):
            try:
                cert = yield start_tls(p)
            except Exception:
                # TODO: remove this retry. This is a temporary fix to support
                # compatibility until TLS is fully deployed.
                print ('STARTTLS failed; will retry without encryption in case '
                       'we are connecting to a legacy manager.')
                p = yield getConnection(host, port, name, password, tls='off')
                print 'Connected without encryption.'
                returnValue(p)
            try:
                yield ping(p)
            except Exception:
                print 'STARTTLS failed due to untrusted server certificate:'
                print 'SHA1 Fingerprint={}'.format(crypto.fingerprint(cert))
                print
                while True:
                    ans = raw_input(
                            "Accept server certificate for host '{}'? "
                            "(accept just this [O]nce; [S]ave and always "
                            "accept this cert; [R]eject) ".format(host))
                    if ans.lower() in ['o', 's', 'r']:
                        break
                    else:
                        print 'Invalid input:', ans
                if ans.lower() == 'r':
                    raise
                p = yield connect()
                yield start_tls(p, cert)
                yield ping(p)
                if ans.lower() == 's':
                    # save now that we know TLS succeeded,
                    # including hostname verification.
                    crypto.save_cert(host, cert)