add pubkey auth
This commit is contained in:
parent
bdf67a89f7
commit
5a394749bf
24 changed files with 822 additions and 107 deletions
|
@ -121,9 +121,9 @@ public final class Server implements IThreadListener {
|
|||
private final List<Dimension> unload = Lists.<Dimension>newArrayList();
|
||||
private final Map<String, Position> warps = Maps.<String, Position>newTreeMap();
|
||||
private final CommandEnvironment scriptEnv = new CommandEnvironment(this);
|
||||
private final KeyPair keyPair;
|
||||
private final boolean debug;
|
||||
|
||||
private KeyPair keyPair;
|
||||
private WorldServer space;
|
||||
private ChannelFuture endpoint;
|
||||
|
||||
|
@ -169,7 +169,7 @@ public final class Server implements IThreadListener {
|
|||
Log.flushLog();
|
||||
}
|
||||
|
||||
public static void saveServerConfig(long time) {
|
||||
public static void saveServerConfig(long time, Server server) {
|
||||
TagObject data = new TagObject();
|
||||
data.setLong("Time", time);
|
||||
data.setLong("LastAccess", System.currentTimeMillis());
|
||||
|
@ -182,6 +182,10 @@ public final class Server implements IThreadListener {
|
|||
}
|
||||
data.setObject("Config", cfg);
|
||||
data.setObject("Universe", UniverseRegistry.toTags());
|
||||
if(server != null) {
|
||||
data.setByteArray("PrivateKey", server.getPrivateKey().getEncoded());
|
||||
data.setByteArray("PublicKey", server.getPublicKey().getEncoded());
|
||||
}
|
||||
File nfile = new File("server.cdt.tmp");
|
||||
File lfile = new File("server.cdt");
|
||||
try {
|
||||
|
@ -195,7 +199,7 @@ public final class Server implements IThreadListener {
|
|||
}
|
||||
}
|
||||
|
||||
public static long loadServerConfig() {
|
||||
public long loadServerConfig() {
|
||||
Config.clear();
|
||||
UniverseRegistry.clear();
|
||||
File file = new File("server.cdt");
|
||||
|
@ -216,6 +220,12 @@ public final class Server implements IThreadListener {
|
|||
Log.IO.info("Version: %s", version);
|
||||
Log.IO.info("Weltzeit: %d Ticks / %d Sekunden", time, time / 20L);
|
||||
Log.IO.info("Zuletzt geladen: %s", new SimpleDateFormat("dd.MM.yyyy HH:mm:ss").format(new Date(lastPlayed)));
|
||||
if(tag.hasByteArray("PrivateKey") && tag.hasByteArray("PublicKey")) {
|
||||
PrivateKey key = EncryptUtil.decodePrivateKey(tag.getByteArray("PrivateKey"));
|
||||
PublicKey pubkey = EncryptUtil.decodePublicKey(tag.getByteArray("PublicKey"));
|
||||
if(key != null && pubkey != null)
|
||||
this.keyPair = new KeyPair(pubkey, key);
|
||||
}
|
||||
return time;
|
||||
}
|
||||
catch(Exception e) {
|
||||
|
@ -258,7 +268,6 @@ public final class Server implements IThreadListener {
|
|||
}
|
||||
}
|
||||
}, "password");
|
||||
this.keyPair = EncryptUtil.generateKeyPair();
|
||||
}
|
||||
|
||||
public CommandEnvironment getScriptEnvironment() {
|
||||
|
@ -283,7 +292,7 @@ public final class Server implements IThreadListener {
|
|||
|
||||
public void saveWorldInfo() {
|
||||
if(!this.debug) {
|
||||
saveServerConfig(this.space.getDayTime());
|
||||
saveServerConfig(this.space.getDayTime(), this);
|
||||
WorldServer.saveWarps(this.warps);
|
||||
}
|
||||
}
|
||||
|
@ -452,7 +461,11 @@ public final class Server implements IThreadListener {
|
|||
public void run(long time) {
|
||||
if(!this.debug) {
|
||||
Converter.convert();
|
||||
long wtime = loadServerConfig();
|
||||
long wtime = this.loadServerConfig();
|
||||
if(this.keyPair == null) {
|
||||
Log.SYSTEM.info("Generiere neues Schlüsselpaar");
|
||||
this.keyPair = EncryptUtil.generateKeyPair();
|
||||
}
|
||||
// if(dtime == -1L) // {
|
||||
// dtime = World.START_TIME;
|
||||
//// Config.set("spawnDim", "1", null);
|
||||
|
@ -485,6 +498,8 @@ public final class Server implements IThreadListener {
|
|||
// }
|
||||
}
|
||||
else {
|
||||
Log.SYSTEM.info("Generiere temporäres Schlüsselpaar");
|
||||
this.keyPair = EncryptUtil.generateKeyPair();
|
||||
Config.clear();
|
||||
UniverseRegistry.clear();
|
||||
Config.set("daylightCycle", "false", false);
|
||||
|
@ -831,29 +846,41 @@ public final class Server implements IThreadListener {
|
|||
radius > 0 ? 0.0f : Config.spawnPitch, world.dimension.getDimensionId());
|
||||
}
|
||||
|
||||
public String addPlayer(NetConnection connection, String loginUser, String loginPass) {
|
||||
public String addPlayer(NetConnection connection, String loginUser, String loginPass, PublicKey loginKey) {
|
||||
TagObject tag = this.readPlayer(loginUser);
|
||||
Player conn = new Player(this, connection, loginUser);
|
||||
if(tag != null)
|
||||
conn.readTags(tag);
|
||||
if(Config.authenticate) {
|
||||
if(conn.getPassword() == null && conn.getPubkey() == null) {
|
||||
if(tag != null)
|
||||
return loginKey != null ? "Falscher Pubkey" : "Falsches Passwort";
|
||||
if(!Config.register)
|
||||
return "Anmeldung neuer Accounts ist auf diesem Server deaktiviert (Whitelisted)";
|
||||
if(Config.playerLimit > 0 && this.players.size() >= Config.playerLimit)
|
||||
return String.format("Der Server ist voll (%d/%d)!", this.players.size(), Config.playerLimit);
|
||||
if(loginKey != null) {
|
||||
conn.setPubkey(loginKey);
|
||||
Log.NETWORK.info(loginUser + " registrierte sich mit Pubkey");
|
||||
}
|
||||
else {
|
||||
if(loginPass == null || loginPass.length() == 0)
|
||||
return "Ein neues Passwort ist erforderlich um diesen Server zu betreten (mindestens " + Config.minPassLength + " Zeichen)";
|
||||
if(loginPass.length() < Config.minPassLength)
|
||||
return "Passwort ist zu kurz, mindestens " + Config.minPassLength + " Zeichen";
|
||||
conn.setPassword(loginPass);
|
||||
Log.NETWORK.info(loginUser + " registrierte sich mit Passwort");
|
||||
}
|
||||
}
|
||||
else if(conn.getPubkey() != null ? !conn.getPubkey().equals(loginKey) : !conn.getPassword().equals(loginPass)) {
|
||||
return loginKey != null ? "Falscher Pubkey" : "Falsches Passwort";
|
||||
}
|
||||
else {
|
||||
Log.NETWORK.info(loginUser + " loggte sich mit " + (loginKey != null ? "Pubkey" : "Passwort") + " ein");
|
||||
}
|
||||
}
|
||||
if(Config.playerLimit > 0 && this.players.size() >= Config.playerLimit && !conn.isAdmin())
|
||||
return String.format("Der Server ist voll (%d/%d)!", this.players.size(), Config.playerLimit);
|
||||
if(conn.getPassword() == null) {
|
||||
if(!Config.register)
|
||||
return "Anmeldung neuer Accounts ist auf diesem Server deaktiviert (Whitelisted)";
|
||||
if(loginPass.length() == 0)
|
||||
return "Ein neues Passwort ist erforderlich um diesen Server zu betreten (mindestens " + Config.minPassLength + " Zeichen)";
|
||||
if(loginPass.length() < Config.minPassLength)
|
||||
return "Passwort ist zu kurz, mindestens " + Config.minPassLength + " Zeichen";
|
||||
conn.setPassword(loginPass);
|
||||
Log.NETWORK.info(loginUser + " registrierte sich mit Passwort");
|
||||
}
|
||||
else if(!conn.getPassword().equals(loginPass)) {
|
||||
return "Falsches Passwort";
|
||||
}
|
||||
else {
|
||||
Log.NETWORK.info(loginUser + " loggte sich mit Passwort ein");
|
||||
}
|
||||
if(Config.compression >= 0) {
|
||||
connection.sendPacket(new RPacketEnableCompression(Config.compression), new ChannelFutureListener() {
|
||||
public void operationComplete(ChannelFuture future) throws Exception {
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package server.network;
|
||||
|
||||
import java.security.PrivateKey;
|
||||
import java.security.PublicKey;
|
||||
import java.security.SecureRandom;
|
||||
import java.util.Arrays;
|
||||
|
||||
|
@ -9,20 +10,28 @@ import javax.crypto.SecretKey;
|
|||
import common.color.TextColor;
|
||||
import common.init.Config;
|
||||
import common.log.Log;
|
||||
import common.net.util.concurrent.Future;
|
||||
import common.net.util.concurrent.GenericFutureListener;
|
||||
import common.network.ILoginHandler;
|
||||
import common.network.IPlayer;
|
||||
import common.network.NetConnection;
|
||||
import common.network.NetHandler;
|
||||
import common.packet.LPacketPasswordResponse;
|
||||
import common.packet.LPacketChallenge;
|
||||
import common.packet.LPacketPassword;
|
||||
import common.packet.LPacketPubkey;
|
||||
import common.packet.LPacketResponse;
|
||||
import common.packet.LPacketStartEncrypt;
|
||||
import common.packet.RPacketChallenge;
|
||||
import common.packet.RPacketDisconnect;
|
||||
import common.packet.RPacketRequestEncrypt;
|
||||
import common.packet.RPacketResponse;
|
||||
import common.packet.RPacketServerConfig;
|
||||
import server.Server;
|
||||
|
||||
public class LoginHandler extends NetHandler implements ILoginHandler
|
||||
{
|
||||
private static enum LoginState {
|
||||
INIT, ENCRYPT, PASSWORD, AUTHENTICATED, ACCEPTED;
|
||||
INIT, ENCRYPT, PROOF, PASSWORD, CHALLENGE, AUTHENTICATED, ACCEPTED;
|
||||
}
|
||||
|
||||
private static final SecureRandom TOKEN_RNG = new SecureRandom();
|
||||
|
@ -35,6 +44,7 @@ public class LoginHandler extends NetHandler implements ILoginHandler
|
|||
private String loginUser;
|
||||
private String loginPass;
|
||||
private byte[] loginToken;
|
||||
private PublicKey loginKey;
|
||||
|
||||
public LoginHandler(Server server, NetConnection netManager)
|
||||
{
|
||||
|
@ -97,7 +107,7 @@ public class LoginHandler extends NetHandler implements ILoginHandler
|
|||
//// player.netHandler.kick("Du hast dich von einen anderen Ort verbunden");
|
||||
// }
|
||||
// this.networkManager.sendPacket(new RPacketLoginSuccess());
|
||||
String kick = this.server.addPlayer(this.netManager, this.loginUser, this.loginPass);
|
||||
String kick = this.server.addPlayer(this.netManager, this.loginUser, this.loginPass, this.loginKey);
|
||||
if(kick != null)
|
||||
this.closeConnection(kick);
|
||||
else
|
||||
|
@ -107,10 +117,16 @@ public class LoginHandler extends NetHandler implements ILoginHandler
|
|||
public void sendLoginPacket() {
|
||||
if(this.state != LoginState.INIT)
|
||||
throw new IllegalStateException("Unerwartetes Handshake-Paket");
|
||||
this.state = LoginState.ENCRYPT;
|
||||
this.loginToken = new byte[4];
|
||||
TOKEN_RNG.nextBytes(this.loginToken);
|
||||
this.netManager.sendPacket(new RPacketRequestEncrypt(this.server.getPublicKey(), this.loginToken));
|
||||
if(Config.encrypt) {
|
||||
this.state = LoginState.ENCRYPT;
|
||||
this.loginToken = new byte[4];
|
||||
TOKEN_RNG.nextBytes(this.loginToken);
|
||||
this.netManager.sendPacket(new RPacketRequestEncrypt(this.server.getPublicKey(), this.loginToken));
|
||||
}
|
||||
else {
|
||||
this.state = LoginState.PASSWORD;
|
||||
this.netManager.sendPacket(new RPacketServerConfig(Config.accessRequired, Config.authenticate, Config.authenticate && Config.passwordAuth, false));
|
||||
}
|
||||
}
|
||||
|
||||
public void processEncryption(LPacketStartEncrypt packet) {
|
||||
|
@ -121,26 +137,81 @@ public class LoginHandler extends NetHandler implements ILoginHandler
|
|||
throw new IllegalStateException("Fehlerhaftes Token");
|
||||
SecretKey key = packet.getKey(pkey);
|
||||
this.netManager.startEncryption(key);
|
||||
this.state = LoginState.PROOF;
|
||||
}
|
||||
|
||||
public void processChallenge(LPacketChallenge packet) {
|
||||
if(this.state != LoginState.PROOF)
|
||||
throw new IllegalStateException("Unerwartetes Anforderungs-Paket");
|
||||
this.state = LoginState.PASSWORD;
|
||||
this.netManager.sendPacket(new RPacketResponse(packet.getToken(this.server.getPrivateKey())), new GenericFutureListener < Future <? super Void >> () {
|
||||
public void operationComplete(Future <? super Void > u) throws Exception {
|
||||
LoginHandler.this.netManager.sendPacket(new RPacketServerConfig(Config.accessRequired, Config.authenticate, Config.authenticate && Config.passwordAuth,
|
||||
Config.authenticate && Config.pubkeyAuth));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private boolean checkAccess(String access) {
|
||||
if(Config.accessRequired) {
|
||||
if(Config.password.length() < 8) {
|
||||
this.closeConnection("Es ist kein Zugangspasswort für diesen Server konfiguriert");
|
||||
return false;
|
||||
}
|
||||
if(!Config.password.equals(access)) {
|
||||
this.closeConnection("Falsches Zugangspasswort");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public void processPasswordResponse(LPacketPasswordResponse packetIn) {
|
||||
public void processPassword(LPacketPassword packet) {
|
||||
if(this.state != LoginState.PASSWORD)
|
||||
throw new IllegalStateException("Unerwartetes Passwort-Paket");
|
||||
this.loginUser = packetIn.getUser();
|
||||
this.loginPass = packetIn.getPassword();
|
||||
this.loginUser = packet.getUser();
|
||||
if(this.loginUser.isEmpty() || !IPlayer.isValidUser(this.loginUser))
|
||||
throw new IllegalStateException("Ungültiger Nutzername!");
|
||||
// if(!this.checkConnect(packetIn.getAccess()))
|
||||
// return;
|
||||
if(Config.password.length() < 8) {
|
||||
this.closeConnection("Es ist kein Zugangspasswort für diesen Server konfiguriert");
|
||||
return;
|
||||
if(!Config.passwordAuth && Config.authenticate) {
|
||||
this.closeConnection("Dieser Server " + (Config.pubkeyAuth && Config.encrypt ? "benötigt einen öffentlichen Schlüssel zur Authentifizierung" : "hat keine Authentifizierungsmethode konfiguriert"));
|
||||
return;
|
||||
}
|
||||
if(!Config.password.equals(packetIn.getAccess())) {
|
||||
this.closeConnection("Falsches Zugangspasswort");
|
||||
return;
|
||||
if(!this.checkAccess(packet.getAccess()))
|
||||
return;
|
||||
if(Config.authenticate)
|
||||
this.loginPass = packet.getPassword();
|
||||
this.state = LoginState.AUTHENTICATED;
|
||||
}
|
||||
|
||||
public void processPubkey(LPacketPubkey packet) {
|
||||
if(this.state != LoginState.PASSWORD)
|
||||
throw new IllegalStateException("Unerwartetes Pubkey-Paket");
|
||||
this.loginUser = packet.getUser();
|
||||
if(this.loginUser.isEmpty() || !IPlayer.isValidUser(this.loginUser))
|
||||
throw new IllegalStateException("Ungültiger Nutzername!");
|
||||
if((!Config.pubkeyAuth || !Config.encrypt) && Config.authenticate) {
|
||||
this.closeConnection("Dieser Server " + (Config.passwordAuth ? "benötigt ein Passwort zur Authentifizierung" : "hat keine Authentifizierungsmethode konfiguriert"));
|
||||
return;
|
||||
}
|
||||
if(!this.checkAccess(packet.getAccess()))
|
||||
return;
|
||||
if(Config.authenticate) {
|
||||
this.loginKey = packet.getKey();
|
||||
this.loginToken = new byte[32];
|
||||
TOKEN_RNG.nextBytes(this.loginToken);
|
||||
this.netManager.sendPacket(new RPacketChallenge(this.loginKey, this.loginToken));
|
||||
this.state = LoginState.CHALLENGE;
|
||||
}
|
||||
else {
|
||||
this.state = LoginState.AUTHENTICATED;
|
||||
}
|
||||
}
|
||||
|
||||
public void processResponse(LPacketResponse packet) {
|
||||
if(this.state != LoginState.CHALLENGE)
|
||||
throw new IllegalStateException("Unerwartetes Beweis-Paket");
|
||||
if(!Arrays.equals(this.loginToken, packet.getToken()))
|
||||
throw new IllegalStateException("Fehlerhaftes Beweis-Token");
|
||||
this.state = LoginState.AUTHENTICATED;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package server.network;
|
||||
|
||||
import java.security.PublicKey;
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedList;
|
||||
|
@ -110,6 +111,7 @@ import common.tileentity.TileEntitySign;
|
|||
import common.util.BlockPos;
|
||||
import common.util.BoundingBox;
|
||||
import common.util.ChunkPos;
|
||||
import common.util.EncryptUtil;
|
||||
import common.util.ExtMath;
|
||||
import common.util.Facing;
|
||||
import common.util.IntHashMap;
|
||||
|
@ -171,6 +173,7 @@ public class Player extends NetHandler implements ICrafting, Executor, IPlayer
|
|||
private int ping;
|
||||
private boolean deleted;
|
||||
private String password;
|
||||
private PublicKey pubkey;
|
||||
private boolean profiling;
|
||||
|
||||
private int selectionDim = Integer.MIN_VALUE;
|
||||
|
@ -347,6 +350,14 @@ public class Player extends NetHandler implements ICrafting, Executor, IPlayer
|
|||
public String getPassword() {
|
||||
return this.password;
|
||||
}
|
||||
|
||||
public void setPubkey(PublicKey key) {
|
||||
this.pubkey = key;
|
||||
}
|
||||
|
||||
public PublicKey getPubkey() {
|
||||
return this.pubkey;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
@ -619,6 +630,8 @@ public class Player extends NetHandler implements ICrafting, Executor, IPlayer
|
|||
this.admin = tag.getBool("admin");
|
||||
if(tag.hasString("password"))
|
||||
this.password = tag.getString("password");
|
||||
if(tag.hasByteArray("pubkey"))
|
||||
this.pubkey = EncryptUtil.decodePublicKey(tag.getByteArray("pubkey"));
|
||||
this.selected = tag.getInt("selected");
|
||||
List<TagObject> list = tag.getList("characters");
|
||||
for(int z = 0; z < list.size(); z++) {
|
||||
|
@ -633,6 +646,8 @@ public class Player extends NetHandler implements ICrafting, Executor, IPlayer
|
|||
tag.setBool("admin", this.admin);
|
||||
if(this.password != null)
|
||||
tag.setString("password", this.password);
|
||||
if(this.pubkey != null)
|
||||
tag.setByteArray("pubkey", this.pubkey.getEncoded());
|
||||
if(!this.characters.isEmpty()) {
|
||||
tag.setInt("selected", this.selected);
|
||||
List<TagObject> list = Lists.newArrayList();
|
||||
|
|
|
@ -1308,7 +1308,7 @@ public abstract class Converter {
|
|||
Config.set(rule.getValue(), rules.getString(rule.getKey()), false);
|
||||
}
|
||||
Log.IO.info("Speichere neue server.cdt ...");
|
||||
Server.saveServerConfig(World.START_TIME);
|
||||
Server.saveServerConfig(World.START_TIME, null);
|
||||
Weather weather = tag.getByte("thundering") != 0 ? Weather.THUNDER : (tag.getByte("raining") != 0 ? Weather.RAIN : Weather.CLEAR);
|
||||
if(weather != Weather.CLEAR) {
|
||||
TagObject dataTag = new TagObject();
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue