forked from Qortal/qortal
Added 'localAuthBypassEnabled' setting to allow users to opt in to the old method of local authentication at their own risk.
This commit is contained in:
parent
f062acfd7c
commit
06e122f303
@ -1,6 +1,10 @@
|
|||||||
package org.qortal.api;
|
package org.qortal.api;
|
||||||
|
|
||||||
|
import org.qortal.settings.Settings;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.net.InetAddress;
|
||||||
|
import java.net.UnknownHostException;
|
||||||
|
|
||||||
import javax.servlet.http.HttpServletRequest;
|
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 final String API_KEY_HEADER = "X-API-KEY";
|
||||||
|
|
||||||
public static void checkApiCallAllowed(HttpServletRequest request) {
|
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()) {
|
if (!apiKey.generated()) {
|
||||||
// Not generated an API key yet, so disallow sensitive API calls
|
// Not generated an API key yet, so disallow sensitive API calls
|
||||||
throw ApiExceptionFactory.INSTANCE.createCustomException(request, ApiError.UNAUTHORIZED, "API key not generated");
|
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);
|
String passedApiKey = request.getHeader(API_KEY_HEADER);
|
||||||
if (passedApiKey == null) {
|
if (passedApiKey == null) {
|
||||||
// We require an API key to be passed
|
|
||||||
throw ApiExceptionFactory.INSTANCE.createCustomException(request, ApiError.UNAUTHORIZED, "Missing 'X-API-KEY' header");
|
throw ApiExceptionFactory.INSTANCE.createCustomException(request, ApiError.UNAUTHORIZED, "Missing 'X-API-KEY' header");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!apiKey.equals(passedApiKey)) {
|
|
||||||
// The API keys must match
|
// The API keys must match
|
||||||
|
if (!apiKey.equals(passedApiKey)) {
|
||||||
throw ApiExceptionFactory.INSTANCE.createCustomException(request, ApiError.UNAUTHORIZED, "API key invalid");
|
throw ApiExceptionFactory.INSTANCE.createCustomException(request, ApiError.UNAUTHORIZED, "API key invalid");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -15,7 +15,6 @@ import javax.xml.bind.annotation.XmlAccessType;
|
|||||||
import javax.xml.bind.annotation.XmlAccessorType;
|
import javax.xml.bind.annotation.XmlAccessorType;
|
||||||
import javax.xml.transform.stream.StreamSource;
|
import javax.xml.transform.stream.StreamSource;
|
||||||
|
|
||||||
import bsh.This;
|
|
||||||
import org.apache.logging.log4j.LogManager;
|
import org.apache.logging.log4j.LogManager;
|
||||||
import org.apache.logging.log4j.Logger;
|
import org.apache.logging.log4j.Logger;
|
||||||
import org.eclipse.persistence.exceptions.XMLMarshalException;
|
import org.eclipse.persistence.exceptions.XMLMarshalException;
|
||||||
@ -77,6 +76,8 @@ public class Settings {
|
|||||||
private String apiKey = null;
|
private String apiKey = null;
|
||||||
/** Storage location for API key generated by API (Nov 2021 onwards) */
|
/** Storage location for API key generated by API (Nov 2021 onwards) */
|
||||||
private String apiKeyPath = "";
|
private String apiKeyPath = "";
|
||||||
|
/** Whether to allow automatic authentication from localhost (loopback) addresses */
|
||||||
|
private boolean localAuthBypassEnabled = false;
|
||||||
|
|
||||||
private Boolean apiRestricted;
|
private Boolean apiRestricted;
|
||||||
private boolean apiLoggingEnabled = false;
|
private boolean apiLoggingEnabled = false;
|
||||||
@ -488,6 +489,10 @@ public class Settings {
|
|||||||
return this.apiKeyPath;
|
return this.apiKeyPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isLocalAuthBypassEnabled() {
|
||||||
|
return this.localAuthBypassEnabled;
|
||||||
|
}
|
||||||
|
|
||||||
public boolean isApiLoggingEnabled() {
|
public boolean isApiLoggingEnabled() {
|
||||||
return this.apiLoggingEnabled;
|
return this.apiLoggingEnabled;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user