Forbid multiple ALI redirects (#78)

This commit is contained in:
yushijinhun 2020-08-12 20:29:43 +08:00
parent 0bd7134c81
commit b12dd75fa5
No known key found for this signature in database
GPG Key ID: 5BC167F73EA558E4

View File

@ -29,10 +29,8 @@ import java.io.UncheckedIOException;
import java.lang.instrument.Instrumentation;
import java.net.HttpURLConnection;
import java.net.InetSocketAddress;
import java.net.MalformedURLException;
import java.net.Proxy;
import java.net.URL;
import java.net.URLConnection;
import java.net.Proxy.Type;
import java.nio.file.Paths;
import java.util.ArrayList;
@ -122,8 +120,6 @@ public final class AuthlibInjector {
public static final String PROP_DISABLE_HTTPD = "authlibinjector.httpd.disable";
public static final String PROP_ALI_REDIRECT_LIMIT = "authlibinjector.ali.redirectLimit";
// ====
// ==== Package filtering ====
@ -187,8 +183,6 @@ public final class AuthlibInjector {
}
// ====
private static final int REDIRECT_LIMIT = Integer.getInteger(PROP_ALI_REDIRECT_LIMIT, 5);
private AuthlibInjector() {}
private static boolean booted = false;
@ -242,7 +236,7 @@ public final class AuthlibInjector {
ExecutionEnvironment side = detectSide();
Logging.LAUNCH.fine("Detected side: " + side);
apiRoot = parseInputUrl(apiRoot);
apiRoot = addHttpsIfMissing(apiRoot);
Logging.CONFIG.info("API root: " + apiRoot);
warnIfHttp(apiRoot);
@ -252,30 +246,17 @@ public final class AuthlibInjector {
if (!prefetched.isPresent()) {
try {
HttpURLConnection connection;
boolean redirectAllowed = side == ExecutionEnvironment.SERVER;
int redirectCount = 0;
for (;;) {
connection = (HttpURLConnection) new URL(apiRoot).openConnection();
Optional<String> ali = getApiLocationIndication(connection);
if (ali.isPresent()) {
if (!redirectAllowed) {
Logging.CONFIG.warning("Redirect is not allowed, ignoring ALI: " + ali.get());
break;
}
HttpURLConnection connection = (HttpURLConnection) new URL(apiRoot).openConnection();
String ali = connection.getHeaderField("x-authlib-injector-api-location");
if (ali != null) {
URL absoluteAli = new URL(connection.getURL(), ali);
if (!urlEqualsIgnoreSlash(apiRoot, absoluteAli.toString())) {
connection.disconnect();
apiRoot = ali.get();
if (redirectCount >= REDIRECT_LIMIT) {
Logging.CONFIG.severe("Exceeded maximum number of redirects (" + REDIRECT_LIMIT + "), refusing to redirect to: " + apiRoot);
throw new InjectorInitializationException();
}
redirectCount++;
Logging.CONFIG.info("Redirect to: " + apiRoot);
Logging.CONFIG.info("Redirect to: " + absoluteAli);
apiRoot = absoluteAli.toString();
warnIfHttp(apiRoot);
} else {
break;
connection = (HttpURLConnection) absoluteAli.openConnection();
}
}
@ -303,6 +284,9 @@ public final class AuthlibInjector {
Logging.CONFIG.fine("Metadata: " + metadataResponse);
if (!apiRoot.endsWith("/"))
apiRoot += "/";
YggdrasilConfiguration configuration;
try {
configuration = YggdrasilConfiguration.parse(apiRoot, metadataResponse);
@ -322,43 +306,20 @@ public final class AuthlibInjector {
}
}
private static String appendSuffixSlash(String url) {
if (!url.endsWith("/")) {
return url + "/";
} else {
return url;
}
}
private static String parseInputUrl(String url) {
private static String addHttpsIfMissing(String url) {
String lowercased = url.toLowerCase();
if (!lowercased.startsWith("http://") && !lowercased.startsWith("https://")) {
url = "https://" + url;
}
url = appendSuffixSlash(url);
return url;
}
private static Optional<String> getApiLocationIndication(URLConnection conn) {
return Optional.ofNullable(conn.getHeaderFields().get("X-Authlib-Injector-API-Location"))
.flatMap(list -> list.isEmpty() ? Optional.empty() : Optional.of(list.get(0)))
.flatMap(indication -> {
String currentUrl = appendSuffixSlash(conn.getURL().toString());
String newUrl;
try {
newUrl = appendSuffixSlash(new URL(conn.getURL(), indication).toString());
} catch (MalformedURLException e) {
Logging.CONFIG.warning("Failed to resolve absolute ALI, the header is [" + indication + "]. Ignore it.");
return Optional.empty();
}
if (newUrl.equals(currentUrl)) {
return Optional.empty();
} else {
return Optional.of(newUrl);
}
});
private static boolean urlEqualsIgnoreSlash(String a, String b) {
if (!a.endsWith("/"))
a += "/";
if (!b.endsWith("/"))
b += "/";
return a.equals(b);
}
private static ExecutionEnvironment detectSide() {