Creating an SSH server

Lee Painter

The Maverick Synergy Java SSH API makes it incredibly simple to create your own SSH server. Let's dive straight in and take a 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 that 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 own program.

The startup of the server is asynchronous, so the start method will return after a successful start or throw an exception if the server could not be started. 

Of course with this minimal configuration, no users will be able to 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 login.

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 a number of different authenticators, including password, public key, 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 multiple password and/or multiple public key authenticators. For each type, password, or public key, they will be processed in the order you added them, if a user fails to authenticate with the first then 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 so we connected, 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. This is what you have already seen when you attempted to connect using the ssh command line to your running 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 own virtual shell implementation that provides an interactive shell which 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 if we use some of our built-in file system support. In order 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.0.0-SNAPSHOT</version>
   </dependency>

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

server.setFileFactory(new VirtualFileFactory( 
new VirtualMountTemplate("/", "tmp/${username}", 
new VFSFileFactory())));

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, download some files. You now have a working SSH server that supports SFTP.

Configuring Port Forwarding

By default, a client will not be able to use port forwarding with our example code. You have to explicitly enable forwarding in order 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 will be able to 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 also:

server.getForwardingPolicy().allowGatewayForwarding();

For more information on port forwarding configuration please see the Configuring port forwarding article. 

Further Reading

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

Authenticating users with Passwords

Authenticating users with Public Keys

Configuring SFTP

Implementing your own File System

Configuring Port Forwarding