GUACAMOLE-566: Handle all exceptions, not just GuacamoleException instances.
Project: http://git-wip-us.apache.org/repos/asf/guacamole-client/repo Commit: http://git-wip-us.apache.org/repos/asf/guacamole-client/commit/a3faf6a2 Tree: http://git-wip-us.apache.org/repos/asf/guacamole-client/tree/a3faf6a2 Diff: http://git-wip-us.apache.org/repos/asf/guacamole-client/diff/a3faf6a2 Branch: refs/heads/master Commit: a3faf6a2eeb0955fede6db74156d51df22da4a39 Parents: 75c8fc8 Author: Nick Couchman <[email protected]> Authored: Tue May 29 22:13:04 2018 -0400 Committer: Nick Couchman <[email protected]> Committed: Tue May 29 22:13:04 2018 -0400 ---------------------------------------------------------------------- .../rest/GuacamoleExceptionMapper.java | 111 ----------------- .../guacamole/rest/RESTExceptionMapper.java | 118 +++++++++++++++++++ .../guacamole/rest/RESTServiceModule.java | 4 +- 3 files changed, 120 insertions(+), 113 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/a3faf6a2/guacamole/src/main/java/org/apache/guacamole/rest/GuacamoleExceptionMapper.java ---------------------------------------------------------------------- diff --git a/guacamole/src/main/java/org/apache/guacamole/rest/GuacamoleExceptionMapper.java b/guacamole/src/main/java/org/apache/guacamole/rest/GuacamoleExceptionMapper.java deleted file mode 100644 index dd8c76e..0000000 --- a/guacamole/src/main/java/org/apache/guacamole/rest/GuacamoleExceptionMapper.java +++ /dev/null @@ -1,111 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.apache.guacamole.rest; - -import com.google.inject.Inject; -import com.google.inject.Singleton; -import java.lang.annotation.Annotation; -import java.lang.reflect.Method; -import java.util.Map; -import javax.servlet.http.HttpServletRequest; -import javax.ws.rs.FormParam; -import javax.ws.rs.QueryParam; -import javax.ws.rs.core.Context; -import javax.ws.rs.core.MediaType; -import javax.ws.rs.core.Response; -import javax.ws.rs.ext.ExceptionMapper; -import javax.ws.rs.ext.Provider; -import org.aopalliance.intercept.MethodInvocation; -import org.apache.guacamole.GuacamoleException; -import org.apache.guacamole.GuacamoleUnauthorizedException; -import org.apache.guacamole.rest.auth.AuthenticationService; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * A class that maps GuacamoleExceptions in a way that returns a - * custom response to the user via JSON rather than allowing the default - * web application error handling to take place. - */ -@Provider -@Singleton -public class GuacamoleExceptionMapper - implements ExceptionMapper<GuacamoleException> { - - /** - * The logger for this class. - */ - private final Logger logger = LoggerFactory.getLogger(GuacamoleExceptionMapper.class); - - /** - * The request associated with this instance of this mapper. - */ - @Context private HttpServletRequest request; - - /** - * The authentication service associated with the currently active session. - */ - @Inject - private AuthenticationService authenticationService; - - /** - * Returns the authentication token that is in use in the current session, - * if present, or null if otherwise. - * - * @return - * The authentication token for the current session, or null if no - * token is present. - */ - private String getAuthenticationToken() { - - @SuppressWarnings("unchecked") - Map<String, String[]> parameters = request.getParameterMap(); - - for (String paramName : parameters.keySet()) { - if (paramName.equals("token")) { - String tokenParams[] = parameters.get(paramName); - if (tokenParams[0] != null && !tokenParams[0].isEmpty()) - return tokenParams[0]; - } - } - - return null; - - } - - @Override - public Response toResponse(GuacamoleException e) { - - if (e instanceof GuacamoleUnauthorizedException) { - String token = getAuthenticationToken(); - - if (authenticationService.destroyGuacamoleSession(token)) - logger.debug("Implicitly invalidated session for token \"{}\"", token); - } - - return Response - .status(e.getHttpStatusCode()) - .entity(new APIError(e)) - .type(MediaType.APPLICATION_JSON) - .build(); - - } - -} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/a3faf6a2/guacamole/src/main/java/org/apache/guacamole/rest/RESTExceptionMapper.java ---------------------------------------------------------------------- diff --git a/guacamole/src/main/java/org/apache/guacamole/rest/RESTExceptionMapper.java b/guacamole/src/main/java/org/apache/guacamole/rest/RESTExceptionMapper.java new file mode 100644 index 0000000..ae35274 --- /dev/null +++ b/guacamole/src/main/java/org/apache/guacamole/rest/RESTExceptionMapper.java @@ -0,0 +1,118 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.guacamole.rest; + +import com.google.inject.Inject; +import com.google.inject.Singleton; +import javax.servlet.http.HttpServletRequest; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import javax.ws.rs.ext.ExceptionMapper; +import javax.ws.rs.ext.Provider; +import org.apache.guacamole.GuacamoleException; +import org.apache.guacamole.GuacamoleUnauthorizedException; +import org.apache.guacamole.rest.auth.AuthenticationService; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * A class that maps GuacamoleExceptions in a way that returns a + * custom response to the user via JSON rather than allowing the default + * web application error handling to take place. + */ +@Provider +@Singleton +public class RESTExceptionMapper implements ExceptionMapper<Throwable> { + + /** + * The logger for this class. + */ + private final Logger logger = LoggerFactory.getLogger(RESTExceptionMapper.class); + + /** + * The request associated with this instance of this mapper. + */ + @Context + private HttpServletRequest request; + + /** + * The authentication service associated with the currently active session. + */ + @Inject + private AuthenticationService authenticationService; + + /** + * Returns the authentication token that is in use in the current session, + * if present, or null if otherwise. + * + * @return + * The authentication token for the current session, or null if no + * token is present. + */ + private String getAuthenticationToken() { + + String token = request.getParameter("token"); + if (token != null && !token.isEmpty()) + return token; + + return null; + + } + + @Override + public Response toResponse(Throwable t) { + + // Ensure any associated session is invalidated if unauthorized + if (t instanceof GuacamoleUnauthorizedException) { + String token = getAuthenticationToken(); + + if (authenticationService.destroyGuacamoleSession(token)) + logger.debug("Implicitly invalidated session for token \"{}\"", token); + } + + // Translate GuacamoleException subclasses to HTTP error codes + if (t instanceof GuacamoleException) + return Response + .status(((GuacamoleException) t).getHttpStatusCode()) + .entity(new APIError((GuacamoleException)t)) + .type(MediaType.APPLICATION_JSON) + .build(); + + // Rethrow unchecked exceptions such that they are properly wrapped + String message = t.getMessage(); + if (message != null) + logger.error("Unexpected internal error: {}", message); + else + logger.error("An internal error occurred, but did not contain " + + "an error message. Enable debug-level logging for " + + "details."); + + logger.debug("Unexpected error in REST endpoint.", t); + + return Response + .status(Response.Status.INTERNAL_SERVER_ERROR) + .entity("Unexpected Internal Error.") + .type(MediaType.APPLICATION_JSON) + .build(); + + } + +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/a3faf6a2/guacamole/src/main/java/org/apache/guacamole/rest/RESTServiceModule.java ---------------------------------------------------------------------- diff --git a/guacamole/src/main/java/org/apache/guacamole/rest/RESTServiceModule.java b/guacamole/src/main/java/org/apache/guacamole/rest/RESTServiceModule.java index 8075b1e..b23eec6 100644 --- a/guacamole/src/main/java/org/apache/guacamole/rest/RESTServiceModule.java +++ b/guacamole/src/main/java/org/apache/guacamole/rest/RESTServiceModule.java @@ -84,8 +84,8 @@ public class RESTServiceModule extends ServletModule { bind(AuthTokenGenerator.class).to(SecureRandomAuthTokenGenerator.class); bind(DecorationService.class); - // Get the ExceptionMapper that will rewrite exceptions into JSON. - bind(GuacamoleExceptionMapper.class); + // Automatically translate GuacamoleExceptions for REST methods + bind(RESTExceptionMapper.class); // Set up the API endpoints bind(ExtensionRESTService.class);
