Drakon MUD Server: Dev Diary 1

So I’ve been tinkering around with writing a MUD server in java, one that uses all the new network features we’ve developed since MUDs were a big deal. Basically, I want to use an SSH connection to secure the communication, and support an external API so other developers could write more elaborate clients. My ultimate goal is to use this multiplayer real-time server and exposed API to provide the backend and interaction for multiplayer games on mobile clients.

Honestly, I have no idea how I’m going to do this, because I’ve never written a MUD server or toyed around with SSH like this.

So my first diary (and probably the first few iterations of them) will be research, trying stuff out and seeing what works and what doesn’t.

Step 1: SSH Research

So if I want my server to be secure, I’m going to need to know HOW to secure it, so I might as well start by writing an SSH server, and adding a MUD server underneath it. So how does one write an SSH server?
A bit of Googling brought up Apache MINA: While this project promises a lot of things, the important thing here is it’s support for “SSHd : A Java library supporting the SSHH protocol”

Awesome, this should be easy! I just pull down the code from https://github.com/apache/mina-sshd, compile it and that should give me the dependencies I need. Yea, it’s not that easy.

I won’t describe my dependency hell to you because it’s a little tangential, but if you want more details (or help) just send me a message. I started a new java project with dependencies on:

  • commons-codec-1.9
  • gson-2.2.4
  • log4j-1.2.17
  • slf4j-api-1.7.6
  • slf4j-log4j12-1.7.6
  • sshd-core-0.10.1

Set up a simple echo server

There are a few example SSHd servers in the code, and a really basic example of how to use the library can be found here.

int port = 5180;
SshServer sshServer = SshServer.setUpDefaultServer();
sshServer.setPort(port);
sshServer.setKeyPairProvider(Utils.createTestHostKeyProvider());
sshServer.setShellFactory(new EchoShellFactory());
sshServer.setPasswordAuthenticator(new BogusPasswordAuthenticator());

try {
server.start();
} catch (IOException e) {
e.printStackTrace();
}

This is pretty much a straight copy from the test file. But an SSH server that lets anyone connect is kind of silly, since we’re trying to do this securely. So instead of a BogusPasswordAuthenticator, let’s make a DrakonPasswordAuthencator. I want it to read in user data from a JSON file, compare usernames and passwords, and if the info matches, “log in” that user. Which really just means preload that user-specific data.

Programming by intention usually leads to stuff I understand pretty well, so the first thing I did was design out what the users.json file would look like.


[
{
"id" : 1,
"name": "admin",
"password": "admin",
"password": "d033e22ae348aeb5660fc2140aec35850c4da997",
"email": "admin@localhost"
}
]

NOTE: using flaws (or features) of JSON, I put the password in plaintext above the actual password definition. When parsing the file, the last key is the only one saved, so I can “comment” the user data file with the plaintext password. Don’t need a double password definition, and definitely would not store plaintext passwords.

Password is a SHA1 hash of the password “admin”, so to log in to the server we would want to type something like:
$ ssh admin@localhost -p 5180

Now I just need a way to parse the user file and decide if the login information is correct or not. First, I write my own PasswordAuthenticator.


package com.eyeofmidas.drakon.auth;

import java.util.ArrayList;

import org.apache.sshd.server.PasswordAuthenticator;
import org.apache.sshd.server.session.ServerSession;

import com.eyeofmidas.drakon.user.User;
import com.eyeofmidas.drakon.user.UserFileReader;

public class DrakonPasswordAuthenticator implements PasswordAuthenticator {

@Override
public boolean authenticate(String username, String password, ServerSession session) {
UserFileReader userFileReader = new UserFileReader();
ArrayList users = userFileReader.read("data/users.json");
for(User user : users) {
if(user.isAuthUser(username, password)){
return true;
}
}
return false;
}

}

The UserFileReader really just opens a connection to the file and reads in the json data one element at a time. It will read in all the users, building an ArrayList of User objects, and then return it to the authenticator. The User object is mostly a dummy object that holds the unique information for one particular user, but it also has a function “isAuthUser” that does a bit of hashing and matching to determine if the username and password match the user object.


package com.eyeofmidas.drakon.user;

import org.apache.commons.codec.digest.DigestUtils;

public class User {

private int id;
private String name;
private String password;
private String email;

public void setId(int nextInt) {
id = nextInt;
}

public void setName(String nextString) {
name = nextString;
}

public void setPassword(String nextString) {
password = nextString;
}

public int getId() {
return id;
}

public String getName() {
return name;
}

public String getEmail() {
return email;
}

public boolean isAuthUser(String username, String userPassword) {
userPassword = DigestUtils.sha1Hex(userPassword);
return (name.equals(username) && password.equals(userPassword));
}

public void setEmail(String nextString) {
email = nextString;
}

}

Enable password authentication

So now we have a class that reads in a json collection of user data, creates an arraylist of Users, and our authenticator can now use that to determine who is logging in. Have to tell the server about it, though!


sshServer.setPasswordAuthenticator(new DrakonPasswordAuthenticator());

Cool! Now our server will only echo back to us if we’ve got the right username and password! Next time I’ll work on making the EchoServer do more than just echo, and maybe toy around with using private/public keys for authentication.

You can follow me along with my code here: https://github.com/EyeOfMidas/drakon

And I will gradually update this blog as I make changes.

Advertisements
Drakon MUD Server: Dev Diary 1

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s