001/** 002 * Copyright 2010-2014 The Kuali Foundation 003 * 004 * Licensed under the Educational Community License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.opensource.org/licenses/ecl2.php 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package org.kuali.common.util.secure.channel; 017 018import java.io.BufferedOutputStream; 019import java.io.ByteArrayInputStream; 020import java.io.ByteArrayOutputStream; 021import java.io.File; 022import java.io.IOException; 023import java.io.InputStream; 024import java.io.OutputStream; 025import java.util.ArrayList; 026import java.util.List; 027import java.util.Properties; 028 029import org.apache.commons.io.FileUtils; 030import org.apache.commons.io.FilenameUtils; 031import org.apache.commons.io.IOUtils; 032import org.apache.commons.lang3.StringUtils; 033import org.kuali.common.util.Assert; 034import org.kuali.common.util.CollectionUtils; 035import org.kuali.common.util.Encodings; 036import org.kuali.common.util.LocationUtils; 037import org.kuali.common.util.PropertyUtils; 038import org.kuali.common.util.Str; 039import org.kuali.common.util.base.Threads; 040import org.kuali.common.util.property.ImmutableProperties; 041import org.slf4j.Logger; 042import org.slf4j.LoggerFactory; 043 044import com.google.common.base.Optional; 045import com.google.common.collect.ImmutableList; 046import com.jcraft.jsch.Channel; 047import com.jcraft.jsch.ChannelExec; 048import com.jcraft.jsch.ChannelSftp; 049import com.jcraft.jsch.JSch; 050import com.jcraft.jsch.JSchException; 051import com.jcraft.jsch.Session; 052import com.jcraft.jsch.SftpATTRS; 053import com.jcraft.jsch.SftpException; 054 055/** 056 * @deprecated 057 */ 058@Deprecated 059public final class DefaultSecureChannel implements SecureChannel { 060 061 private static final Logger logger = LoggerFactory.getLogger(DefaultSecureChannel.class); 062 063 private static final String SFTP = "sftp"; 064 private static final String EXEC = "exec"; 065 private static final String FORWARDSLASH = "/"; 066 private final File knownHosts; 067 private final File config; 068 private final boolean useConfigFile; 069 private final boolean includeDefaultPrivateKeyLocations; 070 private final boolean strictHostKeyChecking; 071 private final int port; 072 private final int waitForClosedSleepMillis; 073 private final String encoding; 074 private final String username; 075 private final String hostname; 076 private final Optional<Integer> connectTimeout; 077 private final List<File> privateKeys; 078 private final List<String> privateKeyStrings; 079 private final Properties options; 080 081 private Session session; 082 private ChannelSftp sftp; 083 private boolean open = false; 084 085 @Override 086 public synchronized void open() throws IOException { 087 Assert.isFalse(open, "Already open"); 088 logOpen(); 089 try { 090 JSch jsch = getJSch(); 091 this.session = openSession(jsch); 092 this.sftp = openSftpChannel(session, connectTimeout); 093 this.open = true; 094 } catch (JSchException e) { 095 throw new IOException("Unexpected error opening secure channel", e); 096 } 097 } 098 099 @Override 100 public synchronized void close() { 101 if (!open) { 102 return; 103 } 104 logger.info("Closing secure channel [{}]", ChannelUtils.getLocation(username, hostname)); 105 closeQuietly(sftp); 106 closeQuietly(session); 107 this.open = false; 108 } 109 110 @Override 111 public Result executeCommand(String command) { 112 return executeCommand(command, null); 113 } 114 115 @Override 116 public Result executeCommand(String command, String stdin) { 117 Assert.noBlanks(command); 118 ChannelExec exec = null; 119 InputStream stdoutStream = null; 120 ByteArrayOutputStream stderrStream = null; 121 InputStream stdinStream = null; 122 try { 123 // Preserve start time 124 long start = System.currentTimeMillis(); 125 // Open an exec channel 126 exec = (ChannelExec) session.openChannel(EXEC); 127 // Convert the command string to bytes 128 byte[] commandBytes = Str.getBytes(command, encoding); 129 // Store the command on the exec channel 130 exec.setCommand(commandBytes); 131 // Prepare the stdin stream 132 stdinStream = getInputStream(stdin, encoding); 133 // Prepare the stderr stream 134 stderrStream = new ByteArrayOutputStream(); 135 // Get the stdout stream from the ChannelExec object 136 stdoutStream = exec.getInputStream(); 137 // Update the ChannelExec object with the stdin stream 138 exec.setInputStream(stdinStream); 139 // Update the ChannelExec object with the stderr stream 140 exec.setErrStream(stderrStream); 141 // Execute the command. 142 // This consumes anything from stdin and stores output in stdout/stderr 143 connect(exec, Optional.<Integer> absent()); 144 // Convert stdout and stderr to String's 145 String stdout = Str.getString(IOUtils.toByteArray(stdoutStream), encoding); 146 String stderr = Str.getString(stderrStream.toByteArray(), encoding); 147 // Make sure the channel is closed 148 waitForClosed(exec, waitForClosedSleepMillis); 149 // Return the result of executing the command 150 return new Result(command, exec.getExitStatus(), stdin, stdout, stderr, encoding, start, System.currentTimeMillis()); 151 } catch (Exception e) { 152 throw new IllegalStateException(e); 153 } finally { 154 // Cleanup 155 IOUtils.closeQuietly(stdinStream); 156 IOUtils.closeQuietly(stdoutStream); 157 IOUtils.closeQuietly(stderrStream); 158 closeQuietly(exec); 159 } 160 } 161 162 @Override 163 public void executeNoWait(String command) { 164 Assert.notBlank(command); 165 ChannelExec exec = null; 166 try { 167 // Open an exec channel 168 exec = (ChannelExec) session.openChannel(EXEC); 169 // Convert the command string to bytes 170 byte[] commandBytes = Str.getBytes(command, encoding); 171 // Store the command on the exec channel 172 exec.setCommand(commandBytes); 173 // Execute the command. 174 // This consumes anything from stdin and stores output in stdout/stderr 175 connect(exec, Optional.<Integer> absent()); 176 } catch (Exception e) { 177 throw new IllegalStateException(e); 178 } finally { 179 closeQuietly(exec); 180 } 181 } 182 183 protected InputStream getInputStream(String s, String encoding) { 184 if (s == null) { 185 return null; 186 } else { 187 return new ByteArrayInputStream(Str.getBytes(s, encoding)); 188 } 189 } 190 191 protected void waitForClosed(ChannelExec exec, long millis) { 192 while (!exec.isClosed()) { 193 Threads.sleep(millis); 194 } 195 } 196 197 @Override 198 public RemoteFile getWorkingDirectory() { 199 try { 200 String workingDirectory = sftp.pwd(); 201 return getMetaData(workingDirectory); 202 } catch (SftpException e) { 203 throw new IllegalStateException(e); 204 } 205 } 206 207 protected void logOpen() { 208 logger.info("Opening secure channel [{}] encoding={}", ChannelUtils.getLocation(username, hostname), encoding); 209 logger.debug("Private key files - {}", privateKeys.size()); 210 logger.debug("Private key strings - {}", privateKeyStrings.size()); 211 logger.debug("Private key config file - {}", config); 212 logger.debug("Private key config file use - {}", useConfigFile); 213 logger.debug("Include default private key locations - {}", includeDefaultPrivateKeyLocations); 214 logger.debug("Known hosts file - {}", knownHosts); 215 logger.debug("Port - {}", port); 216 logger.debug("Connect timeout - {}", connectTimeout); 217 logger.debug("Strict host key checking - {}", strictHostKeyChecking); 218 logger.debug("Configuring channel with {} custom options", options.size()); 219 PropertyUtils.debug(options); 220 } 221 222 protected ChannelSftp openSftpChannel(Session session, Optional<Integer> timeout) throws JSchException { 223 ChannelSftp sftp = (ChannelSftp) session.openChannel(SFTP); 224 connect(sftp, timeout); 225 return sftp; 226 } 227 228 protected void connect(Channel channel, Optional<Integer> timeout) throws JSchException { 229 if (timeout.isPresent()) { 230 channel.connect(timeout.get()); 231 } else { 232 channel.connect(); 233 } 234 } 235 236 protected void closeQuietly(Session session) { 237 if (session != null) { 238 session.disconnect(); 239 } 240 } 241 242 protected void closeQuietly(Channel channel) { 243 if (channel != null) { 244 channel.disconnect(); 245 } 246 } 247 248 private static Properties getSessionProperties(Properties options, boolean strictHostKeyChecking) { 249 Properties properties = new Properties(); 250 properties.putAll(options); 251 if (!strictHostKeyChecking) { 252 properties.setProperty(SSHUtils.STRICT_HOST_KEY_CHECKING, SSHUtils.NO); 253 } 254 return properties; 255 } 256 257 protected Session openSession(JSch jsch) throws JSchException { 258 Session session = jsch.getSession(username, hostname, port); 259 session.setConfig(options); 260 if (connectTimeout.isPresent()) { 261 session.connect(connectTimeout.get()); 262 } else { 263 session.connect(); 264 } 265 return session; 266 } 267 268 protected JSch getJSch() throws JSchException { 269 JSch jsch = getJSch(privateKeys, privateKeyStrings); 270 if (strictHostKeyChecking && knownHosts.exists()) { 271 String path = LocationUtils.getCanonicalPath(knownHosts); 272 jsch.setKnownHosts(path); 273 } 274 return jsch; 275 } 276 277 protected JSch getJSch(List<File> privateKeys, List<String> privateKeyStrings) throws JSchException { 278 JSch jsch = new JSch(); 279 for (File privateKey : privateKeys) { 280 String path = LocationUtils.getCanonicalPath(privateKey); 281 jsch.addIdentity(path); 282 } 283 int count = 0; 284 for (String privateKeyString : privateKeyStrings) { 285 String name = "privateKeyString-" + Integer.toString(count++); 286 byte[] bytes = Str.getBytes(privateKeyString, encoding); 287 jsch.addIdentity(name, bytes, null, null); 288 } 289 return jsch; 290 } 291 292 protected static List<File> getUniquePrivateKeyFiles(List<File> privateKeys, boolean useConfigFile, File config, boolean includeDefaultPrivateKeyLocations) { 293 List<String> paths = new ArrayList<String>(); 294 for (File privateKey : privateKeys) { 295 paths.add(LocationUtils.getCanonicalPath(privateKey)); 296 } 297 if (useConfigFile) { 298 for (String path : SSHUtils.getFilenames(config)) { 299 paths.add(path); 300 } 301 } 302 if (includeDefaultPrivateKeyLocations) { 303 for (String path : SSHUtils.PRIVATE_KEY_DEFAULTS) { 304 paths.add(path); 305 } 306 } 307 List<String> uniquePaths = CollectionUtils.getUniqueStrings(paths); 308 return SSHUtils.getExistingAndReadable(uniquePaths); 309 } 310 311 @Override 312 public RemoteFile getMetaData(String absolutePath) { 313 Assert.noBlanks(absolutePath); 314 return fillInAttributes(absolutePath); 315 } 316 317 @Override 318 public void deleteFile(String absolutePath) { 319 RemoteFile file = getMetaData(absolutePath); 320 if (isStatus(file, Status.MISSING)) { 321 return; 322 } 323 if (file.isDirectory()) { 324 throw new IllegalArgumentException("[" + ChannelUtils.getLocation(username, hostname, file) + "] is a directory."); 325 } 326 try { 327 sftp.rm(absolutePath); 328 } catch (SftpException e) { 329 throw new IllegalStateException(e); 330 } 331 } 332 333 @Override 334 public boolean exists(String absolutePath) { 335 RemoteFile file = getMetaData(absolutePath); 336 return isStatus(file, Status.EXISTS); 337 } 338 339 @Override 340 public boolean isDirectory(String absolutePath) { 341 RemoteFile file = getMetaData(absolutePath); 342 return isStatus(file, Status.EXISTS) && file.isDirectory(); 343 } 344 345 protected RemoteFile fillInAttributes(String path) { 346 try { 347 SftpATTRS attributes = sftp.stat(path); 348 return fillInAttributes(path, attributes); 349 } catch (SftpException e) { 350 return handleNoSuchFileException(path, e); 351 } 352 } 353 354 protected RemoteFile fillInAttributes(String path, SftpATTRS attributes) { 355 boolean directory = attributes.isDir(); 356 int permissions = attributes.getPermissions(); 357 int userId = attributes.getUId(); 358 int groupId = attributes.getGId(); 359 long size = attributes.getSize(); 360 Status status = Status.EXISTS; 361 return new RemoteFile.Builder(path).directory(directory).permissions(permissions).userId(userId).groupId(groupId).size(size).status(status).build(); 362 } 363 364 @Override 365 public void copyFile(File source, RemoteFile destination) { 366 Assert.notNull(source); 367 Assert.isTrue(source.exists()); 368 Assert.isTrue(!source.isDirectory()); 369 Assert.isTrue(source.canRead()); 370 copyLocationToFile(LocationUtils.getCanonicalURLString(source), destination); 371 } 372 373 @Override 374 public void copyFileToDirectory(File source, RemoteFile directory) { 375 String filename = source.getName(); 376 String absolutePath = getAbsolutePath(directory.getAbsolutePath(), filename); 377 RemoteFile file = new RemoteFile.Builder(absolutePath).clone(directory).build(); 378 copyFile(source, file); 379 } 380 381 @Override 382 public void copyLocationToFile(String location, RemoteFile destination) { 383 Assert.notNull(location); 384 Assert.isTrue(LocationUtils.exists(location), location + " does not exist"); 385 InputStream in = null; 386 try { 387 in = LocationUtils.getInputStream(location); 388 copyInputStreamToFile(in, destination); 389 } catch (Exception e) { 390 throw new IllegalStateException(e); 391 } finally { 392 IOUtils.closeQuietly(in); 393 } 394 } 395 396 @Override 397 public void copyStringToFile(String string, RemoteFile destination) { 398 Assert.notNull(string); 399 Assert.notBlank(encoding); 400 InputStream in = new ByteArrayInputStream(Str.getBytes(string, encoding)); 401 copyInputStreamToFile(in, destination); 402 IOUtils.closeQuietly(in); 403 } 404 405 @Override 406 public String toString(RemoteFile source) { 407 Assert.notNull(source); 408 Assert.hasText(source.getAbsolutePath()); 409 Assert.notBlank(encoding); 410 ByteArrayOutputStream out = new ByteArrayOutputStream(); 411 try { 412 copyFile(source, out); 413 return out.toString(encoding); 414 } catch (IOException e) { 415 throw new IllegalStateException("Unexpected IO error", e); 416 } finally { 417 IOUtils.closeQuietly(out); 418 } 419 } 420 421 @Override 422 public void copyInputStreamToFile(InputStream source, RemoteFile destination) { 423 Assert.notNull(source); 424 try { 425 createDirectories(destination); 426 sftp.put(source, destination.getAbsolutePath()); 427 } catch (SftpException e) { 428 throw new IllegalStateException(e); 429 } 430 } 431 432 protected String getAbsolutePath(String absolutePath, String filename) { 433 if (StringUtils.endsWith(absolutePath, FORWARDSLASH)) { 434 return absolutePath + filename; 435 } else { 436 return absolutePath + FORWARDSLASH + filename; 437 } 438 } 439 440 @Override 441 public void copyLocationToDirectory(String location, RemoteFile directory) { 442 String filename = LocationUtils.getFilename(location); 443 String absolutePath = getAbsolutePath(directory.getAbsolutePath(), filename); 444 RemoteFile file = new RemoteFile.Builder(absolutePath).clone(directory).build(); 445 copyLocationToFile(location, file); 446 } 447 448 @Override 449 public void copyFile(RemoteFile source, File destination) { 450 OutputStream out = null; 451 try { 452 out = new BufferedOutputStream(FileUtils.openOutputStream(destination)); 453 copyFile(source, out); 454 } catch (Exception e) { 455 throw new IllegalStateException(e); 456 } finally { 457 IOUtils.closeQuietly(out); 458 } 459 } 460 461 @Override 462 public void copyRemoteFile(String absolutePath, OutputStream out) throws IOException { 463 try { 464 sftp.get(absolutePath, out); 465 } catch (SftpException e) { 466 throw new IOException("Unexpected IO error", e); 467 } 468 } 469 470 @Override 471 public void copyFile(RemoteFile source, OutputStream out) throws IOException { 472 copyRemoteFile(source.getAbsolutePath(), out); 473 } 474 475 @Override 476 public void copyFileToDirectory(RemoteFile source, File destination) { 477 String filename = FilenameUtils.getName(source.getAbsolutePath()); 478 File newDestination = new File(destination, filename); 479 copyFile(source, newDestination); 480 } 481 482 @Override 483 public void createDirectory(RemoteFile dir) { 484 Assert.isTrue(dir.isDirectory()); 485 try { 486 createDirectories(dir); 487 } catch (SftpException e) { 488 throw new IllegalStateException(e); 489 } 490 } 491 492 protected void createDirectories(RemoteFile file) throws SftpException { 493 boolean directoryIndicator = file.isDirectory(); 494 RemoteFile remoteFile = fillInAttributes(file.getAbsolutePath()); 495 validate(remoteFile, directoryIndicator); 496 List<String> directories = LocationUtils.getNormalizedPathFragments(file.getAbsolutePath(), file.isDirectory()); 497 for (String directory : directories) { 498 RemoteFile parentDir = fillInAttributes(directory); 499 validate(parentDir, true); 500 if (!isStatus(parentDir, Status.EXISTS)) { 501 mkdir(parentDir); 502 } 503 } 504 } 505 506 protected boolean isStatus(RemoteFile file, Status status) { 507 Optional<Status> remoteStatus = file.getStatus(); 508 if (remoteStatus.isPresent()) { 509 return remoteStatus.get().equals(status); 510 } else { 511 return false; 512 } 513 } 514 515 protected void validate(RemoteFile file, boolean directoryIndicator) { 516 // Make sure status has been filled in 517 Assert.isTrue(file.getStatus().isPresent()); 518 519 // Convenience flags 520 boolean missing = isStatus(file, Status.MISSING); 521 boolean exists = isStatus(file, Status.EXISTS); 522 523 // It it is supposed to be a directory, make sure it's a directory 524 // If it is supposed to be a regular file, make sure it's a regular file 525 boolean correctFileType = file.isDirectory() == directoryIndicator; 526 527 // Is everything as it should be? 528 boolean valid = missing || exists && correctFileType; 529 530 Assert.isTrue(valid, getInvalidExistingFileMessage(file)); 531 } 532 533 protected String getInvalidExistingFileMessage(RemoteFile existing) { 534 if (existing.isDirectory()) { 535 return "[" + ChannelUtils.getLocation(username, hostname, existing) + "] is an existing directory. Unable to create file."; 536 } else { 537 return "[" + ChannelUtils.getLocation(username, hostname, existing) + "] is an existing file. Unable to create directory."; 538 } 539 } 540 541 protected void mkdir(RemoteFile dir) { 542 try { 543 String path = dir.getAbsolutePath(); 544 logger.debug("Creating [{}]", path); 545 sftp.mkdir(path); 546 setAttributes(dir); 547 } catch (SftpException e) { 548 throw new IllegalStateException(e); 549 } 550 } 551 552 protected void setAttributes(RemoteFile file) throws SftpException { 553 String path = file.getAbsolutePath(); 554 if (file.getPermissions().isPresent()) { 555 sftp.chmod(file.getPermissions().get(), path); 556 } 557 if (file.getGroupId().isPresent()) { 558 sftp.chgrp(file.getGroupId().get(), path); 559 } 560 if (file.getUserId().isPresent()) { 561 sftp.chown(file.getUserId().get(), path); 562 } 563 } 564 565 protected RemoteFile handleNoSuchFileException(String path, SftpException e) { 566 if (isNoSuchFileException(e)) { 567 return new RemoteFile.Builder(path).status(Status.MISSING).build(); 568 } else { 569 throw new IllegalStateException(e); 570 } 571 } 572 573 protected boolean isNoSuchFileException(SftpException exception) { 574 return exception.id == ChannelSftp.SSH_FX_NO_SUCH_FILE; 575 } 576 577 public static class Builder { 578 579 // Required 580 private final String username; 581 private final String hostname; 582 583 // Optional 584 private File knownHosts = SSHUtils.DEFAULT_KNOWN_HOSTS; 585 private File config = SSHUtils.DEFAULT_CONFIG_FILE; 586 private boolean useConfigFile = true; 587 private boolean includeDefaultPrivateKeyLocations = true; 588 private boolean strictHostKeyChecking = true; 589 private int port = SSHUtils.DEFAULT_PORT; 590 private int waitForClosedSleepMillis = 10; 591 private String encoding = Encodings.UTF8; 592 private Optional<Integer> connectTimeout = Optional.absent(); 593 private Properties options = ImmutableProperties.of(); 594 private List<File> privateKeys = ImmutableList.of(); 595 private List<String> privateKeyStrings = ImmutableList.of(); 596 597 public DefaultSecureChannel build() { 598 Assert.noBlanks(username, hostname, encoding); 599 Assert.noNulls(knownHosts, config, connectTimeout, options, privateKeys, privateKeyStrings); 600 Assert.isTrue(SSHUtils.isValidPort(port), port + " is invalid"); 601 Assert.isTrue(waitForClosedSleepMillis > 0, "waitForClosedSleepMillis must be a positive integer"); 602 if (connectTimeout.isPresent()) { 603 Assert.isTrue(connectTimeout.get() > 0, "connectTimeout must be a positive integer"); 604 } 605 if (useConfigFile) { 606 Assert.exists(config); 607 Assert.isTrue(config.canRead(), "[" + config + "] exists but is not readable"); 608 } 609 this.options = ImmutableProperties.of(getSessionProperties(options, strictHostKeyChecking)); 610 this.privateKeys = ImmutableList.copyOf(getUniquePrivateKeyFiles(privateKeys, useConfigFile, config, includeDefaultPrivateKeyLocations)); 611 this.privateKeyStrings = ImmutableList.copyOf(privateKeyStrings); 612 return new DefaultSecureChannel(this); 613 } 614 615 public Builder(String username, String hostname) { 616 this.username = username; 617 this.hostname = hostname; 618 } 619 620 public Builder knownHosts(File knownHosts) { 621 this.knownHosts = knownHosts; 622 return this; 623 } 624 625 public Builder config(File config) { 626 this.config = config; 627 return this; 628 } 629 630 public Builder useConfigFile(boolean useConfigFile) { 631 this.useConfigFile = useConfigFile; 632 return this; 633 } 634 635 public Builder includeDefaultPrivateKeyLocations(boolean includeDefaultPrivateKeyLocations) { 636 this.includeDefaultPrivateKeyLocations = includeDefaultPrivateKeyLocations; 637 return this; 638 } 639 640 public Builder strictHostKeyChecking(boolean strictHostKeyChecking) { 641 this.strictHostKeyChecking = strictHostKeyChecking; 642 return this; 643 } 644 645 public Builder port(int port) { 646 this.port = port; 647 return this; 648 } 649 650 public Builder waitForClosedSleepMillis(int waitForClosedSleepMillis) { 651 this.waitForClosedSleepMillis = waitForClosedSleepMillis; 652 return this; 653 } 654 655 public Builder encoding(String encoding) { 656 this.encoding = encoding; 657 return this; 658 } 659 660 public Builder connectTimeout(int connectTimeout) { 661 this.connectTimeout = Optional.of(connectTimeout); 662 return this; 663 } 664 665 public Builder options(Properties options) { 666 this.options = options; 667 return this; 668 } 669 670 public Builder privateKeys(List<File> privateKeys) { 671 this.privateKeys = privateKeys; 672 return this; 673 } 674 675 public Builder privateKeyStrings(List<String> privateKeyStrings) { 676 this.privateKeyStrings = privateKeyStrings; 677 return this; 678 } 679 680 } 681 682 private DefaultSecureChannel(Builder builder) { 683 this.username = builder.username; 684 this.hostname = builder.hostname; 685 this.knownHosts = builder.knownHosts; 686 this.config = builder.config; 687 this.useConfigFile = builder.useConfigFile; 688 this.includeDefaultPrivateKeyLocations = builder.includeDefaultPrivateKeyLocations; 689 this.strictHostKeyChecking = builder.strictHostKeyChecking; 690 this.port = builder.port; 691 this.waitForClosedSleepMillis = builder.waitForClosedSleepMillis; 692 this.encoding = builder.encoding; 693 this.connectTimeout = builder.connectTimeout; 694 this.options = builder.options; 695 this.privateKeys = builder.privateKeys; 696 this.privateKeyStrings = builder.privateKeyStrings; 697 } 698 699 public Session getSession() { 700 return session; 701 } 702 703 public void setSession(Session session) { 704 this.session = session; 705 } 706 707 public ChannelSftp getSftp() { 708 return sftp; 709 } 710 711 public void setSftp(ChannelSftp sftp) { 712 this.sftp = sftp; 713 } 714 715 public File getKnownHosts() { 716 return knownHosts; 717 } 718 719 public File getConfig() { 720 return config; 721 } 722 723 public boolean isUseConfigFile() { 724 return useConfigFile; 725 } 726 727 public boolean isIncludeDefaultPrivateKeyLocations() { 728 return includeDefaultPrivateKeyLocations; 729 } 730 731 public boolean isStrictHostKeyChecking() { 732 return strictHostKeyChecking; 733 } 734 735 @Override 736 public int getPort() { 737 return port; 738 } 739 740 public int getWaitForClosedSleepMillis() { 741 return waitForClosedSleepMillis; 742 } 743 744 public String getEncoding() { 745 return encoding; 746 } 747 748 @Override 749 public String getUsername() { 750 return username; 751 } 752 753 @Override 754 public String getHostname() { 755 return hostname; 756 } 757 758 public Optional<Integer> getConnectTimeout() { 759 return connectTimeout; 760 } 761 762 public List<File> getPrivateKeys() { 763 return privateKeys; 764 } 765 766 public List<String> getPrivateKeyStrings() { 767 return privateKeyStrings; 768 } 769 770 public Properties getOptions() { 771 return options; 772 } 773 774}