def setup_secure_access(self): try: from twisted.cred import portal portal = portal.Portal(NetconfRealm(self, self.grpc_client)) # setup userid-password access password_file = '{}/{}/{}'.format(dir_path, C.CLIENT_CRED_DIRECTORY, self.client_passwords_file) portal.registerChecker(FilePasswordDB(password_file)) # setup access when client uses keys keys_file = '{}/{}/{}'.format(dir_path, C.CLIENT_CRED_DIRECTORY, self.client_public_keys_file) with open(keys_file) as f: users = [line.rstrip('\n') for line in f] users_dict = {} for user in users: users_dict[user.split(':')[0]] = [ keys.Key.fromFile('{}/{}/{}'.format( dir_path, C.CLIENT_CRED_DIRECTORY, user.split(':')[1])) ] sshDB = SSHPublicKeyChecker(InMemorySSHKeyDB(users_dict)) portal.registerChecker(sshDB) return portal except Exception as e: log.error('setup-secure-access-fail', exception=repr(e))
def generateChecker(self, argstring=''): """ This checker factory ignores the argument string. Everything needed to authenticate users is pulled out of the public keys listed in user .ssh/ directories. """ return SSHPublicKeyChecker(UNIXAuthorizedKeysFiles())
def startService(self): components.registerAdapter(SSHSession, SSHAvatar, session.ISession) portal = ptl.Portal(SSHRealm()) passwdDB = InMemoryUsernamePasswordDatabaseDontUse() passwdDB.addUser(b'user', b'password') sshDB = SSHPublicKeyChecker( InMemorySSHKeyDB({b'user': [keys.Key.fromFile(CLIENT_RSA_PUBLIC)]})) portal.registerChecker(passwdDB) portal.registerChecker(sshDB) SSHServerFactory.portal = portal self.endpoint = TCP4ServerEndpoint(reactor, 2222) self.endpoint.listen(SSHServerFactory())
def conch_helper(endpoint, proto=None, namespace=dict(), keyDir=None, keySize=4096): """ Return a L{SSHKeyDirectory} based SSH service with the given parameters. Authorized keys are read as per L{SSHKeyDirectory} with ``baseDir`` being ``keyDir/users``. @param endpoint: endpoint for the SSH service @param namespace: the manhole namespace @param keyDir: directory that holds server/server.key file and users directory, which is used as ``baseDir`` in L{SSHKeyDirectory} @see: L{SSHKeyDirectory} """ if keyDir is None: from twisted.python._appdirs import getDataDirectory keyDir = getDataDirectory() keyDir = filepath.FilePath(keyDir) keyDir.child("server").makedirs(True) keyDir.child("users").makedirs(True) checker = SSHPublicKeyChecker(SSHKeyDirectory(keyDir.child("users"))) if proto is None: sshRealm = manhole_ssh.TerminalRealm() sshRealm.chainedProtocolFactory = chainedProtocolFactory(namespace) else: sshRealm = SSHSimpleRealm(proto) sshPortal = portal.Portal(sshRealm, [checker]) sshKeyPath = keyDir.child("server").child("server.key") sshKey = keys._getPersistentRSAKey(sshKeyPath, keySize) sshFactory = manhole_ssh.ConchFactory(sshPortal) sshFactory.publicKeys[b"ssh-rsa"] = sshKey sshFactory.privateKeys[b"ssh-rsa"] = sshKey sshService = strports.service(endpoint, sshFactory) return sshService
def __init__(self, client, accountfile): self.client = client self.passwords = BytesKeyDict() pubkeys = BytesKeyDict() self.rootcaps = BytesKeyDict() with open(abspath_expanduser_unicode(accountfile), "rb") as f: for line in f: line = line.strip() if line.startswith(b"#") or not line: continue name, passwd, rest = line.split(None, 2) if passwd.startswith(b"ssh-"): bits = rest.split() keystring = b" ".join([passwd] + bits[:-1]) key = keys.Key.fromString(keystring) rootcap = bits[-1] pubkeys[name] = [key] else: self.passwords[name] = passwd rootcap = rest self.rootcaps[name] = rootcap self._pubkeychecker = SSHPublicKeyChecker(InMemorySSHKeyDB(pubkeys))
# Server's host keys. # To simplify the example this server is defined only with a host key of # type RSA. publicKeys = {'ssh-rsa': keys.Key.fromFile(SERVER_RSA_PUBLIC)} privateKeys = {'ssh-rsa': keys.Key.fromFile(SERVER_RSA_PRIVATE)} # Service handlers. services = { 'ssh-userauth': userauth.SSHUserAuthServer, 'ssh-connection': connection.SSHConnection } def getPrimes(self): """ See: L{factory.SSHFactory} """ return PRIMES portal = portal.Portal(ExampleRealm()) passwdDB = InMemoryUsernamePasswordDatabaseDontUse() passwdDB.addUser('user', 'password') sshDB = SSHPublicKeyChecker( InMemorySSHKeyDB({'user': [keys.Key.fromFile(CLIENT_RSA_PUBLIC)]})) portal.registerChecker(passwdDB) portal.registerChecker(sshDB) ExampleFactory.portal = portal if __name__ == '__main__': reactor.listenTCP(5022, ExampleFactory()) reactor.run()
def startService(self): """ This is the main entry point into the service when it starts. Multiple components need to be created and assembled to create the final service. It helps to look at the process in reverse. An endpoint (`ep`) is created that listens on a port. When a connection is received, it uses a protocol `factory` to create a new SSH protocol instance. The factory is configure with a portal that will be used to authenticate users and create avatars for them at the service. The factory portal registered a :py:class:`SSHPublicKeychecker` instance so that users can authenticate using SSH public/private key pairs. The allowed public keys and the matching users are configured in a JSON file that the service reads on start up. The protocol factory (:py:class:`twisted.conch.ssh.factory.SSHFactory`) is indirectly responsible for calling the `login` method on its portal. When the "ssh-userauth" service of the SSH protocol is requested, the factory creates an instance of :py:class:`twisted.conch.ssh.userauth.SSHUserAuthServer` to create a public key credential and pass it to the portal's `login` method. It is at this point the public key checker can authenticate the credential. The portal was also configured with `self.realmFactory` which happens to produce an instance of :py:class:`auth.SSHRealm`. This realm creates an avatar instance which will represent the user on the service side of the connection. The avatar created will be an instance of :py:class:`auth.SSHAvatar`. This avatar is responsible for connecting the user to the service application logic. """ assert self.realmFactory is not None, "`realmFactory` must not be None!" with open(self.servicePrivateKey, "r") as privateBlobFile: privateBlob = privateBlobFile.read() privateKey = Key.fromString(data=privateBlob) with open(self.servicePublicKey, "r") as publicBlobFile: publicBlob = publicBlobFile.read() publicKey = Key.fromString(data=publicBlob) factory = SSHFactory() factory.privateKeys = {b'ssh-rsa': privateKey} factory.publicKeys = {b'ssh-rsa': publicKey} sshRealm = self.realmFactory() sshRealm.reactor = self.reactor sshPortal = Portal(sshRealm) factory.portal = sshPortal with open(self.key_db_path, "r") as f: raw_key_map = json.load(f) l = [] for avatar_id, keys in raw_key_map.items(): key_objects = [Key.fromString(k.encode('utf-8')) for k in keys] l.append((avatar_id.encode('utf-8'), key_objects)) key_map = dict(l) keydb = InMemorySSHKeyDB(key_map) factory.portal.registerChecker(SSHPublicKeyChecker(keydb)) ep = endpoints.serverFromString(self.reactor, self.endpoint_str) d = ep.listen(factory) self.port_info_ = [] d.addCallback(self.onListen)
pass def closed(self): pass from twisted.python import components components.registerAdapter(ExampleSession, ExampleAvatar, session.ISession) class ExampleFactory(factory.SSHFactory): publicKeys = {'ssh-rsa': keys.Key.fromString(data=publicKey)} privateKeys = {'ssh-rsa': keys.Key.fromString(data=privateKey)} services = { 'ssh-userauth': userauth.SSHUserAuthServer, 'ssh-connection': connection.SSHConnection } portal = portal.Portal(SSHDemoRealm()) passwdDB = InMemoryUsernamePasswordDatabaseDontUse() passwdDB.addUser('user', 'password') sshDB = SSHPublicKeyChecker( InMemorySSHKeyDB({'user': [keys.Key.fromString(data=publicKey)]})) portal.registerChecker(passwdDB) portal.registerChecker(sshDB) ExampleFactory.portal = portal if __name__ == '__main__': reactor.listenTCP(interface="0.0.0.0", port=2222, factory=ExampleFactory()) reactor.run()
self.env = {} def request_pty_req(self, data): print "request pty" return True def request_shell(self, data): protocol = EchoProtocol() transport = SSHSessionProcessProtocol(self) protocol.makeConnection(transport) transport.makeConnection(wrapProtocol(protocol)) self.client = transport return True def request_env(self, data): (key, value, _) = getNS(data, count=2) self.env[key] = value return True if __name__ == '__main__': portal = portal.Portal(MetisRealm()) sshDB = SSHPublicKeyChecker( InMemorySSHKeyDB({ 'edd': [keys.Key.fromFile('/Users/edd/.ssh/id_rsa.personal.pub')] })) portal.registerChecker(sshDB) factory = MetisSSHFactory(portal) reactor.listenTCP(5022, factory) reactor.run()
def __init__(self): passwdDB = InMemoryUsernamePasswordDatabaseDontUse(user="******") sshDB = SSHPublicKeyChecker( InMemorySSHKeyDB({b"user": [keys.Key.fromFile(CLIENT_RSA_PUBLIC)]})) self.portal = portal.Portal(ExampleRealm(), [passwdDB, sshDB])
def getObjshPortal(protocol_class, acl_options): realm = ObjshRealm(protocol_class) portal = cred_portal.Portal(realm) # ssh client's public key sshclient_pubkey_folders = acl_options.get('client_publickeys') if sshclient_pubkey_folders: del acl_options['client_publickeys'] client_keydb = {} loaded_folders = [] for sshclient_pubkey_folder in sshclient_pubkey_folders: if sshclient_pubkey_folder in loaded_folders: continue if not os.path.exists(sshclient_pubkey_folder): continue loaded_folders.append(sshclient_pubkey_folder) for file in os.listdir(sshclient_pubkey_folder): username, ext = os.path.splitext(file) if username.startswith('.') or ext != '.pub': continue try: client_keydb[username].append( ssh_keys.Key.fromFile( os.path.join(sshclient_pubkey_folder, file))) log.msg('load key-based ssh user ' + username) except KeyError: try: client_keydb[username] = [ ssh_keys.Key.fromFile( os.path.join(sshclient_pubkey_folder, file)) ] log.msg('load key-based ssh user ' + username) except ssh_keys.BadKeyError: log.msg('Warning! failed to load sshkey of ' + username) sshDB = SSHPublicKeyChecker(InMemorySSHKeyDB(client_keydb)) # this should register to portal to make it work portal.registerChecker(sshDB) # username, password based authentication cascading_checker = CascadingChecker() for acl_name, acl_settings in acl_options.items(): if acl_settings['kind'] == 'LDAP': if LDAPBindingChecker is None: log.msg( 'Warning: package ldaptor is not installed, LDAP authentication ignored' ) continue #basedn = 'dc=example,dc=com' basedn = acl_settings['basedn'] query = '(%s=%%(name)s)' % acl_settings['uid_attrname'] cfg = ldaptor_config.LDAPConfig(basedn, { basedn: (acl_settings['host'], acl_settings.get('port', 389)) }, None, query) checker = LDAPBindingChecker(acl_settings['uid_attrname'], cfg) cascading_checker.registerChecker(checker) elif acl_settings['kind'] == 'PAM': # system accounts cascading_checker.registerChecker( PamPasswordDatabase(acl_settings['usernames'], acl_settings['username_prefix'])) elif acl_settings['kind'] == 'IN_MEMORY_ACCOUNTS': # in memory accounts passwdDB = InMemoryUsernamePasswordDatabaseDontUse() for username, password in acl_settings.get('accounts', {}).items(): username = username.strip() # do not allow empty username password = password.strip() # do not allow empty password if password and username: passwdDB.addUser(username, password) log.msg('Warning! in memory account: %s' % (username)) cascading_checker.registerChecker(passwdDB) else: raise ValueError('Acl kind of %s is unknown' % acl_name) portal.registerChecker(cascading_checker) return portal
def __init__(self, client, accountfile): self.client = client path = abspath_expanduser_unicode(accountfile) with open_account_file(path) as f: self.rootcaps, pubkeys = load_account_file(f) self._pubkeychecker = SSHPublicKeyChecker(InMemorySSHKeyDB(pubkeys))