diff --git a/Mage.Client/src/main/java/mage/client/MageFrame.java b/Mage.Client/src/main/java/mage/client/MageFrame.java index daba6ff038e..542a99aef6f 100644 --- a/Mage.Client/src/main/java/mage/client/MageFrame.java +++ b/Mage.Client/src/main/java/mage/client/MageFrame.java @@ -699,7 +699,7 @@ public class MageFrame extends javax.swing.JFrame implements MageClient { public boolean connect(Connection connection) { client = new Client(instance); - boolean result = client.connect(connection.getUsername(), connection.getHost(), connection.getPort(), version); + boolean result = client.connect(connection.getUsername(), connection.getHost(), connection.getPort(), true, version); return result; } diff --git a/Mage.Client/src/test/java/mage/client/game/MultiConnectTest.java b/Mage.Client/src/test/java/mage/client/game/MultiConnectTest.java index d54a08287d1..99d7764055e 100644 --- a/Mage.Client/src/test/java/mage/client/game/MultiConnectTest.java +++ b/Mage.Client/src/test/java/mage/client/game/MultiConnectTest.java @@ -61,7 +61,7 @@ public class MultiConnectTest { connection.setPort(17171); connection.setProxyType(Connection.ProxyType.NONE); - client.connect(username, "localhost", 17171, version); + client.connect(username, "localhost", 17171, true, version); } public MageVersion getVersion() { @@ -75,6 +75,7 @@ public class MultiConnectTest { connected++; } + @Override public void disconnected(boolean errorCall) { logger.info("disconnected"); } @@ -158,8 +159,8 @@ public class MultiConnectTest { private void sleep(int ms) { try { Thread.sleep(ms); - } catch (Exception e) { - e.printStackTrace(); + } catch (InterruptedException e) { + logger.error("Error", e); } } } diff --git a/Mage.Network/src/main/java/org/mage/network/Client.java b/Mage.Network/src/main/java/org/mage/network/Client.java index 85ce8e10508..9e73ee6c5eb 100644 --- a/Mage.Network/src/main/java/org/mage/network/Client.java +++ b/Mage.Network/src/main/java/org/mage/network/Client.java @@ -10,11 +10,14 @@ import io.netty.channel.socket.nio.NioSocketChannel; import io.netty.handler.codec.serialization.ClassResolvers; import io.netty.handler.codec.serialization.ObjectDecoder; import io.netty.handler.codec.serialization.ObjectEncoder; +import io.netty.handler.ssl.SslContext; +import io.netty.handler.ssl.util.InsecureTrustManagerFactory; import io.netty.handler.timeout.IdleStateHandler; import java.util.Collection; import java.util.List; import java.util.Set; import java.util.UUID; +import javax.net.ssl.SSLException; import mage.cards.decks.DeckCardLists; import mage.constants.ManaType; import mage.constants.PlayerAction; @@ -59,9 +62,12 @@ public class Client { private final ClientRegisteredMessageHandler clientRegisteredMessageHandler; private final ServerMessageHandler serverMessageHandler; + private SslContext sslCtx; private Channel channel; private EventLoopGroup group; - private String username; + private String username; + private String host; + private int port; public Client(MageClient client) { this.client = client; @@ -73,12 +79,19 @@ public class Client { serverMessageHandler = new ServerMessageHandler(); } - public boolean connect(String userName, String host, int port, MageVersion version) { + public boolean connect(String userName, String host, int port, boolean ssl, MageVersion version) { this.username = userName; + this.host = host; + this.port = port; group = new NioEventLoopGroup(); try { + if (ssl) { + sslCtx = SslContext.newClientContext(InsecureTrustManagerFactory.INSTANCE); + } else { + sslCtx = null; + } Bootstrap b = new Bootstrap(); b.group(group) .channel(NioSocketChannel.class) @@ -90,7 +103,7 @@ public class Client { clientRegisteredMessageHandler.registerClient(); client.connected(userName + "@" + host + ":" + port + " "); return true; - } catch (InterruptedException ex) { + } catch (SSLException | InterruptedException ex) { logger.fatal("Error connecting", ex); client.inform("Error connecting", MessageType.ERROR); group.shutdownGracefully(); @@ -103,6 +116,9 @@ public class Client { @Override public void initChannel(SocketChannel ch) throws Exception { + if (sslCtx != null) { + ch.pipeline().addLast(sslCtx.newHandler(ch.alloc(), host, port)); + } ch.pipeline().addLast(new ObjectDecoder(ClassResolvers.cacheDisabled(null))); ch.pipeline().addLast(new ObjectEncoder()); diff --git a/Mage.Network/src/main/java/org/mage/network/Server.java b/Mage.Network/src/main/java/org/mage/network/Server.java index d19b87bacd2..41511f7e43e 100644 --- a/Mage.Network/src/main/java/org/mage/network/Server.java +++ b/Mage.Network/src/main/java/org/mage/network/Server.java @@ -14,6 +14,8 @@ import io.netty.handler.codec.serialization.ObjectDecoder; import io.netty.handler.codec.serialization.ObjectEncoder; import io.netty.handler.logging.LogLevel; import io.netty.handler.logging.LoggingHandler; +import io.netty.handler.ssl.SslContext; +import io.netty.handler.ssl.util.SelfSignedCertificate; import io.netty.handler.timeout.IdleStateHandler; import io.netty.util.concurrent.DefaultEventExecutorGroup; import io.netty.util.concurrent.EventExecutorGroup; @@ -47,6 +49,8 @@ public class Server { private static final int IDLE_TIMEOUT = 60; public static final ChannelGroup clients = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE); + + private SslContext sslCtx; private final HeartbeatHandler heartbeatHandler; private final PingMessageHandler pingMessageHandler = new PingMessageHandler(); @@ -69,7 +73,15 @@ public class Server { serverMessageHandler = new ServerMessageHandler(server); } - public void start(int port) { + public void start(int port, boolean ssl) throws Exception { + + if (ssl) { + SelfSignedCertificate ssc = new SelfSignedCertificate(); + sslCtx = SslContext.newServerContext(ssc.certificate(), ssc.privateKey()); + } else { + sslCtx = null; + } + EventLoopGroup bossGroup = new NioEventLoopGroup(); EventLoopGroup workerGroup = new NioEventLoopGroup(); @@ -95,6 +107,9 @@ public class Server { @Override public void initChannel(SocketChannel ch) throws Exception { + if (sslCtx != null) { + ch.pipeline().addLast(sslCtx.newHandler(ch.alloc())); + } ch.pipeline().addLast(new ObjectDecoder(ClassResolvers.cacheDisabled(null))); ch.pipeline().addLast(new ObjectEncoder()); diff --git a/Mage.Server/config/config.xml b/Mage.Server/config/config.xml index ec01eac5b80..62049a2fc80 100644 --- a/Mage.Server/config/config.xml +++ b/Mage.Server/config/config.xml @@ -35,6 +35,7 @@ userNamePattern="[^a-z0-9_]" maxAiOpponents="15" saveGameActivated="false" + useSSL="true" /> diff --git a/Mage.Server/src/main/java/mage/server/Main.java b/Mage.Server/src/main/java/mage/server/Main.java index d3698f34e3e..e269ffa5d01 100644 --- a/Mage.Server/src/main/java/mage/server/Main.java +++ b/Mage.Server/src/main/java/mage/server/Main.java @@ -212,7 +212,7 @@ public class Main implements MageServer { try { instance = new Main(adminPassword, testMode); server = new Server(instance); - server.start(config.getPort()); + server.start(config.getPort(), config.isUseSSL()); // Parameter: serializationtype => jboss // InvokerLocator serverLocator = new InvokerLocator(connection.getURI()); // if (!isAlreadyRunning(serverLocator)) { @@ -1320,7 +1320,7 @@ public class Main implements MageServer { return (MatchType) Class.forName(plugin.getTypeName(), true, classLoader).newInstance(); } catch (ClassNotFoundException ex) { logger.warn("Game type not found:" + plugin.getJar() + " - check plugin folder", ex); - } catch (Exception ex) { + } catch (MalformedURLException | InstantiationException | IllegalAccessException ex) { logger.fatal("Error loading game type " + plugin.getJar(), ex); } return null; @@ -1333,7 +1333,7 @@ public class Main implements MageServer { return (TournamentType) Class.forName(plugin.getTypeName(), true, classLoader).newInstance(); } catch (ClassNotFoundException ex) { logger.warn("Tournament type not found:" + plugin.getName() + " / "+ plugin.getJar() + " - check plugin folder", ex); - } catch (Exception ex) { + } catch (MalformedURLException | InstantiationException | IllegalAccessException ex) { logger.fatal("Error loading game type " + plugin.getJar(), ex); } return null; diff --git a/Mage.Server/src/main/java/mage/server/util/Config.java b/Mage.Server/src/main/java/mage/server/util/Config.java index 65cd7b7dd82..4694951c7cd 100644 --- a/Mage.Server/src/main/java/mage/server/util/Config.java +++ b/Mage.Server/src/main/java/mage/server/util/Config.java @@ -61,6 +61,7 @@ public class Config { maxUserNameLength = Integer.parseInt(p.getProperty("maxUserNameLength")); userNamePattern = p.getProperty("userNamePattern"); saveGameActivated = Boolean.parseBoolean(p.getProperty("saveGameActivated")); + useSSL = Boolean.parseBoolean(p.getProperty("useSSL")); } public static final String remoteServer; @@ -76,5 +77,6 @@ public class Config { public static final int maxUserNameLength; public static final String userNamePattern; public static final boolean saveGameActivated; + public static final boolean useSSL; } diff --git a/Mage.Server/src/main/java/mage/server/util/Config.xsd b/Mage.Server/src/main/java/mage/server/util/Config.xsd index bc0ab04a678..7360a80d73c 100644 --- a/Mage.Server/src/main/java/mage/server/util/Config.xsd +++ b/Mage.Server/src/main/java/mage/server/util/Config.xsd @@ -31,6 +31,7 @@ + diff --git a/Mage.Server/src/main/java/mage/server/util/ConfigSettings.java b/Mage.Server/src/main/java/mage/server/util/ConfigSettings.java index cee5d5bdee6..485fde0c119 100644 --- a/Mage.Server/src/main/java/mage/server/util/ConfigSettings.java +++ b/Mage.Server/src/main/java/mage/server/util/ConfigSettings.java @@ -120,8 +120,12 @@ public class ConfigSettings { } public Boolean isSaveGameActivated() { - return config.getServer().isSaveGameActivated(); -} + return config.getServer().isSaveGameActivated(); + } + + public Boolean isUseSSL() { + return config.getServer().isUseSSL(); + } public List getPlayerTypes() { return config.getPlayerTypes().getPlayerType(); diff --git a/Mage.Server/src/main/java/mage/server/util/resources/config.xml b/Mage.Server/src/main/java/mage/server/util/resources/config.xml index 56ca070a03c..d8f61819b85 100644 --- a/Mage.Server/src/main/java/mage/server/util/resources/config.xml +++ b/Mage.Server/src/main/java/mage/server/util/resources/config.xml @@ -16,6 +16,7 @@ userNamePattern="[^a-z0-9_]" maxAiOpponents="15" saveGameActivated="false" + useSSL="true" /> diff --git a/Mage.Server/src/main/xml-resources/jaxb/Config/Config.xsd b/Mage.Server/src/main/xml-resources/jaxb/Config/Config.xsd index 8e57894338c..3d8aac9d911 100644 --- a/Mage.Server/src/main/xml-resources/jaxb/Config/Config.xsd +++ b/Mage.Server/src/main/xml-resources/jaxb/Config/Config.xsd @@ -32,6 +32,7 @@ +