Надежный пример того, как использовать SFTP с использованием аутентификации с открытым закрытым ключом с Java

Недавно наш клиент неожиданно переместил некоторые важные файлы, которые мы собираем, с ftp на sftp-сервер. Первоначально у меня сложилось впечатление, что было бы просто написать или найти утилиту Java, которая может обрабатывать sftp, но это определенно не так. Что также усугубило эту проблему, так это то, что мы пытаемся подключиться к sftp-серверу с платформы Windows (поэтому определение того, где SSH_HOME находится на клиенте, становится очень запутанным).

Я использовал библиотеку apache-commons-vfs, и мне удалось получить решение, которое надежно работает для аутентификации по имени пользователя/паролю, но пока ничего, что могло бы надежно обрабатывать аутентификацию с закрытым/открытым ключом.

Следующий пример работает для аутентификации по имени пользователя/паролю, но я хочу настроить его для аутентификации с закрытым/открытым ключом.

public static void sftpGetFile(String server, String userName,String password, 
        String remoteDir, String localDir, String fileNameRegex)
    {

       File localDirFile  = new File(localDir);
       FileSystemManager fsManager = null;

       if (!localDirFile.exists()) {
           localDirFile.mkdirs();
       }

       try {
           fsManager = VFS.getManager();
       } catch (FileSystemException ex) {
           LOGGER.error("Failed to get fsManager from VFS",ex);
           throw new RuntimeException("Failed to get fsManager from VFS", ex);
       }

       UserAuthenticator auth = new StaticUserAuthenticator(null, userName,password);

       FileSystemOptions opts = new FileSystemOptions();

       try {
           DefaultFileSystemConfigBuilder.getInstance().setUserAuthenticator(opts,
                   auth);
       } catch (FileSystemException ex) {
           LOGGER.error("setUserAuthenticator failed", ex);
           throw new RuntimeException("setUserAuthenticator failed", ex);
       }
       Pattern filePattern = Pattern.compile(fileNameRegex);
       String startPath = "sftp://" + server + remoteDir;
       FileObject[] children;

       // Set starting path on remote SFTP server.
       FileObject sftpFile;
       try {
           sftpFile = fsManager.resolveFile(startPath, opts);

           LOGGER.info("SFTP connection successfully established to " +
                   startPath);
       } catch (FileSystemException ex) {
           LOGGER.error("SFTP error parsing path " +
                   remoteDir,
                   ex);

           throw new RuntimeException("SFTP error parsing path " +
                   remoteDir,
                   ex);
       }

       // Get a directory listing
       try {
           children = sftpFile.getChildren();
       } catch (FileSystemException ex) {
           throw new RuntimeException("Error collecting directory listing of " +
                   startPath, ex);
       }

       search:
       for (FileObject f : children) {
           try {
               String relativePath =
                       File.separatorChar + f.getName().getBaseName();

               if (f.getType() == FileType.FILE) {
                   System.out.println("Examining remote file " + f.getName());

                   if (!filePattern.matcher(f.getName().getPath()).matches()) {
                       LOGGER.info("  Filename does not match, skipping file ." +
                               relativePath);
                       continue search;
                   }

                   String localUrl = "file://" + localDir + relativePath;
                   String standardPath = localDir + relativePath;
                   System.out.println("  Standard local path is " + standardPath);
                   LocalFile localFile =
                           (LocalFile) fsManager.resolveFile(localUrl);
                   System.out.println("    Resolved local file name: " +
                           localFile.getName());

                   if (!localFile.getParent().exists()) {
                       localFile.getParent().createFolder();
                   }

                   System.out.println("  ### Retrieving file ###");
                   localFile.copyFrom(f,
                           new AllFileSelector());
               } else {
                   System.out.println("Ignoring non-file " + f.getName());
               }
           } catch (FileSystemException ex) {
               throw new RuntimeException("Error getting file type for " +
                       f.getName(), ex);
           }

       }

       FileSystem fs = null;
       if (children.length > 0) {
           fs = children[0].getFileSystem(); // This works even if the src is closed.
           fsManager.closeFileSystem(fs);
       }
    }

Мой закрытый ключ хранится в известном месте, а мой открытый ключ был передан на сервер (мы проверили, что эти ключи успешно работают при подключении с помощью других инструментов)

Я поэкспериментировал с добавлением следующая строка

SftpFileSystemConfigBuilder.getInstance().setIdentities(this.opts, new File[]{new File("c:/Users/bobtbuilder/.ssh/id_dsa.ppk")});

Это успешно загружает закрытый ключ во всю структуру, но никогда не использует этот ключ для дальнейшей аутентификации.

Любая помощь или направление, которые были приняты самым теплым образом

16
задан Robert 26 June 2012 в 11:24
поделиться