GUACAMOLE-1152: Correctly differentiate between client errors and server errors.

By definition, a client error is not an internal error, but an
intentional refusal of the server to handle a malformed or otherwise
invalid request. These should not be handled in the same way as server
errors which unexpectedly block processing of a request and should be
corrected by an administrator.

In the case of GUACAMOLE-1152, client errors should not be ignored even
if failures are explicitly configured as tolerated for the associated
authentication provider.
This commit is contained in:
Michael Jumper
2020-08-17 16:48:52 -07:00
parent 475d9419cc
commit 10e47a19ff
2 changed files with 23 additions and 63 deletions

View File

@@ -21,12 +21,12 @@ package org.apache.guacamole.extension;
import java.util.Set; import java.util.Set;
import java.util.UUID; import java.util.UUID;
import org.apache.guacamole.GuacamoleClientException;
import org.apache.guacamole.GuacamoleException; import org.apache.guacamole.GuacamoleException;
import org.apache.guacamole.net.auth.AuthenticatedUser; import org.apache.guacamole.net.auth.AuthenticatedUser;
import org.apache.guacamole.net.auth.AuthenticationProvider; import org.apache.guacamole.net.auth.AuthenticationProvider;
import org.apache.guacamole.net.auth.Credentials; import org.apache.guacamole.net.auth.Credentials;
import org.apache.guacamole.net.auth.UserContext; import org.apache.guacamole.net.auth.UserContext;
import org.apache.guacamole.net.auth.credentials.GuacamoleCredentialsException;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@@ -190,41 +190,15 @@ public class AuthenticationProviderFacade implements AuthenticationProvider {
return authProvider.authenticateUser(credentials); return authProvider.authenticateUser(credentials);
} }
// Pass through credential exceptions untouched, as these are not // Pass through client exceptions untouched, including credential
// internal failures // exceptions, as these are not internal failures
catch (GuacamoleCredentialsException e) { catch (GuacamoleClientException e) {
throw e; throw e;
} }
// Pass through all other exceptions (aborting authentication entirely) // Pass through all other exceptions (aborting authentication entirely)
// only if not configured to ignore such failures // only if not configured to ignore such failures
catch (GuacamoleException e) { catch (GuacamoleException | RuntimeException | Error e) {
// Skip using this authentication provider if configured to ignore
// internal failures during auth
if (isFailureTolerated()) {
warnAuthProviderSkipped(e);
return null;
}
warnAuthAborted();
throw e;
}
catch (RuntimeException e) {
// Skip using this authentication provider if configured to ignore
// internal failures during auth
if (isFailureTolerated()) {
warnAuthProviderSkipped(e);
return null;
}
warnAuthAborted();
throw e;
}
catch (Error e) {
// Skip using this authentication provider if configured to ignore // Skip using this authentication provider if configured to ignore
// internal failures during auth // internal failures during auth
@@ -274,41 +248,15 @@ public class AuthenticationProviderFacade implements AuthenticationProvider {
return authProvider.getUserContext(authenticatedUser); return authProvider.getUserContext(authenticatedUser);
} }
// Pass through credential exceptions untouched, as these are not // Pass through client exceptions untouched, including credential
// internal failures // exceptions, as these are not internal failures
catch (GuacamoleCredentialsException e) { catch (GuacamoleClientException e) {
throw e; throw e;
} }
// Pass through all other exceptions (aborting authentication entirely) // Pass through all other exceptions (aborting authentication entirely)
// only if not configured to ignore such failures // only if not configured to ignore such failures
catch (GuacamoleException e) { catch (GuacamoleException | RuntimeException | Error e) {
// Skip using this authentication provider if configured to ignore
// internal failures during auth
if (isFailureTolerated()) {
warnAuthProviderSkipped(e);
return null;
}
warnAuthAborted();
throw e;
}
catch (RuntimeException e) {
// Skip using this authentication provider if configured to ignore
// internal failures during auth
if (isFailureTolerated()) {
warnAuthProviderSkipped(e);
return null;
}
warnAuthAborted();
throw e;
}
catch (Error e) {
// Skip using this authentication provider if configured to ignore // Skip using this authentication provider if configured to ignore
// internal failures during auth // internal failures during auth

View File

@@ -27,6 +27,7 @@ import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response; import javax.ws.rs.core.Response;
import javax.ws.rs.ext.ExceptionMapper; import javax.ws.rs.ext.ExceptionMapper;
import javax.ws.rs.ext.Provider; import javax.ws.rs.ext.Provider;
import org.apache.guacamole.GuacamoleClientException;
import org.apache.guacamole.GuacamoleException; import org.apache.guacamole.GuacamoleException;
import org.apache.guacamole.GuacamoleUnauthorizedException; import org.apache.guacamole.GuacamoleUnauthorizedException;
import org.apache.guacamole.rest.auth.AuthenticationService; import org.apache.guacamole.rest.auth.AuthenticationService;
@@ -91,14 +92,25 @@ public class RESTExceptionMapper implements ExceptionMapper<Throwable> {
} }
// Translate GuacamoleException subclasses to HTTP error codes // Translate GuacamoleException subclasses to HTTP error codes
if (t instanceof GuacamoleException) if (t instanceof GuacamoleException) {
// Always log the human-readable details of GuacacamoleExceptions
// for the benefit of the administrator
if (t instanceof GuacamoleClientException)
logger.debug("Client request rejected: {}", t.getMessage());
else {
logger.error("Request could not be processed: {}", t.getMessage());
logger.debug("Processing of request aborted by extension.", t);
}
return Response return Response
.status(((GuacamoleException) t).getHttpStatusCode()) .status(((GuacamoleException) t).getHttpStatusCode())
.entity(new APIError((GuacamoleException) t)) .entity(new APIError((GuacamoleException) t))
.type(MediaType.APPLICATION_JSON) .type(MediaType.APPLICATION_JSON)
.build(); .build();
}
// Rethrow unchecked exceptions such that they are properly wrapped // Wrap unchecked exceptions
String message = t.getMessage(); String message = t.getMessage();
if (message != null) if (message != null)
logger.error("Unexpected internal error: {}", message); logger.error("Unexpected internal error: {}", message);