From 89b4ff642fe5687e96f27e35044e635ec470b7b8 Mon Sep 17 00:00:00 2001 From: Michael Jumper Date: Mon, 13 Apr 2015 12:38:03 -0700 Subject: [PATCH] GUAC-1102: Reconstitute consumed HTTP requests with an external collection of parameter name/value pairs. --- .../guacamole/net/basic/rest/APIRequest.java | 107 ++++++++++++++++++ .../net/basic/rest/auth/TokenRESTService.java | 21 +++- 2 files changed, 125 insertions(+), 3 deletions(-) create mode 100644 guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/APIRequest.java diff --git a/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/APIRequest.java b/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/APIRequest.java new file mode 100644 index 000000000..c1a79cc7c --- /dev/null +++ b/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/APIRequest.java @@ -0,0 +1,107 @@ +/* + * Copyright (C) 2015 Glyptodon LLC + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package org.glyptodon.guacamole.net.basic.rest; + +import java.util.Collections; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletRequestWrapper; +import javax.ws.rs.core.MultivaluedMap; + +/** + * Wrapper for HttpServletRequest which uses a given MultivaluedMap to provide + * the values of all request parameters. + * + * @author Michael Jumper + */ +public class APIRequest extends HttpServletRequestWrapper { + + /** + * Map of all request parameter names to their corresponding values. + */ + private final Map parameters; + + /** + * Wraps the given HttpServletRequest, using the given MultivaluedMap to + * provide all request parameters. All HttpServletRequest functions which + * do not deal with parameter names and values are delegated to the wrapped + * request. + * + * @param request + * The HttpServletRequest to wrap. + * + * @param parameters + * All request parameters. + */ + public APIRequest(HttpServletRequest request, + MultivaluedMap parameters) { + + super(request); + + // Copy parameters from given MultivaluedMap + this.parameters = new HashMap(parameters.size()); + for (Map.Entry> entry : parameters.entrySet()) { + + // Get parameter name and all corresponding values + String name = entry.getKey(); + List values = entry.getValue(); + + // Add parameters to map + this.parameters.put(name, values.toArray(new String[values.size()])); + + } + + } + + @Override + public String[] getParameterValues(String name) { + return parameters.get(name); + } + + @Override + public Enumeration getParameterNames() { + return Collections.enumeration(parameters.keySet()); + } + + @Override + public Map getParameterMap() { + return Collections.unmodifiableMap(parameters); + } + + @Override + public String getParameter(String name) { + + // If no such parameter exists, just return null + String[] values = getParameterValues(name); + if (values == null) + return null; + + // Otherwise, return first value + return values[0]; + + } + +} diff --git a/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/auth/TokenRESTService.java b/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/auth/TokenRESTService.java index 9e46507bc..c7f7da6e8 100644 --- a/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/auth/TokenRESTService.java +++ b/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/auth/TokenRESTService.java @@ -34,6 +34,7 @@ import javax.ws.rs.PathParam; import javax.ws.rs.Produces; import javax.ws.rs.core.Context; import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.MultivaluedMap; import javax.ws.rs.core.Response.Status; import javax.xml.bind.DatatypeConverter; import org.glyptodon.guacamole.GuacamoleException; @@ -41,6 +42,7 @@ import org.glyptodon.guacamole.net.auth.AuthenticationProvider; import org.glyptodon.guacamole.net.auth.Credentials; import org.glyptodon.guacamole.net.auth.UserContext; import org.glyptodon.guacamole.net.basic.GuacamoleSession; +import org.glyptodon.guacamole.net.basic.rest.APIRequest; import org.glyptodon.guacamole.net.basic.rest.AuthProviderRESTExposure; import org.glyptodon.guacamole.net.basic.rest.HTTPException; import org.slf4j.Logger; @@ -140,8 +142,16 @@ public class TokenRESTService { * An optional existing auth token for the user who is to be * authenticated. * - * @param request - * The HttpServletRequest associated with the login attempt. + * @param consumedRequest + * The HttpServletRequest associated with the login attempt. The + * parameters of this request may not be accessible, as the request may + * have been fully consumed by JAX-RS. + * + * @param parameters + * A MultivaluedMap containing all parameters from the given HTTP + * request. All request parameters must be made available through this + * map, even if those parameters are no longer accessible within the + * now-fully-consumed HTTP request. * * @return The auth token for the newly logged-in user. * @throws GuacamoleException If an error prevents successful login. @@ -151,8 +161,13 @@ public class TokenRESTService { public APIAuthToken createToken(@FormParam("username") String username, @FormParam("password") String password, @FormParam("token") String token, - @Context HttpServletRequest request) throws GuacamoleException { + @Context HttpServletRequest consumedRequest, + MultivaluedMap parameters) + throws GuacamoleException { + // Reconstitute the HTTP request with the map of parameters + HttpServletRequest request = new APIRequest(consumedRequest, parameters); + // Pull existing session if token provided GuacamoleSession existingSession; if (token != null)