GUACAMOLE-2052: Maintain independent copy of request details in Credentials.

This commit is contained in:
Michael Jumper
2025-04-12 11:50:48 -07:00
parent 7d4009f91b
commit 4670ad0b90
17 changed files with 697 additions and 213 deletions

View File

@@ -21,10 +21,9 @@ package org.apache.guacamole.auth.json;
import com.google.inject.Inject;
import inet.ipaddr.IPAddressString;
import java.util.ArrayList;
import java.util.Collection;
import javax.servlet.http.HttpServletRequest;
import org.apache.guacamole.GuacamoleException;
import org.apache.guacamole.net.auth.Credentials;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -59,17 +58,17 @@ public class RequestValidationService {
}
/**
* Returns whether the given request can be used for authentication, taking
* into account restrictions specified within guacamole.properties.
* Returns whether the given credentials can be used for authentication,
* taking into account restrictions specified within guacamole.properties.
*
* @param request
* The HTTP request to test.
* @param credentials
* The credentials of the authentication request to test.
*
* @return
* true if the given request comes from a trusted source and can be
* true if the given credentials come from a trusted source and can be
* used for authentication, false otherwise.
*/
public boolean isAuthenticationAllowed(HttpServletRequest request) {
public boolean isAuthenticationAllowed(Credentials credentials) {
// Pull list of all trusted networks
Collection<String> trustedNetworks;
@@ -79,14 +78,14 @@ public class RequestValidationService {
// Deny all requests if restrictions cannot be parsed
catch (GuacamoleException e) {
logger.warn("Authentication request from \"{}\" is DENIED due to parse error: {}", request.getRemoteAddr(), e.getMessage());
logger.warn("Authentication request from \"{}\" is DENIED due to parse error: {}", credentials.getRemoteAddress(), e.getMessage());
logger.debug("Error parsing authentication request restrictions from guacamole.properties.", e);
return false;
}
// All requests are allowed if no restrictions are defined
if (trustedNetworks.isEmpty()) {
logger.debug("Authentication request from \"{}\" is ALLOWED (no restrictions).", request.getRemoteAddr());
logger.debug("Authentication request from \"{}\" is ALLOWED (no restrictions).", credentials.getRemoteAddress());
return true;
}
@@ -94,15 +93,15 @@ public class RequestValidationService {
for (String network : trustedNetworks) {
// Request is allowed if any subnet matches
if (new IPAddressString(network).contains(new IPAddressString(request.getRemoteAddr()))) {
logger.debug("Authentication request from \"{}\" is ALLOWED (matched subnet).", request.getRemoteAddr());
if (new IPAddressString(network).contains(new IPAddressString(credentials.getRemoteAddress()))) {
logger.debug("Authentication request from \"{}\" is ALLOWED (matched subnet).", credentials.getRemoteAddress());
return true;
}
}
// Otherwise request is denied - no subnets matched
logger.debug("Authentication request from \"{}\" is DENIED (did not match subnet).", request.getRemoteAddr());
logger.debug("Authentication request from \"{}\" is DENIED (did not match subnet).", credentials.getRemoteAddress());
return false;
}

View File

@@ -31,7 +31,6 @@ import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import javax.servlet.http.HttpServletRequest;
import org.apache.guacamole.GuacamoleException;
import org.apache.guacamole.auth.json.ConfigurationService;
import org.apache.guacamole.auth.json.CryptoService;
@@ -121,18 +120,13 @@ public class UserDataService {
String json;
byte[] correctSignature;
// Pull HTTP request, if available
HttpServletRequest request = credentials.getRequest();
if (request == null)
return null;
// Abort if the request itself is not allowed
if (!requestService.isAuthenticationAllowed(request))
if (!requestService.isAuthenticationAllowed(credentials))
return null;
// Pull base64-encoded, encrypted JSON data from HTTP request, if any
// such data is present
String base64 = request.getParameter(ENCRYPTED_DATA_PARAMETER);
String base64 = credentials.getParameter(ENCRYPTED_DATA_PARAMETER);
if (base64 == null)
return null;

View File

@@ -33,6 +33,7 @@ import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import javax.servlet.ServletInputStream;
import javax.servlet.RequestDispatcher;
import org.apache.guacamole.net.auth.Credentials;
import org.junit.Test;
import static org.junit.Assert.*;
@@ -375,13 +376,13 @@ public class RequestValidationServiceTest {
requestService = new RequestValidationService(new MockConfigurationService(null));
try {
assertTrue(requestService.isAuthenticationAllowed(mockHttpServletRequest("1.1.1.1")));
assertTrue(requestService.isAuthenticationAllowed(mockHttpServletRequest("10.10.10.10")));
assertTrue(requestService.isAuthenticationAllowed(mockHttpServletRequest("100.100.100.100")));
assertTrue(requestService.isAuthenticationAllowed(mockHttpServletRequest("1:1:1:1:1:1:1:1")));
assertTrue(requestService.isAuthenticationAllowed(mockHttpServletRequest("10:10:10:10:10:10:10:10")));
assertTrue(requestService.isAuthenticationAllowed(mockHttpServletRequest("100:100:100:100:100:100:100:100")));
assertTrue(requestService.isAuthenticationAllowed(mockHttpServletRequest("1000:1000:1000:1000:1000:1000:1000:1000")));
assertTrue(requestService.isAuthenticationAllowed(new Credentials(null, null, mockHttpServletRequest("1.1.1.1"))));
assertTrue(requestService.isAuthenticationAllowed(new Credentials(null, null, mockHttpServletRequest("10.10.10.10"))));
assertTrue(requestService.isAuthenticationAllowed(new Credentials(null, null, mockHttpServletRequest("100.100.100.100"))));
assertTrue(requestService.isAuthenticationAllowed(new Credentials(null, null, mockHttpServletRequest("1:1:1:1:1:1:1:1"))));
assertTrue(requestService.isAuthenticationAllowed(new Credentials(null, null, mockHttpServletRequest("10:10:10:10:10:10:10:10"))));
assertTrue(requestService.isAuthenticationAllowed(new Credentials(null, null, mockHttpServletRequest("100:100:100:100:100:100:100:100"))));
assertTrue(requestService.isAuthenticationAllowed(new Credentials(null, null, mockHttpServletRequest("1000:1000:1000:1000:1000:1000:1000:1000"))));
}
catch (AssertionError e) {
fail("A network was denied to authenticate even though no trusted networks were specified.");
@@ -399,18 +400,18 @@ public class RequestValidationServiceTest {
requestService = new RequestValidationService(new MockConfigurationService("10.0.0.0/8,127.0.0.0/8,172.16.0.0/12,192.168.0.0/16,1.2.3.4/32,::1/128,fc00::/7"));
try {
assertTrue(requestService.isAuthenticationAllowed(mockHttpServletRequest("10.0.0.0")));
assertTrue(requestService.isAuthenticationAllowed(mockHttpServletRequest("10.255.255.255")));
assertTrue(requestService.isAuthenticationAllowed(mockHttpServletRequest("127.0.0.0")));
assertTrue(requestService.isAuthenticationAllowed(mockHttpServletRequest("127.255.255.255")));
assertTrue(requestService.isAuthenticationAllowed(mockHttpServletRequest("172.16.0.0")));
assertTrue(requestService.isAuthenticationAllowed(mockHttpServletRequest("172.31.255.255")));
assertTrue(requestService.isAuthenticationAllowed(mockHttpServletRequest("192.168.0.0")));
assertTrue(requestService.isAuthenticationAllowed(mockHttpServletRequest("192.168.255.255")));
assertTrue(requestService.isAuthenticationAllowed(mockHttpServletRequest("1.2.3.4")));
assertTrue(requestService.isAuthenticationAllowed(mockHttpServletRequest("::1")));
assertTrue(requestService.isAuthenticationAllowed(mockHttpServletRequest("fc00::")));
assertTrue(requestService.isAuthenticationAllowed(mockHttpServletRequest("fdff:ffff:ffff:ffff:ffff:ffff:ffff:ffff")));
assertTrue(requestService.isAuthenticationAllowed(new Credentials(null, null, mockHttpServletRequest("10.0.0.0"))));
assertTrue(requestService.isAuthenticationAllowed(new Credentials(null, null, mockHttpServletRequest("10.255.255.255"))));
assertTrue(requestService.isAuthenticationAllowed(new Credentials(null, null, mockHttpServletRequest("127.0.0.0"))));
assertTrue(requestService.isAuthenticationAllowed(new Credentials(null, null, mockHttpServletRequest("127.255.255.255"))));
assertTrue(requestService.isAuthenticationAllowed(new Credentials(null, null, mockHttpServletRequest("172.16.0.0"))));
assertTrue(requestService.isAuthenticationAllowed(new Credentials(null, null, mockHttpServletRequest("172.31.255.255"))));
assertTrue(requestService.isAuthenticationAllowed(new Credentials(null, null, mockHttpServletRequest("192.168.0.0"))));
assertTrue(requestService.isAuthenticationAllowed(new Credentials(null, null, mockHttpServletRequest("192.168.255.255"))));
assertTrue(requestService.isAuthenticationAllowed(new Credentials(null, null, mockHttpServletRequest("1.2.3.4"))));
assertTrue(requestService.isAuthenticationAllowed(new Credentials(null, null, mockHttpServletRequest("::1"))));
assertTrue(requestService.isAuthenticationAllowed(new Credentials(null, null, mockHttpServletRequest("fc00::"))));
assertTrue(requestService.isAuthenticationAllowed(new Credentials(null, null, mockHttpServletRequest("fdff:ffff:ffff:ffff:ffff:ffff:ffff:ffff"))));
}
catch (AssertionError e) {
fail("A trusted network was denied to authenticate.");
@@ -428,20 +429,20 @@ public class RequestValidationServiceTest {
requestService = new RequestValidationService(new MockConfigurationService("10.0.0.0/8,127.0.0.0/8,172.16.0.0/12,192.168.0.0/16,1.2.3.4/32,::1/128,fc00::/7"));
try {
assertFalse(requestService.isAuthenticationAllowed(mockHttpServletRequest("9.255.255.255")));
assertFalse(requestService.isAuthenticationAllowed(mockHttpServletRequest("11.0.0.0")));
assertFalse(requestService.isAuthenticationAllowed(mockHttpServletRequest("126.255.255.255")));
assertFalse(requestService.isAuthenticationAllowed(mockHttpServletRequest("128.0.0.0")));
assertFalse(requestService.isAuthenticationAllowed(mockHttpServletRequest("172.15.255.255")));
assertFalse(requestService.isAuthenticationAllowed(mockHttpServletRequest("172.32.0.0")));
assertFalse(requestService.isAuthenticationAllowed(mockHttpServletRequest("192.167.255.255")));
assertFalse(requestService.isAuthenticationAllowed(mockHttpServletRequest("192.169.0.0")));
assertFalse(requestService.isAuthenticationAllowed(mockHttpServletRequest("1.2.3.3")));
assertFalse(requestService.isAuthenticationAllowed(mockHttpServletRequest("1.2.3.5")));
assertFalse(requestService.isAuthenticationAllowed(mockHttpServletRequest("::0")));
assertFalse(requestService.isAuthenticationAllowed(mockHttpServletRequest("::2")));
assertFalse(requestService.isAuthenticationAllowed(mockHttpServletRequest("fbff:ffff:ffff:ffff:ffff:ffff:ffff:ffff")));
assertFalse(requestService.isAuthenticationAllowed(mockHttpServletRequest("fe00::")));
assertFalse(requestService.isAuthenticationAllowed(new Credentials(null, null, mockHttpServletRequest("9.255.255.255"))));
assertFalse(requestService.isAuthenticationAllowed(new Credentials(null, null, mockHttpServletRequest("11.0.0.0"))));
assertFalse(requestService.isAuthenticationAllowed(new Credentials(null, null, mockHttpServletRequest("126.255.255.255"))));
assertFalse(requestService.isAuthenticationAllowed(new Credentials(null, null, mockHttpServletRequest("128.0.0.0"))));
assertFalse(requestService.isAuthenticationAllowed(new Credentials(null, null, mockHttpServletRequest("172.15.255.255"))));
assertFalse(requestService.isAuthenticationAllowed(new Credentials(null, null, mockHttpServletRequest("172.32.0.0"))));
assertFalse(requestService.isAuthenticationAllowed(new Credentials(null, null, mockHttpServletRequest("192.167.255.255"))));
assertFalse(requestService.isAuthenticationAllowed(new Credentials(null, null, mockHttpServletRequest("192.169.0.0"))));
assertFalse(requestService.isAuthenticationAllowed(new Credentials(null, null, mockHttpServletRequest("1.2.3.3"))));
assertFalse(requestService.isAuthenticationAllowed(new Credentials(null, null, mockHttpServletRequest("1.2.3.5"))));
assertFalse(requestService.isAuthenticationAllowed(new Credentials(null, null, mockHttpServletRequest("::0"))));
assertFalse(requestService.isAuthenticationAllowed(new Credentials(null, null, mockHttpServletRequest("::2"))));
assertFalse(requestService.isAuthenticationAllowed(new Credentials(null, null, mockHttpServletRequest("fbff:ffff:ffff:ffff:ffff:ffff:ffff:ffff"))));
assertFalse(requestService.isAuthenticationAllowed(new Credentials(null, null, mockHttpServletRequest("fe00::"))));
}
catch (AssertionError e) {
fail("An untrusted network was allowed to authenticate.");