GUACAMOLE-2181: Rely on automatic stack traces for debug-level logs.

This commit is contained in:
Michael Jumper committed 2025-12-08 20:24:10 -08:00
1 parent c92694c458
commit ea06e01ddd
44 files changed
+152 -243

No files matched your search

@@ -343,15 +343,13 @@ public class ModeledConnection extends ModeledChildDirectoryObject<ConnectionMod
// Translate connection limit attribute // Translate connection limit attribute
try { getModel().setMaxConnections(NumericField.parse(attributes.get(MAX_CONNECTIONS_NAME))); } try { getModel().setMaxConnections(NumericField.parse(attributes.get(MAX_CONNECTIONS_NAME))); }
catch (NumberFormatException e) { catch (NumberFormatException e) {
logger.warn("Not setting maximum connections: {}", e.getMessage()); logger.warn("Not setting maximum connections: {}", e.getMessage(), e);
logger.debug("Unable to parse numeric attribute.", e);
} }
// Translate per-user connection limit attribute // Translate per-user connection limit attribute
try { getModel().setMaxConnectionsPerUser(NumericField.parse(attributes.get(MAX_CONNECTIONS_PER_USER_NAME))); } try { getModel().setMaxConnectionsPerUser(NumericField.parse(attributes.get(MAX_CONNECTIONS_PER_USER_NAME))); }
catch (NumberFormatException e) { catch (NumberFormatException e) {
logger.warn("Not setting maximum connections per user: {}", e.getMessage()); logger.warn("Not setting maximum connections per user: {}", e.getMessage(), e);
logger.debug("Unable to parse numeric attribute.", e);
} }
// Translate guacd hostname // Translate guacd hostname
@@ -360,8 +358,7 @@ public class ModeledConnection extends ModeledChildDirectoryObject<ConnectionMod
// Translate guacd port // Translate guacd port
try { getModel().setProxyPort(NumericField.parse(attributes.get(GUACD_PORT_NAME))); } try { getModel().setProxyPort(NumericField.parse(attributes.get(GUACD_PORT_NAME))); }
catch (NumberFormatException e) { catch (NumberFormatException e) {
logger.warn("Not setting guacd port: {}", e.getMessage()); logger.warn("Not setting guacd port: {}", e.getMessage(), e);
logger.debug("Unable to parse numeric attribute.", e);
} }
// Translate guacd encryption method // Translate guacd encryption method
@@ -382,8 +379,7 @@ public class ModeledConnection extends ModeledChildDirectoryObject<ConnectionMod
// Translate connection weight attribute // Translate connection weight attribute
try { getModel().setConnectionWeight(NumericField.parse(attributes.get(CONNECTION_WEIGHT))); } try { getModel().setConnectionWeight(NumericField.parse(attributes.get(CONNECTION_WEIGHT))); }
catch (NumberFormatException e) { catch (NumberFormatException e) {
logger.warn("Not setting the connection weight: {}", e.getMessage()); logger.warn("Not setting the connection weight: {}", e.getMessage(), e);
logger.debug("Unable to parse numeric attribute.", e);
} }
// Translate failover-only attribute // Translate failover-only attribute
@@ -200,15 +200,13 @@ public class ModeledConnectionGroup extends ModeledChildDirectoryObject<Connecti
// Translate connection limit attribute // Translate connection limit attribute
try { getModel().setMaxConnections(NumericField.parse(attributes.get(MAX_CONNECTIONS_NAME))); } try { getModel().setMaxConnections(NumericField.parse(attributes.get(MAX_CONNECTIONS_NAME))); }
catch (NumberFormatException e) { catch (NumberFormatException e) {
logger.warn("Not setting maximum connections: {}", e.getMessage()); logger.warn("Not setting maximum connections: {}", e.getMessage(), e);
logger.debug("Unable to parse numeric attribute.", e);
} }
// Translate per-user connection limit attribute // Translate per-user connection limit attribute
try { getModel().setMaxConnectionsPerUser(NumericField.parse(attributes.get(MAX_CONNECTIONS_PER_USER_NAME))); } try { getModel().setMaxConnectionsPerUser(NumericField.parse(attributes.get(MAX_CONNECTIONS_PER_USER_NAME))); }
catch (NumberFormatException e) { catch (NumberFormatException e) {
logger.warn("Not setting maximum connections per user: {}", e.getMessage()); logger.warn("Not setting maximum connections per user: {}", e.getMessage(), e);
logger.debug("Unable to parse numeric attribute.", e);
} }
// Translate session affinity attribute // Translate session affinity attribute
@@ -778,8 +778,9 @@ public abstract class AbstractGuacamoleTunnelService implements GuacamoleTunnelS
// If connection failed due to an upstream error, retry other // If connection failed due to an upstream error, retry other
// connections // connections
catch (GuacamoleUpstreamException e) { catch (GuacamoleUpstreamException e) {
logger.info("Upstream error intercepted for connection \"{}\". Failing over to next connection in group...", connection.getIdentifier()); logger.info("Upstream error intercepted for connection \"{}\". "
logger.debug("Upstream remote desktop reported an error during connection.", e); + "Failing over to next connection in group...",
connection.getIdentifier(), e);
connections.remove(connection); connections.remove(connection);
upstreamHasFailed = true; upstreamHasFailed = true;
} }
@@ -442,8 +442,7 @@ public class ModeledUser extends ModeledPermissions<UserModel> implements User {
if (attributes.containsKey(ACCESS_WINDOW_START_ATTRIBUTE_NAME)) { if (attributes.containsKey(ACCESS_WINDOW_START_ATTRIBUTE_NAME)) {
try { getModel().setAccessWindowStart(parseTime(attributes.get(ACCESS_WINDOW_START_ATTRIBUTE_NAME))); } try { getModel().setAccessWindowStart(parseTime(attributes.get(ACCESS_WINDOW_START_ATTRIBUTE_NAME))); }
catch (ParseException e) { catch (ParseException e) {
logger.warn("Not setting start time of user access window: {}", e.getMessage()); logger.warn("Not setting start time of user access window: {}", e.getMessage(), e);
logger.debug("Unable to parse time attribute.", e);
} }
} }
@@ -451,8 +450,7 @@ public class ModeledUser extends ModeledPermissions<UserModel> implements User {
if (attributes.containsKey(ACCESS_WINDOW_END_ATTRIBUTE_NAME)) { if (attributes.containsKey(ACCESS_WINDOW_END_ATTRIBUTE_NAME)) {
try { getModel().setAccessWindowEnd(parseTime(attributes.get(ACCESS_WINDOW_END_ATTRIBUTE_NAME))); } try { getModel().setAccessWindowEnd(parseTime(attributes.get(ACCESS_WINDOW_END_ATTRIBUTE_NAME))); }
catch (ParseException e) { catch (ParseException e) {
logger.warn("Not setting end time of user access window: {}", e.getMessage()); logger.warn("Not setting end time of user access window: {}", e.getMessage(), e);
logger.debug("Unable to parse time attribute.", e);
} }
} }
@@ -460,8 +458,7 @@ public class ModeledUser extends ModeledPermissions<UserModel> implements User {
if (attributes.containsKey(VALID_FROM_ATTRIBUTE_NAME)) { if (attributes.containsKey(VALID_FROM_ATTRIBUTE_NAME)) {
try { getModel().setValidFrom(parseDate(attributes.get(VALID_FROM_ATTRIBUTE_NAME))); } try { getModel().setValidFrom(parseDate(attributes.get(VALID_FROM_ATTRIBUTE_NAME))); }
catch (ParseException e) { catch (ParseException e) {
logger.warn("Not setting user validity start date: {}", e.getMessage()); logger.warn("Not setting user validity start date: {}", e.getMessage(), e);
logger.debug("Unable to parse date attribute.", e);
} }
} }
@@ -469,8 +466,7 @@ public class ModeledUser extends ModeledPermissions<UserModel> implements User {
if (attributes.containsKey(VALID_UNTIL_ATTRIBUTE_NAME)) { if (attributes.containsKey(VALID_UNTIL_ATTRIBUTE_NAME)) {
try { getModel().setValidUntil(parseDate(attributes.get(VALID_UNTIL_ATTRIBUTE_NAME))); } try { getModel().setValidUntil(parseDate(attributes.get(VALID_UNTIL_ATTRIBUTE_NAME))); }
catch (ParseException e) { catch (ParseException e) {
logger.warn("Not setting user validity end date: {}", e.getMessage()); logger.warn("Not setting user validity end date: {}", e.getMessage(), e);
logger.debug("Unable to parse date attribute.", e);
} }
} }
@@ -325,13 +325,9 @@ public class ModeledUserContext extends RestrictedObject
} }
catch (GuacamoleException e) { catch (GuacamoleException e) {
logger.warn("Unable to determine if access window enforcement is"
logger.warn( + " enabled for active sessions; enforcing by default: {}",
"Unable to determine if access window enforcement is" e.getMessage(), e);
+ " enabled for active sessions; enforcing by default: {}"
, e.getMessage());
logger.debug("Unable to determine access window enforcement policy.", e);
} }
// A user context is valid if the associated user's account is valid // A user context is valid if the associated user's account is valid
@@ -78,14 +78,15 @@ public class RequestValidationService {
// Deny all requests if restrictions cannot be parsed // Deny all requests if restrictions cannot be parsed
catch (GuacamoleException e) { catch (GuacamoleException e) {
logger.warn("Authentication request from \"{}\" is DENIED due to parse error: {}", credentials.getRemoteAddress(), e.getMessage()); logger.warn("Authentication request from \"{}\" is DENIED due to "
logger.debug("Error parsing authentication request restrictions from guacamole.properties.", e); + "parse error: {}", credentials.getRemoteAddress(), e.getMessage(), e);
return false; return false;
} }
// All requests are allowed if no restrictions are defined // All requests are allowed if no restrictions are defined
if (trustedNetworks.isEmpty()) { if (trustedNetworks.isEmpty()) {
logger.debug("Authentication request from \"{}\" is ALLOWED (no restrictions).", credentials.getRemoteAddress()); logger.debug("Authentication request from \"{}\" is ALLOWED (no "
+ "restrictions).", credentials.getRemoteAddress());
return true; return true;
} }
@@ -94,14 +95,16 @@ public class RequestValidationService {
// Request is allowed if any subnet matches // Request is allowed if any subnet matches
if (new IPAddressString(network).contains(new IPAddressString(credentials.getRemoteAddress()))) { if (new IPAddressString(network).contains(new IPAddressString(credentials.getRemoteAddress()))) {
logger.debug("Authentication request from \"{}\" is ALLOWED (matched subnet).", credentials.getRemoteAddress()); logger.debug("Authentication request from \"{}\" is ALLOWED "
+ "(matched subnet).", credentials.getRemoteAddress());
return true; return true;
} }
} }
// Otherwise request is denied - no subnets matched // Otherwise request is denied - no subnets matched
logger.debug("Authentication request from \"{}\" is DENIED (did not match subnet).", credentials.getRemoteAddress()); logger.debug("Authentication request from \"{}\" is DENIED (did not "
+ "match subnet).", credentials.getRemoteAddress());
return false; return false;
} }
@@ -168,22 +168,19 @@ public class UserDataService {
// Fail if base64 data is not valid // Fail if base64 data is not valid
catch (IllegalArgumentException e) { catch (IllegalArgumentException e) {
logger.warn("Submitted data is not proper base64."); logger.warn("Submitted data is not proper base64: {}", e.getMessage(), e);
logger.debug("Invalid base64 data.", e);
return null; return null;
} }
// Handle lack of standard UTF-8 support (should never happen) // Handle lack of standard UTF-8 support (should never happen)
catch (UnsupportedEncodingException e) { catch (UnsupportedEncodingException e) {
logger.error("Unexpected lack of support for UTF-8: {}", e.getMessage()); logger.error("Unexpected lack of support for UTF-8: {}", e.getMessage(), e);
logger.debug("Unable to decode base64 data as UTF-8.", e);
return null; return null;
} }
// Fail if decryption or key retrieval fails for any reason // Fail if decryption or key retrieval fails for any reason
catch (GuacamoleException e) { catch (GuacamoleException e) {
logger.error("Decryption of received data failed: {}", e.getMessage()); logger.error("Decryption of received data failed: {}", e.getMessage(), e);
logger.debug("Unable to decrypt received data.", e);
return null; return null;
} }
@@ -205,8 +202,7 @@ public class UserDataService {
// Fail UserData creation if JSON is invalid/unreadable // Fail UserData creation if JSON is invalid/unreadable
catch (IOException e) { catch (IOException e) {
logger.error("Received JSON is invalid: {}", e.getMessage()); logger.error("Received JSON is invalid: {}", e.getMessage(), e);
logger.debug("Error parsing UserData JSON.", e);
return null; return null;
} }
@@ -322,8 +322,7 @@ public class LDAPConnectionService {
ldapConnection.close(); ldapConnection.close();
logger.error("Binding with the LDAP server at \"{}\" as user " logger.error("Binding with the LDAP server at \"{}\" as user "
+ "\"{}\" failed: {}", config.getLdapHost(), bindUser, + "\"{}\" failed: {}", config.getLdapHost(), bindUser,
e.getMessage()); e.getMessage(), e);
logger.debug("Unable to bind to LDAP server.", e);
return null; return null;
} }
@@ -369,8 +368,8 @@ public class LDAPConnectionService {
} }
catch (LdapInvalidDnException e) { catch (LdapInvalidDnException e) {
logger.error("Credentials of existing connection cannot be used. " logger.error("Credentials of existing connection cannot be used. "
+ "The username used (\"{}\") is not a valid DN.", username); + "The username used (\"{}\") is not a valid DN.",
logger.debug("Cannot bind using invalid DN.", e); username, e);
ldapConnection.close(); ldapConnection.close();
return null; return null;
} }
@@ -265,8 +265,7 @@ public class ObjectQueryService {
+ "URL \"{}\".", url); + "URL \"{}\".", url);
} }
catch (GuacamoleException e) { catch (GuacamoleException e) {
logger.warn("Referral to \"{}\" could not be followed: {}", url, e.getMessage()); logger.warn("Referral to \"{}\" could not be followed: {}", url, e.getMessage(), e);
logger.debug("Failed to follow LDAP referral.", e);
} }
} }
@@ -122,7 +122,7 @@ public class ConfigurationService {
} }
catch (IOException e) { catch (IOException e) {
logger.error("\"{}\" could not be read/parsed: {}", ldapServers, e.getMessage()); logger.error("\"{}\" could not be read/parsed: {}", ldapServers, e.getMessage(), e);
} }
} }
else else
@@ -202,8 +202,7 @@ public class ConnectionService {
} }
catch (LdapInvalidAttributeValueException e) { catch (LdapInvalidAttributeValueException e) {
logger.error("Invalid value for {} attribute: {}", logger.error("Invalid value for {} attribute: {}",
LDAP_ATTRIBUTE_NAME_ID, e.getMessage()); LDAP_ATTRIBUTE_NAME_ID, e.getMessage(), e);
logger.debug("LDAP exception while getting CN attribute.", e);
return null; return null;
} }
@@ -223,8 +222,7 @@ public class ConnectionService {
config.setProtocol(protocol.getString()); config.setProtocol(protocol.getString());
} }
catch (LdapInvalidAttributeValueException e) { catch (LdapInvalidAttributeValueException e) {
logger.error("Invalid value of the protocol entry: {}", e.getMessage()); logger.error("Invalid value of the protocol entry: {}", e.getMessage(), e);
logger.debug("LDAP exception when getting protocol value.", e);
return null; return null;
} }
@@ -234,8 +232,7 @@ public class ConnectionService {
proxyConfig = getProxyConfiguration(entry); proxyConfig = getProxyConfiguration(entry);
} }
catch (GuacamoleException e) { catch (GuacamoleException e) {
logger.error("Failed to retrieve proxy configuration.", e.getMessage()); logger.error("Failed to retrieve proxy configuration.", e.getMessage(), e);
logger.debug("Guacamole Exception when retrieving proxy configuration.", e);
return null; return null;
} }
@@ -250,8 +247,7 @@ public class ConnectionService {
parameter = parameterAttribute.getString(); parameter = parameterAttribute.getString();
} }
catch (LdapInvalidAttributeValueException e) { catch (LdapInvalidAttributeValueException e) {
logger.warn("Parameter value not valid for {}: {}", cnName, e.getMessage()); logger.warn("Parameter value not valid for {}: {}", cnName, e.getMessage(), e);
logger.debug("LDAP exception when getting parameter value.", e);
return null; return null;
} }
parameterAttribute.remove(parameter); parameterAttribute.remove(parameter);
@@ -394,8 +390,7 @@ public class ConnectionService {
return new GuacamoleProxyConfiguration(proxyHostname, proxyPort, proxyEncryption); return new GuacamoleProxyConfiguration(proxyHostname, proxyPort, proxyEncryption);
} }
catch (LdapInvalidAttributeValueException e) { catch (LdapInvalidAttributeValueException e) {
logger.error("Invalid value in proxy configuration: {}", e.getMessage()); logger.error("Invalid value in proxy configuration: {}", e.getMessage(), e);
logger.debug("LDAP exception fetching proxy attribute value.", e);
throw new GuacamoleServerException("Invalid LDAP value in proxy configuration.", e); throw new GuacamoleServerException("Invalid LDAP value in proxy configuration.", e);
} }
} }
@@ -214,9 +214,7 @@ public class UserGroupService {
} }
catch (LdapInvalidAttributeValueException e) { catch (LdapInvalidAttributeValueException e) {
logger.error("User group missing identifier: {}", logger.error("User group missing identifier: {}",
e.getMessage()); e.getMessage(), e);
logger.debug("LDAP exception while getting "
+ "group identifier.", e);
} }
} }
} }
@@ -280,8 +278,7 @@ public class UserGroupService {
} }
catch (LdapInvalidAttributeValueException e) { catch (LdapInvalidAttributeValueException e) {
logger.error("User group missing identifier: {}", logger.error("User group missing identifier: {}",
e.getMessage()); e.getMessage(), e);
logger.debug("LDAP exception while getting group identifier.", e);
} }
}); });
@@ -95,7 +95,6 @@ public class AuthenticationProviderService {
RadiusAttribute stateAttr = challengePacket.findAttribute(Attr_State.TYPE); RadiusAttribute stateAttr = challengePacket.findAttribute(Attr_State.TYPE);
if (stateAttr == null) { if (stateAttr == null) {
logger.error("Something went wrong, state attribute not present."); logger.error("Something went wrong, state attribute not present.");
logger.debug("State Attribute turned up null, which shouldn't happen in AccessChallenge.");
return null; return null;
} }
@@ -103,7 +102,6 @@ public class AuthenticationProviderService {
RadiusAttribute replyAttr = challengePacket.findAttribute(Attr_ReplyMessage.TYPE); RadiusAttribute replyAttr = challengePacket.findAttribute(Attr_ReplyMessage.TYPE);
if (replyAttr == null) { if (replyAttr == null) {
logger.error("No reply message received from the server."); logger.error("No reply message received from the server.");
logger.debug("Expecting a Attr_ReplyMessage attribute on this packet, and did not get one.");
return null; return null;
} }
@@ -162,8 +160,7 @@ public class AuthenticationProviderService {
null); null);
} }
catch (GuacamoleException e) { catch (GuacamoleException e) {
logger.error("Cannot configure RADIUS server: {}", e.getMessage()); logger.error("Cannot configure RADIUS server: {}", e.getMessage(), e);
logger.debug("Error configuring RADIUS server.", e);
throw new GuacamoleInvalidCredentialsException("Authentication error.", CredentialsInfo.USERNAME_PASSWORD); throw new GuacamoleInvalidCredentialsException("Authentication error.", CredentialsInfo.USERNAME_PASSWORD);
} }
} }
@@ -184,13 +181,11 @@ public class AuthenticationProviderService {
stateBytes); stateBytes);
} }
catch (IllegalArgumentException e) { catch (IllegalArgumentException e) {
logger.warn("Illegal hexadecimal value while parsing RADIUS state string: {}", e.getMessage()); logger.warn("Illegal hexadecimal value while parsing RADIUS state string: {}", e.getMessage(), e);
logger.debug("Encountered exception while attempting to parse the hexidecimal state value.", e);
throw new GuacamoleInvalidCredentialsException("Authentication error.", CredentialsInfo.USERNAME_PASSWORD); throw new GuacamoleInvalidCredentialsException("Authentication error.", CredentialsInfo.USERNAME_PASSWORD);
} }
catch (GuacamoleException e) { catch (GuacamoleException e) {
logger.error("Cannot configure RADIUS server: {}", e.getMessage()); logger.error("Cannot configure RADIUS server: {}", e.getMessage(), e);
logger.debug("Error configuring RADIUS server.", e);
throw new GuacamoleInvalidCredentialsException("Authentication error.", CredentialsInfo.USERNAME_PASSWORD); throw new GuacamoleInvalidCredentialsException("Authentication error.", CredentialsInfo.USERNAME_PASSWORD);
} }
} }
@@ -245,18 +245,15 @@ public class RadiusConnectionService {
} }
catch (RadiusException e) { catch (RadiusException e) {
logger.error("Unable to complete authentication.", e.getMessage()); logger.error("Unable to complete authentication: {}", e.getMessage(), e);
logger.debug("Authentication with RADIUS failed.", e);
return null; return null;
} }
catch (NoSuchAlgorithmException e) { catch (NoSuchAlgorithmException e) {
logger.error("No such RADIUS algorithm: {}", e.getMessage()); logger.error("No such RADIUS algorithm: {}", e.getMessage(), e);
logger.debug("Unknown RADIUS algorithm.", e);
return null; return null;
} }
catch (UnknownHostException e) { catch (UnknownHostException e) {
logger.error("Could not resolve address: {}", e.getMessage()); logger.error("Could not resolve address: {}", e.getMessage(), e);
logger.debug("Exception resolving host address.", e);
return null; return null;
} }
finally { finally {
@@ -64,8 +64,7 @@ public class HostRestrictionParser {
addressList.add(hostName); addressList.add(hostName);
} }
catch (HostNameException e) { catch (HostNameException e) {
LOGGER.warn("Invalid host name or IP: {}", host); LOGGER.warn("Invalid host name or IP: {}", host, e);
LOGGER.debug("HostNameException.", e.getMessage());
} }
} }
@@ -122,12 +122,10 @@ public class TokenValidationService {
} }
// Log any failures to validate/parse the JWT // Log any failures to validate/parse the JWT
catch (MalformedClaimException e) { catch (MalformedClaimException e) {
logger.info("Rejected OpenID token with malformed claim: {}", e.getMessage()); logger.info("Rejected OpenID token with malformed claim: {}", e.getMessage(), e);
logger.debug("Malformed claim within received JWT.", e);
} }
catch (InvalidJwtException e) { catch (InvalidJwtException e) {
logger.info("Rejected invalid OpenID token: {}", e.getMessage()); logger.info("Rejected invalid OpenID token: {}", e.getMessage(), e);
logger.debug("Invalid JWT received.", e);
} }
return null; return null;
@@ -160,8 +158,7 @@ public class TokenValidationService {
return username; return username;
} }
catch (MalformedClaimException e) { catch (MalformedClaimException e) {
logger.info("Rejected OpenID token with malformed claim: {}", e.getMessage()); logger.info("Rejected OpenID token with malformed claim: {}", e.getMessage(), e);
logger.debug("Malformed claim within received JWT.", e);
} }
// Warn if username was not present in token, as it likely means // Warn if username was not present in token, as it likely means
@@ -203,8 +200,7 @@ public class TokenValidationService {
return Collections.unmodifiableSet(new HashSet<>(oidcGroups)); return Collections.unmodifiableSet(new HashSet<>(oidcGroups));
} }
catch (MalformedClaimException e) { catch (MalformedClaimException e) {
logger.info("Rejected OpenID token with malformed claim: {}", e.getMessage()); logger.info("Rejected OpenID token with malformed claim: {}", e.getMessage(), e);
logger.debug("Malformed claim within received JWT.", e);
} }
} }
@@ -262,8 +258,7 @@ public class TokenValidationService {
return Collections.unmodifiableMap(tokens); return Collections.unmodifiableMap(tokens);
} }
catch (MalformedClaimException e) { catch (MalformedClaimException e) {
logger.info("Rejected OpenID token with malformed claim: {}", e.getMessage()); logger.info("Rejected OpenID token with malformed claim: {}", e.getMessage(), e);
logger.debug("Malformed claim within received JWT.", e);
} }
} }
@@ -125,8 +125,7 @@ public class AssertionConsumerServiceResource extends SSOResource {
// If invalid, redirect back to main page to re-attempt authentication // If invalid, redirect back to main page to re-attempt authentication
catch (GuacamoleException e) { catch (GuacamoleException e) {
logger.warn("Authentication attempted with an invalid SAML response: {}", e.getMessage()); logger.warn("Authentication attempted with an invalid SAML response: {}", e.getMessage(), e);
logger.debug("Received SAML response failed validation.", e);
return Response.seeOther(guacBase).build(); return Response.seeOther(guacBase).build();
} }
@@ -351,16 +351,16 @@ public class SSLClientAuthenticationResource extends SSOResource {
} }
catch (GuacamoleClientException e) { catch (GuacamoleClientException e) {
logger.warn("SSL/TLS client authentication attempt rejected: {}", e.getMessage()); logger.warn("SSL/TLS client authentication attempt rejected: {}",
logger.debug("SSL/TLS client authentication failed.", e); e.getMessage(), e);
} }
catch (GuacamoleException e) { catch (GuacamoleException e) {
logger.error("SSL/TLS client authentication attempt could not be processed: {}", e.getMessage()); logger.error("SSL/TLS client authentication attempt could not be "
logger.debug("SSL/TLS client authentication failed.", e); + "processed: {}", e.getMessage(), e);
} }
catch (RuntimeException | Error e) { catch (RuntimeException | Error e) {
logger.error("SSL/TLS client authentication attempt failed internally: {}", e.getMessage()); logger.error("SSL/TLS client authentication attempt failed "
logger.debug("Internal failure processing SSL/TLS client authentication attempt.", e); + "internally: {}", e.getMessage(), e);
} }
return sessionManager.generateInvalid(); return sessionManager.generateInvalid();
@@ -128,8 +128,7 @@ public class UserVerificationService {
// If key is not valid base32, warn but otherwise pretend the key does // If key is not valid base32, warn but otherwise pretend the key does
// not exist // not exist
catch (IllegalArgumentException e) { catch (IllegalArgumentException e) {
logger.warn("TOTP key of user \"{}\" is not valid base32.", self.getIdentifier()); logger.warn("TOTP key of user \"{}\" is not valid base32.", self.getIdentifier(), e);
logger.debug("TOTP key is not valid base32.", e);
return null; return null;
} }
@@ -218,9 +217,7 @@ public class UserVerificationService {
+ "lack permission to update their own account and the " + "lack permission to update their own account and the "
+ "TOTP extension was unable to obtain privileged access. " + "TOTP extension was unable to obtain privileged access. "
+ "TOTP will be disabled for this user.", + "TOTP will be disabled for this user.",
self.getIdentifier()); self.getIdentifier(), e);
logger.debug("Permission denied to set TOTP key of user "
+ "account.", e);
return false; return false;
} }
catch (GuacamoleUnsupportedException e) { catch (GuacamoleUnsupportedException e) {
@@ -422,8 +419,7 @@ public class UserVerificationService {
} }
catch (InvalidKeyException e) { catch (InvalidKeyException e) {
logger.warn("User \"{}\" is associated with an invalid TOTP key.", username); logger.warn("User \"{}\" is associated with an invalid TOTP key.", username, e);
logger.debug("TOTP key is not valid.", e);
} }
// Provided code is not valid // Provided code is not valid
@@ -147,8 +147,8 @@ public class HistoryConnectionRecord extends DelegatingConnectionRecord {
} }
catch (IOException e) { catch (IOException e) {
logger.warn("Possible session recording \"{}\" could not be " logger.warn("Possible session recording \"{}\" could not be "
+ "identified as it cannot be read: {}", file, e.getMessage()); + "identified as it cannot be read: {}",
logger.debug("Possible session recording \"{}\" could not be read.", file, e); file, e.getMessage(), e);
} }
finally { finally {
@@ -161,9 +161,7 @@ public class HistoryConnectionRecord extends DelegatingConnectionRecord {
catch (IOException e) { catch (IOException e) {
logger.warn("Unexpected error closing recording file \"{}\": {}", logger.warn("Unexpected error closing recording file \"{}\": {}",
file, e.getMessage()); file, e.getMessage(), e);
logger.debug("Session recording file \"{}\" could not be closed.",
file, e);
} }
} }
@@ -297,8 +295,9 @@ public class HistoryConnectionRecord extends DelegatingConnectionRecord {
.array()); .array());
} }
catch (MalformedURLException e) { catch (MalformedURLException e) {
logger.warn("Ignoring file \"{}\" as a unique URL and UUID for that file could not be generated: {}", e.getMessage()); logger.warn("Ignoring file \"{}\" as a unique URL and UUID for "
logger.debug("URL for file \"{}\" could not be determined.", file, e); + "that file could not be generated: {}",
e.getMessage(), e);
return; return;
} }
@@ -155,15 +155,12 @@ public class KsmAttributeService implements VaultAttributeService {
catch (GuacamoleException e) { catch (GuacamoleException e) {
logger.warn( // If the configuration can't be parsed, default to not exposing
"Unable to determine if KSM user attributes " // the attributes
+ "should be exposed due to config parsing error: {}.", e.getMessage()); logger.warn("Unable to determine if KSM user attributes should be "
logger.debug( + "exposed due to config parsing error: {}.", e.getMessage(), e);
"Config parsing error prevented checking user attribute configuration",
e);
// If the configuration can't be parsed, default to not exposing the attributes
return Collections.emptyList(); return Collections.emptyList();
} }
} }
@@ -781,7 +781,7 @@ public class KsmClient {
// Show the warning only if there is no fallback function // Show the warning only if there is no fallback function
// and this was the last attempt // and this was the last attempt
logger.warn("Keeper notation \"{}\" could not be resolved " logger.warn("Keeper notation \"{}\" could not be resolved "
+ "to a record: {}", notation, e.getMessage()); + "to a record: {}", notation, e.getMessage(), e);
return CompletableFuture.completedFuture(null); return CompletableFuture.completedFuture(null);
} }
@@ -87,13 +87,10 @@ import com.google.inject.assistedinject.AssistedInject;
boolean userKsmConfigEnabled = false; boolean userKsmConfigEnabled = false;
try { try {
userKsmConfigEnabled = configurationService.getAllowUserConfig(); userKsmConfigEnabled = configurationService.getAllowUserConfig();
} catch (GuacamoleException e) { }
catch (GuacamoleException e) {
logger.warn( logger.warn("Disabling user KSM config due to exception: {}",
"Disabling user KSM config due to exception: {}" e.getMessage(), e);
, e.getMessage());
logger.debug("Error looking up if user KSM config is enabled.", e);
} }
// If user-specific KSM configuration is not enabled, do not expose the // If user-specific KSM configuration is not enabled, do not expose the
@@ -112,4 +109,4 @@ import com.google.inject.assistedinject.AssistedInject;
return attributes; return attributes;
} }
} }
@@ -328,13 +328,12 @@ public abstract class GuacamoleHTTPTunnelServlet extends HttpServlet {
// Catch any thrown guacamole exception and attempt to pass within the // Catch any thrown guacamole exception and attempt to pass within the
// HTTP response, logging each error appropriately. // HTTP response, logging each error appropriately.
catch (GuacamoleClientException e) { catch (GuacamoleClientException e) {
logger.warn("HTTP tunnel request rejected: {}", e.getMessage()); logger.warn("HTTP tunnel request rejected: {}", e.getMessage(), e);
sendError(response, e.getStatus().getGuacamoleStatusCode(), sendError(response, e.getStatus().getGuacamoleStatusCode(),
e.getStatus().getHttpStatusCode(), e.getMessage()); e.getStatus().getHttpStatusCode(), e.getMessage());
} }
catch (GuacamoleException e) { catch (GuacamoleException e) {
logger.error("HTTP tunnel request failed: {}", e.getMessage()); logger.error("HTTP tunnel request failed: {}", e.getMessage(), e);
logger.debug("Internal error in HTTP tunnel.", e);
sendError(response, e.getStatus().getGuacamoleStatusCode(), sendError(response, e.getStatus().getGuacamoleStatusCode(),
e.getStatus().getHttpStatusCode(), "Internal server error."); e.getStatus().getHttpStatusCode(), "Internal server error.");
} }
@@ -205,8 +205,7 @@ public abstract class GuacamoleWebSocketTunnelEndpoint extends Endpoint {
} }
catch (GuacamoleException e) { catch (GuacamoleException e) {
logger.error("Creation of WebSocket tunnel to guacd failed: {}", e.getMessage()); logger.error("Creation of WebSocket tunnel to guacd failed: {}", e.getMessage(), e);
logger.debug("Error connecting WebSocket tunnel.", e);
closeConnection(session, e.getStatus().getGuacamoleStatusCode(), closeConnection(session, e.getStatus().getGuacamoleStatusCode(),
e.getWebSocketCode()); e.getWebSocketCode());
return; return;
@@ -265,8 +264,7 @@ public abstract class GuacamoleWebSocketTunnelEndpoint extends Endpoint {
// to pass within the WebSocket connection, logging // to pass within the WebSocket connection, logging
// each error appropriately. // each error appropriately.
catch (GuacamoleClientException e) { catch (GuacamoleClientException e) {
logger.info("WebSocket connection terminated: {}", e.getMessage()); logger.info("WebSocket connection terminated: {}", e.getMessage(), e);
logger.debug("WebSocket connection terminated due to client error.", e);
closeConnection(session, e.getStatus().getGuacamoleStatusCode(), closeConnection(session, e.getStatus().getGuacamoleStatusCode(),
e.getWebSocketCode()); e.getWebSocketCode());
} }
@@ -275,8 +273,7 @@ public abstract class GuacamoleWebSocketTunnelEndpoint extends Endpoint {
closeConnection(session, GuacamoleStatus.SUCCESS); closeConnection(session, GuacamoleStatus.SUCCESS);
} }
catch (GuacamoleException e) { catch (GuacamoleException e) {
logger.error("Connection to guacd terminated abnormally: {}", e.getMessage()); logger.error("Connection to guacd terminated abnormally: {}", e.getMessage(), e);
logger.debug("Internal error during connection to guacd.", e);
closeConnection(session, e.getStatus().getGuacamoleStatusCode(), closeConnection(session, e.getStatus().getGuacamoleStatusCode(),
e.getWebSocketCode()); e.getWebSocketCode());
} }
@@ -158,9 +158,8 @@ class DefaultEnvironment extends DelegatingEnvironment {
logger.error("Defaulting to case-sensitive handling of " logger.error("Defaulting to case-sensitive handling of "
+ "usernames and group names as the desired case " + "usernames and group names as the desired case "
+ "sensitivity configuration could not be read: {}", + "sensitivity configuration could not be read: {}",
e.getMessage()); e.getMessage(), e);
logger.debug("Error reading case sensitivity configuration.", e);
return CaseSensitivity.ENABLED; return CaseSensitivity.ENABLED;
} }
@@ -266,8 +266,9 @@ public class LocalEnvironment implements Environment {
} }
catch (IOException e) { catch (IOException e) {
logger.error("Unable to read connection parameter information from \"{}\": {}", file.getAbsolutePath(), e.getMessage()); logger.error("Unable to read connection parameter "
logger.debug("Error reading protocol JSON.", e); + "information from \"{}\": {}",
file.getAbsolutePath(), e.getMessage(), e);
} }
} }
@@ -290,8 +291,9 @@ public class LocalEnvironment implements Environment {
protocols.put(protocol, readProtocol(stream)); protocols.put(protocol, readProtocol(stream));
} }
catch (IOException e) { catch (IOException e) {
logger.error("Unable to read pre-defined connection parameter information for protocol \"{}\": {}", protocol, e.getMessage()); logger.error("Unable to read pre-defined connection "
logger.debug("Error reading pre-defined protocol JSON.", e); + "parameter information for protocol \"{}\": {}",
protocol, e.getMessage(), e);
} }
} }
@@ -166,8 +166,7 @@ public class GuacamoleServletContextListener extends GuiceServletContextListener
logger.info("Read configuration parameters from \"{}\".", guacProperties); logger.info("Read configuration parameters from \"{}\".", guacProperties);
} }
catch (GuacamoleException e) { catch (GuacamoleException e) {
logger.error("Unable to read guacamole.properties: {}", e.getMessage()); logger.error("Unable to read guacamole.properties: {}", e.getMessage(), e);
logger.debug("Error reading guacamole.properties.", e);
} }
// For any values not defined in GUACAMOLE_HOME/guacamole.properties, // For any values not defined in GUACAMOLE_HOME/guacamole.properties,
@@ -181,8 +180,7 @@ public class GuacamoleServletContextListener extends GuiceServletContextListener
} }
} }
catch (GuacamoleException e) { catch (GuacamoleException e) {
logger.error("Unable to configure support for environment properties: {}", e.getMessage()); logger.error("Unable to configure support for environment properties: {}", e.getMessage(), e);
logger.debug("Error reading \"{}\" property from guacamole.properties.", ENABLE_ENVIRONMENT_PROPERTIES.getName(), e);
} }
// For any values not defined in GUACAMOLE_HOME/guacamole.properties // For any values not defined in GUACAMOLE_HOME/guacamole.properties
@@ -198,8 +196,7 @@ public class GuacamoleServletContextListener extends GuiceServletContextListener
} }
} }
catch (GuacamoleException e) { catch (GuacamoleException e) {
logger.error("Unable to configure support for file environment properties: {}", e.getMessage()); logger.error("Unable to configure support for file environment properties: {}", e.getMessage(), e);
logger.debug("Error reading \"{}\" property from guacamole.properties.", ENABLE_FILE_ENVIRONMENT_PROPERTIES.getName(), e);
} }
// Now that at least the main guacamole.properties source of // Now that at least the main guacamole.properties source of
@@ -225,8 +222,7 @@ public class GuacamoleServletContextListener extends GuiceServletContextListener
}); });
} }
catch (GuacamoleException e) { catch (GuacamoleException e) {
logger.error("An extension listening for application startup failed: {}", e.getMessage()); logger.error("An extension listening for application startup failed: {}", e.getMessage(), e);
logger.debug("Extension failed internally while handling the application startup event.", e);
} }
} }
@@ -307,8 +303,7 @@ public class GuacamoleServletContextListener extends GuiceServletContextListener
}); });
} }
catch (GuacamoleException e) { catch (GuacamoleException e) {
logger.error("An extension listening for application shutdown failed: {}", e.getMessage()); logger.error("An extension listening for application shutdown failed: {}", e.getMessage(), e);
logger.debug("Extension failed internally while handling the application shutdown event.", e);
} }
} }
@@ -320,8 +320,7 @@ public class GuacamoleSession {
}); });
} }
catch (GuacamoleException e) { catch (GuacamoleException e) {
logger.error("An extension listening for session invalidation failed: {}", e.getMessage()); logger.error("An extension listening for session invalidation failed: {}", e.getMessage(), e);
logger.debug("Extension failed internally while handling the session invalidation event.", e);
} }
} }
@@ -51,8 +51,8 @@ public class SystemFileEnvironmentGuacamoleProperties implements GuacamoleProper
return Files.asCharSource(new File(filename), StandardCharsets.UTF_8).read(); return Files.asCharSource(new File(filename), StandardCharsets.UTF_8).read();
} }
catch (IOException e) { catch (IOException e) {
logger.error("Property \"{}\" could not be read from file \"{}\": {}", name, filename, e.getMessage()); logger.error("Property \"{}\" could not be read from file \"{}\": {}", name,
logger.debug("Error reading property value from file.", e); filename, e.getMessage(), e);
} }
} }
@@ -106,13 +106,13 @@ public class FileAuthenticationProvider extends SimpleAuthenticationProvider {
parser = SAXParserFactory.newInstance().newSAXParser(); parser = SAXParserFactory.newInstance().newSAXParser();
} }
catch (ParserConfigurationException e) { catch (ParserConfigurationException e) {
logger.error("Unable to create XML parser for reading \"{}\": {}", USER_MAPPING_FILENAME, e.getMessage()); logger.error("Unable to create XML parser for reading \"{}\": {}",
logger.debug("An instance of SAXParser could not be created.", e); USER_MAPPING_FILENAME, e.getMessage(), e);
return null; return null;
} }
catch (SAXException e) { catch (SAXException e) {
logger.error("Unable to create XML parser for reading \"{}\": {}", USER_MAPPING_FILENAME, e.getMessage()); logger.error("Unable to create XML parser for reading \"{}\": {}",
logger.debug("An instance of SAXParser could not be created.", e); USER_MAPPING_FILENAME, e.getMessage(), e);
return null; return null;
} }
@@ -138,15 +138,13 @@ public class FileAuthenticationProvider extends SimpleAuthenticationProvider {
// If the file is unreadable, return no mapping // If the file is unreadable, return no mapping
catch (IOException e) { catch (IOException e) {
logger.warn("Unable to read user mapping file \"{}\": {}", userMappingFile, e.getMessage()); logger.warn("Unable to read user mapping file \"{}\": {}", userMappingFile, e.getMessage(), e);
logger.debug("Error reading user mapping file.", e);
return null; return null;
} }
// If the file cannot be parsed, return no mapping // If the file cannot be parsed, return no mapping
catch (SAXException e) { catch (SAXException e) {
logger.warn("User mapping file \"{}\" is not valid: {}", userMappingFile, e.getMessage()); logger.warn("User mapping file \"{}\" is not valid: {}", userMappingFile, e.getMessage(), e);
logger.debug("Error parsing user mapping file.", e);
return null; return null;
} }
@@ -182,15 +182,11 @@ public class AuthenticationProviderFacade implements AuthenticationProvider {
* authentication provider being skipped. * authentication provider being skipped.
*/ */
private void warnAuthProviderSkipped(Throwable e) { private void warnAuthProviderSkipped(Throwable e) {
logger.warn("The \"{}\" authentication provider has been skipped due " logger.warn("The \"{}\" authentication provider has been skipped due "
+ "to an internal error. If this is unexpected or you are the " + "to an internal error. If this is unexpected or you are the "
+ "developer of this authentication provider, you may wish to " + "developer of this authentication provider, you may wish to "
+ "enable debug-level logging: {}", + "enable debug-level logging: {}",
getIdentifier(), e.getMessage()); getIdentifier(), e.getMessage(), e);
logger.debug("Authentication provider skipped due to an internal failure.", e);
} }
/** /**
@@ -434,8 +434,9 @@ public class ExtensionModule extends ServletModule {
// Use empty set by default if property cannot be parsed // Use empty set by default if property cannot be parsed
catch (GuacamoleException e) { catch (GuacamoleException e) {
logger.warn("The list of authentication providers specified via the \"{}\" property could not be parsed: {}", SKIP_IF_UNAVAILABLE.getName(), e.getMessage()); logger.warn("The list of authentication providers specified via "
logger.debug("Unable to parse \"{}\" property.", SKIP_IF_UNAVAILABLE.getName(), e); + "the \"{}\" property could not be parsed: {}",
SKIP_IF_UNAVAILABLE.getName(), e.getMessage(), e);
return Collections.<String>emptySet(); return Collections.<String>emptySet();
} }
@@ -457,8 +458,9 @@ public class ExtensionModule extends ServletModule {
// Sort by filename if the desired order cannot be read // Sort by filename if the desired order cannot be read
catch (GuacamoleException e) { catch (GuacamoleException e) {
logger.warn("The list of extensions specified via the \"{}\" property could not be parsed: {}", EXTENSION_PRIORITY.getName(), e.getMessage()); logger.warn("The list of extensions specified via the \"{}\" "
logger.debug("Unable to parse \"{}\" property.", EXTENSION_PRIORITY.getName(), e); + "property could not be parsed: {}",
EXTENSION_PRIORITY.getName(), e.getMessage(), e);
return ExtensionOrderProperty.DEFAULT_COMPARATOR; return ExtensionOrderProperty.DEFAULT_COMPARATOR;
} }
@@ -522,8 +524,8 @@ public class ExtensionModule extends ServletModule {
} }
catch (GuacamoleException e) { catch (GuacamoleException e) {
logger.error("Extension \"{}\" could not be loaded: {}", extensionFile.getName(), e.getMessage()); logger.error("Extension \"{}\" could not be loaded: {}",
logger.debug("Unable to load extension.", e); extensionFile.getName(), e.getMessage(), e);
} }
} }
@@ -125,8 +125,7 @@ public class LanguageResourceService {
// Warn of failure to parse // Warn of failure to parse
catch (GuacamoleException e) { catch (GuacamoleException e) {
parsedAllowedLanguages = null; parsedAllowedLanguages = null;
logger.error("Unable to parse list of allowed languages: {}", e.getMessage()); logger.error("Unable to parse list of allowed languages: {}", e.getMessage(), e);
logger.debug("Error parsing list of allowed languages.", e);
} }
this.allowedLanguages = parsedAllowedLanguages; this.allowedLanguages = parsedAllowedLanguages;
@@ -308,8 +307,7 @@ public class LanguageResourceService {
} }
catch (IOException e) { catch (IOException e) {
logger.error("Unable to merge language resource \"{}\": {}", key, e.getMessage()); logger.error("Unable to merge language resource \"{}\": {}", key, e.getMessage(), e);
logger.debug("Error merging language resource.", e);
} }
} }
@@ -437,8 +435,7 @@ public class LanguageResourceService {
// Continue with next language if unable to read // Continue with next language if unable to read
catch (IOException e) { catch (IOException e) {
logger.warn("Unable to read language resource \"{}\".", languageKey); logger.warn("Unable to read language resource \"{}\".", languageKey, e);
logger.debug("Error reading language resource.", e);
} }
} }
@@ -61,35 +61,29 @@ class ProviderFactory {
catch (NoSuchMethodException e) { catch (NoSuchMethodException e) {
logger.error("The {} extension in use is not properly defined. " logger.error("The {} extension in use is not properly defined. "
+ "Please contact the developers of the extension or, if you " + "Please contact the developers of the extension or, if you "
+ "are the developer, turn on debug-level logging.", typeName); + "are the developer, turn on debug-level logging.",
logger.debug("{} is missing a default constructor.", typeName, e);
providerClass.getName(), e);
} }
catch (SecurityException e) { catch (SecurityException e) {
logger.error("The Java security manager is preventing extensions " logger.error("The Java security manager is preventing extensions "
+ "from being loaded. Please check the configuration of Java or your " + "from being loaded. Please check the configuration of Java or your "
+ "servlet container."); + "servlet container.", e);
logger.debug("Creation of {} disallowed by security manager.",
providerClass.getName(), e);
} }
catch (InstantiationException e) { catch (InstantiationException e) {
logger.error("The {} extension in use is not properly defined. " logger.error("The {} extension in use is not properly defined. "
+ "Please contact the developers of the extension or, if you " + "Please contact the developers of the extension or, if you "
+ "are the developer, turn on debug-level logging.", typeName); + "are the developer, turn on debug-level logging.",
logger.debug("{} cannot be instantiated.", providerClass.getName(), e); typeName, e);
} }
catch (IllegalAccessException e) { catch (IllegalAccessException e) {
logger.error("The {} extension in use is not properly defined. " logger.error("The {} extension in use is not properly defined. "
+ "Please contact the developers of the extension or, if you " + "Please contact the developers of the extension or, if you "
+ "are the developer, turn on debug-level logging."); + "are the developer, turn on debug-level logging.", e);
logger.debug("Default constructor of {} is not public.", typeName, e);
} }
catch (IllegalArgumentException e) { catch (IllegalArgumentException e) {
logger.error("The {} extension in use is not properly defined. " logger.error("The {} extension in use is not properly defined. "
+ "Please contact the developers of the extension or, if you " + "Please contact the developers of the extension or, if you "
+ "are the developer, turn on debug-level logging.", typeName); + "are the developer, turn on debug-level logging.", typeName, e);
logger.debug("Default constructor of {} cannot accept zero arguments.",
providerClass.getName(), e);
} }
catch (InvocationTargetException e) { catch (InvocationTargetException e) {
// Obtain causing error - create relatively-informative stub error if cause is unknown // Obtain causing error - create relatively-informative stub error if cause is unknown
@@ -97,8 +91,7 @@ class ProviderFactory {
if (cause == null) if (cause == null)
cause = new GuacamoleException("Error encountered during initialization."); cause = new GuacamoleException("Error encountered during initialization.");
logger.error("{} extension failed to start: {}", typeName, cause.getMessage()); logger.error("{} extension failed to start: {}", typeName, cause.getMessage(), cause);
logger.debug("{} instantiation failed.", providerClass.getName(), e);
} }
return instance; return instance;
@@ -187,7 +187,7 @@ public class LogModule extends AbstractModule {
} }
catch (FileNotFoundException e) { catch (FileNotFoundException e) {
logger.info("Logback configuration could not be read " logger.info("Logback configuration could not be read "
+ "from \"{}\": {}", logbackFile, e.getMessage()); + "from \"{}\": {}", logbackFile, e.getMessage(), e);
} }
} }
@@ -200,7 +200,7 @@ public class LogModule extends AbstractModule {
} }
catch (GuacamoleException e) { catch (GuacamoleException e) {
level = LogLevel.INFO; level = LogLevel.INFO;
logger.error("Falling back to \"{}\" log level: {}", level.getCanonicalName(), e.getMessage()); logger.error("Falling back to \"{}\" log level: {}", level.getCanonicalName(), e.getMessage(), e);
} }
return level.getLogbackConfiguration(); return level.getLogbackConfiguration();
@@ -232,12 +232,10 @@ public class LogModule extends AbstractModule {
} }
catch (JoranException e) { catch (JoranException e) {
logger.error("Initialization of logback failed: {}", e.getMessage()); logger.error("Initialization of logback failed: {}", e.getMessage(), e);
logger.debug("Unable to load logback configuration.", e);
} }
catch (IOException e) { catch (IOException e) {
logger.warn("Logback configuration file could not be cleanly closed: {}", e.getMessage()); logger.warn("Logback configuration file could not be cleanly closed: {}", e.getMessage(), e);
logger.debug("Failed to close logback configuration file.", e);
} }
} }
@@ -75,7 +75,7 @@ public class RESTExceptionMapper implements ExceptionMapper<Throwable> {
if (t instanceof GuacamoleUnauthorizedException) { if (t instanceof GuacamoleUnauthorizedException) {
String token = authenticationService.getAuthenticationToken(request); String token = authenticationService.getAuthenticationToken(request);
if (authenticationService.destroyGuacamoleSession(token)) if (authenticationService.destroyGuacamoleSession(token))
logger.debug("Implicitly invalidated session for token \"{}\"", token); logger.debug("Implicitly invalidated session for token \"{}\"", token, t);
} }
// Translate GuacamoleException subclasses to HTTP error codes // Translate GuacamoleException subclasses to HTTP error codes
@@ -84,11 +84,9 @@ public class RESTExceptionMapper implements ExceptionMapper<Throwable> {
// Always log the human-readable details of GuacacamoleExceptions // Always log the human-readable details of GuacacamoleExceptions
// for the benefit of the administrator // for the benefit of the administrator
if (t instanceof GuacamoleClientException) if (t instanceof GuacamoleClientException)
logger.debug("Client request rejected: {}", t.getMessage()); logger.debug("Client request rejected: {}", t.getMessage(), t);
else { else
logger.error("Request could not be processed: {}", t.getMessage()); logger.error("Request could not be processed: {}", t.getMessage(), t);
logger.debug("Processing of request aborted by extension.", t);
}
return Response return Response
.status(((GuacamoleException) t).getHttpStatusCode()) .status(((GuacamoleException) t).getHttpStatusCode())
@@ -100,13 +98,11 @@ public class RESTExceptionMapper implements ExceptionMapper<Throwable> {
// Wrap unchecked exceptions // 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, t);
else else
logger.error("An internal error occurred, but did not contain " logger.error("An internal error occurred, but did not contain "
+ "an error message. Enable debug-level logging for " + "an error message. Enable debug-level logging for "
+ "details."); + "details.", t);
logger.debug("Unexpected error in REST endpoint.", t);
return Response return Response
.status(Response.Status.INTERNAL_SERVER_ERROR) .status(Response.Status.INTERNAL_SERVER_ERROR)
@@ -433,12 +433,12 @@ public class AuthenticationService {
// This line SHOULD be unreachable unless a bug causes // This line SHOULD be unreachable unless a bug causes
// rethrowCause() to not actually rethrow the underlying failure // rethrowCause() to not actually rethrow the underlying failure
Throwable cause = e.getCause(); Throwable cause = e.getCause();
if (cause != null) { if (cause != null)
logger.warn("An underlying internal error was not correctly rethrown by rethrowCause(): {}", cause.getMessage()); logger.warn("An underlying internal error was not correctly "
logger.debug("Internal error not rethrown by rethrowCause().", cause); + "rethrown by rethrowCause(): {}", cause.getMessage(), cause);
}
else else
logger.warn("An underlying internal error was not correctly rethrown by rethrowCause()."); logger.warn("An underlying internal error was not correctly "
+ "rethrown by rethrowCause().");
throw e.getCauseAsGuacamoleException(); throw e.getCauseAsGuacamoleException();
@@ -81,8 +81,7 @@ public class HashTokenSessionMap implements TokenSessionMap {
sessionTimeoutValue = environment.getProperty(API_SESSION_TIMEOUT, 60); sessionTimeoutValue = environment.getProperty(API_SESSION_TIMEOUT, 60);
} }
catch (GuacamoleException e) { catch (GuacamoleException e) {
logger.error("Unable to read guacamole.properties: {}", e.getMessage()); logger.error("Unable to read guacamole.properties: {}", e.getMessage(), e);
logger.debug("Error while reading session timeout value.", e);
sessionTimeoutValue = 60; sessionTimeoutValue = 60;
} }
@@ -69,8 +69,7 @@ public class InterceptedStreamMap<T extends Closeable> {
stream.close(); stream.close();
} }
catch (IOException e) { catch (IOException e) {
logger.warn("Unable to close intercepted stream: {}", e.getMessage()); logger.warn("Unable to close intercepted stream: {}", e.getMessage(), e);
logger.debug("I/O error prevented closure of intercepted stream.", e);
} }
// Notify waiting threads that the stream has ended // Notify waiting threads that the stream has ended
@@ -130,8 +130,7 @@ public class OutputStreamInterceptingFilter
blob = BaseEncoding.base64().decode(data); blob = BaseEncoding.base64().decode(data);
} }
catch (IllegalArgumentException e) { catch (IllegalArgumentException e) {
logger.warn("Received base64 data for intercepted stream was invalid."); logger.warn("Received base64 data for intercepted stream was invalid.", e);
logger.debug("Decoding base64 data for intercepted stream failed.", e);
return null; return null;
} }
@@ -240,8 +240,7 @@ public abstract class GuacamoleWebSocketTunnelServlet extends WebSocketServlet {
tunnel = doConnect(tunnelRequest); tunnel = doConnect(tunnelRequest);
} }
catch (GuacamoleException e) { catch (GuacamoleException e) {
logger.error("Creation of WebSocket tunnel to guacd failed: {}", e.getMessage()); logger.error("Creation of WebSocket tunnel to guacd failed: {}", e.getMessage(), e);
logger.debug("Error connecting WebSocket tunnel.", e);
closeConnection(connection, e.getStatus().getGuacamoleStatusCode(), closeConnection(connection, e.getStatus().getGuacamoleStatusCode(),
e.getWebSocketCode()); e.getWebSocketCode());
return; return;
@@ -295,8 +294,7 @@ public abstract class GuacamoleWebSocketTunnelServlet extends WebSocketServlet {
// to pass within the WebSocket connection, logging // to pass within the WebSocket connection, logging
// each error appropriately. // each error appropriately.
catch (GuacamoleClientException e) { catch (GuacamoleClientException e) {
logger.info("WebSocket connection terminated: {}", e.getMessage()); logger.info("WebSocket connection terminated: {}", e.getMessage(), e);
logger.debug("WebSocket connection terminated due to client error.", e);
closeConnection(connection, e.getStatus().getGuacamoleStatusCode(), closeConnection(connection, e.getStatus().getGuacamoleStatusCode(),
e.getWebSocketCode()); e.getWebSocketCode());
} }
@@ -305,8 +303,7 @@ public abstract class GuacamoleWebSocketTunnelServlet extends WebSocketServlet {
closeConnection(connection, GuacamoleStatus.SUCCESS); closeConnection(connection, GuacamoleStatus.SUCCESS);
} }
catch (GuacamoleException e) { catch (GuacamoleException e) {
logger.error("Connection to guacd terminated abnormally: {}", e.getMessage()); logger.error("Connection to guacd terminated abnormally: {}", e.getMessage(), e);
logger.debug("Internal error during connection to guacd.", e);
closeConnection(connection, e.getStatus().getGuacamoleStatusCode(), closeConnection(connection, e.getStatus().getGuacamoleStatusCode(),
e.getWebSocketCode()); e.getWebSocketCode());
} }
@@ -196,8 +196,7 @@ public abstract class GuacamoleWebSocketTunnelListener implements WebSocketListe
} }
catch (GuacamoleException e) { catch (GuacamoleException e) {
logger.error("Creation of WebSocket tunnel to guacd failed: {}", e.getMessage()); logger.error("Creation of WebSocket tunnel to guacd failed: {}", e.getMessage(), e);
logger.debug("Error connecting WebSocket tunnel.", e);
closeConnection(session, e.getStatus().getGuacamoleStatusCode(), e.getWebSocketCode()); closeConnection(session, e.getStatus().getGuacamoleStatusCode(), e.getWebSocketCode());
return; return;
} }
@@ -245,8 +244,7 @@ public abstract class GuacamoleWebSocketTunnelListener implements WebSocketListe
// to pass within the WebSocket connection, logging // to pass within the WebSocket connection, logging
// each error appropriately. // each error appropriately.
catch (GuacamoleClientException e) { catch (GuacamoleClientException e) {
logger.info("WebSocket connection terminated: {}", e.getMessage()); logger.info("WebSocket connection terminated: {}", e.getMessage(), e);
logger.debug("WebSocket connection terminated due to client error.", e);
closeConnection(session, e.getStatus().getGuacamoleStatusCode(), closeConnection(session, e.getStatus().getGuacamoleStatusCode(),
e.getWebSocketCode()); e.getWebSocketCode());
} }
@@ -255,8 +253,7 @@ public abstract class GuacamoleWebSocketTunnelListener implements WebSocketListe
closeConnection(session, GuacamoleStatus.SUCCESS); closeConnection(session, GuacamoleStatus.SUCCESS);
} }
catch (GuacamoleException e) { catch (GuacamoleException e) {
logger.error("Connection to guacd terminated abnormally: {}", e.getMessage()); logger.error("Connection to guacd terminated abnormally: {}", e.getMessage(), e);
logger.debug("Internal error during connection to guacd.", e);
closeConnection(session, e.getStatus().getGuacamoleStatusCode(), closeConnection(session, e.getStatus().getGuacamoleStatusCode(),
e.getWebSocketCode()); e.getWebSocketCode());
} }
@@ -268,8 +268,7 @@ public abstract class GuacamoleWebSocketTunnelServlet extends WebSocketServlet {
tunnel = doConnect(tunnelRequest); tunnel = doConnect(tunnelRequest);
} }
catch (GuacamoleException e) { catch (GuacamoleException e) {
logger.error("Creation of WebSocket tunnel to guacd failed: {}", e.getMessage()); logger.error("Creation of WebSocket tunnel to guacd failed: {}", e.getMessage(), e);
logger.debug("Error connecting WebSocket tunnel.", e);
closeConnection(outbound, e.getStatus().getGuacamoleStatusCode(), closeConnection(outbound, e.getStatus().getGuacamoleStatusCode(),
e.getWebSocketCode()); e.getWebSocketCode());
return; return;
@@ -323,8 +322,7 @@ public abstract class GuacamoleWebSocketTunnelServlet extends WebSocketServlet {
// to pass within the WebSocket connection, logging // to pass within the WebSocket connection, logging
// each error appropriately. // each error appropriately.
catch (GuacamoleClientException e) { catch (GuacamoleClientException e) {
logger.info("WebSocket connection terminated: {}", e.getMessage()); logger.info("WebSocket connection terminated: {}", e.getMessage(), e);
logger.debug("WebSocket connection terminated due to client error.", e);
closeConnection(outbound, e.getStatus().getGuacamoleStatusCode(), closeConnection(outbound, e.getStatus().getGuacamoleStatusCode(),
e.getWebSocketCode()); e.getWebSocketCode());
} }
@@ -333,8 +331,7 @@ public abstract class GuacamoleWebSocketTunnelServlet extends WebSocketServlet {
closeConnection(outbound, GuacamoleStatus.SUCCESS); closeConnection(outbound, GuacamoleStatus.SUCCESS);
} }
catch (GuacamoleException e) { catch (GuacamoleException e) {
logger.error("Connection to guacd terminated abnormally: {}", e.getMessage()); logger.error("Connection to guacd terminated abnormally: {}", e.getMessage(), e);
logger.debug("Internal error during connection to guacd.", e);
closeConnection(outbound, e.getStatus().getGuacamoleStatusCode(), closeConnection(outbound, e.getStatus().getGuacamoleStatusCode(),
e.getWebSocketCode()); e.getWebSocketCode());
} }