diff --git a/src/main/java/org/qortal/api/Security.java b/src/main/java/org/qortal/api/Security.java index 75e2facc..e0a45339 100644 --- a/src/main/java/org/qortal/api/Security.java +++ b/src/main/java/org/qortal/api/Security.java @@ -1,6 +1,10 @@ package org.qortal.api; +import org.qortal.settings.Settings; + import java.io.IOException; +import java.net.InetAddress; +import java.net.UnknownHostException; import javax.servlet.http.HttpServletRequest; @@ -9,21 +13,35 @@ public abstract class Security { public static final String API_KEY_HEADER = "X-API-KEY"; public static void checkApiCallAllowed(HttpServletRequest request) { - ApiKey apiKey = Security.getApiKey(request); + // We may want to allow automatic authentication for local requests, if enabled in settings + boolean localAuthBypassEnabled = Settings.getInstance().isLocalAuthBypassEnabled(); + if (localAuthBypassEnabled) { + try { + InetAddress remoteAddr = InetAddress.getByName(request.getRemoteAddr()); + if (remoteAddr.isLoopbackAddress()) { + // Request originates from loopback address, so allow it + return; + } + } catch (UnknownHostException e) { + // Ignore failure, and fallback to API key authentication + } + } + // Retrieve the API key + ApiKey apiKey = Security.getApiKey(request); if (!apiKey.generated()) { // Not generated an API key yet, so disallow sensitive API calls throw ApiExceptionFactory.INSTANCE.createCustomException(request, ApiError.UNAUTHORIZED, "API key not generated"); } + // We require an API key to be passed String passedApiKey = request.getHeader(API_KEY_HEADER); if (passedApiKey == null) { - // We require an API key to be passed throw ApiExceptionFactory.INSTANCE.createCustomException(request, ApiError.UNAUTHORIZED, "Missing 'X-API-KEY' header"); } + // The API keys must match if (!apiKey.equals(passedApiKey)) { - // The API keys must match throw ApiExceptionFactory.INSTANCE.createCustomException(request, ApiError.UNAUTHORIZED, "API key invalid"); } } diff --git a/src/main/java/org/qortal/settings/Settings.java b/src/main/java/org/qortal/settings/Settings.java index a3835ad7..b2723328 100644 --- a/src/main/java/org/qortal/settings/Settings.java +++ b/src/main/java/org/qortal/settings/Settings.java @@ -15,7 +15,6 @@ import javax.xml.bind.annotation.XmlAccessType; import javax.xml.bind.annotation.XmlAccessorType; import javax.xml.transform.stream.StreamSource; -import bsh.This; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.eclipse.persistence.exceptions.XMLMarshalException; @@ -77,6 +76,8 @@ public class Settings { private String apiKey = null; /** Storage location for API key generated by API (Nov 2021 onwards) */ private String apiKeyPath = ""; + /** Whether to allow automatic authentication from localhost (loopback) addresses */ + private boolean localAuthBypassEnabled = false; private Boolean apiRestricted; private boolean apiLoggingEnabled = false; @@ -488,6 +489,10 @@ public class Settings { return this.apiKeyPath; } + public boolean isLocalAuthBypassEnabled() { + return this.localAuthBypassEnabled; + } + public boolean isApiLoggingEnabled() { return this.apiLoggingEnabled; }