Compare commits

..

1 Commits

Author SHA1 Message Date
hierynomus
a95fad89a0 Fixed NPE in decrypt by passing in empty char[] 2015-01-20 09:34:12 +01:00
51 changed files with 564 additions and 2071 deletions

1
.gitattributes vendored
View File

@@ -1 +0,0 @@
*.bat text eol=crlf

View File

@@ -1,2 +1 @@
language: java
sudo: false
language: java

View File

@@ -1,52 +1,9 @@
= sshj - SSHv2 library for Java
Jeroen van Erp
:sshj_groupid: com.hierynomus
:sshj_version: 0.13.0
:source-highlighter: pygments
image::https://travis-ci.org/hierynomus/sshj.svg?branch=master[]
To get started, have a look at one of the examples. Hopefully you will find the API pleasant to work with :)
== Getting SSHJ
To get SSHJ, you have two options:
. Add a dependency to SSHJ to your project.
. Build SSHJ yourself.
And, if you want, you can also run the SSHJ examples.
Binary releases of SSHJ are not provided here, but you can download it http://search.maven.org/#artifactdetails%7C{sshj_groupid}%7Csshj%7C{sshj_version}%7Cjar[straight from the Maven Central repository] if you want to.
== Depending on SSHJ
If you're building your project using Maven, you can add the following dependency to the `pom.xml`:
[source,xml,subs="verbatim,attributes"]
----
<dependency>
<groupId>{sshj_groupid}</groupId>
<artifactId>sshj</artifactId>
<version>{sshj_version}</version>
</dependency>
----
If your project is built using another build tool that uses the Maven Central repository, translate this dependency into the format used by your build tool.
== Building SSHJ
. Clone the Overthere repository.
. Ensure you have Java6 installed with the http://www.oracle.com/technetwork/java/javase/downloads/jce-6-download-429243.html[Unlimited strength Java Cryptography Extensions (JCE)].
. Run the command `./gradlew clean build`.
== Running the examples
In the `examples` directory, there is a separate Maven project that shows how the library can be used in some sample cases. If you want to run them, follow these guidelines:
. Install http://maven.apache.org/[Maven 2.2.1] or up.
. Clone the Overthere repository.
. Go into the `examples` directory and run the command `mvn eclipse:eclipse`.
. Import the `examples` project into Eclipse.
. Change the login details in the example classes (address, username and password) and run them!
== Features of the library include:
* reading known_hosts files for host key verification
@@ -56,6 +13,7 @@ In the `examples` directory, there is a separate Maven project that shows how th
* scp + complete sftp version 0-3 implementation
== Supported algorithms
Implementations / adapters for the following algorithms are included:
ciphers::
@@ -80,37 +38,17 @@ If you need something that is not included, it shouldn't be too hard to add (do
== Dependencies
Java 6+. http://www.slf4j.org/download.html[slf4j] is required. http://www.bouncycastle.org/java.html[bouncycastle] is highly recommended and required for using some of the crypto algorithms. http://www.jcraft.com/jzlib/[jzlib] is required for using zlib compression.
== Reporting bugs
Issue tracker: https://github.com/hierynomus/sshj/issues
Issue tracker https://github.com/hierynomus/sshj/issues
== Discussion
Google Group: http://groups.google.com/group/sshj-users
Google Group http://groups.google.com/group/sshj-users
== Contributing
Fork away!
== Release history
SSHJ 0.13.0 (2015-08-18)::
* Merged https://github.com/hierynomus/sshj/issues/199[#199]: Fix for IndexOutOfBoundsException in ReadAheadRemoteFileInputStream, fixes https://github.com/hierynomus/sshj/issues/183[#183]
* Merged https://github.com/hierynomus/sshj/issues/195[#195]: New authentication supported: `gssapi-with-mic`
* Merged https://github.com/hierynomus/sshj/issues/201[#201]: New option to verify negotiated key exchange algorithms
* Merged https://github.com/hierynomus/sshj/issues/196[#196]: Fix for looking up complete hostname in known hosts file
SSHJ 0.12.0 (2015-04-14)::
* Added support for HTTP proxies when running JDK6 or JDK7, fixes: https://github.com/hierynomus/sshj/issues/170[#170]
* Merged https://github.com/hierynomus/sshj/issues/186[#186]: Fix for detecting end-of-stream
* Compiling to JDK6, fixes https://github.com/hierynomus/sshj/issues/179[#179] and https://github.com/hierynomus/sshj/issues/185[#185]
* Correctly close socket and channel when LocalPortForwarder fails to open and start the channel (Fixes https://github.com/hierynomus/sshj/issues/175[#175] and https://github.com/hierynomus/sshj/issues/176[#176])
* Merged https://github.com/hierynomus/sshj/issues/181[#181]: Invalid write packet length when reading with offset (Fixes https://github.com/hierynomus/sshj/issues/180[#180])
SSHJ 0.11.0 (2015-01-23)::
* New maven coordinates `com.hierynomus:sshj:0.11.0` as https://github.com/hierynomus[@hierynomus] took over as maintainer of SSHJ
* Migrated build system to Gradle 2.2.1
* Merged https://github.com/hierynomus/sshj/issues/150[#150]: Fix for incorrect file handle on some SSH servers, fixes: https://github.com/hierynomus/sshj/issues/54[#54], https://github.com/hierynomus/sshj/issues/119[#119], https://github.com/hierynomus/sshj/issues/168[#168], https://github.com/hierynomus/sshj/issues/169[#169]
* Made `jzlib` optional in OSGi bundling, fixes: https://github.com/hierynomus/sshj/issues/162[#162]
* Improved some log levels, fixes: https://github.com/hierynomus/sshj/issues/161[#161]
* Merged https://github.com/hierynomus/sshj/issues/156[#156], https://github.com/hierynomus/sshj/issues/164[#164], https://github.com/hierynomus/sshj/issues/165[#165]: Fixed block sizes for `hmac-sha2-256` and `hmac-sha2-512`
* Merged https://github.com/hierynomus/sshj/issues/141[#141]: Add proxy support
* Merged https://github.com/hierynomus/sshj/issues/157[#157], https://github.com/hierynomus/sshj/issues/163[#163]: Doc and build fixes
* Upgraded BouncyCastle to 1.51, fixes: https://github.com/hierynomus/sshj/issues/142[#142]
* Implemented keep-alive with connection drop detection, fixes https://github.com/hierynomus/sshj/issues/166[#166]
Fork away!

View File

@@ -3,17 +3,14 @@ apply plugin: "maven"
apply plugin: "signing"
apply plugin: "osgi"
group = "com.hierynomus"
version = "0.13.0"
group = "nl.javadude"
version = "0.11.0-SNAPSHOT"
repositories {
mavenCentral()
mavenLocal()
}
sourceCompatibility = 1.6
targetCompatibility = 1.6
configurations {
compile {
transitive = false
@@ -22,21 +19,12 @@ configurations {
test {
include "**/*Test.*"
if (!project.hasProperty("allTests")) {
useJUnit {
excludeCategories 'com.hierynomus.sshj.test.SlowTests'
excludeCategories 'com.hierynomus.sshj.test.KnownFailingTests'
}
}
afterSuite { descriptor, result ->
if (descriptor.className != null) {
def indicator = "\u001B[32m✓\u001b[0m"
if (result.failedTestCount > 0) {
indicator = "\u001B[31m✘\u001b[0m"
}
logger.lifecycle("$indicator Test ${descriptor.name}; Executed: ${result.testCount}/\u001B[32m${result.successfulTestCount}\u001B[0m/\u001B[31m${result.failedTestCount}\u001B[0m")
def indicator = "\u001B[32m✓\u001b[0m"
if (result.failedTestCount > 0) {
indicator = "\u001B[31m✘\u001b[0m"
}
logger.lifecycle("$indicator Test ${descriptor.name}; Executed: ${result.testCount}/\u001B[32m${result.successfulTestCount}\u001B[0m/\u001B[31m${result.failedTestCount}\u001B[0m")
}
}
@@ -165,4 +153,4 @@ uploadArchives {
}
}
}
}
}

View File

@@ -21,10 +21,10 @@
<modelVersion>4.0.0</modelVersion>
<groupId>com.hierynomus</groupId>
<artifactId>sshj-examples</artifactId>
<groupId>net.schmizz</groupId>
<artifactId>sshj</artifactId>
<packaging>jar</packaging>
<version>0.13.0</version>
<version>0.10.0</version>
<name>sshj-examples</name>
<description>Examples for SSHv2 library for Java</description>
@@ -53,9 +53,9 @@
<dependencies>
<dependency>
<groupId>com.hierynomus</groupId>
<groupId>net.schmizz</groupId>
<artifactId>sshj</artifactId>
<version>0.13.0</version>
<version>0.10.0</version>
</dependency>
</dependencies>

View File

@@ -1,55 +0,0 @@
/**
* Copyright 2009 sshj contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.schmizz.sshj.examples;
import net.schmizz.keepalive.KeepAliveProvider;
import net.schmizz.sshj.DefaultConfig;
import net.schmizz.sshj.SSHClient;
import net.schmizz.sshj.common.IOUtils;
import net.schmizz.sshj.connection.channel.direct.Session;
import net.schmizz.sshj.connection.channel.direct.Session.Command;
import net.schmizz.sshj.transport.verification.PromiscuousVerifier;
import java.io.IOException;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
/** This examples demonstrates how to setup keep-alive to detect connection dropping. */
public class KeepAlive {
public static void main(String... args)
throws IOException, InterruptedException {
DefaultConfig defaultConfig = new DefaultConfig();
defaultConfig.setKeepAliveProvider(KeepAliveProvider.KEEP_ALIVE);
final SSHClient ssh = new SSHClient(defaultConfig);
try {
ssh.addHostKeyVerifier(new PromiscuousVerifier());
ssh.connect(args[0]);
ssh.getConnection().getKeepAlive().setKeepAliveInterval(5); //every 60sec
ssh.authPassword(args[1], args[2]);
Session session = ssh.startSession();
session.allocateDefaultPTY();
new CountDownLatch(1).await();
try {
session.allocateDefaultPTY();
} finally {
session.close();
}
} finally {
ssh.disconnect();
}
}
}

Binary file not shown.

View File

@@ -1,6 +0,0 @@
#Wed Jan 21 09:17:25 CET 2015
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-2.3-bin.zip

164
gradlew vendored
View File

@@ -1,164 +0,0 @@
#!/usr/bin/env bash
##############################################################################
##
## Gradle start up script for UN*X
##
##############################################################################
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS=""
APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"
warn ( ) {
echo "$*"
}
die ( ) {
echo
echo "$*"
echo
exit 1
}
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
case "`uname`" in
CYGWIN* )
cygwin=true
;;
Darwin* )
darwin=true
;;
MINGW* )
msys=true
;;
esac
# For Cygwin, ensure paths are in UNIX format before anything is touched.
if $cygwin ; then
[ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
fi
# Attempt to set APP_HOME
# Resolve links: $0 may be a link
PRG="$0"
# Need this for relative symlinks.
while [ -h "$PRG" ] ; do
ls=`ls -ld "$PRG"`
link=`expr "$ls" : '.*-> \(.*\)$'`
if expr "$link" : '/.*' > /dev/null; then
PRG="$link"
else
PRG=`dirname "$PRG"`"/$link"
fi
done
SAVED="`pwd`"
cd "`dirname \"$PRG\"`/" >&-
APP_HOME="`pwd -P`"
cd "$SAVED" >&-
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD="$JAVA_HOME/jre/sh/java"
else
JAVACMD="$JAVA_HOME/bin/java"
fi
if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
else
JAVACMD="java"
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
# Increase the maximum file descriptors if we can.
if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
MAX_FD_LIMIT=`ulimit -H -n`
if [ $? -eq 0 ] ; then
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
MAX_FD="$MAX_FD_LIMIT"
fi
ulimit -n $MAX_FD
if [ $? -ne 0 ] ; then
warn "Could not set maximum file descriptor limit: $MAX_FD"
fi
else
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
fi
fi
# For Darwin, add options to specify how the application appears in the dock
if $darwin; then
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
fi
# For Cygwin, switch paths to Windows format before running java
if $cygwin ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
# We build the pattern for arguments to be converted via cygpath
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
SEP=""
for dir in $ROOTDIRSRAW ; do
ROOTDIRS="$ROOTDIRS$SEP$dir"
SEP="|"
done
OURCYGPATTERN="(^($ROOTDIRS))"
# Add a user-defined pattern to the cygpath arguments
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
fi
# Now convert the arguments - kludge to limit ourselves to /bin/sh
i=0
for arg in "$@" ; do
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
else
eval `echo args$i`="\"$arg\""
fi
i=$((i+1))
done
case $i in
(0) set -- ;;
(1) set -- "$args0" ;;
(2) set -- "$args0" "$args1" ;;
(3) set -- "$args0" "$args1" "$args2" ;;
(4) set -- "$args0" "$args1" "$args2" "$args3" ;;
(5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
(6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
(7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
(8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
(9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
esac
fi
# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
function splitJvmOpts() {
JVM_OPTS=("$@")
}
eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"

90
gradlew.bat vendored
View File

@@ -1,90 +0,0 @@
@if "%DEBUG%" == "" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@rem
@rem ##########################################################################
@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS=
set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto init
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto init
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:init
@rem Get command-line arguments, handling Windowz variants
if not "%OS%" == "Windows_NT" goto win9xME_args
if "%@eval[2+2]" == "4" goto 4NT_args
:win9xME_args
@rem Slurp the command line arguments.
set CMD_LINE_ARGS=
set _SKIP=2
:win9xME_args_slurp
if "x%~1" == "x" goto execute
set CMD_LINE_ARGS=%*
goto execute
:4NT_args
@rem Get arguments from the 4NT Shell from JP Software
set CMD_LINE_ARGS=%$
:execute
@rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
:end
@rem End local scope for the variables with windows NT shell
if "%ERRORLEVEL%"=="0" goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
exit /b 1
:mainEnd
if "%OS%"=="Windows_NT" endlocal
:omega

344
pom.xml Normal file
View File

@@ -0,0 +1,344 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Copyright 2009 sshj contributors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>net.schmizz</groupId>
<artifactId>sshj</artifactId>
<packaging>bundle</packaging>
<version>0.10.1-SNAPSHOT</version>
<name>sshj</name>
<description>SSHv2 library for Java</description>
<url>http://github.com/hierynomus/sshj</url>
<inceptionYear>2009</inceptionYear>
<issueManagement>
<system>github</system>
<url>http://github.com/hierynomus/sshj/issues</url>
</issueManagement>
<scm>
<connection>scm:git:git://github.com/hierynomus/sshj.git</connection>
<developerConnection>scm:git:git@github.com:hierynomus/sshj.git</developerConnection>
<url>http://github.com/hierynomus/sshj</url>
</scm>
<licenses>
<license>
<name>Apache 2</name>
<url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>
<distribution>repo</distribution>
</license>
</licenses>
<parent>
<groupId>org.sonatype.oss</groupId>
<artifactId>oss-parent</artifactId>
<version>7</version>
</parent>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk15on</artifactId>
<version>1.51</version>
</dependency>
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcpkix-jdk15on</artifactId>
<version>1.51</version>
</dependency>
<dependency>
<groupId>com.jcraft</groupId>
<artifactId>jzlib</artifactId>
<version>1.1.3</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-core</artifactId>
<version>1.1.2</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.1.2</version>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.7</version>
</dependency>
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcpkix-jdk15on</artifactId>
</dependency>
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk15on</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.jcraft</groupId>
<artifactId>jzlib</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.sshd</groupId>
<artifactId>sshd-core</artifactId>
<version>0.11.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-core</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-all</artifactId>
<version>1.9.5</version>
<scope>test</scope>
</dependency>
</dependencies>
<developers>
<developer>
<id>hierynomus</id>
<name>Jeroen van Erp</name>
<email>jeroen@hierynomus.com</email>
</developer>
<developer>
<id>shikhar</id>
<name>Shikhar Bhushan</name>
<email>shikhar@schmizz.net</email>
<url>http://schmizz.net</url>
</developer>
<developer>
<id>iterate</id>
<name>David Kocher</name>
<email>dkocher@iterate.ch</email>
<organization>iterate GmbH</organization>
<organizationUrl>https://iterate.ch</organizationUrl>
</developer>
</developers>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<configuration>
<source>1.6</source>
<target>1.6</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<version>2.2.1</version>
<executions>
<execution>
<id>attach-sources</id>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>2.9.1</version>
<configuration>
<encoding>${project.build.sourceEncoding}</encoding>
</configuration>
<executions>
<execution>
<id>attach-javadocs</id>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
<version>2.4.0</version>
<extensions>true</extensions>
<configuration>
<instructions>
<Import-Package>
!net.schmizz.*,
javax.crypto*,
com.jcraft.jzlib*;version="[1.1,2)";resolution:=optional,
org.slf4j*;version="[1.7,5)",
org.bouncycastle*,
*
</Import-Package>
<Export-Package>net.schmizz.*</Export-Package>
</instructions>
</configuration>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>clirr-maven-plugin</artifactId>
<version>2.6.1</version>
</plugin>
<plugin>
<groupId>com.mycila</groupId>
<artifactId>license-maven-plugin</artifactId>
<version>2.6</version>
<configuration>
<header>src/etc/license-header</header>
<properties>
<owner>sshj contributors</owner>
<email>sshj-users@googlegroups.com</email>
</properties>
<excludes>
<exclude>**/README</exclude>
<exclude>src/test/resources/**</exclude>
<exclude>src/main/resources/**</exclude>
</excludes>
</configuration>
<executions>
<execution>
<goals>
<goal>check</goal>
</goals>
</execution>
</executions>
</plugin>
<!-- <plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-gpg-plugin</artifactId>
<version>1.5</version>
<executions>
<execution>
<id>sign-artifacts</id>
<phase>verify</phase>
<goals>
<goal>sign</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.sonatype.plugins</groupId>
<artifactId>nexus-staging-maven-plugin</artifactId>
<version>1.6.2</version>
<extensions>true</extensions>
<configuration>
<serverId>ossrh</serverId>
<nexusUrl>https://oss.sonatype.org/</nexusUrl>
<autoReleaseAfterClose>true</autoReleaseAfterClose>
</configuration>
</plugin>
--> </plugins>
</build>
<distributionManagement>
<repository>
<id>sonatype-nexus-staging</id>
<name>Nexus Release Repository</name>
<url>http://oss.sonatype.org/service/local/staging/deploy/maven2/</url>
</repository>
<snapshotRepository>
<id>sonatype-nexus-snapshots</id>
<name>Sonatype Nexus Snapshots</name>
<url>http://oss.sonatype.org/content/repositories/snapshots</url>
</snapshotRepository>
</distributionManagement>
<profiles>
<profile>
<id>full-deps</id>
<dependencies>
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk15on</artifactId>
</dependency>
<dependency>
<groupId>com.jcraft</groupId>
<artifactId>jzlib</artifactId>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-core</artifactId>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
</dependency>
</dependencies>
</profile>
<profile>
<id>doclint-java8-disable</id>
<activation>
<jdk>[1.8,)</jdk>
</activation>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<configuration>
<additionalparam>-Xdoclint:none</additionalparam>
</configuration>
</plugin>
</plugins>
</build>
</profile>
</profiles>
<reporting>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>clirr-maven-plugin</artifactId>
<version>2.6.1</version>
</plugin>
</plugins>
</reporting>
</project>

View File

@@ -1,13 +0,0 @@
package com.hierynomus.sshj.backport;
import java.math.BigDecimal;
public class JavaVersion {
public static boolean isJava7OrEarlier() {
String property = System.getProperty("java.specification.version");
float diff = Float.parseFloat(property) - 1.7f;
return diff < 0.01;
}
}

View File

@@ -1,62 +0,0 @@
package com.hierynomus.sshj.backport;
import java.io.IOException;
import java.io.InputStream;
import java.net.*;
import java.nio.charset.Charset;
public class Jdk7HttpProxySocket extends Socket {
private Proxy httpProxy = null;
public Jdk7HttpProxySocket(Proxy proxy) {
super(proxy.type() == Proxy.Type.HTTP ? Proxy.NO_PROXY : proxy);
if (proxy.type() == Proxy.Type.HTTP) {
this.httpProxy = proxy;
}
}
@Override
public void connect(SocketAddress endpoint, int timeout) throws IOException {
if (httpProxy != null) {
connectHttpProxy(endpoint, timeout);
} else {
super.connect(endpoint, timeout);
}
}
private void connectHttpProxy(SocketAddress endpoint, int timeout) throws IOException {
super.connect(httpProxy.address(), timeout);
if (!(endpoint instanceof InetSocketAddress)) {
throw new SocketException("Expected an InetSocketAddress to connect to, got: " + endpoint);
}
InetSocketAddress isa = (InetSocketAddress) endpoint;
String httpConnect = "CONNECT " + isa.getHostName() + ":" + isa.getPort() + " HTTP/1.0\n\n";
getOutputStream().write(httpConnect.getBytes(Charset.forName("UTF-8")));
checkAndFlushProxyResponse();
}
private void checkAndFlushProxyResponse()throws IOException {
InputStream socketInput = getInputStream();
byte[] tmpBuffer = new byte[512];
int len = socketInput.read(tmpBuffer, 0, tmpBuffer.length);
if (len == 0) {
throw new SocketException("Empty response from proxy");
}
String proxyResponse = new String(tmpBuffer, 0, len, "UTF-8");
// Expecting HTTP/1.x 200 OK
if (proxyResponse.contains("200")) {
// Flush any outstanding message in buffer
if (socketInput.available() > 0) {
socketInput.skip(socketInput.available());
}
// Proxy Connect Successful
} else {
throw new SocketException("Fail to create Socket\nResponse was:" + proxyResponse);
}
}
}

View File

@@ -1,26 +0,0 @@
package com.hierynomus.sshj.backport;
import java.io.Closeable;
import java.io.IOException;
import java.net.Socket;
public class Sockets {
/**
* Java 7 and up have Socket implemented as Closeable, whereas Java6 did not have this inheritance.
* @param socket The socket to wrap as Closeable
* @return The (potentially wrapped) Socket as a Closeable.
*/
public static Closeable asCloseable(final Socket socket) {
if (Closeable.class.isAssignableFrom(socket.getClass())) {
return Closeable.class.cast(socket);
} else {
return new Closeable() {
@Override
public void close() throws IOException {
socket.close();
}
};
}
}
}

View File

@@ -50,12 +50,9 @@ public class KeepAliveRunner extends KeepAlive {
@Override
protected void doKeepAlive() throws TransportException, ConnectionException {
// Ensure the service is set... This means that the key exchange is done and the connection is up.
if (conn.equals(conn.getTransport().getService())) {
emptyQueue(queue);
checkMaxReached(queue);
queue.add(conn.sendGlobalRequest("keepalive@openssh.com", true, new byte[0]));
}
emptyQueue(queue);
checkMaxReached(queue);
queue.add(conn.sendGlobalRequest("keepalive@openssh.com", true, new byte[0]));
}
private void checkMaxReached(Queue<Promise<SSHPacket, ConnectionException>> queue) throws ConnectionException {

View File

@@ -81,7 +81,7 @@ public class DefaultConfig
private final Logger log = LoggerFactory.getLogger(getClass());
private static final String VERSION = "SSHJ_0_13_0";
private static final String VERSION = "SSHJ_0_9_2";
public DefaultConfig() {
setVersion(VERSION);

View File

@@ -39,7 +39,6 @@ import net.schmizz.sshj.transport.TransportImpl;
import net.schmizz.sshj.transport.compression.DelayedZlibCompression;
import net.schmizz.sshj.transport.compression.NoneCompression;
import net.schmizz.sshj.transport.compression.ZlibCompression;
import net.schmizz.sshj.transport.verification.AlgorithmsVerifier;
import net.schmizz.sshj.transport.verification.HostKeyVerifier;
import net.schmizz.sshj.transport.verification.OpenSSHKnownHosts;
import net.schmizz.sshj.userauth.UserAuth;
@@ -50,7 +49,6 @@ import net.schmizz.sshj.userauth.keyprovider.KeyFormat;
import net.schmizz.sshj.userauth.keyprovider.KeyPairWrapper;
import net.schmizz.sshj.userauth.keyprovider.KeyProvider;
import net.schmizz.sshj.userauth.keyprovider.KeyProviderUtil;
import net.schmizz.sshj.userauth.method.AuthGssApiWithMic;
import net.schmizz.sshj.userauth.method.AuthKeyboardInteractive;
import net.schmizz.sshj.userauth.method.AuthMethod;
import net.schmizz.sshj.userauth.method.AuthPassword;
@@ -60,19 +58,15 @@ import net.schmizz.sshj.userauth.password.PasswordFinder;
import net.schmizz.sshj.userauth.password.PasswordUtils;
import net.schmizz.sshj.userauth.password.Resource;
import net.schmizz.sshj.xfer.scp.SCPFileTransfer;
import org.ietf.jgss.Oid;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.security.auth.login.LoginContext;
import java.io.Closeable;
import java.io.File;
import java.io.IOException;
import java.net.ServerSocket;
import java.security.KeyPair;
import java.security.PublicKey;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Deque;
import java.util.LinkedList;
@@ -159,19 +153,10 @@ public class SSHClient
* Add a {@link HostKeyVerifier} which will be invoked for verifying host key during connection establishment and
* future key exchanges.
*
* @param verifier {@link HostKeyVerifier} instance
* @param hostKeyVerifier {@link HostKeyVerifier} instance
*/
public void addHostKeyVerifier(HostKeyVerifier verifier) {
trans.addHostKeyVerifier(verifier);
}
/**
* Add a {@link AlgorithmsVerifier} which will be invoked for verifying negotiated algorithms.
*
* @param verifier {@link AlgorithmsVerifier} instance
*/
public void addAlgorithmsVerifier(AlgorithmsVerifier verifier) {
trans.addAlgorithmsVerifier(verifier);
public void addHostKeyVerifier(HostKeyVerifier hostKeyVerifier) {
trans.addHostKeyVerifier(hostKeyVerifier);
}
/**
@@ -380,30 +365,6 @@ public class SSHClient
authPublickey(username, keyProviders);
}
/**
* Authenticate {@code username} using the {@code "gssapi-with-mic"} authentication method, given a login context
* for the peer GSS machine and a list of supported OIDs.
* <p/>
* Supported OIDs should be ordered by preference as the SSH server will choose the first OID that it also
* supports. At least one OID is required
*
* @param username user to authenticate
* @param context {@code LoginContext} for the peer GSS machine
* @param supportedOid first supported OID
* @param supportedOids other supported OIDs
*
* @throws UserAuthException in case of authentication failure
* @throws TransportException if there was a transport-layer error
*/
public void authGssApiWithMic(String username, LoginContext context, Oid supportedOid, Oid... supportedOids)
throws UserAuthException, TransportException {
// insert supportedOid to the front of the list since ordering matters
List<Oid> oids = new ArrayList<Oid>(Arrays.asList(supportedOids));
oids.add(0, supportedOid);
auth(username, new AuthGssApiWithMic(context, oids));
}
/**
* Disconnects from the connected SSH server. {@code SSHClient} objects are not reusable therefore it is incorrect
* to attempt connection after this method has been called.

View File

@@ -15,9 +15,6 @@
*/
package net.schmizz.sshj;
import com.hierynomus.sshj.backport.JavaVersion;
import com.hierynomus.sshj.backport.Jdk7HttpProxySocket;
import javax.net.SocketFactory;
import java.io.IOException;
import java.io.InputStream;
@@ -48,53 +45,34 @@ public abstract class SocketClient {
this.defaultPort = defaultPort;
}
public void connect(InetAddress host, int port) throws IOException {
public void connect(InetAddress host, int port)
throws IOException {
socket = socketFactory.createSocket();
socket.connect(new InetSocketAddress(host, port), connectTimeout);
onConnect();
}
/**
* Connect to a host via a proxy.
* @param host The host address to connect to.
* @param port The port to connect to.
* @param proxy The proxy to connect via.
* @deprecated This method will be removed after v0.12.0. If you want to connect via a proxy, you can do this by injecting a {@link javax.net.SocketFactory}
* into the SocketClient. The SocketFactory should create sockets using the {@link java.net.Socket#Socket(java.net.Proxy)} constructor.
*/
@Deprecated
public void connect(InetAddress host, int port, Proxy proxy) throws IOException {
if (JavaVersion.isJava7OrEarlier() && proxy.type() == Proxy.Type.HTTP) {
// Java7 and earlier have no support for HTTP Connect proxies, return our custom socket.
socket = new Jdk7HttpProxySocket(proxy);
} else {
socket = new Socket(proxy);
}
public void connect(InetAddress host, int port, Proxy proxy)
throws IOException {
socket = new Socket(proxy);
socket.connect(new InetSocketAddress(host, port), connectTimeout);
onConnect();
}
public void connect(String hostname, int port) throws IOException {
public void connect(String hostname, int port)
throws IOException {
this.hostname = hostname;
connect(InetAddress.getByName(hostname), port);
}
/**
* Connect to a host via a proxy.
* @param hostname The host name to connect to.
* @param port The port to connect to.
* @param proxy The proxy to connect via.
* @deprecated This method will be removed after v0.12.0. If you want to connect via a proxy, you can do this by injecting a {@link javax.net.SocketFactory}
* into the SocketClient. The SocketFactory should create sockets using the {@link java.net.Socket#Socket(java.net.Proxy)} constructor.
*/
@Deprecated
public void connect(String hostname, int port, Proxy proxy) throws IOException {
public void connect(String hostname, int port, Proxy proxy)
throws IOException {
this.hostname = hostname;
connect(InetAddress.getByName(hostname), port, proxy);
}
public void connect(InetAddress host, int port, InetAddress localAddr, int localPort)
public void connect(InetAddress host, int port,
InetAddress localAddr, int localPort)
throws IOException {
socket = socketFactory.createSocket();
socket.bind(new InetSocketAddress(localAddr, localPort));
@@ -102,44 +80,35 @@ public abstract class SocketClient {
onConnect();
}
public void connect(String hostname, int port, InetAddress localAddr, int localPort) throws IOException {
public void connect(String hostname, int port,
InetAddress localAddr, int localPort)
throws IOException {
this.hostname = hostname;
connect(InetAddress.getByName(hostname), port, localAddr, localPort);
}
public void connect(InetAddress host) throws IOException {
public void connect(InetAddress host)
throws IOException {
connect(host, defaultPort);
}
public void connect(String hostname) throws IOException {
public void connect(String hostname)
throws IOException {
connect(hostname, defaultPort);
}
/**
* Connect to a host via a proxy.
* @param host The host address to connect to.
* @param proxy The proxy to connect via.
* @deprecated This method will be removed after v0.12.0. If you want to connect via a proxy, you can do this by injecting a {@link javax.net.SocketFactory}
* into the SocketClient. The SocketFactory should create sockets using the {@link java.net.Socket#Socket(java.net.Proxy)} constructor.
*/
@Deprecated
public void connect(InetAddress host, Proxy proxy) throws IOException {
public void connect(InetAddress host, Proxy proxy)
throws IOException {
connect(host, defaultPort, proxy);
}
/**
* Connect to a host via a proxy.
* @param hostname The host name to connect to.
* @param proxy The proxy to connect via.
* @deprecated This method will be removed after v0.12.0. If you want to connect via a proxy, you can do this by injecting a {@link javax.net.SocketFactory}
* into the SocketClient. The SocketFactory should create sockets using the {@link java.net.Socket#Socket(java.net.Proxy)} constructor.
*/
@Deprecated
public void connect(String hostname, Proxy proxy) throws IOException {
public void connect(String hostname, Proxy proxy)
throws IOException {
connect(hostname, defaultPort, proxy);
}
public void disconnect() throws IOException {
public void disconnect()
throws IOException {
if (socket != null) {
socket.close();
socket = null;
@@ -162,6 +131,7 @@ public abstract class SocketClient {
return socket.getLocalPort();
}
public InetAddress getLocalAddress() {
return socket.getLocalAddress();
}
@@ -179,11 +149,10 @@ public abstract class SocketClient {
}
public void setSocketFactory(SocketFactory factory) {
if (factory == null) {
if (factory == null)
socketFactory = SocketFactory.getDefault();
} else {
else
socketFactory = factory;
}
}
public SocketFactory getSocketFactory() {
@@ -218,7 +187,8 @@ public abstract class SocketClient {
return output;
}
void onConnect() throws IOException {
void onConnect()
throws IOException {
socket.setSoTimeout(timeout);
input = socket.getInputStream();
output = socket.getOutputStream();

View File

@@ -46,9 +46,6 @@ public enum Message {
USERAUTH_60(60),
USERAUTH_INFO_RESPONSE(61),
USERAUTH_GSSAPI_EXCHANGE_COMPLETE(63),
USERAUTH_GSSAPI_MIC(66),
GLOBAL_REQUEST(80),
REQUEST_SUCCESS(81),
REQUEST_FAILURE(82),

View File

@@ -66,7 +66,7 @@ public class ConnectionImpl
*
* @param config the ssh config
* @param trans transport layer
* @param keepAlive the keep alive provider
* @param keepAlive
*/
public ConnectionImpl(Transport trans, KeepAliveProvider keepAlive) {
super("ssh-connection", trans);

View File

@@ -172,7 +172,7 @@ public final class ChannelOutputStream
if (!closed) {
try {
buffer.flush(false);
// trans.write(new SSHPacket(Message.CHANNEL_EOF).putUInt32(chan.getRecipient()));
trans.write(new SSHPacket(Message.CHANNEL_EOF).putUInt32(chan.getRecipient()));
} finally {
closed = true;
}

View File

@@ -18,12 +18,11 @@ package net.schmizz.sshj.connection.channel;
import net.schmizz.concurrent.Event;
import net.schmizz.sshj.common.IOUtils;
import java.io.Closeable;
import java.io.IOException;
import java.net.Socket;
import java.util.concurrent.TimeUnit;
import static com.hierynomus.sshj.backport.Sockets.asCloseable;
public class SocketStreamCopyMonitor
extends Thread {
@@ -33,6 +32,16 @@ public class SocketStreamCopyMonitor
setDaemon(true);
}
private static Closeable wrapSocket(final Socket socket) {
return new Closeable() {
@Override
public void close()
throws IOException {
socket.close();
}
};
}
public static void monitor(final int frequency, final TimeUnit unit,
final Event<IOException> x, final Event<IOException> y,
final Channel channel, final Socket socket) {
@@ -45,7 +54,7 @@ public class SocketStreamCopyMonitor
}
} catch (IOException ignored) {
} finally {
IOUtils.closeQuietly(channel, asCloseable(socket));
IOUtils.closeQuietly(channel, wrapSocket(socket));
}
}
}).start();

View File

@@ -16,12 +16,12 @@
package net.schmizz.sshj.connection.channel.direct;
import net.schmizz.concurrent.Event;
import net.schmizz.sshj.common.IOUtils;
import net.schmizz.sshj.common.SSHPacket;
import net.schmizz.sshj.common.StreamCopier;
import net.schmizz.sshj.connection.Connection;
import net.schmizz.sshj.connection.ConnectionException;
import net.schmizz.sshj.connection.channel.SocketStreamCopyMonitor;
import net.schmizz.sshj.transport.TransportException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -30,8 +30,6 @@ import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.TimeUnit;
import static com.hierynomus.sshj.backport.Sockets.asCloseable;
public class LocalPortForwarder {
public static class Parameters {
@@ -114,15 +112,11 @@ public class LocalPortForwarder {
this.serverSocket = serverSocket;
}
private void startChannel(Socket socket) throws IOException {
DirectTCPIPChannel chan = new DirectTCPIPChannel(conn, socket, parameters);
try {
chan.open();
chan.start();
} catch (IOException e) {
IOUtils.closeQuietly(chan, asCloseable(socket));
throw e;
}
protected DirectTCPIPChannel openChannel(Socket socket)
throws TransportException, ConnectionException {
final DirectTCPIPChannel chan = new DirectTCPIPChannel(conn, socket, parameters);
chan.open();
return chan;
}
/**
@@ -136,7 +130,7 @@ public class LocalPortForwarder {
while (!Thread.currentThread().isInterrupted()) {
final Socket socket = serverSocket.accept();
log.debug("Got connection from {}", socket.getRemoteSocketAddress());
startChannel(socket);
openChannel(socket).start();
}
log.debug("Interrupted!");
}

View File

@@ -1,12 +1,12 @@
/**
* Copyright 2009 sshj contributors
* <p/>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* <p/>
* http://www.apache.org/licenses/LICENSE-2.0
* <p/>
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -19,7 +19,6 @@ import net.schmizz.concurrent.Promise;
import net.schmizz.sshj.common.Buffer;
import net.schmizz.sshj.sftp.Response.StatusCode;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
@@ -34,31 +33,37 @@ public class RemoteFile
super(requester, path, handle);
}
public FileAttributes fetchAttributes() throws IOException {
public FileAttributes fetchAttributes()
throws IOException {
return requester.request(newRequest(PacketType.FSTAT))
.retrieve(requester.getTimeoutMs(), TimeUnit.MILLISECONDS)
.ensurePacketTypeIs(PacketType.ATTRS)
.readFileAttributes();
}
public long length() throws IOException {
public long length()
throws IOException {
return fetchAttributes().getSize();
}
public void setLength(long len) throws IOException {
public void setLength(long len)
throws IOException {
setAttributes(new FileAttributes.Builder().withSize(len).build());
}
public int read(long fileOffset, byte[] to, int offset, int len) throws IOException {
public int read(long fileOffset, byte[] to, int offset, int len)
throws IOException {
final Response res = asyncRead(fileOffset, len).retrieve(requester.getTimeoutMs(), TimeUnit.MILLISECONDS);
return checkReadResponse(res, to, offset);
}
protected Promise<Response, SFTPException> asyncRead(long fileOffset, int len) throws IOException {
protected Promise<Response, SFTPException> asyncRead(long fileOffset, int len)
throws IOException {
return requester.request(newRequest(PacketType.READ).putUInt64(fileOffset).putUInt32(len));
}
protected int checkReadResponse(Response res, byte[] to, int offset) throws Buffer.BufferException, SFTPException {
protected int checkReadResponse(Response res, byte[] to, int offset)
throws Buffer.BufferException, SFTPException {
switch (res.getType()) {
case DATA:
int recvLen = res.readUInt32AsInt();
@@ -74,25 +79,27 @@ public class RemoteFile
}
}
public void write(long fileOffset, byte[] data, int off, int len) throws IOException {
public void write(long fileOffset, byte[] data, int off, int len)
throws IOException {
checkWriteResponse(asyncWrite(fileOffset, data, off, len));
}
protected Promise<Response, SFTPException> asyncWrite(long fileOffset, byte[] data, int off, int len)
throws IOException {
return requester.request(newRequest(PacketType.WRITE)
.putUInt64(fileOffset)
// TODO The SFTP spec claims this field is unneeded...? See #187
.putUInt32(len)
.putRawBytes(data, off, len)
.putUInt64(fileOffset)
.putUInt32(len - off)
.putRawBytes(data, off, len)
);
}
private void checkWriteResponse(Promise<Response, SFTPException> responsePromise) throws SFTPException {
private void checkWriteResponse(Promise<Response, SFTPException> responsePromise)
throws SFTPException {
responsePromise.retrieve(requester.getTimeoutMs(), TimeUnit.MILLISECONDS).ensureStatusPacketIsOK();
}
public void setAttributes(FileAttributes attrs) throws IOException {
public void setAttributes(FileAttributes attrs)
throws IOException {
requester.request(newRequest(PacketType.FSETSTAT).putFileAttributes(attrs))
.retrieve(requester.getTimeoutMs(), TimeUnit.MILLISECONDS).ensureStatusPacketIsOK();
}
@@ -132,13 +139,15 @@ public class RemoteFile
}
@Override
public void write(int w) throws IOException {
public void write(int w)
throws IOException {
b[0] = (byte) w;
write(b, 0, 1);
}
@Override
public void write(byte[] buf, int off, int len) throws IOException {
public void write(byte[] buf, int off, int len)
throws IOException {
if (unconfirmedWrites.size() > maxUnconfirmedWrites) {
checkWriteResponse(unconfirmedWrites.remove());
}
@@ -147,20 +156,23 @@ public class RemoteFile
}
@Override
public void flush() throws IOException {
public void flush()
throws IOException {
while (!unconfirmedWrites.isEmpty()) {
checkWriteResponse(unconfirmedWrites.remove());
}
}
@Override
public void close() throws IOException {
public void close()
throws IOException {
flush();
}
}
public class RemoteFileInputStream extends InputStream {
public class RemoteFileInputStream
extends InputStream {
private final byte[] b = new byte[1];
@@ -188,29 +200,31 @@ public class RemoteFile
}
@Override
public void reset() throws IOException {
public void reset()
throws IOException {
fileOffset = markPos;
}
@Override
public long skip(long n) throws IOException {
public long skip(long n)
throws IOException {
return (this.fileOffset = Math.min(fileOffset + n, length()));
}
@Override
public int read() throws IOException {
public int read()
throws IOException {
return read(b, 0, 1) == -1 ? -1 : b[0] & 0xff;
}
@Override
public int read(byte[] into, int off, int len) throws IOException {
public int read(byte[] into, int off, int len)
throws IOException {
int read = RemoteFile.this.read(fileOffset, into, off, len);
if (read != -1) {
fileOffset += read;
if (markPos != 0 && read > readLimit) {
// Invalidate mark position
if (markPos != 0 && read > readLimit) // Invalidate mark position
markPos = 0;
}
}
return read;
}
@@ -223,56 +237,27 @@ public class RemoteFile
private final byte[] b = new byte[1];
private final int maxUnconfirmedReads;
private final Queue<Promise<Response, SFTPException>> unconfirmedReads = new LinkedList<Promise<Response, SFTPException>>();
private final Queue<Long> unconfirmedReadOffsets = new LinkedList<Long>();
private final Queue<Promise<Response, SFTPException>> unconfirmedReads;
private long requestOffset;
private long responseOffset;
private long fileOffset;
private boolean eof;
public ReadAheadRemoteFileInputStream(int maxUnconfirmedReads) {
assert 0 <= maxUnconfirmedReads;
this.maxUnconfirmedReads = maxUnconfirmedReads;
this.unconfirmedReads = new LinkedList<Promise<Response, SFTPException>>();
this.fileOffset = 0;
}
public ReadAheadRemoteFileInputStream(int maxUnconfirmedReads, long fileOffset) {
assert 0 <= maxUnconfirmedReads;
assert 0 <= fileOffset;
this.maxUnconfirmedReads = maxUnconfirmedReads;
this.requestOffset = this.responseOffset = fileOffset;
this.unconfirmedReads = new LinkedList<Promise<Response, SFTPException>>();
this.fileOffset = fileOffset;
}
private ByteArrayInputStream pending = new ByteArrayInputStream(new byte[0]);
private boolean retrieveUnconfirmedRead(boolean blocking) throws IOException {
if (unconfirmedReads.size() <= 0) {
return false;
}
if (!blocking && !unconfirmedReads.peek().isDelivered()) {
return false;
}
unconfirmedReadOffsets.remove();
final Response res = unconfirmedReads.remove().retrieve(requester.getTimeoutMs(), TimeUnit.MILLISECONDS);
switch (res.getType()) {
case DATA:
int recvLen = res.readUInt32AsInt();
responseOffset += recvLen;
pending = new ByteArrayInputStream(res.array(), res.rpos(), recvLen);
break;
case STATUS:
res.ensureStatusIs(Response.StatusCode.EOF);
eof = true;
break;
default:
throw new SFTPException("Unexpected packet: " + res.getType());
}
return true;
@Override
public long skip(long n)
throws IOException {
throw new IOException("skip is not supported by ReadAheadFileInputStream, use RemoteFileInputStream instead");
}
@Override
@@ -282,66 +267,26 @@ public class RemoteFile
}
@Override
public int read(byte[] into, int off, int len) throws IOException {
while (!eof && pending.available() <= 0) {
// we also need to go here for len <= 0, because pending may be at
// EOF in which case it would return -1 instead of 0
while (unconfirmedReads.size() <= maxUnconfirmedReads) {
// Send read requests as long as there is no EOF and we have not reached the maximum parallelism
int reqLen = Math.max(1024, len); // don't be shy!
unconfirmedReads.add(RemoteFile.this.asyncRead(requestOffset, reqLen));
unconfirmedReadOffsets.add(requestOffset);
requestOffset += reqLen;
}
long nextOffset = unconfirmedReadOffsets.peek();
if (responseOffset != nextOffset) {
// the server could not give us all the data we needed, so
// we try to fill the gap synchronously
assert responseOffset < nextOffset;
assert 0 < (nextOffset - responseOffset);
assert (nextOffset - responseOffset) <= Integer.MAX_VALUE;
byte[] buf = new byte[(int) (nextOffset - responseOffset)];
int recvLen = RemoteFile.this.read(responseOffset, buf, 0, buf.length);
if (recvLen < 0) {
eof = true;
return -1;
}
if (0 == recvLen) {
// avoid infinite loops
throw new SFTPException("Unexpected response size (0), bailing out");
}
responseOffset += recvLen;
pending = new ByteArrayInputStream(buf, 0, recvLen);
} else if (!retrieveUnconfirmedRead(true /*blocking*/)) {
// this may happen if we change prefetch strategy
// currently, we should never get here...
throw new IllegalStateException("Could not retrieve data for pending read request");
}
public int read(byte[] into, int off, int len)
throws IOException {
while (!eof && unconfirmedReads.size() <= maxUnconfirmedReads) {
// Send read requests as long as there is no EOF and we have not reached the maximum parallelism
unconfirmedReads.add(asyncRead(fileOffset, len));
fileOffset += len;
}
return pending.read(into, off, len);
if (unconfirmedReads.isEmpty()) {
assert eof;
return -1;
}
// Retrieve first in
final Response res = unconfirmedReads.remove().retrieve(requester.getTimeoutMs(), TimeUnit.MILLISECONDS);
final int recvLen = checkReadResponse(res, into, off);
if (recvLen == -1) {
eof = true;
}
return recvLen;
}
@Override
public int available() throws IOException {
boolean lastRead = true;
while (!eof && (pending.available() <= 0) && lastRead) {
lastRead = retrieveUnconfirmedRead(false /*blocking*/);
}
return pending.available();
}
}
}
}

View File

@@ -33,8 +33,6 @@ import net.schmizz.sshj.transport.digest.Digest;
import net.schmizz.sshj.transport.kex.KeyExchange;
import net.schmizz.sshj.transport.mac.MAC;
import net.schmizz.sshj.transport.verification.HostKeyVerifier;
import net.schmizz.sshj.transport.verification.AlgorithmsVerifier;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -70,8 +68,6 @@ final class KeyExchanger
*/
private final Queue<HostKeyVerifier> hostVerifiers = new LinkedList<HostKeyVerifier>();
private final Queue<AlgorithmsVerifier> algorithmVerifiers = new LinkedList<AlgorithmsVerifier>();
private final AtomicBoolean kexOngoing = new AtomicBoolean();
/** What we are expecting from the next packet */
@@ -112,10 +108,6 @@ final class KeyExchanger
hostVerifiers.add(hkv);
}
synchronized void addAlgorithmsVerifier(AlgorithmsVerifier verifier) {
algorithmVerifiers.add(verifier);
}
/**
* Returns the session identifier computed during key exchange.
*
@@ -226,13 +218,6 @@ final class KeyExchanger
final Proposal serverProposal = new Proposal(buf);
negotiatedAlgs = clientProposal.negotiate(serverProposal);
log.debug("Negotiated algorithms: {}", negotiatedAlgs);
for(AlgorithmsVerifier v: algorithmVerifiers) {
log.debug("Trying to verify algorithms with {}", v);
if(!v.verify(negotiatedAlgs)) {
throw new TransportException(DisconnectReason.KEY_EXCHANGE_FAILED,
"Failed to verify negotiated algorithms `" + negotiatedAlgs + "`");
}
}
kex = Factory.Named.Util.create(transport.getConfig().getKeyExchangeFactories(),
negotiatedAlgs.getKeyExchangeAlgorithm());
try {

View File

@@ -48,25 +48,23 @@ public final class Reader
int read;
try {
read = inp.read(recvbuf, 0, needed);
} catch(SocketTimeoutException e) {
}
catch(SocketTimeoutException e) {
if (isInterrupted()) {
throw e;
}
continue;
}
if (read == -1) {
if (read == -1)
throw new TransportException("Broken transport; encountered EOF");
} else {
else
needed = decoder.received(recvbuf, read);
}
}
} catch (Exception e) {
//noinspection StatementWithEmptyBody
if (isInterrupted()) {
// We are meant to shut up and draw to a close if interrupted
} else {
} else
trans.die(e);
}
}
log.debug("Stopping");

View File

@@ -20,7 +20,6 @@ import net.schmizz.sshj.Service;
import net.schmizz.sshj.common.DisconnectReason;
import net.schmizz.sshj.common.SSHPacket;
import net.schmizz.sshj.common.SSHPacketHandler;
import net.schmizz.sshj.transport.verification.AlgorithmsVerifier;
import net.schmizz.sshj.transport.verification.HostKeyVerifier;
import java.io.InputStream;
@@ -52,13 +51,6 @@ public interface Transport
*/
void addHostKeyVerifier(HostKeyVerifier hkv);
/**
* Adds the specified verifier.
*
* @param verifier The verifier to call with negotiated algorithms
*/
void addAlgorithmsVerifier(AlgorithmsVerifier verifier);
/**
* Do key exchange and algorithm negotiation. This can be the initial one or for algorithm renegotiation.
*

View File

@@ -27,7 +27,6 @@ import net.schmizz.sshj.common.IOUtils;
import net.schmizz.sshj.common.Message;
import net.schmizz.sshj.common.SSHException;
import net.schmizz.sshj.common.SSHPacket;
import net.schmizz.sshj.transport.verification.AlgorithmsVerifier;
import net.schmizz.sshj.transport.verification.HostKeyVerifier;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -159,10 +158,7 @@ public final class TransportImpl
// Read server's ID
final Buffer.PlainBuffer buf = new Buffer.PlainBuffer();
while ((serverID = readIdentification(buf)).isEmpty()) {
int b = connInfo.in.read();
if (b == -1)
throw new TransportException("Server closed connection during identification exchange");
buf.putByte((byte) b);
buf.putByte((byte) connInfo.in.read());
}
log.info("Server identity string: {}", serverID);
@@ -236,11 +232,6 @@ public final class TransportImpl
kexer.addHostKeyVerifier(hkv);
}
@Override
public void addAlgorithmsVerifier(AlgorithmsVerifier verifier) {
kexer.addAlgorithmsVerifier(verifier);
}
@Override
public void doKex()
throws TransportException {

View File

@@ -1,27 +0,0 @@
/**
* Copyright 2009 sshj contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.schmizz.sshj.transport.verification;
import net.schmizz.sshj.transport.NegotiatedAlgorithms;
public interface AlgorithmsVerifier {
/**
* Callback is invoked when algorithms have been negotiated between client and server.
* @return False to interrupt the connection
*/
boolean verify(NegotiatedAlgorithms algorithms);
}

View File

@@ -352,7 +352,7 @@ public class OpenSSHKnownHosts
@Override
public boolean appliesTo(KeyType type, String host)
throws IOException {
return type == this.type && hosts.contains(host);
return type == this.type && hostnames.contains(host);
}
}

View File

@@ -139,7 +139,9 @@ public class PKCS8KeyFile
JcePEMDecryptorProviderBuilder decryptorBuilder = new JcePEMDecryptorProviderBuilder();
decryptorBuilder.setProvider("BC");
try {
passphrase = pwdf == null ? null : pwdf.reqPassword(resource);
// Do not return null, as JcePEMDecryptorProviderBuilder$1$1.decrypt would throw an exception
// in that case because it requires a 'password' (i.e. passphrase).
passphrase = pwdf == null ? "".toCharArray() : pwdf.reqPassword(resource);
kp = pemConverter.getKeyPair(encryptedKeyPair.decryptKeyPair(decryptorBuilder.build(passphrase)));
} finally {
PasswordUtils.blankOut(passphrase);

View File

@@ -1,188 +0,0 @@
package net.schmizz.sshj.userauth.method;
import java.security.PrivilegedActionException;
import java.security.PrivilegedExceptionAction;
import java.util.List;
import javax.security.auth.Subject;
import javax.security.auth.login.LoginContext;
import org.ietf.jgss.GSSContext;
import org.ietf.jgss.GSSCredential;
import org.ietf.jgss.GSSException;
import org.ietf.jgss.GSSManager;
import org.ietf.jgss.GSSName;
import org.ietf.jgss.Oid;
import net.schmizz.sshj.common.Buffer.BufferException;
import net.schmizz.sshj.common.Buffer.PlainBuffer;
import net.schmizz.sshj.common.Message;
import net.schmizz.sshj.common.SSHPacket;
import net.schmizz.sshj.transport.TransportException;
import net.schmizz.sshj.userauth.UserAuthException;
/** Implements authentication by GSS-API. */
public class AuthGssApiWithMic
extends AbstractAuthMethod {
private final LoginContext loginContext;
private final List<Oid> mechanismOids;
private final GSSManager manager;
private GSSContext secContext;
public AuthGssApiWithMic(LoginContext loginContext, List<Oid> mechanismOids) {
this(loginContext, mechanismOids, GSSManager.getInstance());
}
public AuthGssApiWithMic(LoginContext loginContext, List<Oid> mechanismOids, GSSManager manager) {
super("gssapi-with-mic");
this.loginContext = loginContext;
this.mechanismOids = mechanismOids;
this.manager = manager;
secContext = null;
}
@Override
public SSHPacket buildReq()
throws UserAuthException {
SSHPacket packet = super.buildReq() // the generic stuff
.putUInt32(mechanismOids.size()); // number of OIDs we support
for (Oid oid : mechanismOids) {
try {
packet.putString(oid.getDER());
} catch (GSSException e) {
throw new UserAuthException("Mechanism OID could not be encoded: " + oid.toString(), e);
}
}
return packet;
}
/**
* PrivilegedExceptionAction to be executed within the given LoginContext for
* initializing the GSSContext.
*
* @author Ben Hamme
*/
private class InitializeContextAction implements PrivilegedExceptionAction<GSSContext> {
private final Oid selectedOid;
public InitializeContextAction(Oid selectedOid) {
this.selectedOid = selectedOid;
}
@Override
public GSSContext run() throws GSSException {
GSSName clientName = manager.createName(params.getUsername(), GSSName.NT_USER_NAME);
GSSCredential clientCreds = manager.createCredential(clientName, GSSContext.DEFAULT_LIFETIME, selectedOid, GSSCredential.INITIATE_ONLY);
GSSName peerName = manager.createName("host@" + params.getTransport().getRemoteHost(), GSSName.NT_HOSTBASED_SERVICE);
GSSContext context = manager.createContext(peerName, selectedOid, clientCreds, GSSContext.DEFAULT_LIFETIME);
context.requestMutualAuth(true);
context.requestInteg(true);
return context;
}
}
private void sendToken(byte[] token) throws TransportException {
SSHPacket packet = new SSHPacket(Message.USERAUTH_INFO_RESPONSE).putString(token);
params.getTransport().write(packet);
}
private void handleContextInitialization(SSHPacket buf)
throws UserAuthException, TransportException {
byte[] bytes;
try {
bytes = buf.readBytes();
} catch (BufferException e) {
throw new UserAuthException("Failed to read byte array from message buffer", e);
}
Oid selectedOid;
try {
selectedOid = new Oid(bytes);
} catch (GSSException e) {
throw new UserAuthException("Exception constructing OID from server response", e);
}
log.debug("Server selected OID: {}", selectedOid.toString());
log.debug("Initializing GSSAPI context");
Subject subject = loginContext.getSubject();
try {
secContext = Subject.doAs(subject, new InitializeContextAction(selectedOid));
} catch (PrivilegedActionException e) {
throw new UserAuthException("Exception during context initialization", e);
}
log.debug("Sending initial token");
byte[] inToken = new byte[0];
try {
byte[] outToken = secContext.initSecContext(inToken, 0, inToken.length);
sendToken(outToken);
} catch (GSSException e) {
throw new UserAuthException("Exception sending initial token", e);
}
}
private byte[] handleTokenFromServer(SSHPacket buf) throws UserAuthException {
byte[] token;
try {
token = buf.readStringAsBytes();
} catch (BufferException e) {
throw new UserAuthException("Failed to read string from message buffer", e);
}
try {
return secContext.initSecContext(token, 0, token.length);
} catch (GSSException e) {
throw new UserAuthException("Exception during token exchange", e);
}
}
private byte[] generateMIC() throws UserAuthException {
byte[] msg = new PlainBuffer().putString(params.getTransport().getSessionID())
.putByte(Message.USERAUTH_REQUEST.toByte())
.putString(params.getUsername())
.putString(params.getNextServiceName())
.putString(getName())
.getCompactData();
try {
return secContext.getMIC(msg, 0, msg.length, null);
} catch (GSSException e) {
throw new UserAuthException("Exception getting message integrity code", e);
}
}
@Override
public void handle(Message cmd, SSHPacket buf)
throws UserAuthException, TransportException {
if (cmd == Message.USERAUTH_60) {
handleContextInitialization(buf);
} else if (cmd == Message.USERAUTH_INFO_RESPONSE) {
byte[] token = handleTokenFromServer(buf);
if (!secContext.isEstablished()) {
log.debug("Sending token");
sendToken(token);
} else {
if (secContext.getIntegState()) {
log.debug("Per-message integrity protection available: finalizing authentication with message integrity code");
params.getTransport().write(new SSHPacket(Message.USERAUTH_GSSAPI_MIC).putString(generateMIC()));
} else {
log.debug("Per-message integrity protection unavailable: finalizing authentication");
params.getTransport().write(new SSHPacket(Message.USERAUTH_GSSAPI_EXCHANGE_COMPLETE));
}
}
} else {
super.handle(cmd, buf);
}
}
}

View File

@@ -33,7 +33,7 @@ import java.util.List;
/** @see <a href="http://blogs.sun.com/janp/entry/how_the_scp_protocol_works">SCP Protocol</a> */
class SCPEngine {
enum Arg {
static enum Arg {
SOURCE('f'),
SINK('t'),
RECURSIVE('r'),
@@ -100,15 +100,13 @@ class SCPEngine {
void execSCPWith(List<Arg> args, String path)
throws SSHException {
final StringBuilder cmd = new StringBuilder(SCP_COMMAND);
for (Arg arg : args) {
for (Arg arg : args)
cmd.append(" ").append(arg);
}
cmd.append(" ");
if (path == null || path.isEmpty()) {
if (path == null || path.isEmpty())
cmd.append(".");
} else {
else
cmd.append("'").append(path.replaceAll("'", "\\'")).append("'");
}
scp = host.startSession().exec(cmd.toString());
}
@@ -121,13 +119,11 @@ class SCPEngine {
exitStatus = scp.getExitStatus();
if (scp.getExitStatus() != 0)
log.warn("SCP exit status: {}", scp.getExitStatus());
} else {
} else
exitStatus = -1;
}
if (scp.getExitSignal() != null) {
if (scp.getExitSignal() != null)
log.warn("SCP exit signal: {}", scp.getExitSignal());
}
}
scp = null;
@@ -137,36 +133,36 @@ class SCPEngine {
throws IOException {
final ByteArrayOutputStream baos = new ByteArrayOutputStream();
int x;
while ((x = scp.getInputStream().read()) != LF) {
while ((x = scp.getInputStream().read()) != LF)
if (x == -1) {
if (baos.size() == 0) {
if (baos.size() == 0)
return "";
} else {
else
throw new IOException("EOF while reading message");
}
} else {
} else
baos.write(x);
}
}
final String msg = baos.toString(IOUtils.UTF8.displayName());
log.debug("Read message: `{}`", msg);
return msg;
}
void sendMessage(String msg) throws IOException {
void sendMessage(String msg)
throws IOException {
log.debug("Sending message: {}", msg);
scp.getOutputStream().write((msg + LF).getBytes(IOUtils.UTF8));
scp.getOutputStream().flush();
check("Message ACK received");
}
void signal(String what) throws IOException {
void signal(String what)
throws IOException {
log.debug("Signalling: {}", what);
scp.getOutputStream().write(0);
scp.getOutputStream().flush();
}
long transferToRemote(StreamCopier.Listener listener, InputStream src, long length) throws IOException {
long transferToRemote(StreamCopier.Listener listener, InputStream src, long length)
throws IOException {
return new StreamCopier(src, scp.getOutputStream())
.bufSize(scp.getRemoteMaxPacketSize()).length(length)
.keepFlushing(false)
@@ -174,7 +170,8 @@ class SCPEngine {
.copy();
}
long transferFromRemote(StreamCopier.Listener listener, OutputStream dest, long length) throws IOException {
long transferFromRemote(StreamCopier.Listener listener, OutputStream dest, long length)
throws IOException {
return new StreamCopier(scp.getInputStream(), dest)
.bufSize(scp.getLocalMaxPacketSize()).length(length)
.keepFlushing(false)

View File

@@ -1,27 +0,0 @@
package com.hierynomus.sshj.connection.channel;
import com.hierynomus.sshj.test.SshFixture;
import net.schmizz.sshj.connection.channel.direct.Session;
import org.junit.Rule;
import org.junit.Test;
import java.io.IOException;
import static org.hamcrest.MatcherAssert.assertThat;
public class ChannelCloseEofTest {
@Rule
public SshFixture fixture = new SshFixture();
@Test
public void shouldCorrectlyHandleSessionChannelEof() throws IOException, InterruptedException {
fixture.setupConnectedDefaultClient().authPassword("jeroen", "jeroen");
Session session = fixture.getClient().startSession();
session.allocateDefaultPTY();
session.close();
Thread.sleep(1000);
assertThat("Should still be connected", fixture.getClient().isConnected());
}
}

View File

@@ -1,34 +0,0 @@
package com.hierynomus.sshj.connection.channel.direct;
import com.hierynomus.sshj.test.SshFixture;
import net.schmizz.sshj.SSHClient;
import net.schmizz.sshj.connection.channel.direct.Session;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import java.io.File;
import java.io.IOException;
import static org.hamcrest.MatcherAssert.assertThat;
public class CommandTest {
@Rule
public SshFixture fixture = new SshFixture();
@Rule
public TemporaryFolder temp = new TemporaryFolder();
@Test
public void shouldExecuteBackgroundCommand() throws IOException {
SSHClient sshClient = fixture.setupConnectedDefaultClient();
sshClient.authPassword("jeroen", "jeroen");
File file = new File(temp.getRoot(), "testdir");
assertThat("File should not exist", !file.exists());
Session.Command exec = sshClient.startSession().exec("mkdir " + file.getPath() + " &");
exec.join();
assertThat("File should exist", file.exists());
assertThat("File should be directory", file.isDirectory());
}
}

View File

@@ -1,54 +0,0 @@
package com.hierynomus.sshj.keepalive;
import com.hierynomus.sshj.test.KnownFailingTests;
import com.hierynomus.sshj.test.SlowTests;
import com.hierynomus.sshj.test.SshFixture;
import net.schmizz.keepalive.KeepAliveProvider;
import net.schmizz.sshj.DefaultConfig;
import net.schmizz.sshj.SSHClient;
import net.schmizz.sshj.userauth.UserAuthException;
import org.junit.Rule;
import org.junit.Test;
import org.junit.experimental.categories.Category;
import java.io.IOException;
import java.lang.management.ManagementFactory;
import java.lang.management.ThreadInfo;
import java.lang.management.ThreadMXBean;
import static org.junit.Assert.fail;
public class KeepAliveThreadTerminationTest {
@Rule
public SshFixture fixture = new SshFixture();
@Test
@Category({SlowTests.class, KnownFailingTests.class})
public void shouldCorrectlyTerminateThreadOnDisconnect() throws IOException, InterruptedException {
DefaultConfig defaultConfig = new DefaultConfig();
defaultConfig.setKeepAliveProvider(KeepAliveProvider.KEEP_ALIVE);
for (int i = 0; i < 10; i++) {
SSHClient sshClient = fixture.setupClient(defaultConfig);
fixture.connectClient(sshClient);
sshClient.getConnection().getKeepAlive().setKeepAliveInterval(1);
try {
sshClient.authPassword("bad", "credentials");
fail("Should not auth.");
} catch (UserAuthException e) {
// OK
}
fixture.stopClient();
Thread.sleep(2000);
}
ThreadMXBean threadMXBean = ManagementFactory.getThreadMXBean();
for (long l : threadMXBean.getAllThreadIds()) {
ThreadInfo threadInfo = threadMXBean.getThreadInfo(l);
if (threadInfo.getThreadName().equals("keep-alive") && threadInfo.getThreadState() != Thread.State.TERMINATED) {
System.err.println("Found thread in state " + threadInfo.getThreadState());
throw new RuntimeException("Found alive keep-alive thread");
}
}
}
}

View File

@@ -1,74 +0,0 @@
package com.hierynomus.sshj.sftp;
import com.hierynomus.sshj.test.SshFixture;
import net.schmizz.sshj.SSHClient;
import net.schmizz.sshj.sftp.OpenMode;
import net.schmizz.sshj.sftp.RemoteFile;
import net.schmizz.sshj.sftp.SFTPEngine;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.EnumSet;
import java.util.Random;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.MatcherAssert.assertThat;
public class RemoteFileTest {
@Rule
public SshFixture fixture = new SshFixture();
@Rule
public TemporaryFolder temp = new TemporaryFolder();
@Test
public void shouldNotGoOutOfBoundsInReadAheadInputStream() throws IOException {
SSHClient ssh = fixture.setupConnectedDefaultClient();
ssh.authPassword("test", "test");
SFTPEngine sftp = new SFTPEngine(ssh).init();
RemoteFile rf;
File file = temp.newFile("SftpReadAheadTest.bin");
rf = sftp.open(file.getPath(), EnumSet.of(OpenMode.WRITE, OpenMode.CREAT));
byte[] data = new byte[8192];
new Random(53).nextBytes(data);
data[3072] = 1;
rf.write(0, data, 0, data.length);
rf.close();
assertThat("The file should exist", file.exists());
rf = sftp.open(file.getPath());
InputStream rs = rf.new ReadAheadRemoteFileInputStream(16 /*maxUnconfirmedReads*/);
byte[] test = new byte[4097];
int n = 0;
while (n < 2048) {
n += rs.read(test, n, 2048 - n);
}
while (n < 3072) {
n += rs.read(test, n, 3072 - n);
}
if (test[3072] != 0) {
System.err.println("buffer overrun!");
}
n += rs.read(test, n, test.length - n); // --> ArrayIndexOutOfBoundsException
byte[] test2 = new byte[data.length];
System.arraycopy(test, 0, test2, 0, test.length);
while (n < data.length) {
n += rs.read(test2, n, data.length - n);
}
assertThat("The written and received data should match", data, equalTo(test2));
}
}

View File

@@ -1,39 +0,0 @@
package com.hierynomus.sshj.sftp;
import com.hierynomus.sshj.test.SshFixture;
import com.hierynomus.sshj.test.util.FileUtil;
import net.schmizz.sshj.SSHClient;
import net.schmizz.sshj.sftp.SFTPClient;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import java.io.File;
import java.io.IOException;
public class SFTPClientTest {
@Rule
public SshFixture fixture = new SshFixture();
@Rule
public TemporaryFolder temp = new TemporaryFolder();
@Test
public void shouldNotThrowExceptionOnCloseBeforeDisconnect() throws IOException {
SSHClient sshClient = fixture.setupConnectedDefaultClient();
sshClient.authPassword("test", "test");
SFTPClient sftpClient = sshClient.newSFTPClient();
File file = temp.newFile("source.txt");
FileUtil.writeToFile(file, "This is the source");
try {
try {
sftpClient.put(file.getPath(), temp.newFile("dest.txt").getPath());
} finally {
sftpClient.close();
}
} finally {
sshClient.disconnect();
}
}
}

View File

@@ -1,9 +0,0 @@
package com.hierynomus.sshj.test;
/**
* Marker interface for JUnit Categories.
*
* This denotes that the test is known to fail, and should be fixed at some time.
*/
public interface KnownFailingTests {
}

View File

@@ -1,4 +0,0 @@
package com.hierynomus.sshj.test;
public interface SlowTests {
}

View File

@@ -1,161 +0,0 @@
package com.hierynomus.sshj.test;
import net.schmizz.sshj.Config;
import net.schmizz.sshj.DefaultConfig;
import net.schmizz.sshj.SSHClient;
import net.schmizz.sshj.transport.TransportException;
import net.schmizz.sshj.userauth.UserAuthException;
import net.schmizz.sshj.util.gss.BogusGSSAuthenticator;
import org.apache.sshd.SshServer;
import org.apache.sshd.common.NamedFactory;
import org.apache.sshd.common.keyprovider.FileKeyPairProvider;
import org.apache.sshd.common.util.OsUtils;
import org.apache.sshd.server.Command;
import org.apache.sshd.server.CommandFactory;
import org.apache.sshd.server.PasswordAuthenticator;
import org.apache.sshd.server.channel.ChannelSession;
import org.apache.sshd.server.command.ScpCommandFactory;
import org.apache.sshd.server.session.ServerSession;
import org.apache.sshd.server.sftp.SftpSubsystem;
import org.apache.sshd.server.shell.ProcessShellFactory;
import org.junit.rules.ExternalResource;
import java.io.IOException;
import java.net.ServerSocket;
import java.util.Arrays;
import java.util.Collections;
import java.util.EnumSet;
import java.util.concurrent.atomic.AtomicBoolean;
/**
* Can be used as a rule to ensure the server is teared down after each test.
*/
public class SshFixture extends ExternalResource {
public static final String hostkey = "src/test/resources/hostkey.pem";
public static final String fingerprint = "ce:a7:c1:cf:17:3f:96:49:6a:53:1a:05:0b:ba:90:db";
private SshServer server = defaultSshServer();
private SSHClient client = null;
private AtomicBoolean started = new AtomicBoolean(false);
private boolean autoStart = true;
public SshFixture(boolean autoStart) {
this.autoStart = autoStart;
}
public SshFixture() {
}
@Override
protected void before() throws Throwable {
if (autoStart) {
start();
}
}
@Override
protected void after() {
stopClient();
stopServer();
}
public void start() throws IOException {
server.start();
started.set(true);
}
public SSHClient setupConnectedDefaultClient() throws IOException {
return connectClient(setupDefaultClient());
}
public SSHClient setupDefaultClient() {
return setupClient(new DefaultConfig());
}
public SSHClient setupClient(Config config) {
if (client == null) {
client = new SSHClient(config);
client.addHostKeyVerifier(fingerprint);
}
return client;
}
public SSHClient getClient() {
if (client != null) {
return client;
}
throw new IllegalStateException("First call one of the setup*Client methods");
}
public SSHClient connectClient(SSHClient client) throws IOException {
client.connect(server.getHost(), server.getPort());
return client;
}
private SshServer defaultSshServer() {
SshServer sshServer = SshServer.setUpDefaultServer();
sshServer.setPort(randomPort());
sshServer.setKeyPairProvider(new FileKeyPairProvider(new String[]{hostkey}));
sshServer.setPasswordAuthenticator(new PasswordAuthenticator() {
@Override
public boolean authenticate(String username, String password, ServerSession session) {
return username.equals(password);
}
});
sshServer.setGSSAuthenticator(new BogusGSSAuthenticator());
sshServer.setSubsystemFactories(Arrays.<NamedFactory<Command>>asList(new SftpSubsystem.Factory()));
sshServer.setCommandFactory(new ScpCommandFactory(new CommandFactory() {
public Command createCommand(String command) {
EnumSet<ProcessShellFactory.TtyOptions> ttyOptions;
if (OsUtils.isUNIX()) {
ttyOptions = EnumSet.of(ProcessShellFactory.TtyOptions.ONlCr);
} else {
ttyOptions = EnumSet.of(ProcessShellFactory.TtyOptions.Echo, ProcessShellFactory.TtyOptions.ICrNl, ProcessShellFactory.TtyOptions.ONlCr);
}
return new ProcessShellFactory(command.split(" "), ttyOptions).create();
}
}));
return sshServer;
}
private int randomPort() {
try {
ServerSocket s = null;
try {
s = new ServerSocket(0);
return s.getLocalPort();
} finally {
if (s != null)
s.close();
}
} catch (IOException e) {
throw new RuntimeException(e);
}
}
public void stopClient() {
if (client != null && client.isConnected()) {
try {
client.disconnect();
} catch (IOException e) {
throw new RuntimeException(e);
} finally {
client = null;
}
} else if (client != null) {
client = null;
}
}
public void stopServer() {
if (started.get()) {
try {
server.stop();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
}

View File

@@ -1,20 +0,0 @@
package com.hierynomus.sshj.test.util;
import net.schmizz.sshj.common.IOUtils;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Writer;
public class FileUtil {
public static void writeToFile(File f, String content) throws IOException {
FileWriter w = new FileWriter(f);
try {
w.write(content);
} finally {
IOUtils.closeQuietly(w);
}
}
}

View File

@@ -1,52 +0,0 @@
package com.hierynomus.sshj.userauth;
import com.hierynomus.sshj.test.SshFixture;
import net.schmizz.sshj.SSHClient;
import net.schmizz.sshj.userauth.method.AuthGssApiWithMic;
import net.schmizz.sshj.util.gss.BogusGSSManager;
import org.junit.Rule;
import org.junit.Test;
import javax.security.auth.login.AppConfigurationEntry;
import javax.security.auth.login.Configuration;
import javax.security.auth.login.LoginContext;
import java.util.Collections;
import static org.junit.Assert.assertTrue;
public class GssApiTest {
@Rule
public SshFixture fixture = new SshFixture();
private static final String LOGIN_CONTEXT_NAME = "TestLoginContext";
private static class TestAuthConfiguration extends Configuration {
private AppConfigurationEntry entry = new AppConfigurationEntry(
"testLoginModule",
AppConfigurationEntry.LoginModuleControlFlag.REQUIRED,
Collections.<String, Object> emptyMap());
@Override
public AppConfigurationEntry[] getAppConfigurationEntry(String name) {
if (name.equals(LOGIN_CONTEXT_NAME)) {
return new AppConfigurationEntry[] { entry };
} else {
return new AppConfigurationEntry[0];
}
}
}
@Test
public void authenticated() throws Exception {
AuthGssApiWithMic authMethod = new AuthGssApiWithMic(
new LoginContext(LOGIN_CONTEXT_NAME, null, null, new TestAuthConfiguration()),
Collections.singletonList(BogusGSSManager.KRB5_MECH),
new BogusGSSManager());
SSHClient defaultClient = fixture.setupConnectedDefaultClient();
defaultClient.auth("user", authMethod);
assertTrue(defaultClient.isAuthenticated());
}
}

View File

@@ -1,39 +1,58 @@
package com.hierynomus.sshj.transport;
/**
* Copyright 2009 sshj contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.schmizz.sshj.transport;
import com.hierynomus.sshj.test.SshFixture;
import net.schmizz.sshj.SSHClient;
import net.schmizz.sshj.common.DisconnectReason;
import net.schmizz.sshj.transport.DisconnectListener;
import net.schmizz.sshj.transport.TransportException;
import net.schmizz.sshj.util.BasicFixture;
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import java.io.IOException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
public class DisconnectionTest {
private AtomicBoolean disconnected = null;
public class Disconnection {
@Rule
public SshFixture fixture = new SshFixture();
private final BasicFixture fixture = new BasicFixture();
private boolean notified;
@Before
public void setupFlag() throws IOException {
disconnected = new AtomicBoolean(false);
// Initialize the client
SSHClient defaultClient = fixture.setupDefaultClient();
defaultClient.getTransport().setDisconnectListener(new DisconnectListener() {
public void setUp()
throws IOException {
fixture.init();
notified = false;
fixture.getClient().getTransport().setDisconnectListener(new DisconnectListener() {
@Override
public void notifyDisconnect(DisconnectReason reason, String message) {
disconnected.set(true);
notified = true;
}
});
fixture.connectClient(defaultClient);
}
@After
public void tearDown()
throws IOException, InterruptedException {
fixture.done();
}
private boolean joinToClientTransport(int seconds) {
@@ -48,8 +67,8 @@ public class DisconnectionTest {
@Test
public void listenerNotifiedOnClientDisconnect()
throws IOException {
fixture.getClient().disconnect();
assertTrue(disconnected.get());
fixture.stopClient();
assertTrue(notified);
}
@Test
@@ -57,13 +76,13 @@ public class DisconnectionTest {
throws InterruptedException, IOException {
fixture.stopServer();
joinToClientTransport(2);
assertTrue(disconnected.get());
assertTrue(notified);
}
@Test
public void joinNotifiedOnClientDisconnect()
throws IOException {
fixture.getClient().disconnect();
fixture.stopClient();
assertTrue(joinToClientTransport(2));
}
@@ -74,4 +93,4 @@ public class DisconnectionTest {
assertFalse(joinToClientTransport(2));
}
}
}

View File

@@ -29,7 +29,6 @@ import java.security.PublicKey;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.CoreMatchers.instanceOf;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
@@ -79,7 +78,6 @@ public class OpenSSHKnownHostsTest {
assertTrue(kh.verify("schmizz.net", 22, key));
assertTrue(kh.verify("69.163.155.180", 22, key));
assertFalse(kh.verify("69.163.155.18", 22, key));
}
@Test

View File

@@ -33,11 +33,9 @@ package net.schmizz.sshj.util;
import net.schmizz.sshj.SSHClient;
import net.schmizz.sshj.transport.TransportException;
import net.schmizz.sshj.userauth.UserAuthException;
import org.apache.sshd.SshServer;
import org.apache.sshd.common.keyprovider.FileKeyPairProvider;
import org.apache.sshd.server.PasswordAuthenticator;
import org.apache.sshd.server.auth.gss.GSSAuthenticator;
import org.apache.sshd.server.session.ServerSession;
import java.io.IOException;
@@ -52,8 +50,6 @@ public class BasicFixture {
public static final String hostname = "localhost";
public final int port = gimmeAPort();
private GSSAuthenticator gssAuthenticator;
private SSHClient client;
private SshServer server;
@@ -103,7 +99,6 @@ public class BasicFixture {
return false;
}
});
server.setGSSAuthenticator(gssAuthenticator);
server.start();
serverRunning = true;
}
@@ -142,10 +137,6 @@ public class BasicFixture {
return client;
}
public void setGssAuthenticator(GSSAuthenticator gssAuthenticator) {
this.gssAuthenticator = gssAuthenticator;
}
public void dummyAuth()
throws UserAuthException, TransportException {
server.setPasswordAuthenticator(new BogusPasswordAuthenticator());

View File

@@ -1,22 +0,0 @@
package net.schmizz.sshj.util.gss;
import org.apache.sshd.server.auth.gss.GSSAuthenticator;
import org.ietf.jgss.GSSCredential;
import org.ietf.jgss.GSSException;
import org.ietf.jgss.GSSManager;
public class BogusGSSAuthenticator
extends GSSAuthenticator {
private final GSSManager manager = new BogusGSSManager();
@Override
public GSSManager getGSSManager() {
return manager;
}
@Override
public GSSCredential getGSSCredential(GSSManager mgr) throws GSSException {
return manager.createCredential(GSSCredential.ACCEPT_ONLY);
}
}

View File

@@ -1,243 +0,0 @@
package net.schmizz.sshj.util.gss;
import static net.schmizz.sshj.util.gss.BogusGSSManager.unavailable;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.nio.charset.Charset;
import java.util.Arrays;
import org.ietf.jgss.ChannelBinding;
import org.ietf.jgss.GSSContext;
import org.ietf.jgss.GSSCredential;
import org.ietf.jgss.GSSException;
import org.ietf.jgss.GSSName;
import org.ietf.jgss.MessageProp;
import org.ietf.jgss.Oid;
public class BogusGSSContext
implements GSSContext {
private static final byte[] INIT_TOKEN = fromString("INIT");
private static final byte[] ACCEPT_TOKEN = fromString("ACCEPT");
private static final byte[] MIC = fromString("LGTM");
private static byte[] fromString(String s) {
return s.getBytes(Charset.forName("UTF-8"));
}
private boolean initialized = false;
private boolean accepted = false;
private boolean integState = false;
private boolean mutualAuthState = false;
@Override
public byte[] initSecContext(byte[] inputBuf, int offset, int len) throws GSSException {
initialized = true;
return INIT_TOKEN;
}
@Override
public int initSecContext(InputStream inStream, OutputStream outStream) throws GSSException {
throw unavailable();
}
@Override
public byte[] acceptSecContext(byte[] inToken, int offset, int len) throws GSSException {
accepted = Arrays.equals(INIT_TOKEN, Arrays.copyOfRange(inToken, offset, offset + len));
return ACCEPT_TOKEN;
}
@Override
public void acceptSecContext(InputStream inStream, OutputStream outStream) throws GSSException {
throw unavailable();
}
@Override
public boolean isEstablished() {
return initialized || accepted;
}
@Override
public void dispose() throws GSSException {}
@Override
public int getWrapSizeLimit(int qop, boolean confReq, int maxTokenSize) throws GSSException {
throw unavailable();
}
@Override
public byte[] wrap(byte[] inBuf, int offset, int len, MessageProp msgProp) throws GSSException {
throw unavailable();
}
@Override
public void wrap(InputStream inStream, OutputStream outStream, MessageProp msgProp) throws GSSException {
throw unavailable();
}
@Override
public byte[] unwrap(byte[] inBuf, int offset, int len, MessageProp msgProp) throws GSSException {
throw unavailable();
}
@Override
public void unwrap(InputStream inStream, OutputStream outStream, MessageProp msgProp) throws GSSException {
throw unavailable();
}
@Override
public byte[] getMIC(byte[] inMsg, int offset, int len, MessageProp msgProp) throws GSSException {
return MIC;
}
@Override
public void getMIC(InputStream inStream, OutputStream outStream, MessageProp msgProp) throws GSSException {
throw unavailable();
}
@Override
public void verifyMIC(byte[] inToken, int tokOffset, int tokLen, byte[] inMsg, int msgOffset, int msgLen, MessageProp msgProp) throws GSSException {
if (!Arrays.equals(MIC, Arrays.copyOfRange(inToken, tokOffset, tokOffset + tokLen))) {
throw new GSSException(GSSException.BAD_MIC);
}
}
@Override
public void verifyMIC(InputStream tokStream, InputStream msgStream, MessageProp msgProp) throws GSSException {
throw unavailable();
}
@Override
public byte[] export() throws GSSException {
throw unavailable();
}
@Override
public void requestMutualAuth(boolean state) throws GSSException {
this.mutualAuthState = state;
}
@Override
public void requestInteg(boolean state) throws GSSException {
this.integState = state;
}
@Override
public void requestReplayDet(boolean state) throws GSSException {
throw unavailable();
}
@Override
public void requestSequenceDet(boolean state) throws GSSException {
throw unavailable();
}
@Override
public void requestCredDeleg(boolean state) throws GSSException {
throw unavailable();
}
@Override
public void requestAnonymity(boolean state) throws GSSException {
throw unavailable();
}
@Override
public void requestConf(boolean state) throws GSSException {
throw unavailable();
}
@Override
public void requestLifetime(int lifetime) throws GSSException {
throw unavailable();
}
@Override
public void setChannelBinding(ChannelBinding cb) throws GSSException {
throw unavailable();
}
@Override
public boolean getMutualAuthState() {
return mutualAuthState;
}
@Override
public boolean getIntegState() {
return integState;
}
@Override
public boolean getCredDelegState() {
return false;
}
@Override
public boolean getReplayDetState() {
return false;
}
@Override
public boolean getSequenceDetState() {
return false;
}
@Override
public boolean getAnonymityState() {
return false;
}
@Override
public boolean isTransferable() throws GSSException {
return false;
}
@Override
public boolean isProtReady() {
return false;
}
@Override
public boolean getConfState() {
return false;
}
@Override
public int getLifetime() {
return INDEFINITE_LIFETIME;
}
@Override
public GSSName getSrcName() throws GSSException {
try {
String hostname = InetAddress.getLocalHost().getCanonicalHostName();
return new BogusGSSName("user@" + hostname, GSSName.NT_HOSTBASED_SERVICE);
} catch (UnknownHostException e) {
throw new IllegalStateException(e);
}
}
@Override
public GSSName getTargName() throws GSSException {
throw unavailable();
}
@Override
public Oid getMech() throws GSSException {
return BogusGSSManager.KRB5_MECH;
}
@Override
public GSSCredential getDelegCred() throws GSSException {
throw unavailable();
}
@Override
public boolean isInitiator() throws GSSException {
return false;
}
}

View File

@@ -1,87 +0,0 @@
package net.schmizz.sshj.util.gss;
import static net.schmizz.sshj.util.gss.BogusGSSManager.unavailable;
import org.ietf.jgss.GSSCredential;
import org.ietf.jgss.GSSException;
import org.ietf.jgss.GSSName;
import org.ietf.jgss.Oid;
public class BogusGSSCredential
implements GSSCredential {
private final GSSName name;
private final int usage;
public BogusGSSCredential(GSSName name, int usage) {
this.name = name;
this.usage = usage;
}
@Override
public void dispose() throws GSSException {}
@Override
public GSSName getName() throws GSSException {
return name;
}
@Override
public GSSName getName(Oid mech) throws GSSException {
return name.canonicalize(mech);
}
@Override
public int getRemainingLifetime() throws GSSException {
return INDEFINITE_LIFETIME;
}
@Override
public int getRemainingInitLifetime(Oid mech) throws GSSException {
return INDEFINITE_LIFETIME;
}
@Override
public int getRemainingAcceptLifetime(Oid mech) throws GSSException {
return INDEFINITE_LIFETIME;
}
@Override
public int getUsage() throws GSSException {
return usage;
}
@Override
public int getUsage(Oid mech) throws GSSException {
return usage;
}
@Override
public Oid[] getMechs() throws GSSException {
return new Oid[] { BogusGSSManager.KRB5_MECH };
}
@Override
public void add(GSSName name, int initLifetime, int acceptLifetime, Oid mech, int usage) throws GSSException {
throw unavailable();
}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
@Override
public int hashCode() {
return (name == null ? 0 : name.hashCode());
}
@Override
public boolean equals(Object obj) {
if (!(obj instanceof BogusGSSCredential)) {
return false;
}
GSSName otherName = ((BogusGSSCredential) obj).name;
return name == null ? otherName == null : name.equals((Object) otherName);
}
}

View File

@@ -1,106 +0,0 @@
package net.schmizz.sshj.util.gss;
import java.security.Provider;
import org.apache.sshd.server.auth.gss.UserAuthGSS;
import org.ietf.jgss.GSSContext;
import org.ietf.jgss.GSSCredential;
import org.ietf.jgss.GSSException;
import org.ietf.jgss.GSSManager;
import org.ietf.jgss.GSSName;
import org.ietf.jgss.Oid;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Implements a fake Kerberos 5 mechanism. MINA only supports Kerberos 5 over
* GSS-API, so we can't implement a separate mechanism.
*/
public class BogusGSSManager
extends GSSManager {
public static final Oid KRB5_MECH = UserAuthGSS.KRB5_MECH;
private static final Logger log = LoggerFactory.getLogger(BogusGSSManager.class);
@Override
public Oid[] getMechs() {
return new Oid[] { KRB5_MECH };
}
@Override
public Oid[] getNamesForMech(Oid mech) throws GSSException {
return new Oid[] { GSSName.NT_EXPORT_NAME, GSSName.NT_HOSTBASED_SERVICE };
}
@Override
public Oid[] getMechsForName(Oid nameType) {
return new Oid[] { KRB5_MECH };
}
@Override
public GSSName createName(String nameStr, Oid nameType) throws GSSException {
return new BogusGSSName(nameStr, nameType);
}
@Override
public GSSName createName(byte[] name, Oid nameType) throws GSSException {
throw unavailable();
}
@Override
public GSSName createName(String nameStr, Oid nameType, Oid mech) throws GSSException {
return this.createName(nameStr, nameType);
}
@Override
public GSSName createName(byte[] name, Oid nameType, Oid mech) throws GSSException {
throw unavailable();
}
@Override
public GSSCredential createCredential(int usage) throws GSSException {
return new BogusGSSCredential(null, usage);
}
@Override
public GSSCredential createCredential(GSSName name, int lifetime, Oid mech, int usage) throws GSSException {
return new BogusGSSCredential(name, usage);
}
@Override
public GSSCredential createCredential(GSSName name, int lifetime, Oid[] mechs, int usage) throws GSSException {
return new BogusGSSCredential(name, usage);
}
@Override
public GSSContext createContext(GSSName peer, Oid mech, GSSCredential myCred, int lifetime) throws GSSException {
return new BogusGSSContext();
}
@Override
public GSSContext createContext(GSSCredential myCred) throws GSSException {
return new BogusGSSContext();
}
@Override
public GSSContext createContext(byte[] interProcessToken) throws GSSException {
throw unavailable();
}
@Override
public void addProviderAtFront(Provider p, Oid mech) throws GSSException {
throw unavailable();
}
@Override
public void addProviderAtEnd(Provider p, Oid mech) throws GSSException {
throw unavailable();
}
static GSSException unavailable() throws GSSException {
GSSException e = new GSSException(GSSException.UNAVAILABLE);
log.error(e.getMessage(), e);
throw e;
}
}

View File

@@ -1,58 +0,0 @@
package net.schmizz.sshj.util.gss;
import static net.schmizz.sshj.util.gss.BogusGSSManager.unavailable;
import org.ietf.jgss.GSSException;
import org.ietf.jgss.GSSName;
import org.ietf.jgss.Oid;
public class BogusGSSName
implements GSSName {
private final String name;
private final Oid oid;
public BogusGSSName(String name, Oid oid) {
this.name = name;
this.oid = oid;
}
@Override
public boolean equals(GSSName another) throws GSSException {
if (!(another instanceof BogusGSSName)) {
throw new GSSException(GSSException.BAD_NAMETYPE);
}
BogusGSSName otherName = (BogusGSSName) another;
return name.equals(otherName.name) && oid.equals(otherName.oid);
}
@Override
public GSSName canonicalize(Oid mech) throws GSSException {
return this;
}
@Override
public byte[] export() throws GSSException {
throw unavailable();
}
@Override
public Oid getStringNameType() throws GSSException {
return oid;
}
@Override
public boolean isAnonymous() {
return false;
}
@Override
public boolean isMN() {
return false;
}
@Override
public String toString() {
return name;
}
}