Beispiel #1
0
class MyFactory(SSHFactory):
    privateKeys = {'ssh-rsa': Key.fromFile(filename=host_key_file)}
    publicKeys = {'ssh-rsa': Key.fromFile(filename=host_key_pub_file)}
    services = {
        'ssh-userauth': SSHUserAuthServer,
        'ssh-connection': SSHConnection
    }
Beispiel #2
0
    def addKeyFile(self, kfile, password=None):
        if not os.path.exists(kfile):
            raise Exception("Key file not found %s", kfile)

        try:
            self.keys.append(Key.fromFile(kfile))
        except EncryptedKeyError:
            self.keys.append(Key.fromFile(kfile, passphrase=password))
Beispiel #3
0
 def makeFactory(self):
     """Create and start the factory that our SSH server uses."""
     factory = Factory(
         get_portal(None, None),
         private_key=Key.fromFile(get_key_path(PRIVATE_KEY_FILE)),
         public_key=Key.fromFile(get_key_path(PUBLIC_KEY_FILE)))
     factory.startFactory()
     return factory
Beispiel #4
0
 def readKey(self, path):
     try:
         return Key.fromFile(path)
     except EncryptedKeyError as ex:
         passphrase = getpass.getpass("%r keyphrase: " % (path, ))
         return Key.fromFile(path, passphrase=passphrase)
     except Exception as ex:
         print(ex)
         raise
Beispiel #5
0
    def addKeyFile(self, kfile, password=None):
        """Import a private key file
        """
        if not os.path.exists(kfile):
            raise Exception("Key file not found %s" % kfile)

        try:
            self.keys.append(Key.fromFile(kfile))
        except EncryptedKeyError:
            self.keys.append(Key.fromFile(kfile, passphrase=password))
Beispiel #6
0
 def __init__(self, settings):
     self.settings = settings
     self.portal = Portal(OpenRukoRealm(settings))
     self.portal.registerChecker(OpenRukoCredentialChecker(settings))
     self.privateKeys = {
         'ssh-rsa': Key.fromFile(settings['gitmouth_private_key']),
     }
     self.publicKeys = {
         'ssh-rsa': Key.fromFile(settings['gitmouth_public_key']),
     }
 def makeFactory(self):
     """Create and start the factory that our SSH server uses."""
     factory = Factory(
         get_portal(None, None),
         private_key=Key.fromFile(
             get_key_path(PRIVATE_KEY_FILE)),
         public_key=Key.fromFile(
             get_key_path(PUBLIC_KEY_FILE)))
     factory.startFactory()
     return factory
Beispiel #8
0
def create_server_factory(urwid_mind_factories, cred_checkers):
    """Convenience to create a server factory with a portal that uses a realm
    serving a given urwid widget against checkers provided.
    """
    rlm = UrwidRealm(urwid_mind_factories)
    ptl = Portal(rlm, cred_checkers)
    factory = ConchFactory(ptl)
    factory.publicKeys[b'ssh-rsa'] = Key.fromFile('test_rsa.pub')
    factory.privateKeys[b'ssh-rsa'] = Key.fromFile('test_rsa')
    return factory
Beispiel #9
0
 def __init__(self, settings):
     self.settings = settings
     self.portal = Portal(Realm(settings))
     self.portal.registerChecker(Checker(settings))
     self.privateKeys = {
         'ssh-rsa': Key.fromFile(settings['hadoukngit']['private_key']),
     }
     self.publicKeys = {
         'ssh-rsa': Key.fromFile(settings['hadoukngit']['public_key']),
     }
 def _testrun(self, keyType, keySize=None):
     filename = self.mktemp()
     if keySize is None:
         subprocess.call(['ckeygen', '-t', keyType, '-f', filename, '--no-passphrase'])
     else:
         subprocess.call(['ckeygen', '-t', keyType, '-f', filename, '--no-passphrase',
             '-b', keySize])
     privKey = Key.fromFile(filename)
     pubKey = Key.fromFile(filename + '.pub')
     if keyType == 'ecdsa':
         self.assertEqual(privKey.type(), 'EC')
     else:
         self.assertEqual(privKey.type(), keyType.upper())
     self.assertTrue(pubKey.isPublic())
Beispiel #11
0
 def __init__(self,
              private_key_path,
              public_key_path,
              moduli_path=None,
              banner=None):
     portal = self._makePortal()
     ssh_factory = ParsnipSSHFactory(
         portal,
         private_key=Key.fromFile(private_key_path),
         public_key=Key.fromFile(public_key_path),
         banner=banner,
         moduli_path=moduli_path
     )
     self.service = strports.service('tcp:22', ssh_factory)
Beispiel #12
0
 def _testrun(self, keyType, keySize=None):
     filename = self.mktemp()
     if keySize is None:
         subprocess.call(['ckeygen', '-t', keyType, '-f', filename, '--no-passphrase'])
     else:
         subprocess.call(['ckeygen', '-t', keyType, '-f', filename, '--no-passphrase',
             '-b', keySize])
     privKey = Key.fromFile(filename)
     pubKey = Key.fromFile(filename + '.pub')
     if keyType == 'ecdsa':
         self.assertEqual(privKey.type(), 'EC')
     else:
         self.assertEqual(privKey.type(), keyType.upper())
     self.assertTrue(pubKey.isPublic())
Beispiel #13
0
 def _testrun(self, keyType, keySize=None, privateKeySubtype=None):
     filename = self.mktemp()
     args = ['ckeygen', '-t', keyType, '-f', filename, '--no-passphrase']
     if keySize is not None:
         args.extend(['-b', keySize])
     if privateKeySubtype is not None:
         args.extend(['--private-key-subtype', privateKeySubtype])
     subprocess.call(args)
     privKey = Key.fromFile(filename)
     pubKey = Key.fromFile(filename + '.pub')
     if keyType == 'ecdsa':
         self.assertEqual(privKey.type(), 'EC')
     else:
         self.assertEqual(privKey.type(), keyType.upper())
     self.assertTrue(pubKey.isPublic())
Beispiel #14
0
def _load_key(filename):
    try:
        return Key.fromFile(filename)
    except EncryptedKeyError:
        for i in xrange(3):
            passphrase = getpass.getpass("passphrase for %s: " % (filename,))
            if not passphrase:
                continue

            try:
                return Key.fromFile(filename, passphrase=passphrase)
            except BadKeyError:
                pass

        raise BadKeyPassphraseError()
Beispiel #15
0
def _load_key(filename):
    try:
        return Key.fromFile(filename)
    except EncryptedKeyError:
        for i in xrange(3):
            passphrase = getpass.getpass("passphrase for %s: " % (filename, ))
            if not passphrase:
                continue

            try:
                return Key.fromFile(filename, passphrase=passphrase)
            except BadKeyError:
                pass

        raise BadKeyPassphraseError()
Beispiel #16
0
 def getPublicKey(self):
     # this works with rsa too
     # just change the name here and in getPrivateKey
     if not os.path.exists(key_path) or self.lastPublicKey:
         # the file doesn't exist, or we've tried a public key
         return
     return Key.fromFile(key_path + ".pub")
Beispiel #17
0
        def generated(ignored):
            key = Key.fromFile(id_rsa.path)

            configuring = deferToThread(
                self.configure_ssh, self.server.ip, self.server.port)
            configuring.addCallback(lambda ignored: key)
            return configuring
Beispiel #18
0
 def getPublicKey(self):
     # this works with rsa too
     # just change the name here and in getPrivateKey
     if not os.path.exists(key_path) or self.lastPublicKey:
         # the file doesn't exist, or we've tried a public key
         return
     return Key.fromFile(key_path + ".pub")
Beispiel #19
0
def connect(sdata, command, username, host, port=22, key_file=None, password=None):
    """
    Connect to an SSH host (as it happens, persistently).
    """
    sdata.set_conn_state('connecting')

    try:
        keys = [Key.fromFile(key_file)] if key_file else None
    except exceptions.IOError as e:
        print('### key load error:', str(e))
        push_failure_message(str(e), sdata)
        return

    endpoint = SSHCommandClientEndpoint.newConnection(
                    reactor, command, username, host, port=int(port),
                    keys=keys, password=password, ui=None,
                    knownHosts=PermissiveKnownHosts())

    factory = Factory()
    factory.protocol = LineProtocol
    factory.sdata = sdata

    d = endpoint.connect(factory)

    # Very small race condition between here and the replacement
    # in connectionMade() above, but I've never managed to hit it.
    def disconnect():
        sdata.log('Disconnecting while still attempting to connect, by request')
        d.cancel()
    sdata.transport_drop_cb = disconnect

    d.addErrback(lambda reason: push_failure_message(reason, sdata))
    return d
 def getPublicKey(self):
     path = self.options['ssh-key']
     # this works with rsa too
     # just change the name here and in getPrivateKey
     if not os.path.exists(path) or self.lastPublicKey:
         # the file doesn't exist, or we've tried a public key
         return
     return Key.fromFile(filename=path + '.pub')
 def getPublicKey(self):
     path = self.options['ssh-key']
     # this works with rsa too
     # just change the name here and in getPrivateKey
     if not os.path.exists(path) or self.lastPublicKey:
         # the file doesn't exist, or we've tried a public key
         return
     return Key.fromFile(filename=path+'.pub')
Beispiel #22
0
 def generated(ignored):
     id_rsa = self.ssh_config.child(b"id_rsa_flocker")
     id_rsa_pub = self.ssh_config.child(b"id_rsa_flocker.pub")
     key = Key.fromFile(id_rsa.path)
     self.assertEqual(
         # Avoid comparing the comment
         key.public().toString("OPENSSH").split()[:2],
         id_rsa_pub.getContent().split()[:2])
Beispiel #23
0
 def _testrun(self, keyType, keySize=None, privateKeySubtype=None):
     filename = self.mktemp()
     args = ["ckeygen", "-t", keyType, "-f", filename, "--no-passphrase"]
     if keySize is not None:
         args.extend(["-b", keySize])
     if privateKeySubtype is not None:
         args.extend(["--private-key-subtype", privateKeySubtype])
     subprocess.call(args)
     privKey = Key.fromFile(filename)
     pubKey = Key.fromFile(filename + ".pub")
     if keyType == "ecdsa":
         self.assertEqual(privKey.type(), "EC")
     elif keyType == "ed25519":
         self.assertEqual(privKey.type(), "Ed25519")
     else:
         self.assertEqual(privKey.type(), keyType.upper())
     self.assertTrue(pubKey.isPublic())
Beispiel #24
0
    def test_key_not_regenerated(self):
        """
        ``create_keypair`` does not generate a new key pair if one can
        already be found in ``id_rsa_flocker`` and ``id_rsa_flocker.pub``.
        """
        ssh_config = FilePath(self.mktemp())
        configurator = OpenSSHConfiguration(
            ssh_config_path=ssh_config, flocker_path=None)

        id_rsa = ssh_config.child(b"id_rsa_flocker")

        configurator.create_keypair()

        expected_key = Key.fromFile(id_rsa.path)

        configurator.create_keypair()

        self.assertEqual(expected_key, Key.fromFile(id_rsa.path))
Beispiel #25
0
    def test_key_not_regenerated(self):
        """
        ``create_keypair`` does not generate a new key pair if one can
        already be found in ``id_rsa_flocker`` and ``id_rsa_flocker.pub``.
        """
        ssh_config = FilePath(self.mktemp())
        configurator = OpenSSHConfiguration(ssh_config_path=ssh_config,
                                            flocker_path=None)

        id_rsa = ssh_config.child(b"id_rsa_flocker")

        configurator.create_keypair()

        expected_key = Key.fromFile(id_rsa.path)

        configurator.create_keypair()

        self.assertEqual(expected_key, Key.fromFile(id_rsa.path))
Beispiel #26
0
    def __init__(self,
                 portal,
                 private_key_path,
                 public_key_path,
                 oops_configuration,
                 main_log,
                 access_log,
                 access_log_path,
                 strport='tcp:22',
                 factory_decorator=None,
                 banner=None):
        """Construct an SSH service.

        :param portal: The `twisted.cred.portal.Portal` that turns
            authentication requests into views on the system.
        :param private_key_path: The path to the SSH server's private key.
        :param public_key_path: The path to the SSH server's public key.
        :param oops_configuration: The section of the configuration file with
            the OOPS config details for this server.
        :param main_log: The name of the logger to log most of the server
            stuff to.
        :param access_log: The name of the logger object to log the server
            access details to.
        :param access_log_path: The path to the access log file.
        :param strport: The port to run the server on, expressed in Twisted's
            "strports" mini-language. Defaults to 'tcp:22'.
        :param factory_decorator: An optional callable that can decorate the
            server factory (e.g. with a
            `twisted.protocols.policies.TimeoutFactory`).  It takes one
            argument, a factory, and must return a factory.
        :param banner: An announcement printed to users when they connect.
            By default, announce nothing.
        """
        ssh_factory = Factory(portal,
                              private_key=Key.fromFile(private_key_path),
                              public_key=Key.fromFile(public_key_path),
                              banner=banner)
        if factory_decorator is not None:
            ssh_factory = factory_decorator(ssh_factory)
        self.service = strports.service(strport, ssh_factory)
        self._oops_configuration = oops_configuration
        self._main_log = main_log
        self._access_log = access_log
        self._access_log_path = access_log_path
Beispiel #27
0
    def __init__(self, base_path):
        """
        :param FilePath base_path: The path beneath which all of the temporary
            SSH server-related files will be created.  An ``ssh`` directory
            will be created as a child of this directory to hold the key pair
            that is generated.  An ``sshd`` directory will also be created here
            to hold the generated host key.  A ``home`` directory is also
            created here and used as the home directory for shell logins to the
            server.
        """
        self.home = base_path.child(b"home")
        self.home.makedirs()

        ssh_path = base_path.child(b"ssh")
        ssh_path.makedirs()
        self.key_path = ssh_path.child(b"key")
        check_call(
            [
                b"ssh-keygen",
                # Specify the path where the generated key is written.
                b"-f",
                self.key_path.path,
                # Specify an empty passphrase.
                b"-N",
                b"",
                # Generate as little output as possible.
                b"-q",
            ]
        )
        key = Key.fromFile(self.key_path.path)

        sshd_path = base_path.child(b"sshd")
        sshd_path.makedirs()
        self.host_key_path = sshd_path.child(b"ssh_host_key")
        check_call(
            [
                b"ssh-keygen",
                # See above for option explanations.
                b"-f",
                self.host_key_path.path,
                b"-N",
                b"",
                b"-q",
            ]
        )

        factory = OpenSSHFactory()
        realm = _UnixSSHRealm(self.home)
        checker = _InMemoryPublicKeyChecker(public_key=key.public())
        factory.portal = Portal(realm, [checker])
        factory.dataRoot = sshd_path.path
        factory.moduliRoot = b"/etc/ssh"

        self._port = reactor.listenTCP(0, factory, interface=b"127.0.0.1")
        self.ip = IPAddress(self._port.getHost().host)
        self.port = self._port.getHost().port
Beispiel #28
0
def get_manhole_factory(namespace):
    """ Build a twisted manhole factory """

    from twisted.conch import manhole, manhole_ssh
    from twisted.cred import portal, checkers

    # I really hate Twisted's default colors
    colors = {
        'identifier': '\x1b[1;36m',
        'keyword': '\x1b[33m',
        'parameter': '\x1b[33m',
        'variable': '\x1b[36m',
        'string': '\x1b[35m',
        'number': '\x1b[1;32m',
        'op': '\x1b[33m'
    }

    manhole.VT102Writer.typeToColor.update(colors)

    realm = manhole_ssh.TerminalRealm()

    def get_manhole(_):
        return manhole.ColoredManhole(namespace)

    realm.chainedProtocolFactory.protocolFactory = get_manhole
    p = portal.Portal(realm)
    checker = checkers.InMemoryUsernamePasswordDatabaseDontUse()
    checker.addUser(config.backdoor_user, config.backdoor_password)
    p.registerChecker(checker)

    factory = manhole_ssh.ConchFactory(p)
    # As of Twisted~v16.0.0 we now have to give host SSH keys to any subclass of SSHFactory
    key_path = os.path.expanduser(config.ssh_key_path)
    factory.publicKeys = {
        'ssh-rsa': Key.fromFile(key_path)
    }

    factory.privateKeys = {
        'ssh-rsa': Key.fromFile(key_path)
    }

    return factory
Beispiel #29
0
def makeService(config):
    key = Key.fromFile(config["key"])
    datapath = FilePath(config['datadir'])

    factory = SSHFactory()
    factory.publicKeys = factory.privateKeys = {key.sshType(): key}

    factory.portal = Portal(
        GittoRealm(datapath),
        [GittoPublicKeyDatabase(datapath.child(".config").child("keys"))])

    return strports.service(config['port'], factory)
Beispiel #30
0
def makeService(config):
    key = Key.fromFile(config["key"])
    datapath = FilePath(config['datadir'])

    factory = SSHFactory()
    factory.publicKeys = factory.privateKeys = {key.sshType(): key}

    factory.portal = Portal(
        GittoRealm(datapath),
        [GittoPublicKeyDatabase(datapath.child(".config").child("keys"))])

    return strports.service(config['port'], factory)
Beispiel #31
0
 def postOptions(self):
     """
     Verify the configuration is usable.
     """
     for required in ["auth-host", "auth-port", "host-key", "client-key",
                      "client-cert"]:
         if self[required] is None:
             raise UsageError("--%s option is required" % (required,))
     try:
         self["host-key"] = Key.fromFile(self["host-key"].path)
     except (IOError, BadKeyError), e:
         raise UsageError("Cannot load host key: %s" % (e,))
Beispiel #32
0
    def __init__(self, base_path):
        """
        :param FilePath base_path: The path beneath which all of the temporary
            SSH server-related files will be created.  An ``ssh`` directory
            will be created as a child of this directory to hold the key pair
            that is generated.  An ``sshd`` directory will also be created here
            to hold the generated host key.  A ``home`` directory is also
            created here and used as the home directory for shell logins to the
            server.
        """
        self.home = base_path.child(b"home")
        self.home.makedirs()

        ssh_path = base_path.child(b"ssh")
        ssh_path.makedirs()
        self.key_path = ssh_path.child(b"key")
        check_call([
            b"ssh-keygen",
            # Specify the path where the generated key is written.
            b"-f",
            self.key_path.path,
            # Specify an empty passphrase.
            b"-N",
            b"",
            # Generate as little output as possible.
            b"-q"
        ])
        key = Key.fromFile(self.key_path.path)

        sshd_path = base_path.child(b"sshd")
        sshd_path.makedirs()
        self.host_key_path = sshd_path.child(b"ssh_host_key")
        check_call([
            b"ssh-keygen",
            # See above for option explanations.
            b"-f",
            self.host_key_path.path,
            b"-N",
            b"",
            b"-q"
        ])

        factory = OpenSSHFactory()
        realm = UnixSSHRealm(self.home)
        checker = _InMemoryPublicKeyChecker(public_key=key.public())
        factory.portal = Portal(realm, [checker])
        factory.dataRoot = sshd_path.path
        factory.moduliRoot = b"/etc/ssh"

        self._port = reactor.listenTCP(0, factory, interface=b"127.0.0.1")
        self.ip = IPAddress(self._port.getHost().host)
        self.port = self._port.getHost().port
Beispiel #33
0
    def getPublicKey(self):
        """
        Return the SSH public key (using the Property KeyPath) or None

        @return: SSH public key
        @rtype: string
        """
        # Don't re-send the same public key if we have already been called.
        # TODO: Would be good to expand to support sending multiple keys.
        if self._key is not None and not self._sent_pk:
            self._sent_pk = True
            keyPath = os.path.expanduser(self.factory.keyPath + ".pub")
            return Key.fromFile(keyPath)
Beispiel #34
0
    def __init__(self, portal, private_key_path, public_key_path,
                 oops_configuration, main_log, access_log,
                 access_log_path, strport='tcp:22', factory_decorator=None,
                 banner=None):
        """Construct an SSH service.

        :param portal: The `twisted.cred.portal.Portal` that turns
            authentication requests into views on the system.
        :param private_key_path: The path to the SSH server's private key.
        :param public_key_path: The path to the SSH server's public key.
        :param oops_configuration: The section of the configuration file with
            the OOPS config details for this server.
        :param main_log: The name of the logger to log most of the server
            stuff to.
        :param access_log: The name of the logger object to log the server
            access details to.
        :param access_log_path: The path to the access log file.
        :param strport: The port to run the server on, expressed in Twisted's
            "strports" mini-language. Defaults to 'tcp:22'.
        :param factory_decorator: An optional callable that can decorate the
            server factory (e.g. with a
            `twisted.protocols.policies.TimeoutFactory`).  It takes one
            argument, a factory, and must return a factory.
        :param banner: An announcement printed to users when they connect.
            By default, announce nothing.
        """
        ssh_factory = Factory(
            portal,
            private_key=Key.fromFile(private_key_path),
            public_key=Key.fromFile(public_key_path),
            banner=banner)
        if factory_decorator is not None:
            ssh_factory = factory_decorator(ssh_factory)
        self.service = strports.service(strport, ssh_factory)
        self._oops_configuration = oops_configuration
        self._main_log = main_log
        self._access_log = access_log
        self._access_log_path = access_log_path
Beispiel #35
0
 def _getKey(self):
     keyPath = os.path.expanduser(self.factory.keyPath)
     log.msg("Expanded SSH key path from KeyPath {0} to {1}".format(self.factory.keyPath, keyPath))
     key = None
     if os.path.exists(keyPath):
         try:
             key = Key.fromFile(keyPath)
         except IOError, ex:
             message = "Unable to read the SSH key file because %s" % (str(ex))
             log.warn(message)
             device = "localhost"  # Fallback
             try:
                 device = socket.getfqdn()
             except:
                 pass
Beispiel #36
0
 def _connect(self, host, port, user, password, private_key_file):
     keys = [Key.fromFile(private_key_file)]
     ep = SSHCommandClientEndpoint.newConnection(
             reactor,
             b'/bin/cat',
             user,
             host,
             port=port,
             password=password,
             keys=keys,
             agentEndpoint=None,
             knownHosts=EveryoneIsAKnownHostsFile())
     factory = Factory()
     factory.protocol = _PersistentProtocol
     return ep.connect(factory).addCallback(self._connected)
Beispiel #37
0
def connect(sdata,
            command,
            username,
            host,
            port=22,
            key_file=None,
            password=None):
    """
    Connect to an SSH host (as it happens, persistently).
    """
    sdata.set_conn_state('connecting')

    try:
        keys = [Key.fromFile(key_file)] if key_file else None
    except exceptions.IOError as e:
        print('### key load error:', str(e))
        push_failure_message(str(e), sdata)
        return

    endpoint = SSHCommandClientEndpoint.newConnection(
        reactor,
        command,
        username,
        host,
        port=int(port),
        keys=keys,
        password=password,
        ui=None,
        knownHosts=PermissiveKnownHosts())

    factory = Factory()
    factory.protocol = LineProtocol
    factory.sdata = sdata

    d = endpoint.connect(factory)

    # Very small race condition between here and the replacement
    # in connectionMade() above, but I've never managed to hit it.
    def disconnect():
        sdata.log(
            'Disconnecting while still attempting to connect, by request')
        d.cancel()

    sdata.transport_drop_cb = disconnect

    d.addErrback(lambda reason: push_failure_message(reason, sdata))
    return d
Beispiel #38
0
def generate_ssh_key(key_file):
    """
    Generate a ssh key.

    :param FilePath key_file: Path to create ssh key at.

    :return Key: The generated key.
    """
    check_call(
        [b"ssh-keygen",
         # Specify the path where the generated key is written.
         b"-f", key_file.path,
         # Specify an empty passphrase.
         b"-N", b"",
         # Generate as little output as possible.
         b"-q"])
    return Key.fromFile(key_file.path)
Beispiel #39
0
    def test_key_generated(self):
        """
        ``create_keypair`` generates a new key pair and writes it locally to
        ``id_rsa_flocker`` and ``id_rsa_flocker.pub``.
        """
        ssh_config = FilePath(self.mktemp())
        configurator = OpenSSHConfiguration(
            ssh_config_path=ssh_config, flocker_path=None)

        configurator.create_keypair()

        id_rsa = ssh_config.child(b"id_rsa_flocker")
        id_rsa_pub = ssh_config.child(b"id_rsa_flocker.pub")
        key = Key.fromFile(id_rsa.path)

        self.assertEqual(
            # Avoid comparing the comment
            key.public().toString(
                type="OPENSSH", extra='test comment').split(None, 2)[:2],
            id_rsa_pub.getContent().split(None, 2)[:2])
Beispiel #40
0
    def test_key_generated(self):
        """
        ``create_keypair`` generates a new key pair and writes it locally to
        ``id_rsa_flocker`` and ``id_rsa_flocker.pub``.
        """
        ssh_config = FilePath(self.mktemp())
        configurator = OpenSSHConfiguration(ssh_config_path=ssh_config,
                                            flocker_path=None)

        configurator.create_keypair()

        id_rsa = ssh_config.child(b"id_rsa_flocker")
        id_rsa_pub = ssh_config.child(b"id_rsa_flocker.pub")
        key = Key.fromFile(id_rsa.path)

        self.assertEqual(
            # Avoid comparing the comment
            key.public().toString(type="OPENSSH",
                                  extra='test comment').split(None, 2)[:2],
            id_rsa_pub.getContent().split(None, 2)[:2])
Beispiel #41
0
    def __init__(self, remote_config, cmd):
        """Create a new remote Astrisk CLI Protocol instance

        Keyword Arguments:
        remote_config The parameters configuring this remote CLI command
        cmd           The CLI command to run
        """
        if REMOTE_ERROR:
            raise REMOTE_ERROR

        self.exitcode = -1
        self.output = ""
        self.err = ""

        self.config = remote_config
        self.cmd = cmd
        self.keys = []

        identity = self.config.get('identity')
        if identity:
            key_path = os.path.expanduser(identity)
            if os.path.exists(key_path):
                passphrase = self.config.get('passphrase')
                self.keys.append(Key.fromFile(key_path, passphrase=passphrase))

        known_hosts_file = self.config.get('known_hosts', '~/.ssh/known_hosts')
        known_hosts_path = FilePath(os.path.expanduser(known_hosts_file))
        if known_hosts_path.exists():
            self.known_hosts = KnownHostsFile.fromPath(known_hosts_path)
        else:
            self.known_hosts = None

        no_agent = self.config.get('no-agent')
        if no_agent or 'SSH_AUTH_SOCK' not in os.environ:
            self.agent_endpoint = None
        else:
            self.agent_endpoint = UNIXClientEndpoint(reactor,
                                                     os.environ['SSH_AUTH_SOCK'])
Beispiel #42
0
    def __init__(self, remote_config, cmd):
        """Create a new remote Astrisk CLI Protocol instance

        Keyword Arguments:
        remote_config The parameters configuring this remote CLI command
        cmd           The CLI command to run
        """
        if REMOTE_ERROR:
            raise REMOTE_ERROR

        self.exitcode = -1
        self.output = ""
        self.err = ""

        self.config = remote_config
        self.cmd = cmd
        self.keys = []

        identity = self.config.get('identity')
        if identity:
            key_path = os.path.expanduser(identity)
            if os.path.exists(key_path):
                passphrase = self.config.get('passphrase')
                self.keys.append(Key.fromFile(key_path, passphrase=passphrase))

        known_hosts_file = self.config.get('known_hosts', '~/.ssh/known_hosts')
        known_hosts_path = FilePath(os.path.expanduser(known_hosts_file))
        if known_hosts_path.exists():
            self.known_hosts = KnownHostsFile.fromPath(known_hosts_path)
        else:
            self.known_hosts = None

        no_agent = self.config.get('no-agent')
        if no_agent or 'SSH_AUTH_SOCK' not in os.environ:
            self.agent_endpoint = None
        else:
            self.agent_endpoint = UNIXClientEndpoint(reactor,
                                                     os.environ['SSH_AUTH_SOCK'])
Beispiel #43
0
def readKey(path):
    try:
        return Key.fromFile(path)
    except EncryptedKeyError:
        passphrase = getpass.getpass(f"{path!r} keyphrase: ")
        return Key.fromFile(path, passphrase=passphrase)
 def __init__(self, privkey):
     pubkey = '.'.join((privkey, 'pub'))
     self.privateKeys = {'ssh-rsa': Key.fromFile(privkey)}
     self.publicKeys = {'ssh-rsa': Key.fromFile(pubkey)}
Beispiel #45
0
    def read_config(self, config: JsonDict, **kwargs: Any) -> None:
        self.server_name = config["server_name"]
        self.server_context = config.get("server_context", None)

        try:
            parse_and_validate_server_name(self.server_name)
        except ValueError as e:
            raise ConfigError(str(e))

        self.pid_file = self.abspath(config.get("pid_file"))
        self.soft_file_limit = config.get("soft_file_limit", 0)
        self.daemonize = bool(config.get("daemonize"))
        self.print_pidfile = bool(config.get("print_pidfile"))
        self.user_agent_suffix = config.get("user_agent_suffix")
        self.use_frozen_dicts = config.get("use_frozen_dicts", False)
        self.serve_server_wellknown = config.get("serve_server_wellknown", False)

        # Whether we should serve a "client well-known":
        #  (a) at .well-known/matrix/client on our client HTTP listener
        #  (b) in the response to /login
        #
        # ... which together help ensure that clients use our public_baseurl instead of
        # whatever they were told by the user.
        #
        # For the sake of backwards compatibility with existing installations, this is
        # True if public_baseurl is specified explicitly, and otherwise False. (The
        # reasoning here is that we have no way of knowing that the default
        # public_baseurl is actually correct for existing installations - many things
        # will not work correctly, but that's (probably?) better than sending clients
        # to a completely broken URL.
        self.serve_client_wellknown = False

        public_baseurl = config.get("public_baseurl")
        if public_baseurl is None:
            public_baseurl = f"https://{self.server_name}/"
            logger.info("Using default public_baseurl %s", public_baseurl)
        else:
            self.serve_client_wellknown = True
            if public_baseurl[-1] != "/":
                public_baseurl += "/"
        self.public_baseurl = public_baseurl

        # check that public_baseurl is valid
        try:
            splits = urllib.parse.urlsplit(self.public_baseurl)
        except Exception as e:
            raise ConfigError(f"Unable to parse URL: {e}", ("public_baseurl",))
        if splits.scheme not in ("https", "http"):
            raise ConfigError(
                f"Invalid scheme '{splits.scheme}': only https and http are supported"
            )
        if splits.query or splits.fragment:
            raise ConfigError(
                "public_baseurl cannot contain query parameters or a #-fragment"
            )

        self.extra_well_known_client_content = config.get(
            "extra_well_known_client_content", {}
        )

        if not isinstance(self.extra_well_known_client_content, dict):
            raise ConfigError(
                "extra_well_known_content must be a dictionary of key-value pairs"
            )

        if "m.homeserver" in self.extra_well_known_client_content:
            raise ConfigError(
                "m.homeserver is not supported in extra_well_known_content, "
                "use public_baseurl in base config instead."
            )
        if "m.identity_server" in self.extra_well_known_client_content:
            raise ConfigError(
                "m.identity_server is not supported in extra_well_known_content, "
                "use default_identity_server in base config instead."
            )

        # Whether to enable user presence.
        presence_config = config.get("presence") or {}
        self.use_presence = presence_config.get("enabled")
        if self.use_presence is None:
            self.use_presence = config.get("use_presence", True)

        # Custom presence router module
        # This is the legacy way of configuring it (the config should now be put in the modules section)
        self.presence_router_module_class = None
        self.presence_router_config = None
        presence_router_config = presence_config.get("presence_router")
        if presence_router_config:
            (
                self.presence_router_module_class,
                self.presence_router_config,
            ) = load_module(presence_router_config, ("presence", "presence_router"))

        # whether to enable the media repository endpoints. This should be set
        # to false if the media repository is running as a separate endpoint;
        # doing so ensures that we will not run cache cleanup jobs on the
        # master, potentially causing inconsistency.
        self.enable_media_repo = config.get("enable_media_repo", True)

        # Whether to require authentication to retrieve profile data (avatars,
        # display names) of other users through the client API.
        self.require_auth_for_profile_requests = config.get(
            "require_auth_for_profile_requests", False
        )

        # Whether to require sharing a room with a user to retrieve their
        # profile data
        self.limit_profile_requests_to_users_who_share_rooms = config.get(
            "limit_profile_requests_to_users_who_share_rooms",
            False,
        )

        # Whether to retrieve and display profile data for a user when they
        # are invited to a room
        self.include_profile_data_on_invite = config.get(
            "include_profile_data_on_invite", True
        )

        if "restrict_public_rooms_to_local_users" in config and (
            "allow_public_rooms_without_auth" in config
            or "allow_public_rooms_over_federation" in config
        ):
            raise ConfigError(
                "Can't use 'restrict_public_rooms_to_local_users' if"
                " 'allow_public_rooms_without_auth' and/or"
                " 'allow_public_rooms_over_federation' is set."
            )

        # Check if the legacy "restrict_public_rooms_to_local_users" flag is set. This
        # flag is now obsolete but we need to check it for backward-compatibility.
        if config.get("restrict_public_rooms_to_local_users", False):
            self.allow_public_rooms_without_auth = False
            self.allow_public_rooms_over_federation = False
        else:
            # If set to 'true', removes the need for authentication to access the server's
            # public rooms directory through the client API, meaning that anyone can
            # query the room directory. Defaults to 'false'.
            self.allow_public_rooms_without_auth = config.get(
                "allow_public_rooms_without_auth", False
            )
            # If set to 'true', allows any other homeserver to fetch the server's public
            # rooms directory via federation. Defaults to 'false'.
            self.allow_public_rooms_over_federation = config.get(
                "allow_public_rooms_over_federation", False
            )

        default_room_version = config.get("default_room_version", DEFAULT_ROOM_VERSION)

        # Ensure room version is a str
        default_room_version = str(default_room_version)

        if default_room_version not in KNOWN_ROOM_VERSIONS:
            raise ConfigError(
                "Unknown default_room_version: %s, known room versions: %s"
                % (default_room_version, list(KNOWN_ROOM_VERSIONS.keys()))
            )

        # Get the actual room version object rather than just the identifier
        self.default_room_version = KNOWN_ROOM_VERSIONS[default_room_version]

        # whether to enable search. If disabled, new entries will not be inserted
        # into the search tables and they will not be indexed. Users will receive
        # errors when attempting to search for messages.
        self.enable_search = config.get("enable_search", True)

        self.filter_timeline_limit = config.get("filter_timeline_limit", 100)

        # Whether we should block invites sent to users on this server
        # (other than those sent by local server admins)
        self.block_non_admin_invites = config.get("block_non_admin_invites", False)

        # Options to control access by tracking MAU
        self.limit_usage_by_mau = config.get("limit_usage_by_mau", False)
        self.max_mau_value = 0
        if self.limit_usage_by_mau:
            self.max_mau_value = config.get("max_mau_value", 0)
        self.mau_stats_only = config.get("mau_stats_only", False)

        self.mau_limits_reserved_threepids = config.get(
            "mau_limit_reserved_threepids", []
        )

        self.mau_trial_days = config.get("mau_trial_days", 0)
        self.mau_appservice_trial_days = config.get("mau_appservice_trial_days", {})
        self.mau_limit_alerting = config.get("mau_limit_alerting", True)

        # How long to keep redacted events in the database in unredacted form
        # before redacting them.
        redaction_retention_period = config.get("redaction_retention_period", "7d")
        if redaction_retention_period is not None:
            self.redaction_retention_period: Optional[int] = self.parse_duration(
                redaction_retention_period
            )
        else:
            self.redaction_retention_period = None

        # How long to keep entries in the `users_ips` table.
        user_ips_max_age = config.get("user_ips_max_age", "28d")
        if user_ips_max_age is not None:
            self.user_ips_max_age: Optional[int] = self.parse_duration(user_ips_max_age)
        else:
            self.user_ips_max_age = None

        # Options to disable HS
        self.hs_disabled = config.get("hs_disabled", False)
        self.hs_disabled_message = config.get("hs_disabled_message", "")

        # Admin uri to direct users at should their instance become blocked
        # due to resource constraints
        self.admin_contact = config.get("admin_contact", None)

        ip_range_blacklist = config.get(
            "ip_range_blacklist", DEFAULT_IP_RANGE_BLACKLIST
        )

        # Attempt to create an IPSet from the given ranges

        # Always blacklist 0.0.0.0, ::
        self.ip_range_blacklist = generate_ip_set(
            ip_range_blacklist, ["0.0.0.0", "::"], config_path=("ip_range_blacklist",)
        )

        self.ip_range_whitelist = generate_ip_set(
            config.get("ip_range_whitelist", ()), config_path=("ip_range_whitelist",)
        )
        # The federation_ip_range_blacklist is used for backwards-compatibility
        # and only applies to federation and identity servers.
        if "federation_ip_range_blacklist" in config:
            # Always blacklist 0.0.0.0, ::
            self.federation_ip_range_blacklist = generate_ip_set(
                config["federation_ip_range_blacklist"],
                ["0.0.0.0", "::"],
                config_path=("federation_ip_range_blacklist",),
            )
            # 'federation_ip_range_whitelist' was never a supported configuration option.
            self.federation_ip_range_whitelist = None
        else:
            # No backwards-compatiblity requrired, as federation_ip_range_blacklist
            # is not given. Default to ip_range_blacklist and ip_range_whitelist.
            self.federation_ip_range_blacklist = self.ip_range_blacklist
            self.federation_ip_range_whitelist = self.ip_range_whitelist

        # (undocumented) option for torturing the worker-mode replication a bit,
        # for testing. The value defines the number of milliseconds to pause before
        # sending out any replication updates.
        self.replication_torture_level = config.get("replication_torture_level")

        # Whether to require a user to be in the room to add an alias to it.
        # Defaults to True.
        self.require_membership_for_aliases = config.get(
            "require_membership_for_aliases", True
        )

        # Whether to allow per-room membership profiles through the send of membership
        # events with profile information that differ from the target's global profile.
        self.allow_per_room_profiles = config.get("allow_per_room_profiles", True)

        # The maximum size an avatar can have, in bytes.
        self.max_avatar_size = config.get("max_avatar_size")
        if self.max_avatar_size is not None:
            self.max_avatar_size = self.parse_size(self.max_avatar_size)

        # The MIME types allowed for an avatar.
        self.allowed_avatar_mimetypes = config.get("allowed_avatar_mimetypes")
        if self.allowed_avatar_mimetypes and not isinstance(
            self.allowed_avatar_mimetypes,
            list,
        ):
            raise ConfigError("allowed_avatar_mimetypes must be a list")

        self.listeners = [parse_listener_def(x) for x in config.get("listeners", [])]

        # no_tls is not really supported any more, but let's grandfather it in
        # here.
        if config.get("no_tls", False):
            l2 = []
            for listener in self.listeners:
                if listener.tls:
                    logger.info(
                        "Ignoring TLS-enabled listener on port %i due to no_tls",
                        listener.port,
                    )
                else:
                    l2.append(listener)
            self.listeners = l2

        self.web_client_location = config.get("web_client_location", None)
        # Non-HTTP(S) web client location is not supported.
        if self.web_client_location and not (
            self.web_client_location.startswith("http://")
            or self.web_client_location.startswith("https://")
        ):
            raise ConfigError("web_client_location must point to a HTTP(S) URL.")

        self.gc_thresholds = read_gc_thresholds(config.get("gc_thresholds", None))
        self.gc_seconds = self.read_gc_intervals(config.get("gc_min_interval", None))

        self.limit_remote_rooms = LimitRemoteRoomsConfig(
            **(config.get("limit_remote_rooms") or {})
        )

        bind_port = config.get("bind_port")
        if bind_port:
            if config.get("no_tls", False):
                raise ConfigError("no_tls is incompatible with bind_port")

            self.listeners = []
            bind_host = config.get("bind_host", "")
            gzip_responses = config.get("gzip_responses", True)

            http_options = HttpListenerConfig(
                resources=[
                    HttpResourceConfig(names=["client"], compress=gzip_responses),
                    HttpResourceConfig(names=["federation"]),
                ],
            )

            self.listeners.append(
                ListenerConfig(
                    port=bind_port,
                    bind_addresses=[bind_host],
                    tls=True,
                    type="http",
                    http_options=http_options,
                )
            )

            unsecure_port = config.get("unsecure_port", bind_port - 400)
            if unsecure_port:
                self.listeners.append(
                    ListenerConfig(
                        port=unsecure_port,
                        bind_addresses=[bind_host],
                        tls=False,
                        type="http",
                        http_options=http_options,
                    )
                )

        manhole = config.get("manhole")
        if manhole:
            self.listeners.append(
                ListenerConfig(
                    port=manhole,
                    bind_addresses=["127.0.0.1"],
                    type="manhole",
                )
            )

        manhole_settings = config.get("manhole_settings") or {}
        validate_config(
            _MANHOLE_SETTINGS_SCHEMA, manhole_settings, ("manhole_settings",)
        )

        manhole_username = manhole_settings.get("username", "matrix")
        manhole_password = manhole_settings.get("password", "rabbithole")
        manhole_priv_key_path = manhole_settings.get("ssh_priv_key_path")
        manhole_pub_key_path = manhole_settings.get("ssh_pub_key_path")

        manhole_priv_key = None
        if manhole_priv_key_path is not None:
            try:
                manhole_priv_key = Key.fromFile(manhole_priv_key_path)
            except Exception as e:
                raise ConfigError(
                    f"Failed to read manhole private key file {manhole_priv_key_path}"
                ) from e

        manhole_pub_key = None
        if manhole_pub_key_path is not None:
            try:
                manhole_pub_key = Key.fromFile(manhole_pub_key_path)
            except Exception as e:
                raise ConfigError(
                    f"Failed to read manhole public key file {manhole_pub_key_path}"
                ) from e

        self.manhole_settings = ManholeConfig(
            username=manhole_username,
            password=manhole_password,
            priv_key=manhole_priv_key,
            pub_key=manhole_pub_key,
        )

        metrics_port = config.get("metrics_port")
        if metrics_port:
            logger.warning(METRICS_PORT_WARNING)

            self.listeners.append(
                ListenerConfig(
                    port=metrics_port,
                    bind_addresses=[config.get("metrics_bind_host", "127.0.0.1")],
                    type="http",
                    http_options=HttpListenerConfig(
                        resources=[HttpResourceConfig(names=["metrics"])]
                    ),
                )
            )

        self.cleanup_extremities_with_dummy_events = config.get(
            "cleanup_extremities_with_dummy_events", True
        )

        # The number of forward extremities in a room needed to send a dummy event.
        self.dummy_events_threshold = config.get("dummy_events_threshold", 10)

        self.enable_ephemeral_messages = config.get("enable_ephemeral_messages", False)

        # Inhibits the /requestToken endpoints from returning an error that might leak
        # information about whether an e-mail address is in use or not on this
        # homeserver, and instead return a 200 with a fake sid if this kind of error is
        # met, without sending anything.
        # This is a compromise between sending an email, which could be a spam vector,
        # and letting the client know which email address is bound to an account and
        # which one isn't.
        self.request_token_inhibit_3pid_errors = config.get(
            "request_token_inhibit_3pid_errors",
            False,
        )

        # Whitelist of domain names that given next_link parameters must have
        next_link_domain_whitelist: Optional[List[str]] = config.get(
            "next_link_domain_whitelist"
        )

        self.next_link_domain_whitelist: Optional[Set[str]] = None
        if next_link_domain_whitelist is not None:
            if not isinstance(next_link_domain_whitelist, list):
                raise ConfigError("'next_link_domain_whitelist' must be a list")

            # Turn the list into a set to improve lookup speed.
            self.next_link_domain_whitelist = set(next_link_domain_whitelist)

        templates_config = config.get("templates") or {}
        if not isinstance(templates_config, dict):
            raise ConfigError("The 'templates' section must be a dictionary")

        self.custom_template_directory: Optional[str] = templates_config.get(
            "custom_template_directory"
        )
        if self.custom_template_directory is not None and not isinstance(
            self.custom_template_directory, str
        ):
            raise ConfigError("'custom_template_directory' must be a string")

        self.use_account_validity_in_account_status: bool = (
            config.get("use_account_validity_in_account_status") or False
        )

        self.rooms_to_exclude_from_sync: List[str] = (
            config.get("exclude_rooms_from_sync") or []
        )

        delete_stale_devices_after: Optional[str] = (
            config.get("delete_stale_devices_after") or None
        )

        if delete_stale_devices_after is not None:
            self.delete_stale_devices_after: Optional[int] = self.parse_duration(
                delete_stale_devices_after
            )
        else:
            self.delete_stale_devices_after = None
Beispiel #46
0
 def __init__(self, settings):
     self.settings = settings
     self.portal = Portal(OpenRukoRealm(settings))
     self.portal.registerChecker(OpenRukoCredentialChecker(settings))
     self.privateKeys = {'ssh-rsa': Key.fromFile(settings['private_key'])}
     self.publicKeys = {'ssh-rsa': Key.fromFile(settings['public_key'])}
Beispiel #47
0
def readKey(path):
    try:
        return Key.fromFile(path)
    except EncryptedKeyError:
        passphrase = getpass.getpass("{!r} keyphrase: ".format(path))
        return Key.fromFile(path, passphrase=passphrase)
 def __init__(self, privkey):
     pubkey = ".".join((privkey, "pub"))
     self.privateKeys = {"ssh-rsa": Key.fromFile(privkey)}
     self.publicKeys = {"ssh-rsa": Key.fromFile(pubkey)}
Beispiel #49
0
 def __init__(self, privkey):
     pubkey = '.'.join((privkey, 'pub'))
     self.privateKeys = {'ssh-rsa': Key.fromFile(privkey)}
     self.publicKeys = {'ssh-rsa': Key.fromFile(pubkey)}
Beispiel #50
0
 def __init__(self, priv_key):
     pub_key = '%s.pub' % priv_key
     self.privateKeys = {'ssh-rsa': Key.fromFile(priv_key)}
     self.publicKeys = {'ssh-rsa': Key.fromFile(pub_key)}
     self.primes = {2048: [(transport.DH_GENERATOR, transport.DH_PRIME)]}
 def getPrivateKey(self):
     path = self.options['ssh-key']
     return defer.succeed(Key.fromFile(path))
Beispiel #52
0
 def getPrivateKey(self):
     return succeed(Key.fromFile(key_path))
Beispiel #53
0
 def ensure_keys(self, reactor):
     key = Key.fromFile(os.path.expanduser(
         "~/.vagrant.d/insecure_private_key"))
     return ensure_agent_has_ssh_key(reactor, key)
Beispiel #54
0
 def ensure_keys(self, reactor):
     key = Key.fromFile(os.path.expanduser(
         "~/.vagrant.d/insecure_private_key"))
     return ensure_agent_has_ssh_key(reactor, key)
 def getPrivateKey(self):
     path = self.options['ssh-key']
     return defer.succeed(Key.fromFile(path))
def readKey(path):
    try:
        return Key.fromFile(path)
    except EncryptedKeyError:
        passphrase = getpass.getpass("%r keyphrase: " % (path,))
        return Key.fromFile(path, passphrase=passphrase)