Bugfixes
Dieser Commit ist enthalten in:
Ursprung
7080792d52
Commit
96e4d46eb5
BIN
AltAuth.png
Normale Datei
BIN
AltAuth.png
Normale Datei
Binäre Datei nicht angezeigt.
Nachher Breite: | Höhe: | Größe: 76 KiB |
22
README.md
22
README.md
@ -1,2 +1,24 @@
|
|||||||
# AltAuth
|
# AltAuth
|
||||||
|
|
||||||
|
AltAuth is a solution to allow players with Mojang account, (untested) banned accounts and (untested) Multiplayer
|
||||||
|
disabled accounts to join online mode Minecraft servers depending on client and server support.
|
||||||
|
This works by redirecting the session server requests to a proxy specified by the server.
|
||||||
|
|
||||||
|
In comparison to the trustless authentication method proposed by Aizistral
|
||||||
|
https://github.com/Aizistral-Studios/Trustless-Authentication this authentication method enables joining of Mojang
|
||||||
|
account players, prevents man in the middle attacks (like vanilla authentication) and is compatible to clients without
|
||||||
|
AltAuth, but requires a trusted third/second party.
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
The build/libs/AltAuth-*-all.jar (produced by running `./gradlew build`) is a valid Fabric (client and server 1.19.2),
|
||||||
|
Bukkit/Spigot/Paper (1.8 - 1.19.2) and BungeeCord/Waterfall mod/plugin. The server needs to be in online mode and
|
||||||
|
specify the domain or ip address of an AltAuth web proxy.
|
||||||
|
|
||||||
|
Since https is a requirement and the example proxy `proxy.py` not yet supporting https the proxy has to run behind a
|
||||||
|
https proxy currently. Configuration of the proxy can be done in the first lines of the proxy script.
|
||||||
|
Banned and multiplayer disabled user support has not been tested yet and is therefore disabled by default.
|
||||||
|
|
||||||
|
## AltAuth Protocol and Proxy behaviour
|
||||||
|
|
||||||
|
![Sequence diagram describing protocol and principle](AltAuth.png "Sequence diagram describing protocol and principle")
|
@ -8,6 +8,7 @@ import io.netty.channel.Channel;
|
|||||||
import io.netty.channel.ChannelDuplexHandler;
|
import io.netty.channel.ChannelDuplexHandler;
|
||||||
import io.netty.channel.ChannelHandlerContext;
|
import io.netty.channel.ChannelHandlerContext;
|
||||||
import io.netty.channel.ChannelPromise;
|
import io.netty.channel.ChannelPromise;
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
import org.bukkit.event.EventHandler;
|
import org.bukkit.event.EventHandler;
|
||||||
import org.bukkit.event.EventPriority;
|
import org.bukkit.event.EventPriority;
|
||||||
@ -29,7 +30,7 @@ public class ProtocolInjector implements Listener {
|
|||||||
private static final Class<?> dedicatedPlayerList = ReflectionUtil.getClass("net.minecraft.server.dedicated.DedicatedPlayerList");
|
private static final Class<?> dedicatedPlayerList = ReflectionUtil.getClass("net.minecraft.server.dedicated.DedicatedPlayerList");
|
||||||
private static final FieldWrapper<?> getPlayerList = ReflectionUtil.getField(craftServer, dedicatedPlayerList, 0);
|
private static final FieldWrapper<?> getPlayerList = ReflectionUtil.getField(craftServer, dedicatedPlayerList, 0);
|
||||||
private static final Class<?> playerList = ReflectionUtil.getClass("net.minecraft.server.players.PlayerList");
|
private static final Class<?> playerList = ReflectionUtil.getClass("net.minecraft.server.players.PlayerList");
|
||||||
private static final Class<?> minecraftServer = ReflectionUtil.getClass("net.minecraft.server.MinecraftServer");
|
public static final Class<?> minecraftServer = ReflectionUtil.getClass("net.minecraft.server.MinecraftServer");
|
||||||
private static final FieldWrapper<?> getMinecraftServer = ReflectionUtil.getField(playerList, minecraftServer, 0);
|
private static final FieldWrapper<?> getMinecraftServer = ReflectionUtil.getField(playerList, minecraftServer, 0);
|
||||||
private static final Class<?> serverConnection = ReflectionUtil.getClass("net.minecraft.server.network.ServerConnection");
|
private static final Class<?> serverConnection = ReflectionUtil.getClass("net.minecraft.server.network.ServerConnection");
|
||||||
private static final FieldWrapper<?> getServerConnection = ReflectionUtil.getField(minecraftServer, serverConnection, 0);
|
private static final FieldWrapper<?> getServerConnection = ReflectionUtil.getField(minecraftServer, serverConnection, 0);
|
||||||
@ -44,6 +45,7 @@ public class ProtocolInjector implements Listener {
|
|||||||
|
|
||||||
private final Plugin plugin;
|
private final Plugin plugin;
|
||||||
private final String handlerName;
|
private final String handlerName;
|
||||||
|
private final Object minecraftServerInstance;
|
||||||
private final List<?> connections;
|
private final List<?> connections;
|
||||||
private boolean closed;
|
private boolean closed;
|
||||||
|
|
||||||
@ -53,7 +55,8 @@ public class ProtocolInjector implements Listener {
|
|||||||
private ProtocolInjector(final Plugin plugin) {
|
private ProtocolInjector(final Plugin plugin) {
|
||||||
this.plugin = plugin;
|
this.plugin = plugin;
|
||||||
this.handlerName = "altauth";
|
this.handlerName = "altauth";
|
||||||
this.connections = getConnections.get(getServerConnection.get(getMinecraftServer.get(getPlayerList.get(plugin.getServer()))));
|
this.minecraftServerInstance = getMinecraftServer.get(getPlayerList.get(plugin.getServer()));
|
||||||
|
this.connections = getConnections.get(getServerConnection.get(minecraftServerInstance));
|
||||||
|
|
||||||
plugin.getServer().getPluginManager().registerEvents(this, plugin);
|
plugin.getServer().getPluginManager().registerEvents(this, plugin);
|
||||||
|
|
||||||
@ -62,6 +65,10 @@ public class ProtocolInjector implements Listener {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Object minecraftServer() {
|
||||||
|
return minecraftServerInstance;
|
||||||
|
}
|
||||||
|
|
||||||
@EventHandler(priority = EventPriority.LOWEST)
|
@EventHandler(priority = EventPriority.LOWEST)
|
||||||
public void onPlayerLogin(PlayerLoginEvent e) {
|
public void onPlayerLogin(PlayerLoginEvent e) {
|
||||||
if(closed)
|
if(closed)
|
||||||
|
@ -10,29 +10,47 @@ import java.util.logging.Level;
|
|||||||
|
|
||||||
public class SessionServiceInjector {
|
public class SessionServiceInjector {
|
||||||
|
|
||||||
private static final Class<?> SESSION_SERVICE = ReflectionUtil.getClass("com.mojang.authlib.yggdrasil.YggdrasilMinecraftSessionService");
|
private static final Class<?> MINECRAFT_SESSION_SERVICE = ReflectionUtil.getClass("com.mojang.authlib.minecraft.MinecraftSessionService");
|
||||||
|
private static final Class<?> YGGDRASIL_SESSION_SERVICE = ReflectionUtil.getClass("com.mojang.authlib.yggdrasil.YggdrasilMinecraftSessionService");
|
||||||
|
|
||||||
private static final ReflectionUtil.FieldWrapper<URL> JOIN_URL = ReflectionUtil.getField(SESSION_SERVICE, URL.class, "JOIN_URL");
|
private static final ReflectionUtil.FieldWrapper<URL> JOIN_URL = ReflectionUtil.getField(YGGDRASIL_SESSION_SERVICE, URL.class, 0);
|
||||||
private static final ReflectionUtil.FieldWrapper<URL> CHECK_URL = ReflectionUtil.getField(SESSION_SERVICE, URL.class, "CHECK_URL");
|
private static final ReflectionUtil.FieldWrapper<URL> CHECK_URL = ReflectionUtil.getField(YGGDRASIL_SESSION_SERVICE, URL.class, 1);
|
||||||
|
|
||||||
|
private final Object sessionService;
|
||||||
private final URL joinUrlBackup;
|
private final URL joinUrlBackup;
|
||||||
private final URL checkUrlBackup;
|
private final URL checkUrlBackup;
|
||||||
|
|
||||||
public SessionServiceInjector(String altAuthServer) {
|
public SessionServiceInjector(String altAuthServer) {
|
||||||
joinUrlBackup = JOIN_URL.get(null);
|
|
||||||
checkUrlBackup = CHECK_URL.get(null);
|
|
||||||
|
|
||||||
altAuthServer = "https://" + altAuthServer + "/session/minecraft/";
|
altAuthServer = "https://" + altAuthServer + "/session/minecraft/";
|
||||||
|
|
||||||
|
if(ReflectionUtil.MINECRAFT_VERSION < 17) { //TODO maybe 16 (untested)
|
||||||
|
sessionService = null;
|
||||||
|
} else if (ReflectionUtil.MINECRAFT_VERSION < 19) {
|
||||||
|
sessionService = ReflectionUtil.getField(ProtocolInjector.minecraftServer, MINECRAFT_SESSION_SERVICE, 0).get(
|
||||||
|
ProtocolInjector.instance.minecraftServer()
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
Class<?> services = ReflectionUtil.getClass("net.minecraft.server.Services");
|
||||||
|
sessionService = ReflectionUtil.getField(services, MINECRAFT_SESSION_SERVICE, 0).get(
|
||||||
|
ReflectionUtil.getField(ProtocolInjector.minecraftServer, services, 0).get(
|
||||||
|
ProtocolInjector.instance.minecraftServer()
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
joinUrlBackup = JOIN_URL.get(sessionService);
|
||||||
|
checkUrlBackup = CHECK_URL.get(sessionService);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
JOIN_URL.set(null, new URL(altAuthServer + "join"));
|
JOIN_URL.set(sessionService, new URL(altAuthServer + "join"));
|
||||||
CHECK_URL.set(null, new URL(altAuthServer + "hasJoined"));
|
CHECK_URL.set(sessionService, new URL(altAuthServer + "hasJoined"));
|
||||||
} catch (MalformedURLException e) {
|
} catch (MalformedURLException e) {
|
||||||
AltAuthBukkit.getInstance().getLogger().log(Level.SEVERE, "Could not create AltAuth URLs", e);
|
AltAuthBukkit.getInstance().getLogger().log(Level.SEVERE, "Could not create AltAuth URLs", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void revert() {
|
public void revert() {
|
||||||
JOIN_URL.set(null, joinUrlBackup);
|
JOIN_URL.set(sessionService, joinUrlBackup);
|
||||||
CHECK_URL.set(null, checkUrlBackup);
|
CHECK_URL.set(sessionService, checkUrlBackup);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -12,19 +12,19 @@ public final class ReflectionUtil {
|
|||||||
private ReflectionUtil() {}
|
private ReflectionUtil() {}
|
||||||
|
|
||||||
private static final String ORG_BUKKIT_CRAFTBUKKIT;
|
private static final String ORG_BUKKIT_CRAFTBUKKIT;
|
||||||
private static final boolean REPLACE_NET_MINECRAFT;
|
public static final int MINECRAFT_VERSION;
|
||||||
static {
|
static {
|
||||||
String craftbukkitPackage;
|
String craftbukkitPackage;
|
||||||
boolean legacyNms;
|
int minecraftVersion;
|
||||||
try {
|
try {
|
||||||
craftbukkitPackage = Bukkit.getServer().getClass().getPackage().getName();
|
craftbukkitPackage = Bukkit.getServer().getClass().getPackage().getName();
|
||||||
legacyNms = Integer.parseInt(craftbukkitPackage.split("[.](?=[^.]*$)")[1].split("_")[1]) < 17;
|
minecraftVersion = Integer.parseInt(craftbukkitPackage.split("[.](?=[^.]*$)")[1].split("_")[1]);
|
||||||
} catch (NoClassDefFoundError e) {
|
} catch (NoClassDefFoundError e) {
|
||||||
craftbukkitPackage = "";
|
craftbukkitPackage = "";
|
||||||
legacyNms = false;
|
minecraftVersion = 0;
|
||||||
}
|
}
|
||||||
ORG_BUKKIT_CRAFTBUKKIT = craftbukkitPackage;
|
ORG_BUKKIT_CRAFTBUKKIT = craftbukkitPackage;
|
||||||
REPLACE_NET_MINECRAFT = legacyNms;
|
MINECRAFT_VERSION = minecraftVersion;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final String LEGACY_NET_MINECRAFT_SERVER = ORG_BUKKIT_CRAFTBUKKIT.replace("org.bukkit.craftbukkit", "net.minecraft.server");
|
private static final String LEGACY_NET_MINECRAFT_SERVER = ORG_BUKKIT_CRAFTBUKKIT.replace("org.bukkit.craftbukkit", "net.minecraft.server");
|
||||||
@ -120,7 +120,7 @@ public final class ReflectionUtil {
|
|||||||
try {
|
try {
|
||||||
if(name.startsWith("org.bukkit.craftbukkit")) {
|
if(name.startsWith("org.bukkit.craftbukkit")) {
|
||||||
return Class.forName(ORG_BUKKIT_CRAFTBUKKIT + name.substring(22));
|
return Class.forName(ORG_BUKKIT_CRAFTBUKKIT + name.substring(22));
|
||||||
} else if(REPLACE_NET_MINECRAFT && name.startsWith("net.minecraft")) {
|
} else if(MINECRAFT_VERSION < 17 && name.startsWith("net.minecraft")) {
|
||||||
return Class.forName(LEGACY_NET_MINECRAFT_SERVER + "." + name.split("[.](?=[^.]*$)")[1]);
|
return Class.forName(LEGACY_NET_MINECRAFT_SERVER + "." + name.split("[.](?=[^.]*$)")[1]);
|
||||||
} else {
|
} else {
|
||||||
return Class.forName(name);
|
return Class.forName(name);
|
||||||
|
3
proxy.py
3
proxy.py
@ -22,7 +22,8 @@ bind_to = ('127.0.0.1', 8080)
|
|||||||
allow_mojang_accounts = True
|
allow_mojang_accounts = True
|
||||||
# Should banned microsoft accounts ("UserBannedException") be allowed to join?
|
# Should banned microsoft accounts ("UserBannedException") be allowed to join?
|
||||||
# Should accounts with disabled multiplayer ("InsufficientPrivilegesException") be allowed to join?
|
# Should accounts with disabled multiplayer ("InsufficientPrivilegesException") be allowed to join?
|
||||||
allowed_microsoft_accounts = ("InsufficientPrivilegesException", "UserBannedException")
|
allowed_microsoft_accounts = ()
|
||||||
|
#allowed_microsoft_accounts = ("InsufficientPrivilegesException", "UserBannedException")
|
||||||
|
|
||||||
|
|
||||||
def moj_request(url, data=None):
|
def moj_request(url, data=None):
|
||||||
|
Laden…
In neuem Issue referenzieren
Einen Benutzer sperren