def makeService(options): """Construct a TCPServer from a LabRAD node.""" name = options['name'] host = options['host'] port = int(options['port']) tls = C.check_tls_mode(options['tls']) return Node(name, host, port, tls)
def _connect(self, password, timeout, tls_mode): tls_mode = C.check_tls_mode(tls_mode) if tls_mode == 'on': raise Exception('TLS is not currently supported with the asyncore ' 'backend') self.connected = False self.serverCache = {} self.settingCache = {} if self.port is None: port = C.MANAGER_PORT_TLS if tls_mode == 'on' else C.MANAGER_PORT else: port = self.port try: sock = socket.create_connection((self.host, port), timeout or 5) socketMap = {} self.cxn = AsyncoreProtocol(sock, map=socketMap) self.loop = threading.Thread(target=asyncore.loop, kwargs={'timeout':0.01, 'map': socketMap}) self.loop.daemon = True self.loop.start() try: return self.login(password, self.name) except Exception, e: self.disconnect() raise except LoginFailedError: raise except Exception, e: raise LoginFailedError(e)
def syncRunServer(srv, host=C.MANAGER_HOST, port=None, username=None, password=None, tls_mode=C.MANAGER_TLS): """Run a labrad server of the specified class in a synchronous context. Returns a context manager to be used with python's with statement that will yield when the server has started and then shut the server down after the context is exited. """ from labrad import protocol 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 start_server(): p = yield protocol.connect(host, port, tls_mode, username, password) yield srv.startup(p) @inlineCallbacks def stop_server(): srv.disconnect() yield srv.onShutdown() thread.startReactor() blockingCallFromThread(reactor, start_server) try: yield finally: try: blockingCallFromThread(reactor, stop_server) except Exception: pass # don't care about exceptions here
def makeService(options): """Construct a TCPServer from a LabRAD node.""" name = options['name'] host = options['host'] port = int(options['port']) password = labrad.support.get_password(host, port) tls_mode = C.check_tls_mode(options['tls']) return Node(name, host, port, password, tls_mode)
def makeService(options): """Construct a TCPServer from a LabRAD node.""" name = options['name'] host = options['host'] port = int(options['port']) username = options['username'] password = options['password'] tls_mode = C.check_tls_mode(options['tls']) return Node(name, host, port, username, password, tls_mode)
def parseServerOptions(name, exit_on_failure=True, options=None): """Parse standard command line options for a server. Args: name (string): The default server name to use if no name is specified on the command line. exit_on_failure (boolean): If True, we call sys.exit when we fail to parse the command line options. Otherwise, we raise UsageError. options (list(string)): If given, parse options from the given strings. Otherwise, will parse options from the command line in sys.argv. Returns: A ServerOptions instance initialized from the command line arguments. This is a dict-like object containing these string-valued keys: 'name', 'node', 'host', 'port', 'password', 'tls' """ from twisted.python import usage class ServerOptions(usage.Options): optParameters = [ ['name', 'n', name, 'Server name.'], ['node', 'd', getNodeName(), 'Node name.'], ['host', 'h', C.MANAGER_HOST, 'Manager location.'], ['port', 'p', None, 'Manager port.', int], ['username', 'u', None, 'Username.'], ['password', 'w', None, 'Login password.'], [ 'tls', 's', C.MANAGER_TLS, 'TLS mode for connecting to manager (on/starttls/off)' ] ] config = ServerOptions() config['tls'] = C.check_tls_mode(config['tls']) try: config.parseOptions(options=options) if config['port'] is None: tls_on = config['tls'] == 'on' config['port'] = C.MANAGER_PORT_TLS if tls_on else C.MANAGER_PORT except usage.UsageError as errortext: print('%s: %s' % (sys.argv[0], errortext)) print('%s: Try --help for usage details.' % (sys.argv[0])) if exit_on_failure: sys.exit(1) else: raise return config
def syncRunServer(srv, host=C.MANAGER_HOST, port=None, password=None, tls=C.MANAGER_TLS): """Run a labrad server of the specified class in a synchronous context. Returns a context manager to be used with python's with statement that will yield when the server has started and then shut the server down after the context is exited. """ tls = C.check_tls_mode(tls) if port is None: port = C.MANAGER_PORT_TLS if tls == 'on' else C.MANAGER_PORT if password is None: password = C.PASSWORD srv.password = password @inlineCallbacks def start_server(): srv.configure_tls(host, tls) if tls == 'on': tls_options = crypto.tls_options(host) reactor.connectSSL(host, port, srv, tls_options) else: reactor.connectTCP(host, port, srv) yield srv.onStartup() @inlineCallbacks def stop_server(): srv.disconnect() yield srv.onShutdown() thread.startReactor() blockingCallFromThread(reactor, start_server) try: yield finally: try: blockingCallFromThread(reactor, stop_server) except Exception: pass # don't care about exceptions here
def parseServerOptions(name, exit_on_failure=True, options=None): """Parse standard command line options for a server. Args: name (string): The default server name to use if no name is specified on the command line. exit_on_failure (boolean): If True, we call sys.exit when we fail to parse the command line options. Otherwise, we raise UsageError. options (list(string)): If given, parse options from the given strings. Otherwise, will parse options from the command line in sys.argv. Returns: A ServerOptions instance initialized from the command line arguments. This is a dict-like object containing these string-valued keys: 'name', 'node', 'host', 'port', 'password', 'tls' """ from twisted.python import usage class ServerOptions(usage.Options): optParameters = [ ['name', 'n', name, 'Server name.'], ['node', 'd', getNodeName(), 'Node name.'], ['host', 'h', C.MANAGER_HOST, 'Manager location.'], ['port', 'p', None, 'Manager port.', int], ['password', 'w', None, 'Login password.'], ['tls', 's', C.MANAGER_TLS, 'TLS mode for connecting to manager (on/starttls/off)']] config = ServerOptions() config['tls'] = C.check_tls_mode(config['tls']) try: config.parseOptions(options=options) if config['password'] is None: config['password'] = support.get_password(host=config['host'], port=config['port'], prompt=False) if config['port'] is None: tls_on = config['tls'] == 'on' config['port'] = C.MANAGER_PORT_TLS if tls_on else C.MANAGER_PORT except usage.UsageError, errortext: print '%s: %s' % (sys.argv[0], errortext) print '%s: Try --help for usage details.' % (sys.argv[0]) if exit_on_failure: sys.exit(1) else: raise
def parseServerOptions(name, exit_on_failure=True, options=None): """Parse standard command line options for a server. Args: name (string): The default server name to use if no name is specified on the command line. exit_on_failure (boolean): If True, we call sys.exit when we fail to parse the command line options. Otherwise, we raise UsageError. options (list(string)): If given, parse options from the given strings. Otherwise, will parse options from the command line in sys.argv. Returns: A ServerOptions instance initialized from the command line arguments. This is a dict-like object containing these string-valued keys: 'name', 'node', 'host', 'port', 'password', 'tls' """ from twisted.python import usage class ServerOptions(usage.Options): optParameters = [ ["name", "n", name, "Server name."], ["node", "d", getNodeName(), "Node name."], ["host", "h", C.MANAGER_HOST, "Manager location."], ["port", "p", None, "Manager port.", int], ["password", "w", C.PASSWORD, "Login password."], ["tls", "s", C.MANAGER_TLS, "TLS mode for connecting to manager (on/starttls/off)"], ] config = ServerOptions() config["tls"] = C.check_tls_mode(config["tls"]) try: config.parseOptions(options=options) if config["port"] is None: tls_on = config["tls"] == "on" config["port"] = C.MANAGER_PORT_TLS if tls_on else C.MANAGER_PORT except usage.UsageError, errortext: print "%s: %s" % (sys.argv[0], errortext) print "%s: Try --help for usage details." % (sys.argv[0]) if exit_on_failure: sys.exit(1) else: raise
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)
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)
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)