mirror of
https://github.com/Minestom/Minestom.git
synced 2025-01-04 23:47:59 +01:00
add BungeeGuard authentication (#1502)
This commit is contained in:
parent
84f4ae040e
commit
e5d0a43ba4
@ -1,12 +1,22 @@
|
||||
package net.minestom.server.extras.bungee;
|
||||
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.format.NamedTextColor;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* BungeeCord forwarding support. This does not count as a security feature, and you will still be required to manage your firewall.
|
||||
* BungeeCord forwarding support. Enabling BungeeGuard support with {@link #setBungeeGuardTokens(Set)} helps to secure the server,
|
||||
* but managing your firewall is still recommended.
|
||||
* <p>
|
||||
* Please consider using {@link net.minestom.server.extras.velocity.VelocityProxy} instead.
|
||||
*/
|
||||
public final class BungeeCordProxy {
|
||||
|
||||
private static Set<String> bungeeGuardTokens = null;
|
||||
|
||||
private static volatile boolean enabled;
|
||||
|
||||
/**
|
||||
@ -24,4 +34,35 @@ public final class BungeeCordProxy {
|
||||
public static boolean isEnabled() {
|
||||
return enabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the tokens used by BungeeGuard authentication.
|
||||
* Setting the tokens to a not-null value enables BungeeGuard authentication,
|
||||
* and setting it to a null value disables BungeeGuard authentication.
|
||||
*
|
||||
* @param tokens The new BungeeGuard authentication tokens
|
||||
*/
|
||||
public static void setBungeeGuardTokens(@Nullable Set<String> tokens) {
|
||||
bungeeGuardTokens = tokens;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether BungeeGuard authentication is enabled.
|
||||
*
|
||||
* @return Whether BungeeGuard authentication is enabled
|
||||
*/
|
||||
public static boolean isBungeeGuardEnabled() {
|
||||
return bungeeGuardTokens != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether a token is one of the valid BungeeGuard tokens
|
||||
*
|
||||
* @param token The token to test
|
||||
* @return Whether the token is a valid BungeeGuard token
|
||||
*/
|
||||
public static boolean isValidBungeeGuardToken(@NotNull String token) {
|
||||
return isBungeeGuardEnabled() && bungeeGuardTokens.contains(token);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -16,6 +16,8 @@ import net.minestom.server.network.player.GameProfile;
|
||||
import net.minestom.server.network.player.PlayerConnection;
|
||||
import net.minestom.server.network.player.PlayerSocketConnection;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.net.SocketAddress;
|
||||
import java.util.ArrayList;
|
||||
@ -27,14 +29,20 @@ import static net.minestom.server.network.NetworkBuffer.*;
|
||||
public record HandshakePacket(int protocolVersion, @NotNull String serverAddress,
|
||||
int serverPort, int nextState) implements ClientPreplayPacket {
|
||||
|
||||
private final static Logger LOGGER = LoggerFactory.getLogger(HandshakePacket.class);
|
||||
|
||||
/**
|
||||
* Text sent if a player tries to connect with an invalid version of the client
|
||||
*/
|
||||
private static final Component INVALID_VERSION_TEXT = Component.text("Invalid Version, please use " + MinecraftServer.VERSION_NAME, NamedTextColor.RED);
|
||||
private static final Component INVALID_BUNGEE_FORWARDING = Component.text("If you wish to use IP forwarding, please enable it in your BungeeCord config as well!", NamedTextColor.RED);
|
||||
|
||||
/**
|
||||
* Indicates that a BungeeGuard authentication was invalid due to missing, multiple, or invalid tokens.
|
||||
*/
|
||||
private static final Component INVALID_BUNGEE_FORWARDING = Component.text("Invalid connection, please connect through the BungeeCord proxy. If you believe this is an error, contact a server administrator.", NamedTextColor.RED);
|
||||
|
||||
public HandshakePacket {
|
||||
if (serverAddress.length() > (BungeeCordProxy.isEnabled() ? Short.MAX_VALUE : 255)) {
|
||||
if (serverAddress.length() > getMaxHandshakeLength()) {
|
||||
throw new IllegalArgumentException("Server address too long: " + serverAddress.length());
|
||||
}
|
||||
}
|
||||
@ -47,7 +55,7 @@ public record HandshakePacket(int protocolVersion, @NotNull String serverAddress
|
||||
@Override
|
||||
public void write(@NotNull NetworkBuffer writer) {
|
||||
writer.write(VAR_INT, protocolVersion);
|
||||
int maxLength = BungeeCordProxy.isEnabled() ? Short.MAX_VALUE : 255;
|
||||
int maxLength = getMaxHandshakeLength();
|
||||
if (serverAddress.length() > maxLength) {
|
||||
throw new IllegalArgumentException("serverAddress is " + serverAddress.length() + " characters long, maximum allowed is " + maxLength);
|
||||
}
|
||||
@ -64,6 +72,12 @@ public record HandshakePacket(int protocolVersion, @NotNull String serverAddress
|
||||
final String[] split = address.split("\00");
|
||||
|
||||
if (split.length == 3 || split.length == 4) {
|
||||
boolean hasProperties = split.length == 4;
|
||||
if (BungeeCordProxy.isBungeeGuardEnabled() && !hasProperties) {
|
||||
bungeeDisconnect(socketConnection);
|
||||
return;
|
||||
}
|
||||
|
||||
address = split[0];
|
||||
|
||||
final SocketAddress socketAddress = new java.net.InetSocketAddress(split[1],
|
||||
@ -78,7 +92,8 @@ public record HandshakePacket(int protocolVersion, @NotNull String serverAddress
|
||||
);
|
||||
|
||||
List<GameProfile.Property> properties = new ArrayList<>();
|
||||
if (split.length == 4) {
|
||||
if (hasProperties) {
|
||||
boolean foundBungeeGuardToken = false;
|
||||
final String rawPropertyJson = split[3];
|
||||
final JsonArray propertyJson = JsonParser.parseString(rawPropertyJson).getAsJsonArray();
|
||||
for (JsonElement element : propertyJson) {
|
||||
@ -92,15 +107,28 @@ public record HandshakePacket(int protocolVersion, @NotNull String serverAddress
|
||||
final String valueString = value.getAsString();
|
||||
final String signatureString = signature == null ? null : signature.getAsString();
|
||||
|
||||
if (BungeeCordProxy.isBungeeGuardEnabled() && nameString.equals("bungeeguard-token")) {
|
||||
if (foundBungeeGuardToken || !BungeeCordProxy.isValidBungeeGuardToken(valueString)) {
|
||||
bungeeDisconnect(socketConnection);
|
||||
return;
|
||||
}
|
||||
|
||||
foundBungeeGuardToken = true;
|
||||
}
|
||||
|
||||
properties.add(new GameProfile.Property(nameString, valueString, signatureString));
|
||||
}
|
||||
|
||||
if (BungeeCordProxy.isBungeeGuardEnabled() && !foundBungeeGuardToken) {
|
||||
bungeeDisconnect(socketConnection);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
final GameProfile gameProfile = new GameProfile(playerUuid, "test", properties);
|
||||
socketConnection.UNSAFE_setProfile(gameProfile);
|
||||
} else {
|
||||
socketConnection.sendPacket(new LoginDisconnectPacket(INVALID_BUNGEE_FORWARDING));
|
||||
socketConnection.disconnect();
|
||||
bungeeDisconnect(socketConnection);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -117,8 +145,7 @@ public record HandshakePacket(int protocolVersion, @NotNull String serverAddress
|
||||
connection.setConnectionState(ConnectionState.LOGIN);
|
||||
} else {
|
||||
// Incorrect client version
|
||||
connection.sendPacket(new LoginDisconnectPacket(INVALID_VERSION_TEXT));
|
||||
connection.disconnect();
|
||||
disconnect(connection, INVALID_VERSION_TEXT);
|
||||
}
|
||||
}
|
||||
default -> {
|
||||
@ -126,4 +153,20 @@ public record HandshakePacket(int protocolVersion, @NotNull String serverAddress
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static int getMaxHandshakeLength() {
|
||||
// BungeeGuard limits handshake length to 2500 characters, while vanilla limits it to 255
|
||||
return BungeeCordProxy.isEnabled() ? (BungeeCordProxy.isBungeeGuardEnabled() ? 2500 : Short.MAX_VALUE) : 255;
|
||||
}
|
||||
|
||||
private void disconnect(@NotNull PlayerConnection connection, @NotNull Component reason) {
|
||||
connection.sendPacket(new LoginDisconnectPacket(reason));
|
||||
connection.disconnect();
|
||||
}
|
||||
|
||||
private void bungeeDisconnect(@NotNull PlayerConnection connection) {
|
||||
LOGGER.warn("{} tried to log in without valid BungeeGuard forwarding information.", connection.getIdentifier());
|
||||
disconnect(connection, INVALID_BUNGEE_FORWARDING);
|
||||
}
|
||||
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user