Creating an SSH server

The Maverick Synergy Java SSH API simplifies creating your SSH server. Let’s dive in and look at the most simple service you can start and how to configure it.

The code below creates a server and starts it on port 2222

SshServer server = new SshServer(2222); 

Runtime.getRuntime().addShutdownHook(new Thread() { 
   public void run() { 
      server.close(); 
   } 
});

server.start();

What does this do?

  1. Creates the SshServer class, passing 2222 as the port on which we want to run the service. 
  2. Adds a shutdown hook to the Runtime class so the server gets closed if the JVM closes. This will help prevent warnings in your IDE, too.
  3. Starts the server

This is all that is needed to start an SSH server in your program.

The server’s start-up is asynchronous, so the start method will return after a successful start or throw an exception if the server cannot be started. 

Of course, with this minimal configuration, no users can log in and authenticate or access any resources because these have not been configured. 

Configure Authentication

Let’s add some code to allow a user to log in.

server.addAuthenticator(new InMemoryPasswordAuthenticator()
      .addUser("admin", "admin".toCharArray())); 

This uses a simple built-in class that holds usernames and passwords in memory. Authenticators are how users will identify and authenticate themselves to the server. We support several authenticators, including passwords, public keys, and challenge-response. All of which we will detail later in our documentation.

We can also add a similar authenticator for public keys:

server.addAuthenticator(new InMemoryPublicKeyAuthenticator() 
   .addAuthorizedKey("admin", 
      SshKeyUtils.getPublicKey(new File("keys/admin.pub"))));

This holds a static key in memory for the admin user. That user will now be able to authenticate via password or public key.

You can add as many authenticators as you want, including passwords and/or public-key authenticators. Each type, password, or public key will be processed in the order you added them; if a user fails to authenticate with the first, it will fall back to the next until all authenticators have been attempted. 

For now, you can try the server we have built out for yourself, fire it up and try to connect over SSH

ssh -p 2222 admin@localhost
password
Enter password for admin
Password:
This server does not support an interactive session.
Goodbye.
Connection to localhost closed.

Ok, we connected and authenticated, but the server closed the connection. This is because we have not configured any further resources for the user to access. 

These are the main areas we need to configure. 

Configuring Sessions

Sessions enable users to execute commands and start an interactive shell. If you do not intend to provide this feature to your users, you do not have to do anything else. The server is configured with an initial implementation of a session that stops the user from executing commands or starting a shell. You already saw this when you attempted to connect using the ssh command line to your server.

The scope of implementing a session provider is far beyond this getting-started documentation. If this is something you want to provide, then we recommend you review our Creating an interactive shell, article which outlines how to configure our virtual shell implementation that provides an interactive shell that you can write commands for in Java.

Configuring a File System

Providing a file system for your users is a much simpler task. We can do this with a single line of code using some of our built-in file system support. To use this, you should ensure you have the maverick-virtual-filesystem module installed. You can do this with Maven by adding the dependency:

   <dependency>
      <groupId>com.sshtools</groupId>
       <artifactId>maverick-virtual-filesystem</artifactId>
       <version>3.1.0</version>
   </dependency>

Then add the following code in-between creating the SshServer and before the call to start. 

server.setFileFactory(new FileFactory() {
  public AbstractFileFactory<?> getFileFactory(SshConnection con) 
		throws IOException, PermissionDeniedException {
   return new VirtualFileFactory(
	new VirtualMountTemplate("/", "tmp/" + con.getUsername(), 
	new VFSFileFactory(), true));
  }
});

What does this code do?

  1. We create an instance of VirtualFileFactory that allows you to build up a virtual file system by mapping virtual paths to external file resources.
  2. We create a single mount so that the user’s root folder is mapped to a folder under the current working directory that only the user can see, i.e. ‘tmp/<username>’.

Now try running your code with this file system enabled:

sftp -oPort=2222 admin@localhost
password
Enter password for admin
Password:
Connected to admin@localhost.
sftp>

Voila! We have connected and have an SFTP session. You can ls, but you will see nothing since the temporary folder will be empty. Go ahead and experiment, add some files, and download some files. You now have a working SSH server that supports SFTP.

Configuring Port Forwarding

By default, a client cannot use port forwarding with our example code. You have to explicitly enable forwarding for this to work.

You can do so by editing the forwarding policy object of the server.

server.getForwardingPolicy().allowForwarding();

For local forwarding, where a client connects to a remote host on the server’s network, they can access any host. 

For remote forwarding, the client will only be able to connect to remote forwarding interfaces from within the localhost of the server.

If you want to enable other computers on the server’s network to access a remote forwarding interface, then you need to enable gateway forwarding:

server.getForwardingPolicy().allowGatewayForwarding();

Please see the Configuring port forwarding article for more information on port forwarding configuration. 

Further Reading

Given this rather easy template to start building your own SSH server, please look at our further documentation on how to configure it to make it your own.

Authenticating users with Passwords

Authenticating users with Public Keys

Configuring SFTP

Implementing your File System

Configuring Port Forwarding