11package com .github .stefanbirkner .fakesftpserver .rule ;
22
33
4- import com .jcraft .jsch .*;
5- import org .apache .commons .io .IOUtils ;
6- import org .assertj .core .api .ThrowableAssert .ThrowingCallable ;
7- import org .junit .Test ;
8- import org .junit .experimental .runners .Enclosed ;
9- import org .junit .runner .RunWith ;
4+ import static com .github .stefanbirkner .fakesftpserver .rule .Executor .executeTestThatThrowsExceptionWithRule ;
5+ import static com .github .stefanbirkner .fakesftpserver .rule .Executor .executeTestWithRule ;
6+ import static com .github .stefanbirkner .fishbowl .Fishbowl .exceptionThrownBy ;
7+ import static java .nio .charset .StandardCharsets .UTF_8 ;
8+ import static org .apache .commons .io .IOUtils .toByteArray ;
9+ import static org .assertj .core .api .Assertions .assertThat ;
10+ import static org .assertj .core .api .Assertions .assertThatThrownBy ;
11+ import static org .assertj .core .api .Assertions .catchThrowable ;
1012
1113import java .io .ByteArrayInputStream ;
1214import java .io .IOException ;
1315import java .io .InputStream ;
1416import java .net .ConnectException ;
17+ import java .net .URISyntaxException ;
1518import java .nio .file .Path ;
1619import java .nio .file .Paths ;
1720import java .util .Vector ;
1821import java .util .concurrent .atomic .AtomicInteger ;
1922
20- import static com .github .stefanbirkner .fakesftpserver .rule .Executor .executeTestThatThrowsExceptionWithRule ;
21- import static com .github .stefanbirkner .fakesftpserver .rule .Executor .executeTestWithRule ;
22- import static com .github .stefanbirkner .fishbowl .Fishbowl .exceptionThrownBy ;
23- import static java .nio .charset .StandardCharsets .UTF_8 ;
24- import static org .apache .commons .io .IOUtils .toByteArray ;
25- import static org .assertj .core .api .Assertions .assertThat ;
26- import static org .assertj .core .api .Assertions .assertThatThrownBy ;
27- import static org .assertj .core .api .Assertions .catchThrowable ;
23+ import org .apache .commons .io .IOUtils ;
24+ import org .assertj .core .api .ThrowableAssert .ThrowingCallable ;
25+ import org .junit .Before ;
26+ import org .junit .Test ;
27+ import org .junit .experimental .runners .Enclosed ;
28+ import org .junit .runner .RunWith ;
29+ import org .slf4j .LoggerFactory ;
30+
31+ import com .jcraft .jsch .ChannelSftp ;
32+ import com .jcraft .jsch .JSch ;
33+ import com .jcraft .jsch .JSchException ;
34+ import com .jcraft .jsch .Session ;
35+ import com .jcraft .jsch .SftpException ;
2836
2937/* Wording according to the draft:
3038 * http://tools.ietf.org/html/draft-ietf-secsh-filexfer-13
3139 */
3240@ RunWith (Enclosed .class )
3341public class FakeSftpServerRuleTest {
42+
43+ private static final org .slf4j .Logger log = LoggerFactory .getLogger (FakeSftpServerRuleTest .class );
44+
3445 private static final byte [] DUMMY_CONTENT = new byte []{1 , 4 , 2 , 4 , 2 , 4 };
3546 private static final int DUMMY_PORT = 46354 ;
3647 private static final InputStream DUMMY_STREAM = new ByteArrayInputStream (DUMMY_CONTENT );
3748 private static final JSch JSCH = new JSch ();
3849 private static final int TIMEOUT = 200 ;
50+ private static Path DUMMY_KEY ;
51+ private static Path DUMMY_AUTHORIZED_KEYS ;
52+ private static Path EMPTY_AUTHORIZED_KEYS ;
53+ private static final String DUMMY_KEY_PASSPHRASE = "unittest" ;
54+
55+ static {
56+ try {
57+ DUMMY_KEY = Paths .get (FakeSftpServerRuleTest .class .getResource ("/keys/dummy_key" ).toURI ());
58+ DUMMY_AUTHORIZED_KEYS = Paths .get (FakeSftpServerRuleTest .class .getResource ("/keys/dummy_key.pub" ).toURI ());
59+ EMPTY_AUTHORIZED_KEYS = Paths .get (FakeSftpServerRuleTest .class .getResource ("/keys/empty_authorized_keys" ).toURI ());
60+ } catch (URISyntaxException e ) {
61+ log .error ("Error loading SSH keys" , e );
62+ }
63+ }
3964
4065 public static class round_trip {
4166 @ Test
@@ -105,6 +130,24 @@ public void the_server_accepts_connections_with_password() {
105130 sftpServer
106131 );
107132 }
133+
134+ @ Test
135+ public void the_server_accepts_connections_with_identity () {
136+ FakeSftpServerRule sftpServer = new FakeSftpServerRule ();
137+ executeTestWithRule (
138+ () -> {
139+ Session session = createSessionWithIdentity (
140+ sftpServer ,
141+ "dummy user" ,
142+ DUMMY_KEY .toString (),
143+ DUMMY_KEY_PASSPHRASE
144+ );
145+ session .connect (TIMEOUT );
146+ JSCH .removeAllIdentity ();
147+ },
148+ sftpServer
149+ );
150+ }
108151 }
109152
110153 public static class server_with_credentials_immediately_set {
@@ -221,6 +264,99 @@ public void the_last_password_is_effective_if_addUser_is_called_multiple_times()
221264 }
222265 }
223266
267+ public static class server_with_identity_immediately_set {
268+
269+ Path privateKeyPath ;
270+ Path authorizedKeysPath ;
271+ @ Before
272+ public void setupIdentity () throws URISyntaxException {
273+ privateKeyPath = Paths .get (FakeSftpServerRuleTest .class .getResource ("/keys/dummy_key" ).toURI ());
274+ authorizedKeysPath = Paths .get (FakeSftpServerRuleTest .class .getResource ("/keys/dummy_key.pub" ).toURI ());
275+ }
276+
277+ @ Test
278+ public void the_server_accepts_connections_with_correct_identity () {
279+ FakeSftpServerRule sftpServer = new FakeSftpServerRule ()
280+ .addIdentity ("dummy user" , DUMMY_AUTHORIZED_KEYS );
281+ executeTestWithRule (
282+ () -> {
283+ Session session = createSessionWithIdentity (
284+ sftpServer ,
285+ "dummy user" ,
286+ DUMMY_KEY .toString (),
287+ DUMMY_KEY_PASSPHRASE
288+ );
289+ session .connect (TIMEOUT );
290+ JSCH .removeAllIdentity ();
291+ },
292+ sftpServer
293+ );
294+ }
295+
296+
297+ @ Test
298+ public void the_server_rejects_connections_with_wrong_passphrase () {
299+ FakeSftpServerRule sftpServer = new FakeSftpServerRule ()
300+ .addIdentity ("dummy user" , DUMMY_AUTHORIZED_KEYS );
301+ executeTestWithRule (
302+ () -> {
303+ Session session = createSessionWithIdentity (
304+ sftpServer ,
305+ "dummy user" ,
306+ DUMMY_KEY .toString (),
307+ "invalid"
308+ );
309+ assertAuthenticationFails (
310+ () -> session .connect (TIMEOUT )
311+ );
312+ JSCH .removeAllIdentity ();
313+ },
314+ sftpServer
315+ );
316+ }
317+
318+ @ Test
319+ public void the_server_rejects_connections_with_wrong_key () {
320+ FakeSftpServerRule sftpServer = new FakeSftpServerRule ()
321+ .addIdentity ("dummy user" , EMPTY_AUTHORIZED_KEYS );
322+ executeTestWithRule (
323+ () -> {
324+ Session session = createSessionWithIdentity (
325+ sftpServer ,
326+ "dummy user" ,
327+ DUMMY_KEY .toString (),
328+ DUMMY_KEY_PASSPHRASE
329+ );
330+ assertAuthenticationFails (
331+ () -> session .connect (TIMEOUT )
332+ );
333+ JSCH .removeAllIdentity ();
334+ },
335+ sftpServer
336+ );
337+ }
338+
339+ @ Test
340+ public void the_last_key_is_effective_if_addIdentity_is_called_multiple_times () {
341+ FakeSftpServerRule sftpServer = new FakeSftpServerRule ()
342+ .addIdentity ("dummy user" , EMPTY_AUTHORIZED_KEYS )
343+ .addIdentity ("dummy user" , DUMMY_AUTHORIZED_KEYS );
344+ executeTestWithRule (
345+ () -> {
346+ Session session = createSessionWithIdentity (
347+ sftpServer ,
348+ "dummy user" ,
349+ DUMMY_KEY .toString (),
350+ DUMMY_KEY_PASSPHRASE
351+ );
352+ session .connect (TIMEOUT );
353+ JSCH .removeAllIdentity ();
354+ },
355+ sftpServer
356+ );
357+ }
358+ }
359+
224360 private static Session createSessionWithCredentials (
225361 FakeSftpServerRule sftpServer ,
226362 String username ,
@@ -230,13 +366,24 @@ private static Session createSessionWithCredentials(
230366 username , password , sftpServer .getPort ()
231367 );
232368 }
369+
370+ private static Session createSessionWithIdentity (
371+ FakeSftpServerRule sftpServer ,
372+ String username ,
373+ String prvkey ,
374+ String passphrase
375+ ) throws JSchException {
376+ return FakeSftpServerRuleTest .createSessionWithIdentity (
377+ username , prvkey , passphrase , sftpServer .getPort ()
378+ );
379+ }
233380
234381 private static void assertAuthenticationFails (
235382 ThrowingCallable connectToServer
236383 ) {
237384 assertThatThrownBy (connectToServer )
238385 .isInstanceOf (JSchException .class )
239- .hasMessage ( " Auth fail" );
386+ .hasMessageMatching ( "( Auth|USERAUTH) fail" );
240387 }
241388 }
242389
@@ -1133,6 +1280,19 @@ private static Session createSessionWithCredentials(
11331280 session .setPassword (password );
11341281 return session ;
11351282 }
1283+
1284+ private static Session createSessionWithIdentity (
1285+ String username ,
1286+ String prvkey ,
1287+ String passphrase ,
1288+ int port
1289+ ) throws JSchException {
1290+ // if you need detailed information add a logger to JSCH
1291+ JSCH .addIdentity (prvkey , passphrase );
1292+ Session session = JSCH .getSession (username , "127.0.0.1" , port );
1293+ session .setConfig ("StrictHostKeyChecking" , "no" );
1294+ return session ;
1295+ }
11361296
11371297 private static byte [] downloadFile (
11381298 FakeSftpServerRule server ,
0 commit comments