mirror of
https://github.com/gyurix1968/guacamole-client.git
synced 2025-09-06 13:17:41 +00:00
GUAC-919: Copy REST and Guice changes over from GUAC-546 branch.
This commit is contained in:
committed by
Michael Jumper
parent
48382b8285
commit
6bf2ff3e2f
Binary file not shown.
@@ -185,6 +185,55 @@
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- Guice - Dependency Injection -->
|
||||
<dependency>
|
||||
<groupId>com.google.inject</groupId>
|
||||
<artifactId>guice</artifactId>
|
||||
<version>3.0</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Guice Servlet -->
|
||||
<dependency>
|
||||
<groupId>com.google.inject.extensions</groupId>
|
||||
<artifactId>guice-servlet</artifactId>
|
||||
<version>3.0</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Jersey - JAX-RS Implementation -->
|
||||
<dependency>
|
||||
<groupId>com.sun.jersey</groupId>
|
||||
<artifactId>jersey-server</artifactId>
|
||||
<version>1.17.1</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Jersey - Guice extension -->
|
||||
<dependency>
|
||||
<groupId>com.sun.jersey.contribs</groupId>
|
||||
<artifactId>jersey-guice</artifactId>
|
||||
<version>1.17.1</version>
|
||||
</dependency>
|
||||
|
||||
<!-- JSR-250 annotations -->
|
||||
<dependency>
|
||||
<groupId>javax.annotation</groupId>
|
||||
<artifactId>jsr250-api</artifactId>
|
||||
<version>1.0</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Apache commons codec library -->
|
||||
<dependency>
|
||||
<groupId>commons-codec</groupId>
|
||||
<artifactId>commons-codec</artifactId>
|
||||
<version>1.4</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Jackson for JSON support -->
|
||||
<dependency>
|
||||
<groupId>com.sun.jersey</groupId>
|
||||
<artifactId>jersey-json</artifactId>
|
||||
<version>1.17.1</version>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
|
@@ -1,452 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2013 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;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.util.Collection;
|
||||
import java.util.regex.Pattern;
|
||||
import javax.servlet.Filter;
|
||||
import javax.servlet.FilterChain;
|
||||
import javax.servlet.FilterConfig;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.ServletRequest;
|
||||
import javax.servlet.ServletResponse;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.servlet.http.HttpSession;
|
||||
import javax.xml.bind.DatatypeConverter;
|
||||
import org.glyptodon.guacamole.GuacamoleClientException;
|
||||
import org.glyptodon.guacamole.GuacamoleException;
|
||||
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.event.SessionListenerCollection;
|
||||
import org.glyptodon.guacamole.net.basic.properties.BasicGuacamoleProperties;
|
||||
import org.glyptodon.guacamole.net.event.AuthenticationFailureEvent;
|
||||
import org.glyptodon.guacamole.net.event.AuthenticationSuccessEvent;
|
||||
import org.glyptodon.guacamole.net.event.listener.AuthenticationFailureListener;
|
||||
import org.glyptodon.guacamole.net.event.listener.AuthenticationSuccessListener;
|
||||
import org.glyptodon.guacamole.properties.GuacamoleProperties;
|
||||
import org.glyptodon.guacamole.protocol.GuacamoleStatus;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Filter which provides watches requests for credentials, authenticating the
|
||||
* user against the configured AuthenticationProvider if credentials are
|
||||
* present. Note that if authentication fails, the request is still allowed. To
|
||||
* restrict access based on the result of authentication, use
|
||||
* RestrictedHttpServlet or RestrictedFilter.
|
||||
*
|
||||
* The user context is retrieved using the authentication provider defined in
|
||||
* guacamole.properties. The authentication provider has access to the request
|
||||
* and session, in addition to any submitted username and password, in order
|
||||
* to authenticate the user.
|
||||
*
|
||||
* The user context will be stored in the current HttpSession.
|
||||
*
|
||||
* Success and failure are logged.
|
||||
*
|
||||
* @author Michael Jumper
|
||||
*/
|
||||
public class AuthenticatingFilter implements Filter {
|
||||
|
||||
/**
|
||||
* Logger for this class.
|
||||
*/
|
||||
private final Logger logger = LoggerFactory.getLogger(AuthenticatingFilter.class);
|
||||
|
||||
/**
|
||||
* The session attribute holding the current UserContext.
|
||||
*/
|
||||
public static final String CONTEXT_ATTRIBUTE = "GUAC_CONTEXT";
|
||||
|
||||
/**
|
||||
* The session attribute holding the credentials authorizing this session.
|
||||
*/
|
||||
public static final String CREDENTIALS_ATTRIBUTE = "GUAC_CREDS";
|
||||
|
||||
/**
|
||||
* The session attribute holding the session-scoped clipboard storage.
|
||||
*/
|
||||
public static final String CLIPBOARD_ATTRIBUTE = "GUAC_CLIP";
|
||||
|
||||
/**
|
||||
* The AuthenticationProvider to use to authenticate all requests.
|
||||
*/
|
||||
private AuthenticationProvider authProvider;
|
||||
|
||||
/**
|
||||
* Whether HTTP authentication should be used (the "Authorization" header).
|
||||
*/
|
||||
private boolean useHttpAuthentication;
|
||||
|
||||
@Override
|
||||
public void init(FilterConfig config) throws ServletException {
|
||||
|
||||
// Parse Guacamole configuration
|
||||
try {
|
||||
|
||||
// Get auth provider instance
|
||||
authProvider = GuacamoleProperties.getRequiredProperty(BasicGuacamoleProperties.AUTH_PROVIDER);
|
||||
|
||||
// Enable HTTP auth, if requested
|
||||
useHttpAuthentication = GuacamoleProperties.getProperty(BasicGuacamoleProperties.ENABLE_HTTP_AUTH, false);
|
||||
|
||||
}
|
||||
catch (GuacamoleException e) {
|
||||
logger.error("Unable to read guacamole.properties: {}", e.getMessage());
|
||||
logger.debug("Error reading guacamole.properties.", e);
|
||||
throw new ServletException(e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Notifies all listeners in the given collection that authentication has
|
||||
* failed.
|
||||
*
|
||||
* @param listeners A collection of all listeners that should be notified.
|
||||
* @param credentials The credentials associated with the authentication
|
||||
* request that failed.
|
||||
*/
|
||||
private void notifyFailed(Collection listeners, Credentials credentials) {
|
||||
|
||||
// Build event for auth failure
|
||||
AuthenticationFailureEvent event = new AuthenticationFailureEvent(credentials);
|
||||
|
||||
// Notify all listeners
|
||||
for (Object listener : listeners) {
|
||||
try {
|
||||
if (listener instanceof AuthenticationFailureListener)
|
||||
((AuthenticationFailureListener) listener).authenticationFailed(event);
|
||||
}
|
||||
catch (GuacamoleException e) {
|
||||
logger.debug("Error notifying AuthenticationFailureListener: {}", e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Notifies all listeners in the given collection that authentication was
|
||||
* successful.
|
||||
*
|
||||
* @param listeners A collection of all listeners that should be notified.
|
||||
* @param context The UserContext created as a result of authentication
|
||||
* success.
|
||||
* @param credentials The credentials associated with the authentication
|
||||
* request that succeeded.
|
||||
* @return true if all listeners are allowing the authentication success,
|
||||
* or if there are no listeners, and false if any listener is
|
||||
* canceling the authentication success. Note that once one
|
||||
* listener cancels, no other listeners will run.
|
||||
* @throws GuacamoleException If any listener throws an error while being
|
||||
* notified. Note that if any listener throws an
|
||||
* error, the success is canceled, and no other
|
||||
* listeners will run.
|
||||
*/
|
||||
private boolean notifySuccess(Collection listeners, UserContext context,
|
||||
Credentials credentials) throws GuacamoleException {
|
||||
|
||||
// Build event for auth success
|
||||
AuthenticationSuccessEvent event =
|
||||
new AuthenticationSuccessEvent(context, credentials);
|
||||
|
||||
// Notify all listeners
|
||||
for (Object listener : listeners) {
|
||||
if (listener instanceof AuthenticationSuccessListener) {
|
||||
|
||||
// Cancel immediately if hook returns false
|
||||
if (!((AuthenticationSuccessListener) listener).authenticationSucceeded(event))
|
||||
return false;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends an error on the given HTTP response using the information within
|
||||
* the given GuacamoleStatus.
|
||||
*
|
||||
* @param response The HTTP response to use to send the error.
|
||||
* @param guac_status The status to send
|
||||
* @param message A human-readable message that can be presented to the
|
||||
* user.
|
||||
* @throws ServletException If an error prevents sending of the error
|
||||
* code.
|
||||
*/
|
||||
public static void sendError(HttpServletResponse response,
|
||||
GuacamoleStatus guac_status, String message)
|
||||
throws ServletException {
|
||||
|
||||
try {
|
||||
|
||||
// If response not committed, send error code and message
|
||||
if (!response.isCommitted()) {
|
||||
response.addHeader("Guacamole-Status-Code", Integer.toString(guac_status.getGuacamoleStatusCode()));
|
||||
response.addHeader("Guacamole-Error-Message", message);
|
||||
response.sendError(guac_status.getHttpStatusCode());
|
||||
}
|
||||
|
||||
}
|
||||
catch (IOException ioe) {
|
||||
|
||||
// If unable to send error at all due to I/O problems,
|
||||
// rethrow as servlet exception
|
||||
throw new ServletException(ioe);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the credentials associated with the given session.
|
||||
*
|
||||
* @param session The session to retrieve credentials from.
|
||||
* @return The credentials associated with the given session.
|
||||
*/
|
||||
public static Credentials getCredentials(HttpSession session) {
|
||||
return (Credentials) session.getAttribute(CREDENTIALS_ATTRIBUTE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the UserContext associated with the given session.
|
||||
*
|
||||
* @param session The session to retrieve UserContext from.
|
||||
* @return The UserContext associated with the given session.
|
||||
*/
|
||||
public static UserContext getUserContext(HttpSession session) {
|
||||
return (UserContext) session.getAttribute(CONTEXT_ATTRIBUTE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the ClipboardState associated with the given session. If none
|
||||
* exists yet, one is created.
|
||||
*
|
||||
* @param session The session to retrieve the ClipboardState from.
|
||||
* @return The ClipboardState associated with the given session.
|
||||
*/
|
||||
public static ClipboardState getClipboardState(HttpSession session) {
|
||||
|
||||
ClipboardState clipboard = (ClipboardState) session.getAttribute(CLIPBOARD_ATTRIBUTE);
|
||||
if (clipboard == null) {
|
||||
clipboard = new ClipboardState();
|
||||
session.setAttribute(CLIPBOARD_ATTRIBUTE, clipboard);
|
||||
}
|
||||
|
||||
return clipboard;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the request given has updated credentials. If this
|
||||
* function returns false, the UserContext will not be updated.
|
||||
*
|
||||
* @param request The request to check for credentials.
|
||||
* @return true if the request contains credentials, false otherwise.
|
||||
*/
|
||||
protected boolean hasNewCredentials(HttpServletRequest request) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Regular expression which matches any IPv4 address.
|
||||
*/
|
||||
private static final String IPV4_ADDRESS_REGEX = "([0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3})";
|
||||
|
||||
/**
|
||||
* Regular expression which matches any IPv6 address.
|
||||
*/
|
||||
private static final String IPV6_ADDRESS_REGEX = "([0-9a-fA-F]*(:[0-9a-fA-F]*){0,7})";
|
||||
|
||||
/**
|
||||
* Regular expression which matches any IP address, regardless of version.
|
||||
*/
|
||||
private static final String IP_ADDRESS_REGEX = "(" + IPV4_ADDRESS_REGEX + "|" + IPV6_ADDRESS_REGEX + ")";
|
||||
|
||||
/**
|
||||
* Pattern which matches valid values of the de-facto standard
|
||||
* "X-Forwarded-For" header.
|
||||
*/
|
||||
private static final Pattern X_FORWARDED_FOR = Pattern.compile("^" + IP_ADDRESS_REGEX + "(, " + IP_ADDRESS_REGEX + ")*$");
|
||||
|
||||
/**
|
||||
* Returns a formatted string containing an IP address, or list of IP
|
||||
* addresses, which represent the HTTP client and any involved proxies. As
|
||||
* the headers used to determine proxies can easily be forged, this data is
|
||||
* superficially validated to ensure that it at least looks like a list of
|
||||
* IPs.
|
||||
*
|
||||
* @param request The HTTP request to format.
|
||||
* @return A formatted string containing one or more IP addresses.
|
||||
*/
|
||||
private String getLoggableAddress(HttpServletRequest request) {
|
||||
|
||||
// Log X-Forwarded-For, if present and valid
|
||||
String header = request.getHeader("X-Forwarded-For");
|
||||
if (header != null && X_FORWARDED_FOR.matcher(header).matches())
|
||||
return "[" + header + ", " + request.getRemoteAddr() + "]";
|
||||
|
||||
// If header absent or invalid, just use source IP
|
||||
return request.getRemoteAddr();
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain)
|
||||
throws IOException, ServletException {
|
||||
|
||||
HttpServletRequest request = (HttpServletRequest) req;
|
||||
HttpServletResponse response = (HttpServletResponse) resp;
|
||||
|
||||
// Set character encoding to UTF-8 if it's not already set
|
||||
if(request.getCharacterEncoding() == null) {
|
||||
try {
|
||||
request.setCharacterEncoding("UTF-8");
|
||||
} catch (UnsupportedEncodingException exception) {
|
||||
throw new ServletException(exception);
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
|
||||
// Obtain context from session
|
||||
HttpSession httpSession = request.getSession(true);
|
||||
UserContext context = getUserContext(httpSession);
|
||||
|
||||
// If new credentials present, update/create context
|
||||
if (hasNewCredentials(request)) {
|
||||
|
||||
// Retrieve username and password from parms
|
||||
String username = request.getParameter("username");
|
||||
String password = request.getParameter("password");
|
||||
|
||||
// If no username/password given, try Authorization header
|
||||
if (useHttpAuthentication && username == null && password == null) {
|
||||
|
||||
String authorization = request.getHeader("Authorization");
|
||||
if (authorization != null && authorization.startsWith("Basic ")) {
|
||||
|
||||
// Decode base64 authorization
|
||||
String basicBase64 = authorization.substring(6);
|
||||
String basicCredentials = new String(DatatypeConverter.parseBase64Binary(basicBase64), "UTF-8");
|
||||
|
||||
// Pull username/password from auth data
|
||||
int colon = basicCredentials.indexOf(':');
|
||||
if (colon != -1) {
|
||||
username = basicCredentials.substring(0, colon);
|
||||
password = basicCredentials.substring(colon+1);
|
||||
}
|
||||
|
||||
else
|
||||
logger.info("Invalid HTTP Basic \"Authorization\" header received.");
|
||||
|
||||
}
|
||||
|
||||
} // end Authorization header fallback
|
||||
|
||||
// Build credentials object
|
||||
Credentials credentials = new Credentials();
|
||||
credentials.setSession(httpSession);
|
||||
credentials.setRequest(request);
|
||||
credentials.setUsername(username);
|
||||
credentials.setPassword(password);
|
||||
|
||||
SessionListenerCollection listeners = new SessionListenerCollection(httpSession);
|
||||
|
||||
// If no cached context, attempt to get new context
|
||||
if (context == null) {
|
||||
|
||||
context = authProvider.getUserContext(credentials);
|
||||
|
||||
// Log successful authentication
|
||||
if (context != null && logger.isInfoEnabled())
|
||||
logger.info("User \"{}\" successfully authenticated from {}.",
|
||||
context.self().getUsername(), getLoggableAddress(request));
|
||||
|
||||
}
|
||||
|
||||
// Otherwise, update existing context
|
||||
else
|
||||
context = authProvider.updateUserContext(context, credentials);
|
||||
|
||||
// If auth failed, notify listeners
|
||||
if (context == null) {
|
||||
|
||||
if (logger.isWarnEnabled()) {
|
||||
|
||||
// Only bother logging failures involving usernames
|
||||
if (credentials.getUsername() != null)
|
||||
logger.info("Authentication attempt from {} for user \"{}\" failed.",
|
||||
getLoggableAddress(request), credentials.getUsername());
|
||||
else
|
||||
logger.debug("Authentication attempt from {} without username failed.",
|
||||
getLoggableAddress(request));
|
||||
}
|
||||
|
||||
notifyFailed(listeners, credentials);
|
||||
}
|
||||
|
||||
// If auth succeeded, notify and check with listeners
|
||||
else if (!notifySuccess(listeners, context, credentials))
|
||||
logger.info("Successful authentication canceled by hook.");
|
||||
|
||||
// If auth still OK, associate context with session
|
||||
else {
|
||||
httpSession.setAttribute(CONTEXT_ATTRIBUTE, context);
|
||||
httpSession.setAttribute(CREDENTIALS_ATTRIBUTE, credentials);
|
||||
}
|
||||
|
||||
} // end if credentials present
|
||||
|
||||
// Allow servlet to run now that authentication has been validated
|
||||
chain.doFilter(request, response);
|
||||
|
||||
}
|
||||
|
||||
// Catch any thrown guacamole exception and attempt to pass within the
|
||||
// HTTP response, logging each error appropriately.
|
||||
catch (GuacamoleClientException e) {
|
||||
logger.info("HTTP request rejected: {}", e.getMessage());
|
||||
logger.debug("HTTP request rejected by AuthenticatingFilter.", e);
|
||||
sendError(response, e.getStatus(), e.getMessage());
|
||||
}
|
||||
catch (GuacamoleException e) {
|
||||
logger.error("Authentication failed internally: {}", e.getMessage());
|
||||
logger.debug("Internal server error during authentication.", e);
|
||||
sendError(response, e.getStatus(), "Internal server error.");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() {
|
||||
// No destruction needed
|
||||
}
|
||||
|
||||
}
|
@@ -22,6 +22,8 @@
|
||||
|
||||
package org.glyptodon.guacamole.net.basic;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.Singleton;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import org.glyptodon.guacamole.GuacamoleException;
|
||||
import org.glyptodon.guacamole.net.GuacamoleTunnel;
|
||||
@@ -35,8 +37,15 @@ import org.slf4j.LoggerFactory;
|
||||
*
|
||||
* @author Michael Jumper
|
||||
*/
|
||||
@Singleton
|
||||
public class BasicGuacamoleTunnelServlet extends GuacamoleHTTPTunnelServlet {
|
||||
|
||||
/**
|
||||
* Service for handling tunnel requests.
|
||||
*/
|
||||
@Inject
|
||||
private TunnelRequestService tunnelRequestService;
|
||||
|
||||
/**
|
||||
* Logger for this class.
|
||||
*/
|
||||
@@ -46,8 +55,8 @@ public class BasicGuacamoleTunnelServlet extends GuacamoleHTTPTunnelServlet {
|
||||
protected GuacamoleTunnel doConnect(HttpServletRequest request) throws GuacamoleException {
|
||||
|
||||
// Attempt to create HTTP tunnel
|
||||
GuacamoleTunnel tunnel = BasicTunnelRequestUtility.createTunnel(new HTTPTunnelRequest(request));
|
||||
|
||||
GuacamoleTunnel tunnel = tunnelRequestService.createTunnel(new HTTPTunnelRequest(request));
|
||||
|
||||
// If successful, warn of lack of WebSocket
|
||||
logger.info("Using HTTP tunnel (not WebSocket). Performance may be sub-optimal.");
|
||||
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2013 Glyptodon LLC
|
||||
* Copyright (C) 2014 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
|
||||
@@ -22,33 +22,31 @@
|
||||
|
||||
package org.glyptodon.guacamole.net.basic;
|
||||
|
||||
import java.io.IOException;
|
||||
import javax.servlet.http.HttpServlet;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.servlet.http.HttpSession;
|
||||
import com.google.inject.Guice;
|
||||
import com.google.inject.Injector;
|
||||
import com.google.inject.servlet.GuiceServletContextListener;
|
||||
import org.glyptodon.guacamole.net.basic.log.LogModule;
|
||||
import org.glyptodon.guacamole.net.basic.rest.RESTModule;
|
||||
import org.glyptodon.guacamole.net.basic.rest.RESTServletModule;
|
||||
|
||||
/**
|
||||
* Logs out the current user by invalidating the associated HttpSession and
|
||||
* redirecting the user to the login page.
|
||||
*
|
||||
* @author Michael Jumper
|
||||
* A ServletContextListener to listen for initialization of the servlet context
|
||||
* in order to set up dependency injection.
|
||||
*
|
||||
* @author James Muehlner
|
||||
*/
|
||||
public class BasicLogout extends HttpServlet {
|
||||
public class BasicServletContextListener extends GuiceServletContextListener {
|
||||
|
||||
@Override
|
||||
protected void service(HttpServletRequest request, HttpServletResponse response)
|
||||
throws IOException {
|
||||
|
||||
// Invalidate session, if any
|
||||
HttpSession httpSession = request.getSession(false);
|
||||
if (httpSession != null)
|
||||
httpSession.invalidate();
|
||||
|
||||
// Redirect to index
|
||||
response.sendRedirect("index.xhtml");
|
||||
protected Injector getInjector() {
|
||||
|
||||
return Guice.createInjector(
|
||||
new LogModule(),
|
||||
new RESTServletModule(),
|
||||
new RESTModule(),
|
||||
new TunnelModule()
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@@ -0,0 +1,164 @@
|
||||
/*
|
||||
* Copyright (C) 2014 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;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import org.glyptodon.guacamole.GuacamoleException;
|
||||
import org.glyptodon.guacamole.net.auth.Credentials;
|
||||
import org.glyptodon.guacamole.net.auth.UserContext;
|
||||
import org.glyptodon.guacamole.net.basic.properties.BasicGuacamoleProperties;
|
||||
import org.glyptodon.guacamole.properties.GuacamoleProperties;
|
||||
|
||||
/**
|
||||
* Contains Guacamole-specific user information which is tied to the current
|
||||
* session, such as the UserContext and current clipboard state.
|
||||
*
|
||||
* @author Michael Jumper
|
||||
*/
|
||||
public class GuacamoleSession {
|
||||
|
||||
/**
|
||||
* The credentials provided when the user logged in.
|
||||
*/
|
||||
private final Credentials credentials;
|
||||
|
||||
/**
|
||||
* The user context associated with this session.
|
||||
*/
|
||||
private final UserContext userContext;
|
||||
|
||||
/**
|
||||
* Collection of all event listeners configured in guacamole.properties.
|
||||
*/
|
||||
private final Collection<Object> listeners = new ArrayList<Object>();
|
||||
|
||||
/**
|
||||
* The current clipboard state.
|
||||
*/
|
||||
private final ClipboardState clipboardState = new ClipboardState();
|
||||
|
||||
/**
|
||||
* Creates a new Guacamole session associated with the given user context.
|
||||
*
|
||||
* @param credentials The credentials provided by the user during login.
|
||||
* @param userContext The user context to associate this session with.
|
||||
* @throws GuacamoleException If an error prevents the session from being
|
||||
* created.
|
||||
*/
|
||||
public GuacamoleSession(Credentials credentials, UserContext userContext) throws GuacamoleException {
|
||||
|
||||
this.credentials = credentials;
|
||||
this.userContext = userContext;
|
||||
|
||||
// Load listeners from guacamole.properties
|
||||
try {
|
||||
|
||||
// Get all listener classes from properties
|
||||
Collection<Class> listenerClasses =
|
||||
GuacamoleProperties.getProperty(BasicGuacamoleProperties.EVENT_LISTENERS);
|
||||
|
||||
// Add an instance of each class to the list
|
||||
if (listenerClasses != null) {
|
||||
for (Class listenerClass : listenerClasses) {
|
||||
|
||||
// Instantiate listener
|
||||
Object listener = listenerClass.getConstructor().newInstance();
|
||||
|
||||
// Add listener to collection of listeners
|
||||
listeners.add(listener);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
catch (InstantiationException e) {
|
||||
throw new GuacamoleException("Listener class is abstract.", e);
|
||||
}
|
||||
catch (IllegalAccessException e) {
|
||||
throw new GuacamoleException("No access to listener constructor.", e);
|
||||
}
|
||||
catch (IllegalArgumentException e) {
|
||||
// This should not happen, given there ARE no arguments
|
||||
throw new GuacamoleException("Illegal arguments to listener constructor.", e);
|
||||
}
|
||||
catch (InvocationTargetException e) {
|
||||
throw new GuacamoleException("Error while instantiating listener.", e);
|
||||
}
|
||||
catch (NoSuchMethodException e) {
|
||||
throw new GuacamoleException("Listener has no default constructor.", e);
|
||||
}
|
||||
catch (SecurityException e) {
|
||||
throw new GuacamoleException("Security restrictions prevent instantiation of listener.", e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the credentials used when the user associated with this session
|
||||
* logged in.
|
||||
*
|
||||
* @return The credentials used when the user associated with this session
|
||||
* logged in.
|
||||
*/
|
||||
public Credentials getCredentials() {
|
||||
return credentials;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the UserContext associated with this session.
|
||||
*
|
||||
* @return The UserContext associated with this session.
|
||||
*/
|
||||
public UserContext getUserContext() {
|
||||
return userContext;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the ClipboardState associated with this session.
|
||||
*
|
||||
* @return The ClipboardState associated with this session.
|
||||
*/
|
||||
public ClipboardState getClipboardState() {
|
||||
return clipboardState;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a collection which iterates over instances of all listeners
|
||||
* defined in guacamole.properties. For each listener defined in
|
||||
* guacamole.properties, a new instance is created and stored in this
|
||||
* collection. The contents of this collection is stored within the
|
||||
* HttpSession, and will be reused if available. Each listener is
|
||||
* instantiated once per session. Listeners are singleton classes within the
|
||||
* session, but not globally.
|
||||
*
|
||||
* @return A collection which iterates over instances of all listeners
|
||||
* defined in guacamole.properties.
|
||||
*/
|
||||
public Collection<Object> getListeners() {
|
||||
return Collections.unmodifiableCollection(listeners);
|
||||
}
|
||||
|
||||
}
|
@@ -1,93 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2014 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;
|
||||
|
||||
import java.io.IOException;
|
||||
import javax.servlet.Filter;
|
||||
import javax.servlet.FilterChain;
|
||||
import javax.servlet.FilterConfig;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.ServletRequest;
|
||||
import javax.servlet.ServletResponse;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.servlet.http.HttpSession;
|
||||
import org.glyptodon.guacamole.net.auth.UserContext;
|
||||
import org.glyptodon.guacamole.protocol.GuacamoleStatus;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Filter which enforces authentication. If no user context is associated with
|
||||
* the current HTTP session, or no HTTP session exists, the request is denied.
|
||||
*
|
||||
* @author Michael Jumper
|
||||
*/
|
||||
public class RestrictedFilter implements Filter {
|
||||
|
||||
/**
|
||||
* Logger for this class.
|
||||
*/
|
||||
private final Logger logger = LoggerFactory.getLogger(RestrictedFilter.class);
|
||||
|
||||
@Override
|
||||
public void init(FilterConfig config) throws ServletException {
|
||||
// No configuration
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain)
|
||||
throws IOException, ServletException {
|
||||
|
||||
HttpServletRequest request = (HttpServletRequest) req;
|
||||
HttpServletResponse response = (HttpServletResponse) resp;
|
||||
|
||||
// Pull user context from session
|
||||
UserContext context = null;
|
||||
HttpSession session = request.getSession(false);
|
||||
if (session != null)
|
||||
context = AuthenticatingFilter.getUserContext(session);
|
||||
|
||||
// If authenticated, proceed with rest of chain
|
||||
if (context != null)
|
||||
chain.doFilter(req, resp);
|
||||
|
||||
// Otherwise, deny entire request
|
||||
else {
|
||||
final GuacamoleStatus status = GuacamoleStatus.CLIENT_UNAUTHORIZED;
|
||||
final String message = "Not authenticated";
|
||||
|
||||
logger.info("HTTP request rejected: {}", message);
|
||||
response.addHeader("Guacamole-Status-Code", Integer.toString(status.getGuacamoleStatusCode()));
|
||||
response.addHeader("Guacamole-Error-Message", message);
|
||||
response.sendError(status.getHttpStatusCode());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() {
|
||||
// No destruction needed
|
||||
}
|
||||
|
||||
}
|
@@ -1,154 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2013 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;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServlet;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.servlet.http.HttpSession;
|
||||
import org.glyptodon.guacamole.GuacamoleClientException;
|
||||
import org.glyptodon.guacamole.GuacamoleException;
|
||||
import org.glyptodon.guacamole.GuacamoleUnauthorizedException;
|
||||
import org.glyptodon.guacamole.GuacamoleUnsupportedException;
|
||||
import org.glyptodon.guacamole.net.auth.UserContext;
|
||||
import org.glyptodon.guacamole.protocol.GuacamoleStatus;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Abstract servlet which provides an restrictedService() function that is only
|
||||
* called if the current HTTP session has already been authenticated by the
|
||||
* AuthenticatingFilter.
|
||||
*
|
||||
* @author Michael Jumper
|
||||
*/
|
||||
public abstract class RestrictedHttpServlet extends HttpServlet {
|
||||
|
||||
/**
|
||||
* Logger for this class.
|
||||
*/
|
||||
private final Logger logger = LoggerFactory.getLogger(RestrictedHttpServlet.class);
|
||||
|
||||
/**
|
||||
* Sends an error on the given HTTP response using the information within
|
||||
* the given GuacamoleStatus.
|
||||
*
|
||||
* @param response The HTTP response to use to send the error.
|
||||
* @param guac_status The status to send
|
||||
* @param message A human-readable message that can be presented to the
|
||||
* user.
|
||||
* @throws ServletException If an error prevents sending of the error
|
||||
* code.
|
||||
*/
|
||||
public static void sendError(HttpServletResponse response,
|
||||
GuacamoleStatus guac_status, String message)
|
||||
throws ServletException {
|
||||
|
||||
try {
|
||||
|
||||
// If response not committed, send error code and message
|
||||
if (!response.isCommitted()) {
|
||||
response.addHeader("Guacamole-Status-Code", Integer.toString(guac_status.getGuacamoleStatusCode()));
|
||||
response.addHeader("Guacamole-Error-Message", message);
|
||||
response.sendError(guac_status.getHttpStatusCode());
|
||||
}
|
||||
|
||||
}
|
||||
catch (IOException ioe) {
|
||||
|
||||
// If unable to send error at all due to I/O problems,
|
||||
// rethrow as servlet exception
|
||||
throw new ServletException(ioe);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void service(HttpServletRequest request, HttpServletResponse response)
|
||||
throws IOException, ServletException {
|
||||
|
||||
// Set character encoding to UTF-8 if it's not already set
|
||||
if(request.getCharacterEncoding() == null) {
|
||||
try {
|
||||
request.setCharacterEncoding("UTF-8");
|
||||
} catch (UnsupportedEncodingException exception) {
|
||||
throw new ServletException(exception);
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
|
||||
// Obtain context from session
|
||||
HttpSession httpSession = request.getSession(true);
|
||||
UserContext context = AuthenticatingFilter.getUserContext(httpSession);
|
||||
|
||||
// If no context, no authorizaton present
|
||||
if (context == null)
|
||||
throw new GuacamoleUnauthorizedException("Not authenticated");
|
||||
|
||||
// Allow servlet to run now that authentication has been validated
|
||||
restrictedService(context, request, response);
|
||||
|
||||
}
|
||||
|
||||
// Catch any thrown guacamole exception and attempt to pass within the
|
||||
// HTTP response, logging each error appropriately.
|
||||
catch (GuacamoleClientException e) {
|
||||
logger.debug("HTTP request rejected by RestrictedHttpServlet.", e);
|
||||
sendError(response, e.getStatus(), e.getMessage());
|
||||
}
|
||||
catch (GuacamoleUnsupportedException e) {
|
||||
logger.debug("Unsupported operation.", e);
|
||||
sendError(response, e.getStatus(), e.getMessage());
|
||||
}
|
||||
catch (GuacamoleException e) {
|
||||
logger.error("HTTP request failed: {}", e.getMessage());
|
||||
logger.debug("Internal server error while handling HTTP request to restricted resource.", e);
|
||||
sendError(response, e.getStatus(), "Internal server error.");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Function called after the request and associated session are validated.
|
||||
* If the current session is not associated with valid credentials, this
|
||||
* function will not be called.
|
||||
*
|
||||
* @param context The current UserContext.
|
||||
* @param request The HttpServletRequest being serviced.
|
||||
* @param response An HttpServletResponse which controls the HTTP response
|
||||
* of this servlet.
|
||||
*
|
||||
* @throws GuacamoleException If an error occurs that interferes with the
|
||||
* normal operation of this servlet.
|
||||
*/
|
||||
protected abstract void restrictedService(
|
||||
UserContext context,
|
||||
HttpServletRequest request, HttpServletResponse response)
|
||||
throws GuacamoleException;
|
||||
|
||||
}
|
@@ -22,29 +22,43 @@
|
||||
|
||||
package org.glyptodon.guacamole.net.basic;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import com.google.inject.Inject;
|
||||
import javax.ws.rs.GET;
|
||||
import javax.ws.rs.Path;
|
||||
import javax.ws.rs.QueryParam;
|
||||
import org.glyptodon.guacamole.GuacamoleException;
|
||||
import org.glyptodon.guacamole.net.auth.UserContext;
|
||||
import org.glyptodon.guacamole.net.basic.rest.AuthProviderRESTExposure;
|
||||
import org.glyptodon.guacamole.net.basic.rest.auth.AuthenticationService;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Dummy servlet which provides an endpoint for arbitrary requests intended to
|
||||
* simply keep the HTTP session from expiring.
|
||||
* REST service which updates the last access time of the Guacamole session,
|
||||
* preventing the session from becoming invalid.
|
||||
*
|
||||
* @author Michael Jumper
|
||||
*/
|
||||
public class SessionKeepAlive extends RestrictedHttpServlet {
|
||||
@Path("/keep-alive")
|
||||
public class SessionKeepAlive {
|
||||
|
||||
/**
|
||||
* A service for authenticating users from auth tokens.
|
||||
*/
|
||||
@Inject
|
||||
private AuthenticationService authenticationService;
|
||||
|
||||
/**
|
||||
* Logger for this class.
|
||||
*/
|
||||
private final Logger logger = LoggerFactory.getLogger(SessionKeepAlive.class);
|
||||
|
||||
@Override
|
||||
protected void restrictedService(
|
||||
UserContext context,
|
||||
HttpServletRequest request, HttpServletResponse response) {
|
||||
@GET
|
||||
@AuthProviderRESTExposure
|
||||
public void updateSession(@QueryParam("token") String authToken) throws GuacamoleException {
|
||||
|
||||
// Tickle the session
|
||||
UserContext context = authenticationService.getUserContext(authToken);
|
||||
|
||||
// Do nothing
|
||||
logger.debug("Keep-alive signal received from user \"{}\".", context.self().getUsername());
|
||||
|
@@ -20,36 +20,31 @@
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
package org.glyptodon.guacamole.net.basic.websocket;
|
||||
package org.glyptodon.guacamole.net.basic;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import javax.servlet.Servlet;
|
||||
import javax.servlet.ServletContext;
|
||||
import javax.servlet.ServletContextEvent;
|
||||
import javax.servlet.ServletContextListener;
|
||||
import com.google.inject.Provider;
|
||||
import com.google.inject.servlet.ServletModule;
|
||||
import java.util.Arrays;
|
||||
import javax.servlet.http.HttpServlet;
|
||||
import javax.websocket.DeploymentException;
|
||||
import javax.websocket.server.ServerContainer;
|
||||
import javax.websocket.server.ServerEndpointConfig;
|
||||
import org.glyptodon.guacamole.GuacamoleException;
|
||||
import org.glyptodon.guacamole.net.basic.GuacamoleClassLoader;
|
||||
import org.glyptodon.guacamole.net.basic.websocket.BasicGuacamoleWebSocketTunnelEndpoint;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Simple ServletContextListener which loads a WebSocket tunnel implementation
|
||||
* if available, using the Servlet 3.0 API to dynamically load and install
|
||||
* the tunnel servlet.
|
||||
*
|
||||
* Note that because Guacamole depends on the Servlet 2.5 API, and 3.0 may
|
||||
* not be available or needed if WebSocket is not desired, the 3.0 API is
|
||||
* detected and invoked dynamically via reflection.
|
||||
* Module which loads tunnel implementations.
|
||||
*
|
||||
* @author Michael Jumper
|
||||
*/
|
||||
public class WebSocketSupportLoader implements ServletContextListener {
|
||||
public class TunnelModule extends ServletModule {
|
||||
|
||||
/**
|
||||
* Logger for this class.
|
||||
*/
|
||||
private final Logger logger = LoggerFactory.getLogger(WebSocketSupportLoader.class);
|
||||
private final Logger logger = LoggerFactory.getLogger(TunnelModule.class);
|
||||
|
||||
/**
|
||||
* Classnames of all legacy (non-JSR) WebSocket tunnel implementations.
|
||||
@@ -94,52 +89,17 @@ public class WebSocketSupportLoader implements ServletContextListener {
|
||||
|
||||
}
|
||||
|
||||
private boolean loadWebSocketTunnel(ServletContext context, String classname) {
|
||||
private boolean loadWebSocketTunnel(String classname) {
|
||||
|
||||
try {
|
||||
|
||||
// Attempt to find WebSocket servlet
|
||||
Class<Servlet> servlet = (Class<Servlet>)
|
||||
Class<HttpServlet> servlet = (Class<HttpServlet>)
|
||||
GuacamoleClassLoader.getInstance().findClass(classname);
|
||||
|
||||
// Dynamically add servlet IF SERVLET 3.0 API AVAILABLE!
|
||||
try {
|
||||
|
||||
// Get servlet registration class
|
||||
Class regClass = Class.forName("javax.servlet.ServletRegistration");
|
||||
|
||||
// Get and invoke addServlet()
|
||||
Method addServlet = ServletContext.class.getMethod("addServlet",
|
||||
String.class, Class.class);
|
||||
Object reg = addServlet.invoke(context, "WebSocketTunnel", servlet);
|
||||
|
||||
// Get and invoke addMapping()
|
||||
Method addMapping = regClass.getMethod("addMapping", String[].class);
|
||||
addMapping.invoke(reg, (Object) new String[]{"/websocket-tunnel"});
|
||||
|
||||
// If we succesfully load and register the WebSocket tunnel servlet,
|
||||
// WebSocket is supported.
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
// Servlet API 3.0 unsupported
|
||||
catch (ClassNotFoundException e) {
|
||||
logger.info("Servlet API 3.0 not found.", e);
|
||||
}
|
||||
catch (NoSuchMethodException e) {
|
||||
logger.warn("Servlet API 3.0 found, but incomplete.", e);
|
||||
}
|
||||
|
||||
// Servlet API 3.0 found, but errors during use
|
||||
catch (IllegalAccessException e) {
|
||||
logger.error("Unable to load WebSocket tunnel servlet: {}", e.getMessage());
|
||||
logger.debug("Error loading WebSocket tunnel servlet.", e);
|
||||
}
|
||||
catch (InvocationTargetException e) {
|
||||
logger.error("Unable to load WebSocket tunnel servlet: {}", e.getMessage());
|
||||
logger.debug("Error loading WebSocket tunnel servlet.", e);
|
||||
}
|
||||
// Add WebSocket servlet
|
||||
serve("/websocket-tunnel").with(servlet);
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
@@ -160,21 +120,50 @@ public class WebSocketSupportLoader implements ServletContextListener {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void contextDestroyed(ServletContextEvent sce) {
|
||||
}
|
||||
protected void configureServlets() {
|
||||
|
||||
@Override
|
||||
public void contextInitialized(ServletContextEvent sce) {
|
||||
bind(TunnelRequestService.class);
|
||||
|
||||
// Set up HTTP tunnel
|
||||
serve("/tunnel").with(BasicGuacamoleTunnelServlet.class);
|
||||
|
||||
// Check for JSR 356 support
|
||||
if (implementsJSR_356()) {
|
||||
|
||||
logger.info("JSR-356 WebSocket support present.");
|
||||
|
||||
// Get container
|
||||
ServerContainer container = (ServerContainer) getServletContext().getAttribute("javax.websocket.server.ServerContainer");
|
||||
if (container == null) {
|
||||
logger.warn("ServerContainer attribute required by JSR-356 is missing. Cannot load JSR-356 WebSocket support.");
|
||||
return;
|
||||
}
|
||||
|
||||
Provider<TunnelRequestService> tunnelRequestServiceProvider = getProvider(TunnelRequestService.class);
|
||||
|
||||
// Build configuration for WebSocket tunnel
|
||||
ServerEndpointConfig config =
|
||||
ServerEndpointConfig.Builder.create(BasicGuacamoleWebSocketTunnelEndpoint.class, "/websocket-tunnel")
|
||||
.configurator(new BasicGuacamoleWebSocketTunnelEndpoint.Configurator(tunnelRequestServiceProvider))
|
||||
.subprotocols(Arrays.asList(new String[]{"guacamole"}))
|
||||
.build();
|
||||
|
||||
try {
|
||||
|
||||
// Add configuration to container
|
||||
container.addEndpoint(config);
|
||||
|
||||
}
|
||||
catch (DeploymentException e) {
|
||||
logger.error("Unable to deploy WebSocket tunnel.", e);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Try to load each WebSocket tunnel in sequence
|
||||
for (String classname : WEBSOCKET_CLASSES) {
|
||||
if (loadWebSocketTunnel(sce.getServletContext(), classname)) {
|
||||
if (loadWebSocketTunnel(classname)) {
|
||||
logger.info("Legacy (non-JSR) WebSocket support loaded: {}", classname);
|
||||
return;
|
||||
}
|
@@ -22,6 +22,9 @@
|
||||
|
||||
package org.glyptodon.guacamole.net.basic;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.Singleton;
|
||||
import org.glyptodon.guacamole.net.basic.rest.clipboard.ClipboardRESTService;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import javax.servlet.http.HttpSession;
|
||||
@@ -37,6 +40,7 @@ import org.glyptodon.guacamole.net.auth.Credentials;
|
||||
import org.glyptodon.guacamole.net.auth.Directory;
|
||||
import org.glyptodon.guacamole.net.auth.UserContext;
|
||||
import org.glyptodon.guacamole.net.basic.event.SessionListenerCollection;
|
||||
import org.glyptodon.guacamole.net.basic.rest.auth.AuthenticationService;
|
||||
import org.glyptodon.guacamole.net.event.TunnelCloseEvent;
|
||||
import org.glyptodon.guacamole.net.event.TunnelConnectEvent;
|
||||
import org.glyptodon.guacamole.net.event.listener.TunnelCloseListener;
|
||||
@@ -55,12 +59,19 @@ import org.slf4j.LoggerFactory;
|
||||
*
|
||||
* @author Michael Jumper
|
||||
*/
|
||||
public class BasicTunnelRequestUtility {
|
||||
@Singleton
|
||||
public class TunnelRequestService {
|
||||
|
||||
/**
|
||||
* Logger for this class.
|
||||
*/
|
||||
private static final Logger logger = LoggerFactory.getLogger(BasicTunnelRequestUtility.class);
|
||||
private final Logger logger = LoggerFactory.getLogger(TunnelRequestService.class);
|
||||
|
||||
/**
|
||||
* A service for authenticating users from auth tokens.
|
||||
*/
|
||||
@Inject
|
||||
private AuthenticationService authenticationService;
|
||||
|
||||
/**
|
||||
* Notifies all listeners in the given collection that a tunnel has been
|
||||
@@ -79,7 +90,7 @@ public class BasicTunnelRequestUtility {
|
||||
* error, the connect is canceled, and no other
|
||||
* listeners will run.
|
||||
*/
|
||||
private static boolean notifyConnect(Collection listeners, UserContext context,
|
||||
private boolean notifyConnect(Collection listeners, UserContext context,
|
||||
Credentials credentials, GuacamoleTunnel tunnel)
|
||||
throws GuacamoleException {
|
||||
|
||||
@@ -119,7 +130,7 @@ public class BasicTunnelRequestUtility {
|
||||
* error, the close is canceled, and no other
|
||||
* listeners will run.
|
||||
*/
|
||||
private static boolean notifyClose(Collection listeners, UserContext context,
|
||||
private boolean notifyClose(Collection listeners, UserContext context,
|
||||
Credentials credentials, GuacamoleTunnel tunnel)
|
||||
throws GuacamoleException {
|
||||
|
||||
@@ -151,7 +162,7 @@ public class BasicTunnelRequestUtility {
|
||||
* @return The created tunnel, or null if the tunnel could not be created.
|
||||
* @throws GuacamoleException If an error occurs while creating the tunnel.
|
||||
*/
|
||||
public static GuacamoleTunnel createTunnel(TunnelRequest request)
|
||||
public GuacamoleTunnel createTunnel(TunnelRequest request)
|
||||
throws GuacamoleException {
|
||||
|
||||
HttpSession httpSession = request.getSession();
|
||||
@@ -169,6 +180,10 @@ public class BasicTunnelRequestUtility {
|
||||
throw e;
|
||||
}
|
||||
|
||||
// Get auth token and session
|
||||
String authToken = request.getParameter("authToken");
|
||||
GuacamoleSession session = authenticationService.getGuacamoleSession(authToken);
|
||||
|
||||
// Get ID of connection
|
||||
String id = request.getParameter("id");
|
||||
TunnelRequest.IdentifierType id_type = TunnelRequest.IdentifierType.getType(id);
|
||||
@@ -181,17 +196,17 @@ public class BasicTunnelRequestUtility {
|
||||
id = id.substring(id_type.PREFIX.length());
|
||||
|
||||
// Get credentials
|
||||
final Credentials credentials = AuthenticatingFilter.getCredentials(httpSession);
|
||||
final Credentials credentials = session.getCredentials();
|
||||
|
||||
// Get context
|
||||
final UserContext context = AuthenticatingFilter.getUserContext(httpSession);
|
||||
|
||||
final UserContext context = session.getUserContext();
|
||||
|
||||
// If no context or no credentials, not logged in
|
||||
if (context == null || credentials == null)
|
||||
throw new GuacamoleSecurityException("Cannot connect - user not logged in.");
|
||||
|
||||
// Get clipboard
|
||||
final ClipboardState clipboard = AuthenticatingFilter.getClipboardState(httpSession);
|
||||
final ClipboardState clipboard = session.getClipboardState();
|
||||
|
||||
// Get client information
|
||||
GuacamoleClientInformation info = new GuacamoleClientInformation();
|
||||
@@ -279,7 +294,7 @@ public class BasicTunnelRequestUtility {
|
||||
|
||||
// Monitor instructions which pertain to server-side events, if necessary
|
||||
try {
|
||||
if (GuacamoleProperties.getProperty(CaptureClipboard.INTEGRATION_ENABLED, false))
|
||||
if (GuacamoleProperties.getProperty(ClipboardRESTService.INTEGRATION_ENABLED, false))
|
||||
return new MonitoringGuacamoleReader(clipboard, super.acquireReader());
|
||||
}
|
||||
catch (GuacamoleException e) {
|
@@ -1,71 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2013 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.crud.connectiongroups;
|
||||
|
||||
import org.glyptodon.guacamole.GuacamoleException;
|
||||
import org.glyptodon.guacamole.net.auth.ConnectionGroup;
|
||||
import org.glyptodon.guacamole.net.auth.Directory;
|
||||
import org.glyptodon.guacamole.net.auth.UserContext;
|
||||
|
||||
/**
|
||||
* A class that provides helper methods for the ConnectionGroup CRUD servlets.
|
||||
*
|
||||
* @author James Muehlner
|
||||
*/
|
||||
class ConnectionGroupUtility {
|
||||
|
||||
// This class should not be instantiated
|
||||
private ConnectionGroupUtility() {}
|
||||
|
||||
/**
|
||||
* Get the ConnectionGroupDirectory with the parent connection group
|
||||
* specified by parentID.
|
||||
*
|
||||
* @param context The UserContext to search for the connectionGroup directory.
|
||||
* @param parentID The ID of the parent connection group to search for.
|
||||
*
|
||||
* @return The ConnectionGroupDirectory with the parent connection group,
|
||||
* if found.
|
||||
* @throws GuacamoleException If an error is encountered while getting the
|
||||
* connection group directory.
|
||||
*/
|
||||
static Directory<String, ConnectionGroup> findConnectionGroupDirectory(
|
||||
UserContext context, String parentID) throws GuacamoleException {
|
||||
|
||||
// Find the correct connection group directory
|
||||
ConnectionGroup rootGroup = context.getRootConnectionGroup();
|
||||
Directory<String, ConnectionGroup> directory;
|
||||
|
||||
Directory<String, ConnectionGroup> connectionGroupDirectory =
|
||||
rootGroup.getConnectionGroupDirectory();
|
||||
|
||||
ConnectionGroup parentGroup = connectionGroupDirectory.get(parentID);
|
||||
|
||||
if(parentGroup == null)
|
||||
return null;
|
||||
|
||||
directory = parentGroup.getConnectionGroupDirectory();
|
||||
|
||||
return directory;
|
||||
}
|
||||
}
|
@@ -1,75 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2013 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.crud.connectiongroups;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import org.glyptodon.guacamole.GuacamoleException;
|
||||
import org.glyptodon.guacamole.net.auth.ConnectionGroup;
|
||||
import org.glyptodon.guacamole.net.auth.Directory;
|
||||
import org.glyptodon.guacamole.net.auth.UserContext;
|
||||
import org.glyptodon.guacamole.net.basic.RestrictedHttpServlet;
|
||||
|
||||
/**
|
||||
* Simple HttpServlet which handles connection group creation.
|
||||
*
|
||||
* @author James Muehlner
|
||||
*/
|
||||
public class Create extends RestrictedHttpServlet {
|
||||
|
||||
@Override
|
||||
protected void restrictedService(
|
||||
UserContext context,
|
||||
HttpServletRequest request, HttpServletResponse response)
|
||||
throws GuacamoleException {
|
||||
|
||||
// Get name and type
|
||||
String name = request.getParameter("name");
|
||||
String type = request.getParameter("type");
|
||||
|
||||
// Get the ID of the parent connection group
|
||||
String parentID = request.getParameter("parentID");
|
||||
|
||||
// Find the correct connection group directory
|
||||
Directory<String, ConnectionGroup> directory =
|
||||
ConnectionGroupUtility.findConnectionGroupDirectory(context, parentID);
|
||||
|
||||
if(directory == null)
|
||||
throw new GuacamoleException("Connection group directory not found.");
|
||||
|
||||
// Create connection skeleton
|
||||
ConnectionGroup connectionGroup = new DummyConnectionGroup();
|
||||
connectionGroup.setName(name);
|
||||
|
||||
if("balancing".equals(type))
|
||||
connectionGroup.setType(ConnectionGroup.Type.BALANCING);
|
||||
else if("organizational".equals(type))
|
||||
connectionGroup.setType(ConnectionGroup.Type.ORGANIZATIONAL);
|
||||
|
||||
// Add connection
|
||||
directory.add(connectionGroup);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -1,59 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2013 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.crud.connectiongroups;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import org.glyptodon.guacamole.GuacamoleException;
|
||||
import org.glyptodon.guacamole.net.auth.ConnectionGroup;
|
||||
import org.glyptodon.guacamole.net.auth.Directory;
|
||||
import org.glyptodon.guacamole.net.auth.UserContext;
|
||||
import org.glyptodon.guacamole.net.basic.RestrictedHttpServlet;
|
||||
|
||||
/**
|
||||
* Simple HttpServlet which handles connection group deletion.
|
||||
*
|
||||
* @author Michael Jumper
|
||||
*/
|
||||
public class Delete extends RestrictedHttpServlet {
|
||||
|
||||
@Override
|
||||
protected void restrictedService(
|
||||
UserContext context,
|
||||
HttpServletRequest request, HttpServletResponse response)
|
||||
throws GuacamoleException {
|
||||
|
||||
// Get ID
|
||||
String identifier = request.getParameter("id");
|
||||
|
||||
// Attempt to get connection group directory
|
||||
Directory<String, ConnectionGroup> directory =
|
||||
context.getRootConnectionGroup().getConnectionGroupDirectory();
|
||||
|
||||
// Remove connection
|
||||
directory.remove(identifier);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -1,60 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2013 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.crud.connectiongroups;
|
||||
|
||||
import org.glyptodon.guacamole.GuacamoleException;
|
||||
import org.glyptodon.guacamole.net.GuacamoleSocket;
|
||||
import org.glyptodon.guacamole.net.auth.AbstractConnectionGroup;
|
||||
import org.glyptodon.guacamole.net.auth.Connection;
|
||||
import org.glyptodon.guacamole.net.auth.ConnectionGroup;
|
||||
import org.glyptodon.guacamole.net.auth.Directory;
|
||||
import org.glyptodon.guacamole.protocol.GuacamoleClientInformation;
|
||||
|
||||
/**
|
||||
* Basic ConnectionGroup skeleton, providing a means of storing Connection data
|
||||
* prior to CRUD operations. This ConnectionGroup has no functionality for actually
|
||||
* performing a connection operation, and does not promote any of the
|
||||
* semantics that would otherwise be present because of the authentication
|
||||
* provider. It is up to the authentication provider to create a new
|
||||
* ConnectionGroup based on the information contained herein.
|
||||
*
|
||||
* @author James Muehlner
|
||||
*/
|
||||
public class DummyConnectionGroup extends AbstractConnectionGroup {
|
||||
|
||||
@Override
|
||||
public GuacamoleSocket connect(GuacamoleClientInformation info) throws GuacamoleException {
|
||||
throw new UnsupportedOperationException("Connection unsupported in DummyConnectionGroup.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Directory<String, Connection> getConnectionDirectory() throws GuacamoleException {
|
||||
throw new UnsupportedOperationException("Connection directory unsupported in DummyConnectionGroup.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Directory<String, ConnectionGroup> getConnectionGroupDirectory() throws GuacamoleException {
|
||||
throw new UnsupportedOperationException("Connection group directory unsuppprted in DummyConnectionGroup.");
|
||||
}
|
||||
|
||||
}
|
@@ -1,218 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2013 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.crud.connectiongroups;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Set;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.xml.stream.XMLOutputFactory;
|
||||
import javax.xml.stream.XMLStreamException;
|
||||
import javax.xml.stream.XMLStreamWriter;
|
||||
import org.glyptodon.guacamole.GuacamoleException;
|
||||
import org.glyptodon.guacamole.GuacamoleSecurityException;
|
||||
import org.glyptodon.guacamole.GuacamoleServerException;
|
||||
import org.glyptodon.guacamole.net.auth.ConnectionGroup;
|
||||
import org.glyptodon.guacamole.net.auth.Directory;
|
||||
import org.glyptodon.guacamole.net.auth.User;
|
||||
import org.glyptodon.guacamole.net.auth.UserContext;
|
||||
import org.glyptodon.guacamole.net.auth.permission.ConnectionPermission;
|
||||
import org.glyptodon.guacamole.net.auth.permission.ObjectPermission;
|
||||
import org.glyptodon.guacamole.net.auth.permission.Permission;
|
||||
import org.glyptodon.guacamole.net.auth.permission.SystemPermission;
|
||||
import org.glyptodon.guacamole.net.basic.RestrictedHttpServlet;
|
||||
|
||||
/**
|
||||
* Simple HttpServlet which outputs XML containing a list of all authorized
|
||||
* connection groups for the current user.
|
||||
*
|
||||
* @author Michael Jumper
|
||||
*/
|
||||
public class List extends RestrictedHttpServlet {
|
||||
|
||||
/**
|
||||
* System administration permission.
|
||||
*/
|
||||
private static final Permission SYSTEM_PERMISSION =
|
||||
new SystemPermission(SystemPermission.Type.ADMINISTER);
|
||||
|
||||
|
||||
/**
|
||||
* Checks whether the given user has permission to perform the given
|
||||
* object operation. Security exceptions are handled appropriately - only
|
||||
* non-security exceptions pass through.
|
||||
*
|
||||
* @param user The user whose permissions should be verified.
|
||||
* @param type The type of operation to check for permission for.
|
||||
* @param identifier The identifier of the connection the operation
|
||||
* would be performed upon.
|
||||
* @return true if permission is granted, false otherwise.
|
||||
*
|
||||
* @throws GuacamoleException If an error occurs while checking permissions.
|
||||
*/
|
||||
private boolean hasConfigPermission(User user, ObjectPermission.Type type,
|
||||
String identifier)
|
||||
throws GuacamoleException {
|
||||
|
||||
// Build permission
|
||||
Permission permission = new ConnectionPermission(
|
||||
type,
|
||||
identifier
|
||||
);
|
||||
|
||||
try {
|
||||
// Return result of permission check, if possible
|
||||
return user.hasPermission(permission);
|
||||
}
|
||||
catch (GuacamoleSecurityException e) {
|
||||
// If cannot check due to security restrictions, no permission
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the XML for the given connection group.
|
||||
*
|
||||
* @param self The user whose permissions dictate the availability of the
|
||||
* data written.
|
||||
* @param xml The XMLStremWriter to use when writing the data.
|
||||
* @param group The connection group whose XML representation will be
|
||||
* written.
|
||||
* @throws GuacamoleException If an error occurs while reading the
|
||||
* requested data.
|
||||
* @throws XMLStreamException If an error occurs while writing the XML.
|
||||
*/
|
||||
private void writeConnectionGroup(User self, XMLStreamWriter xml,
|
||||
ConnectionGroup group) throws GuacamoleException, XMLStreamException {
|
||||
|
||||
// Write group
|
||||
xml.writeStartElement("group");
|
||||
xml.writeAttribute("id", group.getIdentifier());
|
||||
xml.writeAttribute("name", group.getName());
|
||||
|
||||
// Write group type
|
||||
switch (group.getType()) {
|
||||
|
||||
case ORGANIZATIONAL:
|
||||
xml.writeAttribute("type", "organizational");
|
||||
break;
|
||||
|
||||
case BALANCING:
|
||||
xml.writeAttribute("type", "balancing");
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
// Write contained connection groups
|
||||
writeConnectionGroups(self, xml, group.getConnectionGroupDirectory());
|
||||
|
||||
// End of group
|
||||
xml.writeEndElement();
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the XML for the given directory of connection groups.
|
||||
*
|
||||
* @param self The user whose permissions dictate the availability of the
|
||||
* data written.
|
||||
* @param xml The XMLStremWriter to use when writing the data.
|
||||
* @param directory The directory whose XML representation will be
|
||||
* written.
|
||||
* @throws GuacamoleException If an error occurs while reading the
|
||||
* requested data.
|
||||
* @throws XMLStreamException If an error occurs while writing the XML.
|
||||
*/
|
||||
private void writeConnectionGroups(User self, XMLStreamWriter xml,
|
||||
Directory<String, ConnectionGroup> directory)
|
||||
throws GuacamoleException, XMLStreamException {
|
||||
|
||||
// If no connections, write nothing
|
||||
Set<String> identifiers = directory.getIdentifiers();
|
||||
if (identifiers.isEmpty())
|
||||
return;
|
||||
|
||||
// Begin connections
|
||||
xml.writeStartElement("groups");
|
||||
|
||||
// For each entry, write corresponding connection element
|
||||
for (String identifier : identifiers) {
|
||||
|
||||
// Write each group
|
||||
ConnectionGroup group = directory.get(identifier);
|
||||
writeConnectionGroup(self, xml, group);
|
||||
|
||||
}
|
||||
|
||||
// End connections
|
||||
xml.writeEndElement();
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void restrictedService(
|
||||
UserContext context,
|
||||
HttpServletRequest request, HttpServletResponse response)
|
||||
throws GuacamoleException {
|
||||
|
||||
// Do not cache
|
||||
response.setHeader("Cache-Control", "no-cache");
|
||||
|
||||
// Write XML content type
|
||||
response.setHeader("Content-Type", "text/xml");
|
||||
|
||||
// Set encoding
|
||||
response.setCharacterEncoding("UTF-8");
|
||||
|
||||
// Get root group
|
||||
ConnectionGroup root = context.getRootConnectionGroup();
|
||||
|
||||
// Write actual XML
|
||||
try {
|
||||
|
||||
// Get self
|
||||
User self = context.self();
|
||||
|
||||
XMLOutputFactory outputFactory = XMLOutputFactory.newInstance();
|
||||
XMLStreamWriter xml = outputFactory.createXMLStreamWriter(response.getWriter());
|
||||
|
||||
// Write content of root group
|
||||
xml.writeStartDocument();
|
||||
writeConnectionGroup(self, xml, root);
|
||||
xml.writeEndDocument();
|
||||
|
||||
}
|
||||
catch (XMLStreamException e) {
|
||||
throw new GuacamoleServerException(
|
||||
"Unable to write connection group list XML.", e);
|
||||
}
|
||||
catch (IOException e) {
|
||||
throw new GuacamoleServerException(
|
||||
"I/O error writing connection group list XML.", e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -1,66 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2013 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.crud.connectiongroups;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import org.glyptodon.guacamole.GuacamoleException;
|
||||
import org.glyptodon.guacamole.net.auth.ConnectionGroup;
|
||||
import org.glyptodon.guacamole.net.auth.Directory;
|
||||
import org.glyptodon.guacamole.net.auth.UserContext;
|
||||
import org.glyptodon.guacamole.net.basic.RestrictedHttpServlet;
|
||||
|
||||
/**
|
||||
* Simple HttpServlet which handles moving connection groups.
|
||||
*
|
||||
* @author James Muehlner
|
||||
*/
|
||||
public class Move extends RestrictedHttpServlet {
|
||||
|
||||
@Override
|
||||
protected void restrictedService(
|
||||
UserContext context,
|
||||
HttpServletRequest request, HttpServletResponse response)
|
||||
throws GuacamoleException {
|
||||
|
||||
// Get ID
|
||||
String identifier = request.getParameter("id");
|
||||
|
||||
// Get the identifier of the new parent connection group
|
||||
String parentID = request.getParameter("parentID");
|
||||
|
||||
// Attempt to get the new parent connection group directory
|
||||
Directory<String, ConnectionGroup> newParentDirectory =
|
||||
ConnectionGroupUtility.findConnectionGroupDirectory(context, parentID);
|
||||
|
||||
// Attempt to get root connection group directory
|
||||
Directory<String, ConnectionGroup> directory =
|
||||
context.getRootConnectionGroup().getConnectionGroupDirectory();
|
||||
|
||||
// Move connection group
|
||||
directory.move(identifier, newParentDirectory);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -1,70 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2013 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.crud.connectiongroups;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import org.glyptodon.guacamole.GuacamoleException;
|
||||
import org.glyptodon.guacamole.net.auth.ConnectionGroup;
|
||||
import org.glyptodon.guacamole.net.auth.Directory;
|
||||
import org.glyptodon.guacamole.net.auth.UserContext;
|
||||
import org.glyptodon.guacamole.net.basic.RestrictedHttpServlet;
|
||||
|
||||
/**
|
||||
* Simple HttpServlet which handles connection group update.
|
||||
*
|
||||
* @author James Muehlner
|
||||
*/
|
||||
public class Update extends RestrictedHttpServlet {
|
||||
|
||||
@Override
|
||||
protected void restrictedService(
|
||||
UserContext context,
|
||||
HttpServletRequest request, HttpServletResponse response)
|
||||
throws GuacamoleException {
|
||||
|
||||
// Get ID, name, and type
|
||||
String identifier = request.getParameter("id");
|
||||
String name = request.getParameter("name");
|
||||
String type = request.getParameter("type");
|
||||
|
||||
// Attempt to get connection group directory
|
||||
Directory<String, ConnectionGroup> directory =
|
||||
context.getRootConnectionGroup().getConnectionGroupDirectory();
|
||||
|
||||
// Create connection group skeleton
|
||||
ConnectionGroup connectionGroup = directory.get(identifier);
|
||||
connectionGroup.setName(name);
|
||||
|
||||
if("balancing".equals(type))
|
||||
connectionGroup.setType(ConnectionGroup.Type.BALANCING);
|
||||
else if("organizational".equals(type))
|
||||
connectionGroup.setType(ConnectionGroup.Type.ORGANIZATIONAL);
|
||||
|
||||
// Update connection group
|
||||
directory.update(connectionGroup);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -1,72 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2013 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.crud.connections;
|
||||
|
||||
import org.glyptodon.guacamole.GuacamoleException;
|
||||
import org.glyptodon.guacamole.net.auth.Connection;
|
||||
import org.glyptodon.guacamole.net.auth.ConnectionGroup;
|
||||
import org.glyptodon.guacamole.net.auth.Directory;
|
||||
import org.glyptodon.guacamole.net.auth.UserContext;
|
||||
|
||||
/**
|
||||
* A class that provides helper methods for the Connection CRUD servlets.
|
||||
*
|
||||
* @author James Muehlner
|
||||
*/
|
||||
class ConnectionUtility {
|
||||
|
||||
// This class should not be instantiated
|
||||
private ConnectionUtility() {}
|
||||
|
||||
/**
|
||||
* Get the ConnectionDirectory with the parent connection group specified by
|
||||
* parentID.
|
||||
*
|
||||
* @param context The UserContext to search for the connection directory.
|
||||
* @param parentID The ID of the parent connection group to search for.
|
||||
*
|
||||
* @return The ConnectionDirectory with the parent connection group,
|
||||
* if found.
|
||||
* @throws GuacamoleException If an error is encountered while getting the
|
||||
* connection directory.
|
||||
*/
|
||||
static Directory<String, Connection> findConnectionDirectory(
|
||||
UserContext context, String parentID) throws GuacamoleException {
|
||||
|
||||
// Find the correct connection directory
|
||||
ConnectionGroup rootGroup = context.getRootConnectionGroup();
|
||||
Directory<String, Connection> directory;
|
||||
|
||||
Directory<String, ConnectionGroup> connectionGroupDirectory =
|
||||
rootGroup.getConnectionGroupDirectory();
|
||||
|
||||
ConnectionGroup parentGroup = connectionGroupDirectory.get(parentID);
|
||||
|
||||
if(parentGroup == null)
|
||||
return null;
|
||||
|
||||
directory = parentGroup.getConnectionDirectory();
|
||||
|
||||
return directory;
|
||||
}
|
||||
}
|
@@ -1,97 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2013 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.crud.connections;
|
||||
|
||||
import java.util.Enumeration;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import org.glyptodon.guacamole.GuacamoleException;
|
||||
import org.glyptodon.guacamole.net.auth.Connection;
|
||||
import org.glyptodon.guacamole.net.auth.Directory;
|
||||
import org.glyptodon.guacamole.net.auth.UserContext;
|
||||
import org.glyptodon.guacamole.net.basic.RestrictedHttpServlet;
|
||||
import org.glyptodon.guacamole.protocol.GuacamoleConfiguration;
|
||||
|
||||
/**
|
||||
* Simple HttpServlet which handles connection creation.
|
||||
*
|
||||
* @author Michael Jumper
|
||||
*/
|
||||
public class Create extends RestrictedHttpServlet {
|
||||
|
||||
/**
|
||||
* Prefix given to a parameter name when that parameter is a protocol-
|
||||
* specific parameter meant for the configuration.
|
||||
*/
|
||||
public static final String PARAMETER_PREFIX = "_";
|
||||
|
||||
@Override
|
||||
protected void restrictedService(
|
||||
UserContext context,
|
||||
HttpServletRequest request, HttpServletResponse response)
|
||||
throws GuacamoleException {
|
||||
|
||||
// Get name and protocol
|
||||
String name = request.getParameter("name");
|
||||
String protocol = request.getParameter("protocol");
|
||||
|
||||
// Get the ID of the parent connection group
|
||||
String parentID = request.getParameter("parentID");
|
||||
|
||||
// Find the correct connection directory
|
||||
Directory<String, Connection> directory =
|
||||
ConnectionUtility.findConnectionDirectory(context, parentID);
|
||||
|
||||
if(directory == null)
|
||||
throw new GuacamoleException("Connection directory not found.");
|
||||
|
||||
// Create config
|
||||
GuacamoleConfiguration config = new GuacamoleConfiguration();
|
||||
config.setProtocol(protocol);
|
||||
|
||||
// Load parameters into config
|
||||
Enumeration<String> params = request.getParameterNames();
|
||||
while (params.hasMoreElements()) {
|
||||
|
||||
// If parameter starts with prefix, load corresponding parameter
|
||||
// value into config
|
||||
String param = params.nextElement();
|
||||
if (param.startsWith(PARAMETER_PREFIX))
|
||||
config.setParameter(
|
||||
param.substring(PARAMETER_PREFIX.length()),
|
||||
request.getParameter(param));
|
||||
|
||||
}
|
||||
|
||||
// Create connection skeleton
|
||||
Connection connection = new DummyConnection();
|
||||
connection.setName(name);
|
||||
connection.setConfiguration(config);
|
||||
|
||||
// Add connection
|
||||
directory.add(connection);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -1,54 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2013 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.crud.connections;
|
||||
|
||||
import java.util.List;
|
||||
import org.glyptodon.guacamole.GuacamoleException;
|
||||
import org.glyptodon.guacamole.net.GuacamoleSocket;
|
||||
import org.glyptodon.guacamole.net.auth.AbstractConnection;
|
||||
import org.glyptodon.guacamole.net.auth.ConnectionRecord;
|
||||
import org.glyptodon.guacamole.protocol.GuacamoleClientInformation;
|
||||
|
||||
/**
|
||||
* Basic Connection skeleton, providing a means of storing Connection data
|
||||
* prior to CRUD operations. This Connection has no functionality for actually
|
||||
* performing a connection operation, and does not promote any of the
|
||||
* semantics that would otherwise be present because of the authentication
|
||||
* provider. It is up to the authentication provider to create a new
|
||||
* Connection based on the information contained herein.
|
||||
*
|
||||
* @author Michael Jumper
|
||||
*/
|
||||
public class DummyConnection extends AbstractConnection {
|
||||
|
||||
@Override
|
||||
public GuacamoleSocket connect(GuacamoleClientInformation info) throws GuacamoleException {
|
||||
throw new UnsupportedOperationException("Connection unsupported in DummyConnection.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ConnectionRecord> getHistory() throws GuacamoleException {
|
||||
throw new UnsupportedOperationException("History unsupported in DummyConnection.");
|
||||
}
|
||||
|
||||
}
|
@@ -1,342 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2013 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.crud.connections;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Set;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.xml.stream.XMLOutputFactory;
|
||||
import javax.xml.stream.XMLStreamException;
|
||||
import javax.xml.stream.XMLStreamWriter;
|
||||
import org.glyptodon.guacamole.GuacamoleException;
|
||||
import org.glyptodon.guacamole.GuacamoleSecurityException;
|
||||
import org.glyptodon.guacamole.GuacamoleServerException;
|
||||
import org.glyptodon.guacamole.net.auth.Connection;
|
||||
import org.glyptodon.guacamole.net.auth.ConnectionGroup;
|
||||
import org.glyptodon.guacamole.net.auth.ConnectionRecord;
|
||||
import org.glyptodon.guacamole.net.auth.Directory;
|
||||
import org.glyptodon.guacamole.net.auth.User;
|
||||
import org.glyptodon.guacamole.net.auth.UserContext;
|
||||
import org.glyptodon.guacamole.net.auth.permission.ConnectionGroupPermission;
|
||||
import org.glyptodon.guacamole.net.auth.permission.ConnectionPermission;
|
||||
import org.glyptodon.guacamole.net.auth.permission.ObjectPermission;
|
||||
import org.glyptodon.guacamole.net.auth.permission.Permission;
|
||||
import org.glyptodon.guacamole.net.auth.permission.SystemPermission;
|
||||
import org.glyptodon.guacamole.net.basic.RestrictedHttpServlet;
|
||||
import org.glyptodon.guacamole.protocol.GuacamoleConfiguration;
|
||||
|
||||
/**
|
||||
* Simple HttpServlet which outputs XML containing a list of all authorized
|
||||
* configurations for the current user.
|
||||
*
|
||||
* @author Michael Jumper
|
||||
*/
|
||||
public class List extends RestrictedHttpServlet {
|
||||
|
||||
/**
|
||||
* System administration permission.
|
||||
*/
|
||||
private static final Permission SYSTEM_PERMISSION =
|
||||
new SystemPermission(SystemPermission.Type.ADMINISTER);
|
||||
|
||||
|
||||
/**
|
||||
* Checks whether the given user has permission to perform the given
|
||||
* object operation. Security exceptions are handled appropriately - only
|
||||
* non-security exceptions pass through.
|
||||
*
|
||||
* @param user The user whose permissions should be verified.
|
||||
* @param type The type of operation to check for permission for.
|
||||
* @param identifier The identifier of the connection the operation
|
||||
* would be performed upon.
|
||||
* @return true if permission is granted, false otherwise.
|
||||
*
|
||||
* @throws GuacamoleException If an error occurs while checking permissions.
|
||||
*/
|
||||
private boolean hasConfigPermission(User user, ObjectPermission.Type type,
|
||||
String identifier)
|
||||
throws GuacamoleException {
|
||||
|
||||
// Build permission
|
||||
Permission permission = new ConnectionPermission(
|
||||
type,
|
||||
identifier
|
||||
);
|
||||
|
||||
try {
|
||||
// Return result of permission check, if possible
|
||||
return user.hasPermission(permission);
|
||||
}
|
||||
catch (GuacamoleSecurityException e) {
|
||||
// If cannot check due to security restrictions, no permission
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the XML for the given connection group.
|
||||
*
|
||||
* @param self The user whose permissions dictate the availability of the
|
||||
* data written.
|
||||
* @param xml The XMLStremWriter to use when writing the data.
|
||||
* @param group The connection group whose XML representation will be
|
||||
* written.
|
||||
* @throws GuacamoleException If an error occurs while reading the
|
||||
* requested data.
|
||||
* @throws XMLStreamException If an error occurs while writing the XML.
|
||||
*/
|
||||
private void writeConnectionGroup(User self, XMLStreamWriter xml,
|
||||
ConnectionGroup group) throws GuacamoleException, XMLStreamException {
|
||||
|
||||
// Write group
|
||||
xml.writeStartElement("group");
|
||||
xml.writeAttribute("id", group.getIdentifier());
|
||||
xml.writeAttribute("name", group.getName());
|
||||
|
||||
// Write group type
|
||||
switch (group.getType()) {
|
||||
|
||||
case ORGANIZATIONAL:
|
||||
xml.writeAttribute("type", "organizational");
|
||||
break;
|
||||
|
||||
case BALANCING:
|
||||
xml.writeAttribute("type", "balancing");
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
Permission group_admin_permission = new ConnectionGroupPermission(
|
||||
ObjectPermission.Type.ADMINISTER, group.getIdentifier());
|
||||
|
||||
// Attempt to list contained groups and connections ONLY if the group
|
||||
// is organizational or we have admin rights to it
|
||||
if (group.getType() == ConnectionGroup.Type.ORGANIZATIONAL
|
||||
|| self.hasPermission(SYSTEM_PERMISSION)
|
||||
|| self.hasPermission(group_admin_permission)) {
|
||||
writeConnections(self, xml, group.getConnectionDirectory());
|
||||
writeConnectionGroups(self, xml, group.getConnectionGroupDirectory());
|
||||
}
|
||||
|
||||
// End of group
|
||||
xml.writeEndElement();
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the XML for the given connection.
|
||||
*
|
||||
* @param self The user whose permissions dictate the availability of the
|
||||
* data written.
|
||||
* @param xml The XMLStremWriter to use when writing the data.
|
||||
* @param connection The connection whose XML representation will be
|
||||
* written.
|
||||
* @throws GuacamoleException If an error occurs while reading the
|
||||
* requested data.
|
||||
* @throws XMLStreamException If an error occurs while writing the XML.
|
||||
*/
|
||||
private void writeConnection(User self, XMLStreamWriter xml,
|
||||
Connection connection) throws GuacamoleException, XMLStreamException {
|
||||
|
||||
// Write connection
|
||||
xml.writeStartElement("connection");
|
||||
xml.writeAttribute("id", connection.getIdentifier());
|
||||
xml.writeAttribute("name", connection.getName());
|
||||
xml.writeAttribute("protocol",
|
||||
connection.getConfiguration().getProtocol());
|
||||
|
||||
// If update permission available, include parameters
|
||||
if (self.hasPermission(SYSTEM_PERMISSION) ||
|
||||
hasConfigPermission(self, ObjectPermission.Type.UPDATE,
|
||||
connection.getIdentifier())) {
|
||||
|
||||
// As update permission is present, also list parameters
|
||||
GuacamoleConfiguration config = connection.getConfiguration();
|
||||
for (String name : config.getParameterNames()) {
|
||||
|
||||
String value = connection.getConfiguration().getParameter(name);
|
||||
xml.writeStartElement("param");
|
||||
xml.writeAttribute("name", name);
|
||||
|
||||
if (value != null)
|
||||
xml.writeCharacters(value);
|
||||
|
||||
xml.writeEndElement();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Write history
|
||||
xml.writeStartElement("history");
|
||||
for (ConnectionRecord record : connection.getHistory()) {
|
||||
xml.writeStartElement("record");
|
||||
|
||||
// Start date
|
||||
xml.writeAttribute("start",
|
||||
Long.toString(record.getStartDate().getTime()));
|
||||
|
||||
// End date
|
||||
if (record.getEndDate() != null)
|
||||
xml.writeAttribute("end",
|
||||
Long.toString(record.getEndDate().getTime()));
|
||||
|
||||
// Whether connection currently active
|
||||
if (record.isActive())
|
||||
xml.writeAttribute("active", "yes");
|
||||
|
||||
// User involved
|
||||
xml.writeCharacters(record.getUsername());
|
||||
|
||||
xml.writeEndElement();
|
||||
}
|
||||
xml.writeEndElement();
|
||||
|
||||
// End connection
|
||||
xml.writeEndElement();
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the XML for the given directory of connection groups.
|
||||
*
|
||||
* @param self The user whose permissions dictate the availability of the
|
||||
* data written.
|
||||
* @param xml The XMLStremWriter to use when writing the data.
|
||||
* @param directory The directory whose XML representation will be
|
||||
* written.
|
||||
* @throws GuacamoleException If an error occurs while reading the
|
||||
* requested data.
|
||||
* @throws XMLStreamException If an error occurs while writing the XML.
|
||||
*/
|
||||
private void writeConnectionGroups(User self, XMLStreamWriter xml,
|
||||
Directory<String, ConnectionGroup> directory)
|
||||
throws GuacamoleException, XMLStreamException {
|
||||
|
||||
// If no connections, write nothing
|
||||
Set<String> identifiers = directory.getIdentifiers();
|
||||
if (identifiers.isEmpty())
|
||||
return;
|
||||
|
||||
// Begin connections
|
||||
xml.writeStartElement("groups");
|
||||
|
||||
// For each entry, write corresponding connection element
|
||||
for (String identifier : identifiers) {
|
||||
|
||||
// Write each group
|
||||
ConnectionGroup group = directory.get(identifier);
|
||||
writeConnectionGroup(self, xml, group);
|
||||
|
||||
}
|
||||
|
||||
// End connections
|
||||
xml.writeEndElement();
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the XML for the given directory of connections.
|
||||
*
|
||||
* @param self The user whose permissions dictate the availability of the
|
||||
* data written.
|
||||
* @param xml The XMLStremWriter to use when writing the data.
|
||||
* @param directory The directory whose XML representation will be
|
||||
* written.
|
||||
* @throws GuacamoleException If an error occurs while reading the
|
||||
* requested data.
|
||||
* @throws XMLStreamException If an error occurs while writing the XML.
|
||||
*/
|
||||
private void writeConnections(User self, XMLStreamWriter xml,
|
||||
Directory<String, Connection> directory)
|
||||
throws GuacamoleException, XMLStreamException {
|
||||
|
||||
// If no connections, write nothing
|
||||
Set<String> identifiers = directory.getIdentifiers();
|
||||
if (identifiers.isEmpty())
|
||||
return;
|
||||
|
||||
// Begin connections
|
||||
xml.writeStartElement("connections");
|
||||
|
||||
// For each entry, write corresponding connection element
|
||||
for (String identifier : identifiers) {
|
||||
|
||||
// Write each connection
|
||||
Connection connection = directory.get(identifier);
|
||||
writeConnection(self, xml, connection);
|
||||
|
||||
}
|
||||
|
||||
// End connections
|
||||
xml.writeEndElement();
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void restrictedService(
|
||||
UserContext context,
|
||||
HttpServletRequest request, HttpServletResponse response)
|
||||
throws GuacamoleException {
|
||||
|
||||
// Do not cache
|
||||
response.setHeader("Cache-Control", "no-cache");
|
||||
|
||||
// Write XML content type
|
||||
response.setHeader("Content-Type", "text/xml");
|
||||
|
||||
// Set encoding
|
||||
response.setCharacterEncoding("UTF-8");
|
||||
|
||||
// Get root group
|
||||
ConnectionGroup root = context.getRootConnectionGroup();
|
||||
|
||||
// Write actual XML
|
||||
try {
|
||||
|
||||
// Get self
|
||||
User self = context.self();
|
||||
|
||||
XMLOutputFactory outputFactory = XMLOutputFactory.newInstance();
|
||||
XMLStreamWriter xml = outputFactory.createXMLStreamWriter(response.getWriter());
|
||||
|
||||
// Write content of root group
|
||||
xml.writeStartDocument();
|
||||
writeConnectionGroup(self, xml, root);
|
||||
xml.writeEndDocument();
|
||||
|
||||
}
|
||||
catch (XMLStreamException e) {
|
||||
throw new GuacamoleServerException(
|
||||
"Unable to write configuration list XML.", e);
|
||||
}
|
||||
catch (IOException e) {
|
||||
throw new GuacamoleServerException(
|
||||
"I/O error writing configuration list XML.", e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -1,66 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2013 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.crud.connections;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import org.glyptodon.guacamole.GuacamoleException;
|
||||
import org.glyptodon.guacamole.net.auth.Connection;
|
||||
import org.glyptodon.guacamole.net.auth.Directory;
|
||||
import org.glyptodon.guacamole.net.auth.UserContext;
|
||||
import org.glyptodon.guacamole.net.basic.RestrictedHttpServlet;
|
||||
|
||||
/**
|
||||
* Simple HttpServlet which handles moving connections.
|
||||
*
|
||||
* @author Michael Jumper
|
||||
*/
|
||||
public class Move extends RestrictedHttpServlet {
|
||||
|
||||
@Override
|
||||
protected void restrictedService(
|
||||
UserContext context,
|
||||
HttpServletRequest request, HttpServletResponse response)
|
||||
throws GuacamoleException {
|
||||
|
||||
// Get ID
|
||||
String identifier = request.getParameter("id");
|
||||
|
||||
// Get the identifier of the new parent connection group
|
||||
String parentID = request.getParameter("parentID");
|
||||
|
||||
// Attempt to get the new parent connection directory
|
||||
Directory<String, Connection> newParentDirectory =
|
||||
ConnectionUtility.findConnectionDirectory(context, parentID);
|
||||
|
||||
// Attempt to get root connection directory
|
||||
Directory<String, Connection> directory =
|
||||
context.getRootConnectionGroup().getConnectionDirectory();
|
||||
|
||||
// Move connection
|
||||
directory.move(identifier, newParentDirectory);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -1,92 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2013 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.crud.connections;
|
||||
|
||||
import java.util.Enumeration;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import org.glyptodon.guacamole.GuacamoleException;
|
||||
import org.glyptodon.guacamole.net.auth.Connection;
|
||||
import org.glyptodon.guacamole.net.auth.Directory;
|
||||
import org.glyptodon.guacamole.net.auth.UserContext;
|
||||
import org.glyptodon.guacamole.net.basic.RestrictedHttpServlet;
|
||||
import org.glyptodon.guacamole.protocol.GuacamoleConfiguration;
|
||||
|
||||
/**
|
||||
* Simple HttpServlet which handles connection update.
|
||||
*
|
||||
* @author Michael Jumper
|
||||
*/
|
||||
public class Update extends RestrictedHttpServlet {
|
||||
|
||||
/**
|
||||
* Prefix given to a parameter name when that parameter is a protocol-
|
||||
* specific parameter meant for the configuration.
|
||||
*/
|
||||
public static final String PARAMETER_PREFIX = "_";
|
||||
|
||||
@Override
|
||||
protected void restrictedService(
|
||||
UserContext context,
|
||||
HttpServletRequest request, HttpServletResponse response)
|
||||
throws GuacamoleException {
|
||||
|
||||
// Get ID, name, and protocol
|
||||
String identifier = request.getParameter("id");
|
||||
String name = request.getParameter("name");
|
||||
String protocol = request.getParameter("protocol");
|
||||
|
||||
// Attempt to get connection directory
|
||||
Directory<String, Connection> directory =
|
||||
context.getRootConnectionGroup().getConnectionDirectory();
|
||||
|
||||
// Create config
|
||||
GuacamoleConfiguration config = new GuacamoleConfiguration();
|
||||
config.setProtocol(protocol);
|
||||
|
||||
// Load parameters into config
|
||||
Enumeration<String> params = request.getParameterNames();
|
||||
while (params.hasMoreElements()) {
|
||||
|
||||
// If parameter starts with prefix, load corresponding parameter
|
||||
// value into config
|
||||
String param = params.nextElement();
|
||||
if (param.startsWith(PARAMETER_PREFIX))
|
||||
config.setParameter(
|
||||
param.substring(PARAMETER_PREFIX.length()),
|
||||
request.getParameter(param));
|
||||
|
||||
}
|
||||
|
||||
// Create connection skeleton
|
||||
Connection connection = directory.get(identifier);
|
||||
connection.setName(name);
|
||||
connection.setConfiguration(config);
|
||||
|
||||
// Update connection
|
||||
directory.update(connection);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -1,224 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2013 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.crud.permissions;
|
||||
|
||||
import java.io.IOException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.xml.stream.XMLOutputFactory;
|
||||
import javax.xml.stream.XMLStreamException;
|
||||
import javax.xml.stream.XMLStreamWriter;
|
||||
import org.glyptodon.guacamole.GuacamoleClientException;
|
||||
import org.glyptodon.guacamole.GuacamoleException;
|
||||
import org.glyptodon.guacamole.GuacamoleSecurityException;
|
||||
import org.glyptodon.guacamole.GuacamoleServerException;
|
||||
import org.glyptodon.guacamole.net.auth.Directory;
|
||||
import org.glyptodon.guacamole.net.auth.User;
|
||||
import org.glyptodon.guacamole.net.auth.UserContext;
|
||||
import org.glyptodon.guacamole.net.auth.permission.ConnectionGroupPermission;
|
||||
import org.glyptodon.guacamole.net.auth.permission.ConnectionPermission;
|
||||
import org.glyptodon.guacamole.net.auth.permission.ObjectPermission;
|
||||
import org.glyptodon.guacamole.net.auth.permission.Permission;
|
||||
import org.glyptodon.guacamole.net.auth.permission.SystemPermission;
|
||||
import org.glyptodon.guacamole.net.auth.permission.UserPermission;
|
||||
import org.glyptodon.guacamole.net.basic.RestrictedHttpServlet;
|
||||
|
||||
/**
|
||||
* Simple HttpServlet which outputs XML containing a list of all visible
|
||||
* permissions of a given user.
|
||||
*
|
||||
* @author Michael Jumper
|
||||
*/
|
||||
public class List extends RestrictedHttpServlet {
|
||||
|
||||
/**
|
||||
* Returns the XML attribute value representation of the given
|
||||
* SystemPermission.Type.
|
||||
*
|
||||
* @param type The SystemPermission.Type to translate into a String.
|
||||
* @return The XML attribute value representation of the given
|
||||
* SystemPermission.Type.
|
||||
*
|
||||
* @throws GuacamoleException If the type given is not implemented.
|
||||
*/
|
||||
private String toString(SystemPermission.Type type)
|
||||
throws GuacamoleException {
|
||||
|
||||
switch (type) {
|
||||
case CREATE_USER: return "create-user";
|
||||
case CREATE_CONNECTION: return "create-connection";
|
||||
case CREATE_CONNECTION_GROUP: return "create-connection-group";
|
||||
case ADMINISTER: return "admin";
|
||||
}
|
||||
|
||||
throw new GuacamoleException("Unknown permission type: " + type);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the XML attribute value representation of the given
|
||||
* ObjectPermission.Type.
|
||||
*
|
||||
* @param type The ObjectPermission.Type to translate into a String.
|
||||
* @return The XML attribute value representation of the given
|
||||
* ObjectPermission.Type.
|
||||
*
|
||||
* @throws GuacamoleException If the type given is not implemented.
|
||||
*/
|
||||
private String toString(ObjectPermission.Type type)
|
||||
throws GuacamoleException {
|
||||
|
||||
switch (type) {
|
||||
case READ: return "read";
|
||||
case UPDATE: return "update";
|
||||
case DELETE: return "delete";
|
||||
case ADMINISTER: return "admin";
|
||||
}
|
||||
|
||||
throw new GuacamoleException("Unknown permission type: " + type);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void restrictedService(
|
||||
UserContext context,
|
||||
HttpServletRequest request, HttpServletResponse response)
|
||||
throws GuacamoleException {
|
||||
|
||||
// Do not cache
|
||||
response.setHeader("Cache-Control", "no-cache");
|
||||
|
||||
// Set encoding
|
||||
response.setCharacterEncoding("UTF-8");
|
||||
|
||||
// Write actual XML
|
||||
try {
|
||||
|
||||
User user;
|
||||
|
||||
// Get username
|
||||
String username = request.getParameter("user");
|
||||
if (username != null) {
|
||||
|
||||
// Get user directory
|
||||
Directory<String, User> users = context.getUserDirectory();
|
||||
|
||||
// Get specific user
|
||||
user = users.get(username);
|
||||
}
|
||||
else
|
||||
user = context.self();
|
||||
|
||||
if (user == null)
|
||||
throw new GuacamoleSecurityException("No such user.");
|
||||
|
||||
// Write XML content type
|
||||
response.setHeader("Content-Type", "text/xml");
|
||||
|
||||
XMLOutputFactory outputFactory = XMLOutputFactory.newInstance();
|
||||
XMLStreamWriter xml = outputFactory.createXMLStreamWriter(response.getWriter());
|
||||
|
||||
// Begin document
|
||||
xml.writeStartDocument();
|
||||
xml.writeStartElement("permissions");
|
||||
xml.writeAttribute("user", user.getUsername());
|
||||
|
||||
// For each entry, write corresponding user element
|
||||
for (Permission permission : user.getPermissions()) {
|
||||
|
||||
// System permission
|
||||
if (permission instanceof SystemPermission) {
|
||||
|
||||
// Get permission
|
||||
SystemPermission sp = (SystemPermission) permission;
|
||||
|
||||
// Write permission
|
||||
xml.writeEmptyElement("system");
|
||||
xml.writeAttribute("type", toString(sp.getType()));
|
||||
|
||||
}
|
||||
|
||||
// Config permission
|
||||
else if (permission instanceof ConnectionPermission) {
|
||||
|
||||
// Get permission
|
||||
ConnectionPermission cp =
|
||||
(ConnectionPermission) permission;
|
||||
|
||||
// Write permission
|
||||
xml.writeEmptyElement("connection");
|
||||
xml.writeAttribute("type", toString(cp.getType()));
|
||||
xml.writeAttribute("name", cp.getObjectIdentifier());
|
||||
|
||||
}
|
||||
|
||||
// Connection group permission
|
||||
else if (permission instanceof ConnectionGroupPermission) {
|
||||
|
||||
// Get permission
|
||||
ConnectionGroupPermission cgp =
|
||||
(ConnectionGroupPermission) permission;
|
||||
|
||||
// Write permission
|
||||
xml.writeEmptyElement("connection-group");
|
||||
xml.writeAttribute("type", toString(cgp.getType()));
|
||||
xml.writeAttribute("name", cgp.getObjectIdentifier());
|
||||
|
||||
}
|
||||
|
||||
// User permission
|
||||
else if (permission instanceof UserPermission) {
|
||||
|
||||
// Get permission
|
||||
UserPermission up = (UserPermission) permission;
|
||||
|
||||
// Write permission
|
||||
xml.writeEmptyElement("user");
|
||||
xml.writeAttribute("type", toString(up.getType()));
|
||||
xml.writeAttribute("name", up.getObjectIdentifier());
|
||||
|
||||
}
|
||||
|
||||
else
|
||||
throw new GuacamoleClientException(
|
||||
"Unsupported permission type.");
|
||||
|
||||
}
|
||||
|
||||
// End document
|
||||
xml.writeEndElement();
|
||||
xml.writeEndDocument();
|
||||
|
||||
}
|
||||
catch (XMLStreamException e) {
|
||||
throw new GuacamoleServerException(
|
||||
"Unable to write permission list XML.", e);
|
||||
}
|
||||
catch (IOException e) {
|
||||
throw new GuacamoleServerException(
|
||||
"I/O error writing permission list XML.", e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
@@ -1,65 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2013 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.crud.users;
|
||||
|
||||
import java.util.UUID;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import org.glyptodon.guacamole.GuacamoleException;
|
||||
import org.glyptodon.guacamole.net.auth.Directory;
|
||||
import org.glyptodon.guacamole.net.auth.User;
|
||||
import org.glyptodon.guacamole.net.auth.UserContext;
|
||||
import org.glyptodon.guacamole.net.basic.RestrictedHttpServlet;
|
||||
|
||||
/**
|
||||
* Simple HttpServlet which handles user creation.
|
||||
*
|
||||
* @author Michael Jumper
|
||||
*/
|
||||
public class Create extends RestrictedHttpServlet {
|
||||
|
||||
@Override
|
||||
protected void restrictedService(
|
||||
UserContext context,
|
||||
HttpServletRequest request, HttpServletResponse response)
|
||||
throws GuacamoleException {
|
||||
|
||||
// Create user as specified
|
||||
String username = request.getParameter("name");
|
||||
|
||||
// Attempt to get user directory
|
||||
Directory<String, User> directory =
|
||||
context.getUserDirectory();
|
||||
|
||||
// Create user skeleton
|
||||
User user = new DummyUser();
|
||||
user.setUsername(username);
|
||||
user.setPassword(UUID.randomUUID().toString());
|
||||
|
||||
// Add user
|
||||
directory.add(user);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -1,67 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2013 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.crud.users;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import org.glyptodon.guacamole.GuacamoleException;
|
||||
import org.glyptodon.guacamole.net.auth.AbstractUser;
|
||||
import org.glyptodon.guacamole.net.auth.permission.Permission;
|
||||
|
||||
/**
|
||||
* Basic User skeleton, providing a means of storing User data prior to CRUD
|
||||
* operations. This User does not promote any of the semantics that would
|
||||
* otherwise be present because of the authentication provider. It is up to the
|
||||
* authentication provider to create a new User based on the information
|
||||
* contained herein.
|
||||
*
|
||||
* @author Michael Jumper
|
||||
*/
|
||||
public class DummyUser extends AbstractUser {
|
||||
|
||||
/**
|
||||
* Set of all available permissions.
|
||||
*/
|
||||
private Set<Permission> permissions = new HashSet<Permission>();
|
||||
|
||||
@Override
|
||||
public Set<Permission> getPermissions() throws GuacamoleException {
|
||||
return permissions;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasPermission(Permission permission) throws GuacamoleException {
|
||||
return permissions.contains(permission);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addPermission(Permission permission) throws GuacamoleException {
|
||||
permissions.add(permission);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removePermission(Permission permission) throws GuacamoleException {
|
||||
permissions.remove(permission);
|
||||
}
|
||||
|
||||
}
|
@@ -1,106 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2013 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.crud.users;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Set;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.xml.stream.XMLOutputFactory;
|
||||
import javax.xml.stream.XMLStreamException;
|
||||
import javax.xml.stream.XMLStreamWriter;
|
||||
import org.glyptodon.guacamole.GuacamoleException;
|
||||
import org.glyptodon.guacamole.GuacamoleServerException;
|
||||
import org.glyptodon.guacamole.net.auth.Directory;
|
||||
import org.glyptodon.guacamole.net.auth.User;
|
||||
import org.glyptodon.guacamole.net.auth.UserContext;
|
||||
import org.glyptodon.guacamole.net.basic.RestrictedHttpServlet;
|
||||
|
||||
/**
|
||||
* Simple HttpServlet which outputs XML containing a list of all visible users.
|
||||
*
|
||||
* @author Michael Jumper
|
||||
*/
|
||||
public class List extends RestrictedHttpServlet {
|
||||
|
||||
@Override
|
||||
protected void restrictedService(
|
||||
UserContext context,
|
||||
HttpServletRequest request, HttpServletResponse response)
|
||||
throws GuacamoleException {
|
||||
|
||||
// Do not cache
|
||||
response.setHeader("Cache-Control", "no-cache");
|
||||
|
||||
// Write XML content type
|
||||
response.setHeader("Content-Type", "text/xml");
|
||||
|
||||
// Set encoding
|
||||
response.setCharacterEncoding("UTF-8");
|
||||
|
||||
// Write actual XML
|
||||
try {
|
||||
|
||||
// Get user directory
|
||||
Directory<String, User> directory = context.getUserDirectory();
|
||||
|
||||
// Get users
|
||||
Set<String> users = directory.getIdentifiers();
|
||||
|
||||
XMLOutputFactory outputFactory = XMLOutputFactory.newInstance();
|
||||
XMLStreamWriter xml = outputFactory.createXMLStreamWriter(response.getWriter());
|
||||
|
||||
// Begin document
|
||||
xml.writeStartDocument();
|
||||
xml.writeStartElement("users");
|
||||
|
||||
// For each entry, write corresponding user element
|
||||
for (String username : users) {
|
||||
|
||||
// Get user
|
||||
User user = directory.get(username);
|
||||
|
||||
// Write user
|
||||
xml.writeEmptyElement("user");
|
||||
xml.writeAttribute("name", user.getUsername());
|
||||
|
||||
}
|
||||
|
||||
// End document
|
||||
xml.writeEndElement();
|
||||
xml.writeEndDocument();
|
||||
|
||||
}
|
||||
catch (XMLStreamException e) {
|
||||
throw new GuacamoleServerException(
|
||||
"Unable to write configuration list XML.", e);
|
||||
}
|
||||
catch (IOException e) {
|
||||
throw new GuacamoleServerException(
|
||||
"I/O error writing configuration list XML.", e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -1,311 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2013 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.crud.users;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import org.glyptodon.guacamole.GuacamoleClientException;
|
||||
import org.glyptodon.guacamole.GuacamoleException;
|
||||
import org.glyptodon.guacamole.net.auth.Directory;
|
||||
import org.glyptodon.guacamole.net.auth.User;
|
||||
import org.glyptodon.guacamole.net.auth.UserContext;
|
||||
import org.glyptodon.guacamole.net.auth.permission.ConnectionGroupPermission;
|
||||
import org.glyptodon.guacamole.net.auth.permission.ConnectionPermission;
|
||||
import org.glyptodon.guacamole.net.auth.permission.ObjectPermission;
|
||||
import org.glyptodon.guacamole.net.auth.permission.Permission;
|
||||
import org.glyptodon.guacamole.net.auth.permission.SystemPermission;
|
||||
import org.glyptodon.guacamole.net.auth.permission.UserPermission;
|
||||
import org.glyptodon.guacamole.net.basic.RestrictedHttpServlet;
|
||||
|
||||
/**
|
||||
* Simple HttpServlet which handles user update.
|
||||
*
|
||||
* @author Michael Jumper
|
||||
*/
|
||||
public class Update extends RestrictedHttpServlet {
|
||||
|
||||
/**
|
||||
* String given for user creation permission.
|
||||
*/
|
||||
private static final String CREATE_USER_PERMISSION = "create-user";
|
||||
|
||||
/**
|
||||
* String given for connection creation permission.
|
||||
*/
|
||||
private static final String CREATE_CONNECTION_PERMISSION = "create-connection";
|
||||
|
||||
/**
|
||||
* String given for connection group creation permission.
|
||||
*/
|
||||
private static final String CREATE_CONNECTION_GROUP_PERMISSION = "create-connection-group";
|
||||
|
||||
/**
|
||||
* String given for system administration permission.
|
||||
*/
|
||||
private static final String ADMIN_PERMISSION = "admin";
|
||||
|
||||
/**
|
||||
* Prefix given before an object identifier for read permission.
|
||||
*/
|
||||
private static final String READ_PREFIX = "read:";
|
||||
|
||||
/**
|
||||
* Prefix given before an object identifier for delete permission.
|
||||
*/
|
||||
private static final String DELETE_PREFIX = "delete:";
|
||||
|
||||
/**
|
||||
* Prefix given before an object identifier for update permission.
|
||||
*/
|
||||
private static final String UPDATE_PREFIX = "update:";
|
||||
|
||||
/**
|
||||
* Prefix given before an object identifier for administration permission.
|
||||
*/
|
||||
private static final String ADMIN_PREFIX = "admin:";
|
||||
|
||||
/**
|
||||
* Given a permission string, returns the corresponding system permission.
|
||||
*
|
||||
* @param str The permission string to parse.
|
||||
* @return The parsed system permission.
|
||||
* @throws GuacamoleException If the given string could not be parsed.
|
||||
*/
|
||||
private Permission parseSystemPermission(String str)
|
||||
throws GuacamoleException {
|
||||
|
||||
// Create user
|
||||
if (str.equals(CREATE_USER_PERMISSION))
|
||||
return new SystemPermission(SystemPermission.Type.CREATE_USER);
|
||||
|
||||
// Create connection
|
||||
if (str.equals(CREATE_CONNECTION_PERMISSION))
|
||||
return new SystemPermission(SystemPermission.Type.CREATE_CONNECTION);
|
||||
|
||||
// Create connection group
|
||||
if (str.equals(CREATE_CONNECTION_GROUP_PERMISSION))
|
||||
return new SystemPermission(SystemPermission.Type.CREATE_CONNECTION_GROUP);
|
||||
|
||||
// Administration
|
||||
if (str.equals(ADMIN_PERMISSION))
|
||||
return new SystemPermission(SystemPermission.Type.ADMINISTER);
|
||||
|
||||
throw new GuacamoleException("Invalid permission string.");
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a permission string, returns the corresponding user permission.
|
||||
*
|
||||
* @param str The permission string to parse.
|
||||
* @return The parsed user permission.
|
||||
* @throws GuacamoleException If the given string could not be parsed.
|
||||
*/
|
||||
private Permission parseUserPermission(String str)
|
||||
throws GuacamoleException {
|
||||
|
||||
// Read
|
||||
if (str.startsWith(READ_PREFIX))
|
||||
return new UserPermission(ObjectPermission.Type.READ,
|
||||
str.substring(READ_PREFIX.length()));
|
||||
|
||||
// Update
|
||||
if (str.startsWith(UPDATE_PREFIX))
|
||||
return new UserPermission(ObjectPermission.Type.UPDATE,
|
||||
str.substring(UPDATE_PREFIX.length()));
|
||||
|
||||
// Delete
|
||||
if (str.startsWith(DELETE_PREFIX))
|
||||
return new UserPermission(ObjectPermission.Type.DELETE,
|
||||
str.substring(DELETE_PREFIX.length()));
|
||||
|
||||
// Administration
|
||||
if (str.startsWith(ADMIN_PREFIX))
|
||||
return new UserPermission(ObjectPermission.Type.ADMINISTER,
|
||||
str.substring(ADMIN_PREFIX.length()));
|
||||
|
||||
throw new GuacamoleException("Invalid permission string.");
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a permission string, returns the corresponding connection
|
||||
* permission.
|
||||
*
|
||||
* @param str The permission string to parse.
|
||||
* @return The parsed connection permission.
|
||||
* @throws GuacamoleException If the given string could not be parsed.
|
||||
*/
|
||||
private Permission parseConnectionPermission(String str)
|
||||
throws GuacamoleException {
|
||||
|
||||
// Read
|
||||
if (str.startsWith(READ_PREFIX))
|
||||
return new ConnectionPermission(ObjectPermission.Type.READ,
|
||||
str.substring(READ_PREFIX.length()));
|
||||
|
||||
// Update
|
||||
if (str.startsWith(UPDATE_PREFIX))
|
||||
return new ConnectionPermission(ObjectPermission.Type.UPDATE,
|
||||
str.substring(UPDATE_PREFIX.length()));
|
||||
|
||||
// Delete
|
||||
if (str.startsWith(DELETE_PREFIX))
|
||||
return new ConnectionPermission(ObjectPermission.Type.DELETE,
|
||||
str.substring(DELETE_PREFIX.length()));
|
||||
|
||||
// Administration
|
||||
if (str.startsWith(ADMIN_PREFIX))
|
||||
return new ConnectionPermission(ObjectPermission.Type.ADMINISTER,
|
||||
str.substring(ADMIN_PREFIX.length()));
|
||||
|
||||
throw new GuacamoleClientException("Invalid permission string.");
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a permission string, returns the corresponding connection group
|
||||
* permission.
|
||||
*
|
||||
* @param str The permission string to parse.
|
||||
* @return The parsed connection group permission.
|
||||
* @throws GuacamoleException If the given string could not be parsed.
|
||||
*/
|
||||
private Permission parseConnectionGroupPermission(String str)
|
||||
throws GuacamoleException {
|
||||
|
||||
// Read
|
||||
if (str.startsWith(READ_PREFIX))
|
||||
return new ConnectionGroupPermission(ObjectPermission.Type.READ,
|
||||
str.substring(READ_PREFIX.length()));
|
||||
|
||||
// Update
|
||||
if (str.startsWith(UPDATE_PREFIX))
|
||||
return new ConnectionGroupPermission(ObjectPermission.Type.UPDATE,
|
||||
str.substring(UPDATE_PREFIX.length()));
|
||||
|
||||
// Delete
|
||||
if (str.startsWith(DELETE_PREFIX))
|
||||
return new ConnectionGroupPermission(ObjectPermission.Type.DELETE,
|
||||
str.substring(DELETE_PREFIX.length()));
|
||||
|
||||
// Administration
|
||||
if (str.startsWith(ADMIN_PREFIX))
|
||||
return new ConnectionGroupPermission(ObjectPermission.Type.ADMINISTER,
|
||||
str.substring(ADMIN_PREFIX.length()));
|
||||
|
||||
throw new GuacamoleClientException("Invalid permission string.");
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void restrictedService(
|
||||
UserContext context,
|
||||
HttpServletRequest request, HttpServletResponse response)
|
||||
throws GuacamoleException {
|
||||
|
||||
// Create user as specified
|
||||
String username = request.getParameter("name");
|
||||
String password = request.getParameter("password");
|
||||
|
||||
// Attempt to get user directory
|
||||
Directory<String, User> directory =
|
||||
context.getUserDirectory();
|
||||
|
||||
// Get user data, setting password if given
|
||||
User user = directory.get(username);
|
||||
user.setUsername(username);
|
||||
if (password != null)
|
||||
user.setPassword(password);
|
||||
|
||||
/*
|
||||
* NEW PERMISSIONS
|
||||
*/
|
||||
|
||||
// Set added system permissions
|
||||
String[] add_sys_permission = request.getParameterValues("+sys");
|
||||
if (add_sys_permission != null) {
|
||||
for (String str : add_sys_permission)
|
||||
user.addPermission(parseSystemPermission(str));
|
||||
}
|
||||
|
||||
// Set added user permissions
|
||||
String[] add_user_permission = request.getParameterValues("+user");
|
||||
if (add_user_permission != null) {
|
||||
for (String str : add_user_permission)
|
||||
user.addPermission(parseUserPermission(str));
|
||||
}
|
||||
|
||||
// Set added connection permissions
|
||||
String[] add_connection_permission = request.getParameterValues("+connection");
|
||||
if (add_connection_permission != null) {
|
||||
for (String str : add_connection_permission)
|
||||
user.addPermission(parseConnectionPermission(str));
|
||||
}
|
||||
|
||||
// Set added connection group permissions
|
||||
String[] add_connection_group_permission = request.getParameterValues("+connection-group");
|
||||
if (add_connection_group_permission != null) {
|
||||
for (String str : add_connection_group_permission)
|
||||
user.addPermission(parseConnectionGroupPermission(str));
|
||||
}
|
||||
|
||||
/*
|
||||
* REMOVED PERMISSIONS
|
||||
*/
|
||||
|
||||
// Unset removed system permissions
|
||||
String[] remove_sys_permission = request.getParameterValues("-sys");
|
||||
if (remove_sys_permission != null) {
|
||||
for (String str : remove_sys_permission)
|
||||
user.removePermission(parseSystemPermission(str));
|
||||
}
|
||||
|
||||
// Unset removed user permissions
|
||||
String[] remove_user_permission = request.getParameterValues("-user");
|
||||
if (remove_user_permission != null) {
|
||||
for (String str : remove_user_permission)
|
||||
user.removePermission(parseUserPermission(str));
|
||||
}
|
||||
|
||||
// Unset removed connection permissions
|
||||
String[] remove_connection_permission = request.getParameterValues("-connection");
|
||||
if (remove_connection_permission != null) {
|
||||
for (String str : remove_connection_permission)
|
||||
user.removePermission(parseConnectionPermission(str));
|
||||
}
|
||||
|
||||
// Unset removed connection group permissions
|
||||
String[] remove_connection_group_permission = request.getParameterValues("-connection-group");
|
||||
if (remove_connection_group_permission != null) {
|
||||
for (String str : remove_connection_group_permission)
|
||||
user.removePermission(parseConnectionGroupPermission(str));
|
||||
}
|
||||
|
||||
// Update user
|
||||
directory.update(user);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -26,32 +26,26 @@ import ch.qos.logback.classic.LoggerContext;
|
||||
import ch.qos.logback.classic.joran.JoranConfigurator;
|
||||
import ch.qos.logback.core.joran.spi.JoranException;
|
||||
import ch.qos.logback.core.util.StatusPrinter;
|
||||
import com.google.inject.AbstractModule;
|
||||
import java.io.File;
|
||||
import javax.servlet.ServletContextEvent;
|
||||
import javax.servlet.ServletContextListener;
|
||||
import org.glyptodon.guacamole.properties.GuacamoleHome;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Initializes the logback logging subsystem, used behind SLF4J within
|
||||
* Guacamole for all logging.
|
||||
* Initializes the logging subsystem.
|
||||
*
|
||||
* @author Michael Jumper
|
||||
*/
|
||||
public class LogbackInitializer implements ServletContextListener {
|
||||
public class LogModule extends AbstractModule {
|
||||
|
||||
/**
|
||||
* Logger for this class.
|
||||
*/
|
||||
private final Logger logger = LoggerFactory.getLogger(LogbackInitializer.class);
|
||||
private final Logger logger = LoggerFactory.getLogger(LogModule.class);
|
||||
|
||||
@Override
|
||||
public void contextDestroyed(ServletContextEvent sce) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void contextInitialized(ServletContextEvent sce) {
|
||||
protected void configure() {
|
||||
|
||||
// Only load logback configuration if GUACAMOLE_HOME exists
|
||||
File guacamoleHome = GuacamoleHome.getDirectory();
|
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright (C) 2014 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;
|
||||
|
||||
/**
|
||||
* Useful constants for the REST API.
|
||||
*
|
||||
* @author James Muehlner
|
||||
*/
|
||||
public class APIConstants {
|
||||
|
||||
/**
|
||||
* The identifier of the ROOT connection group.
|
||||
*/
|
||||
public static final String ROOT_CONNECTION_GROUP_IDENTIFIER = "ROOT";
|
||||
|
||||
}
|
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Copyright (C) 2014 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;
|
||||
|
||||
/**
|
||||
* A simple object to represent an error to be sent from the REST API.
|
||||
* @author James Muehlner
|
||||
*/
|
||||
public class APIError {
|
||||
|
||||
/**
|
||||
* The error message.
|
||||
*/
|
||||
private final String message;
|
||||
|
||||
/**
|
||||
* Get the error message.
|
||||
* @return The error message.
|
||||
*/
|
||||
public String getMessage() {
|
||||
return message;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new APIError with the specified error message.
|
||||
* @param message The error message.
|
||||
*/
|
||||
public APIError(String message) {
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,104 @@
|
||||
/*
|
||||
* Copyright (C) 2014 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;
|
||||
|
||||
/**
|
||||
* An object for representing the body of a HTTP PATCH method.
|
||||
* See https://tools.ietf.org/html/rfc6902
|
||||
*
|
||||
* @author James Muehlner
|
||||
* @param <T> The type of object being patched.
|
||||
*/
|
||||
public class APIPatch<T> {
|
||||
|
||||
/**
|
||||
* The possible operations for a PATCH request.
|
||||
*/
|
||||
public enum Operation {
|
||||
add, remove, test, copy, replace, move
|
||||
}
|
||||
|
||||
/**
|
||||
* The operation to perform for this patch.
|
||||
*/
|
||||
private Operation op;
|
||||
|
||||
/**
|
||||
* The value for this patch.
|
||||
*/
|
||||
private T value;
|
||||
|
||||
/**
|
||||
* The path for this patch.
|
||||
*/
|
||||
private String path;
|
||||
|
||||
/**
|
||||
* Returns the operation for this patch.
|
||||
* @return the operation for this patch.
|
||||
*/
|
||||
public Operation getOp() {
|
||||
return op;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the operation for this patch.
|
||||
* @param op The operation for this patch.
|
||||
*/
|
||||
public void setOp(Operation op) {
|
||||
this.op = op;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value of this patch.
|
||||
* @return The value of this patch.
|
||||
*/
|
||||
public T getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the value of this patch.
|
||||
* @param value The value of this patch.
|
||||
*/
|
||||
public void setValue(T value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the path for this patch.
|
||||
* @return The path for this patch.
|
||||
*/
|
||||
public String getPath() {
|
||||
return path;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the path for this patch.
|
||||
* @param path The path for this patch.
|
||||
*/
|
||||
public void setPath(String path) {
|
||||
this.path = path;
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* Copyright (C) 2014 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 javax.ws.rs.core.Response;
|
||||
import org.aopalliance.intercept.MethodInterceptor;
|
||||
import org.aopalliance.intercept.MethodInvocation;
|
||||
import org.glyptodon.guacamole.GuacamoleClientException;
|
||||
import org.glyptodon.guacamole.GuacamoleException;
|
||||
import org.glyptodon.guacamole.GuacamoleSecurityException;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* A method interceptor to wrap some custom exception handling around methods
|
||||
* that expose AuthenticationProvider functionality through the REST interface.
|
||||
* Translates various types of GuacamoleExceptions into appropriate HTTP responses.
|
||||
*
|
||||
* @author James Muehlner
|
||||
*/
|
||||
public class AuthProviderRESTExceptionWrapper implements MethodInterceptor {
|
||||
|
||||
@Override
|
||||
public Object invoke(MethodInvocation invocation) throws Throwable {
|
||||
|
||||
// Get the logger for the intercepted class
|
||||
Logger logger = LoggerFactory.getLogger(invocation.getMethod().getDeclaringClass());
|
||||
|
||||
try {
|
||||
return invocation.proceed();
|
||||
}
|
||||
catch(GuacamoleSecurityException e) {
|
||||
throw new HTTPException(Response.Status.FORBIDDEN, e.getMessage() != null ? e.getMessage() : "Permission denied.");
|
||||
}
|
||||
catch(GuacamoleClientException e) {
|
||||
throw new HTTPException(Response.Status.BAD_REQUEST, e.getMessage() != null ? e.getMessage() : "Invalid Request.");
|
||||
}
|
||||
catch(GuacamoleException e) {
|
||||
logger.error("Unexpected GuacamoleException caught while executing " + invocation.getMethod().getName() + ".", e);
|
||||
throw new HTTPException(Response.Status.INTERNAL_SERVER_ERROR, e.getMessage() != null ? e.getMessage() : "Unexpected server error.");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright (C) 2014 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.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Marks that a method exposes functionality from the Guacamole AuthenticationProvider
|
||||
* using a REST interface.
|
||||
*
|
||||
* @author James Muehlner
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ElementType.METHOD})
|
||||
public @interface AuthProviderRESTExposure {}
|
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Copyright (C) 2014 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 javax.ws.rs.WebApplicationException;
|
||||
import javax.ws.rs.core.Response;
|
||||
import javax.ws.rs.core.Response.Status;
|
||||
|
||||
/**
|
||||
* An exception that will result in the given HTTP Status and message or entity
|
||||
* being returned from the API layer.
|
||||
*
|
||||
* @author James Muehlner
|
||||
*/
|
||||
public class HTTPException extends WebApplicationException {
|
||||
|
||||
/**
|
||||
* Construct a new HTTPException with the given HTTP status and entity.
|
||||
*
|
||||
* @param status The HTTP Status to use for the response.
|
||||
* @param entity The entity to use as the body of the response.
|
||||
*/
|
||||
public HTTPException(Status status, Object entity) {
|
||||
super(Response.status(status).entity(entity).build());
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a new HTTPException with the given HTTP status and message. The
|
||||
* message will be wrapped in an APIError container.
|
||||
*
|
||||
* @param status The HTTP Status to use for the response.
|
||||
* @param message The message to build the response entity with.
|
||||
*/
|
||||
public HTTPException(Status status, String message) {
|
||||
super(Response.status(status).entity(new APIError(message)).build());
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright (C) 2014 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.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
import javax.ws.rs.HttpMethod;
|
||||
|
||||
/**
|
||||
* An annotation for using the HTTP PATCH method in the REST endpoints.
|
||||
*
|
||||
* @author James Muehlner
|
||||
*/
|
||||
@Target({ElementType.METHOD})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@HttpMethod("PATCH")
|
||||
public @interface PATCH {}
|
@@ -0,0 +1,89 @@
|
||||
/*
|
||||
* Copyright (C) 2014 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 com.google.inject.AbstractModule;
|
||||
import com.google.inject.matcher.Matchers;
|
||||
import org.glyptodon.guacamole.GuacamoleException;
|
||||
import org.glyptodon.guacamole.net.auth.AuthenticationProvider;
|
||||
import org.glyptodon.guacamole.net.basic.properties.BasicGuacamoleProperties;
|
||||
import org.glyptodon.guacamole.net.basic.rest.auth.AuthTokenGenerator;
|
||||
import org.glyptodon.guacamole.net.basic.rest.auth.AuthenticationService;
|
||||
import org.glyptodon.guacamole.net.basic.rest.auth.BasicTokenSessionMap;
|
||||
import org.glyptodon.guacamole.net.basic.rest.auth.SecureRandomAuthTokenGenerator;
|
||||
import org.glyptodon.guacamole.net.basic.rest.auth.TokenSessionMap;
|
||||
import org.glyptodon.guacamole.net.basic.rest.connection.ConnectionService;
|
||||
import org.glyptodon.guacamole.net.basic.rest.connectiongroup.ConnectionGroupService;
|
||||
import org.glyptodon.guacamole.net.basic.rest.permission.PermissionService;
|
||||
import org.glyptodon.guacamole.net.basic.rest.protocol.ProtocolRetrievalService;
|
||||
import org.glyptodon.guacamole.net.basic.rest.user.UserService;
|
||||
import org.glyptodon.guacamole.properties.GuacamoleProperties;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* A Guice Module for setting up dependency injection for the
|
||||
* Guacamole REST API.
|
||||
*
|
||||
* @author James Muehlner
|
||||
*/
|
||||
public class RESTModule extends AbstractModule {
|
||||
|
||||
/**
|
||||
* Logger for this class.
|
||||
*/
|
||||
private static final Logger logger = LoggerFactory.getLogger(RESTModule.class);
|
||||
|
||||
/**
|
||||
* The AuthenticationProvider to use to authenticate all requests.
|
||||
*/
|
||||
private AuthenticationProvider authProvider;
|
||||
|
||||
@Override
|
||||
protected void configure() {
|
||||
|
||||
// Get auth provider instance
|
||||
try {
|
||||
authProvider = GuacamoleProperties.getRequiredProperty(BasicGuacamoleProperties.AUTH_PROVIDER);
|
||||
}
|
||||
catch (GuacamoleException e) {
|
||||
logger.error("Unable to read authentication provider from guacamole.properties: {}", e.getMessage());
|
||||
logger.debug("Error reading authentication provider from guacamole.properties.", e);
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
bind(AuthenticationProvider.class).toInstance(authProvider);
|
||||
bind(TokenSessionMap.class).toInstance(new BasicTokenSessionMap());
|
||||
bind(ConnectionService.class);
|
||||
bind(ConnectionGroupService.class);
|
||||
bind(PermissionService.class);
|
||||
bind(UserService.class);
|
||||
bind(AuthenticationService.class);
|
||||
bind(ProtocolRetrievalService.class);
|
||||
|
||||
bind(AuthTokenGenerator.class).to(SecureRandomAuthTokenGenerator.class);
|
||||
|
||||
bindInterceptor(Matchers.any(), Matchers.annotatedWith(AuthProviderRESTExposure.class), new AuthProviderRESTExceptionWrapper());
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Copyright (C) 2014 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 com.google.inject.Scopes;
|
||||
import com.google.inject.servlet.ServletModule;
|
||||
import com.sun.jersey.guice.spi.container.servlet.GuiceContainer;
|
||||
import org.codehaus.jackson.jaxrs.JacksonJsonProvider;
|
||||
import org.glyptodon.guacamole.net.basic.rest.auth.LoginRESTService;
|
||||
import org.glyptodon.guacamole.net.basic.rest.connection.ConnectionRESTService;
|
||||
import org.glyptodon.guacamole.net.basic.rest.connectiongroup.ConnectionGroupRESTService;
|
||||
import org.glyptodon.guacamole.net.basic.rest.permission.PermissionRESTService;
|
||||
import org.glyptodon.guacamole.net.basic.rest.protocol.ProtocolRESTService;
|
||||
import org.glyptodon.guacamole.net.basic.rest.user.UserRESTService;
|
||||
|
||||
/**
|
||||
* A Guice Module to set up the servlet mappings for the Guacamole REST API.
|
||||
*
|
||||
* @author James Muehlner
|
||||
*/
|
||||
public class RESTServletModule extends ServletModule {
|
||||
|
||||
@Override
|
||||
protected void configureServlets() {
|
||||
|
||||
// Set up the API endpoints
|
||||
bind(ConnectionRESTService.class);
|
||||
bind(ConnectionGroupRESTService.class);
|
||||
bind(PermissionRESTService.class);
|
||||
bind(ProtocolRESTService.class);
|
||||
bind(UserRESTService.class);
|
||||
bind(LoginRESTService.class);
|
||||
|
||||
// Set up the servlet and JSON mappings
|
||||
bind(GuiceContainer.class);
|
||||
bind(JacksonJsonProvider.class).in(Scopes.SINGLETON);
|
||||
serve("/api/*").with(GuiceContainer.class);
|
||||
|
||||
}
|
||||
|
||||
}
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2013 Glyptodon LLC
|
||||
* Copyright (C) 2014 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
|
||||
@@ -20,32 +20,50 @@
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
package org.glyptodon.guacamole.net.basic;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import org.glyptodon.guacamole.net.auth.UserContext;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
package org.glyptodon.guacamole.net.basic.rest.auth;
|
||||
|
||||
/**
|
||||
* Simple dummy AuthenticatingHttpServlet which provides an endpoint for arbitrary
|
||||
* authentication requests that do not expect a response.
|
||||
*
|
||||
* @author Michael Jumper
|
||||
* A simple object to represent an auth token/userID pair in the API.
|
||||
*
|
||||
* @author James Muehlner
|
||||
*/
|
||||
public class BasicLogin extends RestrictedHttpServlet {
|
||||
public class APIAuthToken {
|
||||
|
||||
/**
|
||||
* The auth token.
|
||||
*/
|
||||
private final String authToken;
|
||||
|
||||
|
||||
/**
|
||||
* The user ID.
|
||||
*/
|
||||
private final String userID;
|
||||
|
||||
/**
|
||||
* Logger for this class.
|
||||
* Get the auth token.
|
||||
* @return The auth token.
|
||||
*/
|
||||
private final Logger logger = LoggerFactory.getLogger(BasicLogin.class);
|
||||
|
||||
@Override
|
||||
protected void restrictedService(
|
||||
UserContext context,
|
||||
HttpServletRequest request, HttpServletResponse response) {
|
||||
logger.debug("Login was successful for user \"{}\".", context.self().getUsername());
|
||||
public String getAuthToken() {
|
||||
return authToken;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the user ID.
|
||||
* @return The user ID.
|
||||
*/
|
||||
public String getUserID() {
|
||||
return userID;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new APIAuthToken Object with the given auth token.
|
||||
*
|
||||
* @param authToken The auth token to create the new APIAuthToken with.
|
||||
* @param userID The ID of the user owning the given token.
|
||||
*/
|
||||
public APIAuthToken(String authToken, String userID) {
|
||||
this.authToken = authToken;
|
||||
this.userID = userID;
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright (C) 2014 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.auth;
|
||||
|
||||
/**
|
||||
* Generates an auth token for an authenticated user.
|
||||
*
|
||||
* @author James Muehlner
|
||||
*/
|
||||
public interface AuthTokenGenerator {
|
||||
|
||||
/**
|
||||
* Get a new auth token.
|
||||
*
|
||||
* @return A new auth token.
|
||||
*/
|
||||
public String getToken();
|
||||
|
||||
}
|
@@ -0,0 +1,81 @@
|
||||
/*
|
||||
* Copyright (C) 2014 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.auth;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
import org.glyptodon.guacamole.GuacamoleException;
|
||||
import org.glyptodon.guacamole.GuacamoleUnauthorizedException;
|
||||
import org.glyptodon.guacamole.net.auth.UserContext;
|
||||
import org.glyptodon.guacamole.net.basic.GuacamoleSession;
|
||||
|
||||
/**
|
||||
* A service for performing authentication checks in REST endpoints.
|
||||
*
|
||||
* @author James Muehlner
|
||||
*/
|
||||
public class AuthenticationService {
|
||||
|
||||
/**
|
||||
* The map of auth tokens to sessions for the REST endpoints.
|
||||
*/
|
||||
@Inject
|
||||
private TokenSessionMap tokenSessionMap;
|
||||
|
||||
/**
|
||||
* Finds the Guacamole session for a given auth token, if the auth token
|
||||
* represents a currently logged in user. Throws an unauthorized error
|
||||
* otherwise.
|
||||
*
|
||||
* @param authToken The auth token to check against the map of logged in users.
|
||||
* @return The session that corresponds to the provided auth token.
|
||||
* @throws GuacamoleException If the auth token does not correspond to any
|
||||
* logged in user.
|
||||
*/
|
||||
public GuacamoleSession getGuacamoleSession(String authToken)
|
||||
throws GuacamoleException {
|
||||
|
||||
// Try to get the session from the map of logged in users.
|
||||
GuacamoleSession session = tokenSessionMap.get(authToken);
|
||||
|
||||
// Authentication failed.
|
||||
if (session == null)
|
||||
throw new GuacamoleUnauthorizedException("Permission Denied.");
|
||||
|
||||
return session;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds the UserContext for a given auth token, if the auth token represents
|
||||
* a currently logged in user. Throws an unauthorized error otherwise.
|
||||
*
|
||||
* @param authToken The auth token to check against the map of logged in users.
|
||||
* @return The user context that corresponds to the provided auth token.
|
||||
* @throws GuacamoleException If the auth token does not correspond to any
|
||||
* logged in user.
|
||||
*/
|
||||
public UserContext getUserContext(String authToken) throws GuacamoleException {
|
||||
return getGuacamoleSession(authToken).getUserContext();
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,143 @@
|
||||
/*
|
||||
* Copyright (C) 2014 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.auth;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import org.glyptodon.guacamole.GuacamoleException;
|
||||
import org.glyptodon.guacamole.net.basic.GuacamoleSession;
|
||||
import org.glyptodon.guacamole.net.basic.properties.BasicGuacamoleProperties;
|
||||
import org.glyptodon.guacamole.properties.GuacamoleProperties;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* A basic, HashMap-based implementation of the TokenSessionMap with support
|
||||
* for session timeouts.
|
||||
*
|
||||
* @author James Muehlner
|
||||
*/
|
||||
public class BasicTokenSessionMap implements TokenSessionMap {
|
||||
|
||||
/**
|
||||
* Logger for this class.
|
||||
*/
|
||||
private static final Logger logger = LoggerFactory.getLogger(BasicTokenSessionMap.class);
|
||||
|
||||
/**
|
||||
* The last time a user with a specific auth token accessed the API.
|
||||
*/
|
||||
private final Map<String, Long> lastAccessTimeMap = new HashMap<String, Long>();
|
||||
|
||||
/**
|
||||
* Keeps track of the authToken to GuacamoleSession mapping.
|
||||
*/
|
||||
private final Map<String, GuacamoleSession> sessionMap = new HashMap<String, GuacamoleSession>();
|
||||
|
||||
/**
|
||||
* The session timeout configuration for an API session, in milliseconds.
|
||||
*/
|
||||
private final long SESSION_TIMEOUT;
|
||||
|
||||
/**
|
||||
* Create a new BasicTokenGuacamoleSessionMap and initialize the session timeout value.
|
||||
*/
|
||||
public BasicTokenSessionMap() {
|
||||
|
||||
// Set up the SESSION_TIMEOUT value, with a one hour default.
|
||||
long sessionTimeoutValue;
|
||||
try {
|
||||
sessionTimeoutValue = GuacamoleProperties.getProperty(BasicGuacamoleProperties.API_SESSION_TIMEOUT, 3600000l);
|
||||
}
|
||||
catch (GuacamoleException e) {
|
||||
logger.error("Unexpected GuacamoleException caught while reading API_SESSION_TIMEOUT property. Defaulting to 1 hour.", e);
|
||||
sessionTimeoutValue = 3600000l;
|
||||
}
|
||||
|
||||
SESSION_TIMEOUT = sessionTimeoutValue;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Evict an authentication token from the map of logged in users and last
|
||||
* access times.
|
||||
*
|
||||
* @param authToken The authentication token to evict.
|
||||
*/
|
||||
private void evict(String authToken) {
|
||||
sessionMap.remove(authToken);
|
||||
lastAccessTimeMap.remove(authToken);
|
||||
}
|
||||
|
||||
/**
|
||||
* Log that the user represented by this auth token has just used the API.
|
||||
*
|
||||
* @param authToken The authentication token to record access time for.
|
||||
*/
|
||||
private void logAccessTime(String authToken) {
|
||||
lastAccessTimeMap.put(authToken, new Date().getTime());
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a session has timed out.
|
||||
* @param authToken The auth token for the session.
|
||||
* @return True if the session has timed out, false otherwise.
|
||||
*/
|
||||
private boolean sessionHasTimedOut(String authToken) {
|
||||
|
||||
if (!lastAccessTimeMap.containsKey(authToken))
|
||||
return true;
|
||||
|
||||
long lastAccessTime = lastAccessTimeMap.get(authToken);
|
||||
long currentTime = new Date().getTime();
|
||||
|
||||
return currentTime - lastAccessTime > SESSION_TIMEOUT;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public GuacamoleSession get(String authToken) {
|
||||
|
||||
// If the session has timed out, evict the token and force the user to log in again
|
||||
if (sessionHasTimedOut(authToken)) {
|
||||
evict(authToken);
|
||||
return null;
|
||||
}
|
||||
|
||||
// Update the last access time and return the GuacamoleSession
|
||||
logAccessTime(authToken);
|
||||
return sessionMap.get(authToken);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void put(String authToken, GuacamoleSession session) {
|
||||
|
||||
// Update the last access time, and create the token/GuacamoleSession mapping
|
||||
logAccessTime(authToken);
|
||||
sessionMap.put(authToken, session);
|
||||
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,124 @@
|
||||
/*
|
||||
* Copyright (C) 2014 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.auth;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.ws.rs.POST;
|
||||
import javax.ws.rs.Path;
|
||||
import javax.ws.rs.Produces;
|
||||
import javax.ws.rs.QueryParam;
|
||||
import javax.ws.rs.core.Context;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
import javax.ws.rs.core.Response.Status;
|
||||
import org.glyptodon.guacamole.GuacamoleException;
|
||||
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.AuthProviderRESTExposure;
|
||||
import org.glyptodon.guacamole.net.basic.rest.HTTPException;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* A service for authenticating to the Guacamole REST API. Given valid
|
||||
* credentials, the service will return an auth token. Invalid credentials will
|
||||
* result in a permission error.
|
||||
*
|
||||
* @author James Muehlner
|
||||
*/
|
||||
|
||||
@Path("/login")
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
public class LoginRESTService {
|
||||
|
||||
/**
|
||||
* The authentication provider used to authenticate this user.
|
||||
*/
|
||||
@Inject
|
||||
private AuthenticationProvider authProvider;
|
||||
|
||||
/**
|
||||
* The map of auth tokens to sessions for the REST endpoints.
|
||||
*/
|
||||
@Inject
|
||||
private TokenSessionMap tokenSessionMap;
|
||||
|
||||
/**
|
||||
* A generator for creating new auth tokens.
|
||||
*/
|
||||
@Inject
|
||||
private AuthTokenGenerator authTokenGenerator;
|
||||
|
||||
/**
|
||||
* Logger for this class.
|
||||
*/
|
||||
private static final Logger logger = LoggerFactory.getLogger(LoginRESTService.class);
|
||||
|
||||
/**
|
||||
* Authenticates a user, generates an auth token, associates that auth token
|
||||
* with the user's UserContext for use by further requests.
|
||||
*
|
||||
* @param username The username of the user who is to be authenticated.
|
||||
* @param password The password of the user who is to be authenticated.
|
||||
* @param request The HttpServletRequest associated with the login attempt.
|
||||
* @return The auth token for the newly logged-in user.
|
||||
* @throws GuacamoleException If an error prevents successful login.
|
||||
*/
|
||||
@POST
|
||||
@AuthProviderRESTExposure
|
||||
public APIAuthToken login(@QueryParam("username") String username,
|
||||
@QueryParam("password") String password,
|
||||
@Context HttpServletRequest request) throws GuacamoleException {
|
||||
|
||||
Credentials credentials = new Credentials();
|
||||
credentials.setUsername(username);
|
||||
credentials.setPassword(password);
|
||||
credentials.setRequest(request);
|
||||
credentials.setSession(request.getSession(true));
|
||||
|
||||
UserContext userContext;
|
||||
try {
|
||||
userContext = authProvider.getUserContext(credentials);
|
||||
}
|
||||
catch(GuacamoleException e) {
|
||||
logger.error("Exception caught while authenticating user.", e);
|
||||
throw new HTTPException(Status.INTERNAL_SERVER_ERROR,
|
||||
"Unexpected server error.");
|
||||
}
|
||||
|
||||
// Authentication failed.
|
||||
if (userContext == null)
|
||||
throw new HTTPException(Status.UNAUTHORIZED, "Permission Denied.");
|
||||
|
||||
String authToken = authTokenGenerator.getToken();
|
||||
|
||||
tokenSessionMap.put(authToken, new GuacamoleSession(credentials, userContext));
|
||||
|
||||
logger.debug("Login was successful for user \"{}\".", userContext.self().getUsername());
|
||||
return new APIAuthToken(authToken, username);
|
||||
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright (C) 2014 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.auth;
|
||||
|
||||
import java.security.SecureRandom;
|
||||
import org.apache.commons.codec.binary.Hex;
|
||||
|
||||
/**
|
||||
* An implementation of the AuthTokenGenerator based around SecureRandom.
|
||||
*
|
||||
* @author James Muehlner
|
||||
*/
|
||||
public class SecureRandomAuthTokenGenerator implements AuthTokenGenerator {
|
||||
|
||||
/**
|
||||
* Instance of SecureRandom for generating the auth token.
|
||||
*/
|
||||
private final SecureRandom secureRandom = new SecureRandom();
|
||||
|
||||
@Override
|
||||
public String getToken() {
|
||||
byte[] bytes = new byte[32];
|
||||
secureRandom.nextBytes(bytes);
|
||||
|
||||
return Hex.encodeHexString(bytes);
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright (C) 2014 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.auth;
|
||||
|
||||
import org.glyptodon.guacamole.net.basic.GuacamoleSession;
|
||||
|
||||
/**
|
||||
* Represents a mapping of auth token to Guacamole session for the REST
|
||||
* authentication system.
|
||||
*
|
||||
* @author James Muehlner
|
||||
*/
|
||||
public interface TokenSessionMap {
|
||||
|
||||
/**
|
||||
* Registers that a user has just logged in with the specified authToken and
|
||||
* GuacamoleSession.
|
||||
*
|
||||
* @param authToken The authentication token for the logged in user.
|
||||
* @param session The GuacamoleSession for the logged in user.
|
||||
*/
|
||||
public void put(String authToken, GuacamoleSession session);
|
||||
|
||||
/**
|
||||
* Get the GuacamoleSession for a logged in user. If the auth token does not
|
||||
* represent a user who is currently logged in, returns null.
|
||||
*
|
||||
* @param authToken The authentication token for the logged in user.
|
||||
* @return The GuacamoleSession for the given auth token, if the auth token
|
||||
* represents a currently logged in user, null otherwise.
|
||||
*/
|
||||
public GuacamoleSession get(String authToken);
|
||||
|
||||
}
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2013 Glyptodon LLC
|
||||
* Copyright (C) 2014 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
|
||||
@@ -21,7 +21,7 @@
|
||||
*/
|
||||
|
||||
/**
|
||||
* Servlets dedicated to CRUD operations related to Connections.
|
||||
* Classes related to the authentication aspect of the Guacamole REST API.
|
||||
*/
|
||||
package org.glyptodon.guacamole.net.basic.crud.connections;
|
||||
package org.glyptodon.guacamole.net.basic.rest.auth;
|
||||
|
@@ -20,26 +20,36 @@
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
package org.glyptodon.guacamole.net.basic;
|
||||
package org.glyptodon.guacamole.net.basic.rest.clipboard;
|
||||
|
||||
import java.io.IOException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.servlet.http.HttpSession;
|
||||
import com.google.inject.Inject;
|
||||
import javax.ws.rs.GET;
|
||||
import javax.ws.rs.Path;
|
||||
import javax.ws.rs.QueryParam;
|
||||
import javax.ws.rs.core.Response;
|
||||
import org.glyptodon.guacamole.GuacamoleException;
|
||||
import org.glyptodon.guacamole.GuacamoleServerException;
|
||||
import org.glyptodon.guacamole.GuacamoleUnsupportedException;
|
||||
import org.glyptodon.guacamole.net.auth.UserContext;
|
||||
import org.glyptodon.guacamole.net.basic.ClipboardState;
|
||||
import org.glyptodon.guacamole.net.basic.GuacamoleSession;
|
||||
import org.glyptodon.guacamole.net.basic.rest.AuthProviderRESTExposure;
|
||||
import org.glyptodon.guacamole.net.basic.rest.auth.AuthenticationService;
|
||||
import org.glyptodon.guacamole.properties.BooleanGuacamoleProperty;
|
||||
import org.glyptodon.guacamole.properties.GuacamoleProperties;
|
||||
|
||||
/**
|
||||
* Servlet which dumps the current contents of the clipboard.
|
||||
* A REST service for reading the current contents of the clipboard.
|
||||
*
|
||||
* @author Michael Jumper
|
||||
*/
|
||||
public class CaptureClipboard extends RestrictedHttpServlet {
|
||||
@Path("/clipboard")
|
||||
public class ClipboardRESTService {
|
||||
|
||||
/**
|
||||
* A service for authenticating users from auth tokens.
|
||||
*/
|
||||
@Inject
|
||||
private AuthenticationService authenticationService;
|
||||
|
||||
/**
|
||||
* The amount of time to wait for clipboard changes, in milliseconds.
|
||||
*/
|
||||
@@ -55,30 +65,23 @@ public class CaptureClipboard extends RestrictedHttpServlet {
|
||||
|
||||
};
|
||||
|
||||
|
||||
@Override
|
||||
protected void restrictedService(
|
||||
UserContext context,
|
||||
HttpServletRequest request, HttpServletResponse response)
|
||||
@GET
|
||||
@AuthProviderRESTExposure
|
||||
public Response getClipboard(@QueryParam("token") String authToken)
|
||||
throws GuacamoleException {
|
||||
|
||||
// Only bother if actually enabled
|
||||
if (GuacamoleProperties.getProperty(INTEGRATION_ENABLED, false)) {
|
||||
|
||||
// Get clipboard
|
||||
final HttpSession session = request.getSession(true);
|
||||
final ClipboardState clipboard = AuthenticatingFilter.getClipboardState(session);
|
||||
GuacamoleSession session = authenticationService.getGuacamoleSession(authToken);
|
||||
final ClipboardState clipboard = session.getClipboardState();
|
||||
|
||||
// Send clipboard contents
|
||||
try {
|
||||
synchronized (clipboard) {
|
||||
clipboard.waitForContents(CLIPBOARD_TIMEOUT);
|
||||
response.setContentType(clipboard.getMimetype());
|
||||
response.getOutputStream().write(clipboard.getContents());
|
||||
}
|
||||
}
|
||||
catch (IOException e) {
|
||||
throw new GuacamoleServerException("Unable to send clipboard contents", e);
|
||||
synchronized (clipboard) {
|
||||
clipboard.waitForContents(CLIPBOARD_TIMEOUT);
|
||||
return Response.ok(clipboard.getContents(),
|
||||
clipboard.getMimetype()).build();
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,194 @@
|
||||
/*
|
||||
* Copyright (C) 2014 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.connection;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import org.codehaus.jackson.annotate.JsonIgnoreProperties;
|
||||
import org.glyptodon.guacamole.GuacamoleException;
|
||||
import org.glyptodon.guacamole.net.auth.Connection;
|
||||
import org.glyptodon.guacamole.net.auth.ConnectionRecord;
|
||||
import org.glyptodon.guacamole.net.basic.rest.APIConstants;
|
||||
import org.glyptodon.guacamole.protocol.GuacamoleConfiguration;
|
||||
|
||||
/**
|
||||
* A simple connection to expose through the REST endpoints.
|
||||
*
|
||||
* @author James Muehlner
|
||||
*/
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public class APIConnection {
|
||||
|
||||
/**
|
||||
* The name of this connection.
|
||||
*/
|
||||
private String name;
|
||||
|
||||
/**
|
||||
* The identifier of this connection.
|
||||
*/
|
||||
private String identifier;
|
||||
|
||||
/**
|
||||
* The identifier of the parent connection group for this connection.
|
||||
*/
|
||||
private String parentIdentifier;
|
||||
|
||||
/**
|
||||
* The protocol of this connection.
|
||||
*/
|
||||
private String protocol;
|
||||
|
||||
/**
|
||||
* The history records associated with this connection.
|
||||
*/
|
||||
private List<? extends ConnectionRecord> history;
|
||||
|
||||
/**
|
||||
* Map of all associated parameter values, indexed by parameter name.
|
||||
*/
|
||||
private Map<String, String> parameters = new HashMap<String, String>();
|
||||
|
||||
/**
|
||||
* Create an empty APIConnection.
|
||||
*/
|
||||
public APIConnection() {}
|
||||
|
||||
/**
|
||||
* Create an APIConnection from a Connection record.
|
||||
* @param connection The connection to create this APIConnection from.
|
||||
* @throws GuacamoleException If a problem is encountered while
|
||||
* instantiating this new APIConnection.
|
||||
*/
|
||||
public APIConnection(Connection connection)
|
||||
throws GuacamoleException {
|
||||
|
||||
this.name = connection.getName();
|
||||
this.identifier = connection.getIdentifier();
|
||||
this.parentIdentifier = connection.getParentIdentifier();
|
||||
this.history = connection.getHistory();
|
||||
|
||||
// Use the explicit ROOT group ID
|
||||
if (this.parentIdentifier == null)
|
||||
this.parentIdentifier = APIConstants.ROOT_CONNECTION_GROUP_IDENTIFIER;
|
||||
|
||||
GuacamoleConfiguration configuration = connection.getConfiguration();
|
||||
|
||||
this.protocol = configuration.getProtocol();
|
||||
|
||||
for (String key: configuration.getParameterNames())
|
||||
this.parameters.put(key, configuration.getParameter(key));
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of this connection.
|
||||
* @return The name of this connection.
|
||||
*/
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the name of this connection.
|
||||
* @param name The name of this connection.
|
||||
*/
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the unique identifier for this connection.
|
||||
* @return The unique identifier for this connection.
|
||||
*/
|
||||
public String getIdentifier() {
|
||||
return identifier;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the unique identifier for this connection.
|
||||
* @param identifier The unique identifier for this connection.
|
||||
*/
|
||||
public void setIdentifier(String identifier) {
|
||||
this.identifier = identifier;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the unique identifier for this connection.
|
||||
* @return The unique identifier for this connection.
|
||||
*/
|
||||
public String getParentIdentifier() {
|
||||
return parentIdentifier;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the parent connection group identifier for this connection.
|
||||
* @param parentIdentifier The parent connection group identifier
|
||||
* for this connection.
|
||||
*/
|
||||
public void setParentIdentifier(String parentIdentifier) {
|
||||
this.parentIdentifier = parentIdentifier;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the history records associated with this connection.
|
||||
* @return The history records associated with this connection.
|
||||
*/
|
||||
public List<? extends ConnectionRecord> getHistory() {
|
||||
return history;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the parameter map for this connection.
|
||||
* @return The parameter map for this connection.
|
||||
*/
|
||||
public Map<String, String> getParameters() {
|
||||
return parameters;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the parameter map for this connection.
|
||||
* @param parameters The parameter map for this connection.
|
||||
*/
|
||||
public void setParameters(Map<String, String> parameters) {
|
||||
this.parameters = parameters;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the protocol for this connection.
|
||||
* @return The protocol for this connection.
|
||||
*/
|
||||
public String getProtocol() {
|
||||
return protocol;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the protocol for this connection.
|
||||
* @param protocol protocol for this connection.
|
||||
*/
|
||||
public void setProtocol(String protocol) {
|
||||
this.protocol = protocol;
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,116 @@
|
||||
/*
|
||||
* Copyright (C) 2014 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.connection;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import org.glyptodon.guacamole.GuacamoleException;
|
||||
import org.glyptodon.guacamole.net.GuacamoleSocket;
|
||||
import org.glyptodon.guacamole.net.auth.Connection;
|
||||
import org.glyptodon.guacamole.net.auth.ConnectionRecord;
|
||||
import org.glyptodon.guacamole.protocol.GuacamoleClientInformation;
|
||||
import org.glyptodon.guacamole.protocol.GuacamoleConfiguration;
|
||||
|
||||
/**
|
||||
* A wrapper to make an APIConnection look like a Connection. Useful where a
|
||||
* org.glyptodon.guacamole.net.auth.Connection is required.
|
||||
*
|
||||
* @author James Muehlner
|
||||
*/
|
||||
public class APIConnectionWrapper implements Connection {
|
||||
|
||||
private final APIConnection apiConnection;
|
||||
|
||||
public APIConnectionWrapper(APIConnection apiConnection) {
|
||||
this.apiConnection = apiConnection;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return apiConnection.getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setName(String name) {
|
||||
apiConnection.setName(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getIdentifier() {
|
||||
return apiConnection.getIdentifier();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setIdentifier(String identifier) {
|
||||
apiConnection.setIdentifier(identifier);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getParentIdentifier() {
|
||||
return apiConnection.getParentIdentifier();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setParentIdentifier(String parentIdentifier) {
|
||||
apiConnection.setParentIdentifier(parentIdentifier);
|
||||
}
|
||||
|
||||
@Override
|
||||
public GuacamoleConfiguration getConfiguration() {
|
||||
|
||||
// Create the GuacamoleConfiguration from the parameter map
|
||||
GuacamoleConfiguration configuration = new GuacamoleConfiguration();
|
||||
|
||||
Map<String, String> parameters = apiConnection.getParameters();
|
||||
|
||||
for(Map.Entry<String, String> entry : parameters.entrySet())
|
||||
configuration.setParameter(entry.getKey(), entry.getValue());
|
||||
|
||||
configuration.setProtocol(apiConnection.getProtocol());
|
||||
|
||||
return configuration;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setConfiguration(GuacamoleConfiguration config) {
|
||||
|
||||
// Create a parameter map from the GuacamoleConfiguration
|
||||
Map<String, String> parameters = apiConnection.getParameters();
|
||||
for(String key : config.getParameterNames())
|
||||
parameters.put(key, config.getParameter(key));
|
||||
|
||||
// Set the protocol
|
||||
apiConnection.setProtocol(config.getProtocol());
|
||||
}
|
||||
|
||||
@Override
|
||||
public GuacamoleSocket connect(GuacamoleClientInformation info) throws GuacamoleException {
|
||||
throw new UnsupportedOperationException("Operation not supported.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<? extends ConnectionRecord> getHistory() throws GuacamoleException {
|
||||
return apiConnection.getHistory();
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,302 @@
|
||||
/*
|
||||
* Copyright (C) 2014 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.connection;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
import java.util.List;
|
||||
import javax.ws.rs.Consumes;
|
||||
import javax.ws.rs.DELETE;
|
||||
import javax.ws.rs.GET;
|
||||
import javax.ws.rs.POST;
|
||||
import javax.ws.rs.PUT;
|
||||
import javax.ws.rs.Path;
|
||||
import javax.ws.rs.PathParam;
|
||||
import javax.ws.rs.Produces;
|
||||
import javax.ws.rs.QueryParam;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
import javax.ws.rs.core.Response.Status;
|
||||
import org.glyptodon.guacamole.GuacamoleClientException;
|
||||
import org.glyptodon.guacamole.GuacamoleException;
|
||||
import org.glyptodon.guacamole.net.auth.Connection;
|
||||
import org.glyptodon.guacamole.net.auth.ConnectionGroup;
|
||||
import org.glyptodon.guacamole.net.auth.Directory;
|
||||
import org.glyptodon.guacamole.net.auth.UserContext;
|
||||
import org.glyptodon.guacamole.net.basic.rest.AuthProviderRESTExposure;
|
||||
import org.glyptodon.guacamole.net.basic.rest.HTTPException;
|
||||
import org.glyptodon.guacamole.net.basic.rest.auth.AuthenticationService;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* A REST Service for handling connection CRUD operations.
|
||||
*
|
||||
* @author James Muehlner
|
||||
*/
|
||||
@Path("/connection")
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
public class ConnectionRESTService {
|
||||
|
||||
/**
|
||||
* Logger for this class.
|
||||
*/
|
||||
private static final Logger logger = LoggerFactory.getLogger(ConnectionRESTService.class);
|
||||
|
||||
/**
|
||||
* A service for authenticating users from auth tokens.
|
||||
*/
|
||||
@Inject
|
||||
private AuthenticationService authenticationService;
|
||||
|
||||
/**
|
||||
* A service for managing the REST endpoint APIConnection objects.
|
||||
*/
|
||||
@Inject
|
||||
private ConnectionService connectionService;
|
||||
|
||||
/**
|
||||
* Gets a list of connections with the given ConnectionGroup parentID.
|
||||
* If no parentID is provided, returns the connections from the root group.
|
||||
*
|
||||
* @param authToken The authentication token that is used to authenticate
|
||||
* the user performing the operation.
|
||||
* @param parentID The ID of the ConnectionGroup the connections
|
||||
* belong to. If null, the root connection group will be used.
|
||||
* @return The connection list.
|
||||
* @throws GuacamoleException If a problem is encountered while listing connections.
|
||||
*/
|
||||
@GET
|
||||
@AuthProviderRESTExposure
|
||||
public List<APIConnection> getConnections(@QueryParam("token") String authToken, @QueryParam("parentID") String parentID)
|
||||
throws GuacamoleException {
|
||||
|
||||
UserContext userContext = authenticationService.getUserContext(authToken);
|
||||
|
||||
// If the parent connection group is passed in, try to find it.
|
||||
ConnectionGroup parentConnectionGroup;
|
||||
if (parentID == null)
|
||||
parentConnectionGroup = userContext.getRootConnectionGroup();
|
||||
|
||||
else {
|
||||
ConnectionGroup rootGroup = userContext.getRootConnectionGroup();
|
||||
Directory<String, ConnectionGroup> connectionGroupDirectory = rootGroup.getConnectionGroupDirectory();
|
||||
parentConnectionGroup = connectionGroupDirectory.get(parentID);
|
||||
}
|
||||
|
||||
if (parentConnectionGroup == null)
|
||||
throw new HTTPException(Status.NOT_FOUND, "No ConnectionGroup found with the provided parentID.");
|
||||
|
||||
Directory<String, Connection> connectionDirectory =
|
||||
parentConnectionGroup.getConnectionDirectory();
|
||||
|
||||
// Return the converted connection directory
|
||||
return connectionService.convertConnectionList(connectionDirectory);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an individual connection.
|
||||
*
|
||||
* @param authToken The authentication token that is used to authenticate
|
||||
* the user performing the operation.
|
||||
* @param connectionID The ID of the Connection..
|
||||
* @return The connection.
|
||||
* @throws GuacamoleException If a problem is encountered while retrieving the connection.
|
||||
*/
|
||||
@GET
|
||||
@Path("/{connectionID}")
|
||||
@AuthProviderRESTExposure
|
||||
public APIConnection getConnection(@QueryParam("token") String authToken,
|
||||
@PathParam("connectionID") String connectionID) throws GuacamoleException {
|
||||
|
||||
UserContext userContext = authenticationService.getUserContext(authToken);
|
||||
|
||||
// Get the connection directory
|
||||
ConnectionGroup rootGroup = userContext.getRootConnectionGroup();
|
||||
Directory<String, Connection> connectionDirectory =
|
||||
rootGroup.getConnectionDirectory();
|
||||
|
||||
// Get the connection
|
||||
Connection connection = connectionDirectory.get(connectionID);
|
||||
if (connection == null)
|
||||
throw new HTTPException(Status.NOT_FOUND, "No Connection found with the provided ID.");
|
||||
|
||||
return new APIConnection(connection);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes an individual connection.
|
||||
*
|
||||
* @param authToken The authentication token that is used to authenticate
|
||||
* the user performing the operation.
|
||||
* @param connectionID The ID of the Connection to delete.
|
||||
* @throws GuacamoleException If a problem is encountered while deleting the connection.
|
||||
*/
|
||||
@DELETE
|
||||
@Path("/{connectionID}")
|
||||
@AuthProviderRESTExposure
|
||||
public void deleteConnection(@QueryParam("token") String authToken, @PathParam("connectionID") String connectionID)
|
||||
throws GuacamoleException {
|
||||
|
||||
UserContext userContext = authenticationService.getUserContext(authToken);
|
||||
|
||||
// Get the connection directory
|
||||
ConnectionGroup rootGroup = userContext.getRootConnectionGroup();
|
||||
Directory<String, Connection> connectionDirectory =
|
||||
rootGroup.getConnectionDirectory();
|
||||
|
||||
// Make sure the connection is there before trying to delete
|
||||
if (connectionDirectory.get(connectionID) == null)
|
||||
throw new HTTPException(Status.NOT_FOUND, "No Connection found with the provided ID.");
|
||||
|
||||
// Delete the connection
|
||||
connectionDirectory.remove(connectionID);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new connection and returns the identifier of the new connection.
|
||||
* If a parentID is provided, the connection will be created in the
|
||||
* connection group with the parentID. Otherwise, the root connection group
|
||||
* will be used.
|
||||
*
|
||||
* @param authToken The authentication token that is used to authenticate
|
||||
* the user performing the operation.
|
||||
* @param parentID The ID of the ConnectionGroup the connections
|
||||
* belong to. If null, the root connection group will be used.
|
||||
* @param connection The connection to create.
|
||||
* @return The identifier of the new connection.
|
||||
* @throws GuacamoleException If a problem is encountered while creating the connection.
|
||||
*/
|
||||
@POST
|
||||
@AuthProviderRESTExposure
|
||||
public String createConnection(@QueryParam("token") String authToken,
|
||||
@QueryParam("parentID") String parentID, APIConnection connection) throws GuacamoleException {
|
||||
|
||||
UserContext userContext = authenticationService.getUserContext(authToken);
|
||||
|
||||
if (connection == null)
|
||||
throw new GuacamoleClientException("A connection is required for this request.");
|
||||
|
||||
// If the parent connection group is passed in, try to find it.
|
||||
ConnectionGroup parentConnectionGroup;
|
||||
if (parentID == null)
|
||||
parentConnectionGroup = userContext.getRootConnectionGroup();
|
||||
|
||||
else {
|
||||
ConnectionGroup rootGroup = userContext.getRootConnectionGroup();
|
||||
Directory<String, ConnectionGroup> connectionGroupDirectory = rootGroup.getConnectionGroupDirectory();
|
||||
parentConnectionGroup = connectionGroupDirectory.get(parentID);
|
||||
}
|
||||
|
||||
if (parentConnectionGroup == null)
|
||||
throw new HTTPException(Status.NOT_FOUND, "No ConnectionGroup found with the provided parentID.");
|
||||
|
||||
Directory<String, Connection> connectionDirectory =
|
||||
parentConnectionGroup.getConnectionDirectory();
|
||||
|
||||
// Create the connection
|
||||
connectionDirectory.add(new APIConnectionWrapper(connection));
|
||||
|
||||
// Return the new connection identifier
|
||||
return connection.getIdentifier();
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates a connection.
|
||||
*
|
||||
* @param authToken The authentication token that is used to authenticate
|
||||
* the user performing the operation.
|
||||
* @param connectionID The ID of the Connection to move.
|
||||
* @param connection The connection to update.
|
||||
* @throws GuacamoleException If a problem is encountered while updating the connection.
|
||||
*/
|
||||
@POST
|
||||
@Path("/{connectionID}")
|
||||
@AuthProviderRESTExposure
|
||||
public void updateConnection(@QueryParam("token") String authToken,
|
||||
@PathParam("connectionID") String connectionID, APIConnection connection) throws GuacamoleException {
|
||||
|
||||
UserContext userContext = authenticationService.getUserContext(authToken);
|
||||
|
||||
if (connection == null)
|
||||
throw new GuacamoleClientException("A connection is required for this request.");
|
||||
|
||||
// Get the connection directory
|
||||
ConnectionGroup rootGroup = userContext.getRootConnectionGroup();
|
||||
Directory<String, Connection> connectionDirectory =
|
||||
rootGroup.getConnectionDirectory();
|
||||
|
||||
Connection connectionFromAuthProvider = connectionDirectory.get(connectionID);
|
||||
|
||||
// Make sure the connection is there before trying to update
|
||||
if (connectionFromAuthProvider == null)
|
||||
throw new HTTPException(Status.NOT_FOUND, "No Connection found with the provided ID.");
|
||||
|
||||
// Copy the information from this connection over to an object from the Auth Provider
|
||||
APIConnectionWrapper wrappedConnection = new APIConnectionWrapper(connection);
|
||||
connectionFromAuthProvider.setConfiguration(wrappedConnection.getConfiguration());
|
||||
connectionFromAuthProvider.setName(wrappedConnection.getName());
|
||||
|
||||
// Update the connection
|
||||
connectionDirectory.update(connectionFromAuthProvider);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Moves an individual connection to a different connection group.
|
||||
*
|
||||
* @param authToken The authentication token that is used to authenticate
|
||||
* the user performing the operation.
|
||||
* @param connectionID The ID of the Connection to move.
|
||||
* @param parentID The ID of the ConnectionGroup the connection is to be moved to.
|
||||
* @throws GuacamoleException If a problem is encountered while moving the connection.
|
||||
*/
|
||||
@PUT
|
||||
@Path("/{connectionID}")
|
||||
@AuthProviderRESTExposure
|
||||
public void moveConnection(@QueryParam("token") String authToken,
|
||||
@PathParam("connectionID") String connectionID, @QueryParam("parentID") String parentID)
|
||||
throws GuacamoleException {
|
||||
|
||||
UserContext userContext = authenticationService.getUserContext(authToken);
|
||||
|
||||
// Get the connection directory
|
||||
ConnectionGroup rootGroup = userContext.getRootConnectionGroup();
|
||||
Directory<String, Connection> connectionDirectory =
|
||||
rootGroup.getConnectionDirectory();
|
||||
|
||||
// Find the new parent connection group
|
||||
Directory<String, ConnectionGroup> connectionGroupDirectory = rootGroup.getConnectionGroupDirectory();
|
||||
ConnectionGroup parentConnectionGroup = connectionGroupDirectory.get(parentID);
|
||||
|
||||
if (parentConnectionGroup == null)
|
||||
throw new HTTPException(Status.NOT_FOUND, "No ConnectionGroup found with the provided parentID.");
|
||||
|
||||
// Move the connection
|
||||
connectionDirectory.move(connectionID, parentConnectionGroup.getConnectionDirectory());
|
||||
}
|
||||
|
||||
}
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2013 Glyptodon LLC
|
||||
* Copyright (C) 2014 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
|
||||
@@ -20,40 +20,40 @@
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
package org.glyptodon.guacamole.net.basic.crud.connections;
|
||||
package org.glyptodon.guacamole.net.basic.rest.connection;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import org.glyptodon.guacamole.GuacamoleException;
|
||||
import org.glyptodon.guacamole.net.auth.Connection;
|
||||
import org.glyptodon.guacamole.net.auth.Directory;
|
||||
import org.glyptodon.guacamole.net.auth.UserContext;
|
||||
import org.glyptodon.guacamole.net.basic.RestrictedHttpServlet;
|
||||
|
||||
/**
|
||||
* Simple HttpServlet which handles connection deletion.
|
||||
*
|
||||
* @author Michael Jumper
|
||||
* A service for performing useful manipulations on REST Connections.
|
||||
*
|
||||
* @author James Muehlner
|
||||
*/
|
||||
public class Delete extends RestrictedHttpServlet {
|
||||
public class ConnectionService {
|
||||
|
||||
/**
|
||||
* Converts a Connection Directory to a list of APIConnection objects for
|
||||
* exposing with the REST endpoints.
|
||||
*
|
||||
* @param connectionDirectory The Connection Directory to convert for REST endpoint use.
|
||||
* @return A List of APIConnection objects for use with the REST endpoint.
|
||||
* @throws GuacamoleException If an error occurs while converting the
|
||||
* connection directory.
|
||||
*/
|
||||
public List<APIConnection> convertConnectionList(Directory<String, Connection> connectionDirectory)
|
||||
throws GuacamoleException {
|
||||
|
||||
@Override
|
||||
protected void restrictedService(
|
||||
UserContext context,
|
||||
HttpServletRequest request, HttpServletResponse response)
|
||||
throws GuacamoleException {
|
||||
|
||||
// Get ID
|
||||
String identifier = request.getParameter("id");
|
||||
|
||||
// Attempt to get connection directory
|
||||
Directory<String, Connection> directory =
|
||||
context.getRootConnectionGroup().getConnectionDirectory();
|
||||
|
||||
// Remove connection
|
||||
directory.remove(identifier);
|
||||
List<APIConnection> restConnections = new ArrayList<APIConnection>();
|
||||
|
||||
for (String connectionID : connectionDirectory.getIdentifiers())
|
||||
restConnections.add(new APIConnection(connectionDirectory.get(connectionID)));
|
||||
|
||||
return restConnections;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2013 Glyptodon LLC
|
||||
* Copyright (C) 2014 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
|
||||
@@ -21,7 +21,7 @@
|
||||
*/
|
||||
|
||||
/**
|
||||
* Servlets dedicated to CRUD operations related to ConnectionGroups.
|
||||
* Classes related to the connection manipulation aspect of the Guacamole REST API.
|
||||
*/
|
||||
package org.glyptodon.guacamole.net.basic.crud.connectiongroups;
|
||||
package org.glyptodon.guacamole.net.basic.rest.connection;
|
||||
|
@@ -0,0 +1,147 @@
|
||||
/*
|
||||
* Copyright (C) 2014 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.connectiongroup;
|
||||
|
||||
import org.codehaus.jackson.annotate.JsonIgnoreProperties;
|
||||
import org.glyptodon.guacamole.net.auth.ConnectionGroup;
|
||||
import org.glyptodon.guacamole.net.auth.ConnectionGroup.Type;
|
||||
import org.glyptodon.guacamole.net.basic.rest.APIConstants;
|
||||
|
||||
/**
|
||||
* A simple connection group to expose through the REST endpoints.
|
||||
*
|
||||
* @author James Muehlner
|
||||
*/
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public class APIConnectionGroup {
|
||||
|
||||
/**
|
||||
* The name of this connection group.
|
||||
*/
|
||||
private String name;
|
||||
|
||||
/**
|
||||
* The identifier of this connection group.
|
||||
*/
|
||||
private String identifier;
|
||||
|
||||
/**
|
||||
* The identifier of the parent connection group for this connection group.
|
||||
*/
|
||||
private String parentIdentifier;
|
||||
|
||||
/**
|
||||
* The type of this connection group.
|
||||
*/
|
||||
private Type type;
|
||||
|
||||
/**
|
||||
* Create an empty APIConnectionGroup.
|
||||
*/
|
||||
public APIConnectionGroup() {}
|
||||
|
||||
/**
|
||||
* Create a new APIConnectionGroup from the given ConnectionGroup record.
|
||||
*
|
||||
* @param connectionGroup The ConnectionGroup record to initialize this
|
||||
* APIConnectionGroup from.
|
||||
*/
|
||||
public APIConnectionGroup(ConnectionGroup connectionGroup) {
|
||||
|
||||
this.identifier = connectionGroup.getIdentifier();
|
||||
this.parentIdentifier = connectionGroup.getParentIdentifier();
|
||||
|
||||
// Use the explicit ROOT group ID
|
||||
if (this.parentIdentifier == null)
|
||||
this.parentIdentifier = APIConstants.ROOT_CONNECTION_GROUP_IDENTIFIER;
|
||||
|
||||
this.name = connectionGroup.getName();
|
||||
this.type = connectionGroup.getType();
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of this connection group.
|
||||
* @return The name of this connection group.
|
||||
*/
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the name of this connection group.
|
||||
* @param name The name of this connection group.
|
||||
*/
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the identifier of this connection group.
|
||||
* @return The identifier of this connection group.
|
||||
*/
|
||||
public String getIdentifier() {
|
||||
return identifier;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the identifier of this connection group.
|
||||
* @param identifier The identifier of this connection group.
|
||||
*/
|
||||
public void setIdentifier(String identifier) {
|
||||
this.identifier = identifier;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the unique identifier for this connection group.
|
||||
* @return The unique identifier for this connection group.
|
||||
*/
|
||||
public String getParentIdentifier() {
|
||||
return parentIdentifier;
|
||||
}
|
||||
/**
|
||||
* Sets the parent connection group identifier for this connection group.
|
||||
* @param parentIdentifier The parent connection group identifier
|
||||
* for this connection group.
|
||||
*/
|
||||
public void setParentIdentifier(String parentIdentifier) {
|
||||
this.parentIdentifier = parentIdentifier;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the type of this connection group.
|
||||
* @return The type of this connection group.
|
||||
*/
|
||||
public Type getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the type of this connection group.
|
||||
* @param type The Type of this connection group.
|
||||
*/
|
||||
public void setType(Type type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,109 @@
|
||||
/*
|
||||
* Copyright (C) 2014 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.connectiongroup;
|
||||
|
||||
import org.glyptodon.guacamole.GuacamoleException;
|
||||
import org.glyptodon.guacamole.net.GuacamoleSocket;
|
||||
import org.glyptodon.guacamole.net.auth.Connection;
|
||||
import org.glyptodon.guacamole.net.auth.ConnectionGroup;
|
||||
import org.glyptodon.guacamole.net.auth.Directory;
|
||||
import org.glyptodon.guacamole.protocol.GuacamoleClientInformation;
|
||||
|
||||
/**
|
||||
* A wrapper to make an APIConnection look like a ConnectionGroup.
|
||||
* Useful where a org.glyptodon.guacamole.net.auth.ConnectionGroup is required.
|
||||
*
|
||||
* @author James Muehlner
|
||||
*/
|
||||
public class APIConnectionGroupWrapper implements ConnectionGroup {
|
||||
|
||||
/**
|
||||
* The wrapped APIConnectionGroup.
|
||||
*/
|
||||
private final APIConnectionGroup apiConnectionGroup;
|
||||
|
||||
/**
|
||||
* Create a new APIConnectionGroupWrapper to wrap the given
|
||||
* APIConnectionGroup as a ConnectionGroup.
|
||||
* @param apiConnectionGroup the APIConnectionGroup to wrap.
|
||||
*/
|
||||
public APIConnectionGroupWrapper(APIConnectionGroup apiConnectionGroup) {
|
||||
this.apiConnectionGroup = apiConnectionGroup;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return apiConnectionGroup.getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setName(String name) {
|
||||
apiConnectionGroup.setName(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getIdentifier() {
|
||||
return apiConnectionGroup.getIdentifier();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setIdentifier(String identifier) {
|
||||
apiConnectionGroup.setIdentifier(identifier);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getParentIdentifier() {
|
||||
return apiConnectionGroup.getParentIdentifier();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setParentIdentifier(String parentIdentifier) {
|
||||
apiConnectionGroup.setParentIdentifier(parentIdentifier);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setType(Type type) {
|
||||
apiConnectionGroup.setType(type);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Type getType() {
|
||||
return apiConnectionGroup.getType();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Directory<String, Connection> getConnectionDirectory() throws GuacamoleException {
|
||||
throw new UnsupportedOperationException("Operation not supported.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Directory<String, ConnectionGroup> getConnectionGroupDirectory() throws GuacamoleException {
|
||||
throw new UnsupportedOperationException("Operation not supported.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public GuacamoleSocket connect(GuacamoleClientInformation info) throws GuacamoleException {
|
||||
throw new UnsupportedOperationException("Operation not supported.");
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,321 @@
|
||||
/*
|
||||
* Copyright (C) 2014 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.connectiongroup;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
import java.util.List;
|
||||
import javax.ws.rs.Consumes;
|
||||
import javax.ws.rs.DELETE;
|
||||
import javax.ws.rs.GET;
|
||||
import javax.ws.rs.POST;
|
||||
import javax.ws.rs.PUT;
|
||||
import javax.ws.rs.Path;
|
||||
import javax.ws.rs.PathParam;
|
||||
import javax.ws.rs.Produces;
|
||||
import javax.ws.rs.QueryParam;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
import javax.ws.rs.core.Response.Status;
|
||||
import org.glyptodon.guacamole.GuacamoleClientException;
|
||||
import org.glyptodon.guacamole.GuacamoleException;
|
||||
import org.glyptodon.guacamole.net.auth.ConnectionGroup;
|
||||
import org.glyptodon.guacamole.net.auth.Directory;
|
||||
import org.glyptodon.guacamole.net.auth.UserContext;
|
||||
import org.glyptodon.guacamole.net.basic.rest.AuthProviderRESTExposure;
|
||||
import org.glyptodon.guacamole.net.basic.rest.HTTPException;
|
||||
import org.glyptodon.guacamole.net.basic.rest.auth.AuthenticationService;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* A REST Service for handling connection group CRUD operations.
|
||||
*
|
||||
* @author James Muehlner
|
||||
*/
|
||||
@Path("/connectionGroup")
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
public class ConnectionGroupRESTService {
|
||||
|
||||
/**
|
||||
* Logger for this class.
|
||||
*/
|
||||
private static final Logger logger = LoggerFactory.getLogger(ConnectionGroupRESTService.class);
|
||||
|
||||
/**
|
||||
* A service for authenticating users from auth tokens.
|
||||
*/
|
||||
@Inject
|
||||
private AuthenticationService authenticationService;
|
||||
|
||||
/**
|
||||
* A service for managing the REST endpoint APIConnection objects.
|
||||
*/
|
||||
@Inject
|
||||
private ConnectionGroupService connectionGroupService;
|
||||
|
||||
/**
|
||||
* The ID that will be guaranteed to refer to the root connection group.
|
||||
*/
|
||||
private static final String ROOT_CONNECTION_GROUP_ID = "ROOT";
|
||||
|
||||
/**
|
||||
* Gets a list of connection groups with the given ConnectionGroup parentID.
|
||||
* If no parentID is provided, returns the connection groups from the root group.
|
||||
*
|
||||
* @param authToken The authentication token that is used to authenticate
|
||||
* the user performing the operation.
|
||||
* @param parentID The ID of the ConnectionGroup the connection groups
|
||||
* belong to. If null, the root connection group will be used.
|
||||
* @return The connection list.
|
||||
* @throws GuacamoleException If a problem is encountered while listing connection groups.
|
||||
*/
|
||||
@GET
|
||||
@AuthProviderRESTExposure
|
||||
public List<APIConnectionGroup> getConnectionGroups(@QueryParam("token") String authToken, @QueryParam("parentID") String parentID)
|
||||
throws GuacamoleException {
|
||||
|
||||
UserContext userContext = authenticationService.getUserContext(authToken);
|
||||
|
||||
// If the parent connection group is passed in, try to find it.
|
||||
ConnectionGroup parentConnectionGroup;
|
||||
if (parentID == null)
|
||||
parentConnectionGroup = userContext.getRootConnectionGroup();
|
||||
|
||||
else {
|
||||
ConnectionGroup rootGroup = userContext.getRootConnectionGroup();
|
||||
Directory<String, ConnectionGroup> connectionGroupDirectory = rootGroup.getConnectionGroupDirectory();
|
||||
parentConnectionGroup = connectionGroupDirectory.get(parentID);
|
||||
}
|
||||
|
||||
if (parentConnectionGroup == null)
|
||||
throw new HTTPException(Status.NOT_FOUND, "No connection group found with the provided parentID.");
|
||||
|
||||
Directory<String, ConnectionGroup> connectionGroupDirectory =
|
||||
parentConnectionGroup.getConnectionGroupDirectory();
|
||||
|
||||
// Return the converted connection group list
|
||||
return connectionGroupService.convertConnectionGroupList(connectionGroupDirectory);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an individual connection group.
|
||||
*
|
||||
* @param authToken The authentication token that is used to authenticate
|
||||
* the user performing the operation.
|
||||
* @param connectionGroupID The ID of the ConnectionGroup.
|
||||
* @return The connection group.
|
||||
* @throws GuacamoleException If a problem is encountered while retrieving the connection group.
|
||||
*/
|
||||
@GET
|
||||
@Path("/{connectionGroupID}")
|
||||
@AuthProviderRESTExposure
|
||||
public APIConnectionGroup getConnectionGroup(@QueryParam("token") String authToken,
|
||||
@PathParam("connectionGroupID") String connectionGroupID) throws GuacamoleException {
|
||||
|
||||
UserContext userContext = authenticationService.getUserContext(authToken);
|
||||
|
||||
// Get the connection group directory
|
||||
ConnectionGroup rootGroup = userContext.getRootConnectionGroup();
|
||||
|
||||
// Return the root group if it was asked for
|
||||
if (connectionGroupID != null && connectionGroupID.equals(ROOT_CONNECTION_GROUP_ID))
|
||||
return new APIConnectionGroup(rootGroup);
|
||||
|
||||
Directory<String, ConnectionGroup> connectionGroupDirectory =
|
||||
rootGroup.getConnectionGroupDirectory();
|
||||
|
||||
// Get the connection group
|
||||
ConnectionGroup connectionGroup = connectionGroupDirectory.get(connectionGroupID);
|
||||
if (connectionGroup == null)
|
||||
throw new HTTPException(Status.NOT_FOUND, "No ConnectionGroup found with the provided ID.");
|
||||
|
||||
// Return the connectiion group
|
||||
return new APIConnectionGroup(connectionGroup);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes an individual connection group.
|
||||
*
|
||||
* @param authToken The authentication token that is used to authenticate
|
||||
* the user performing the operation.
|
||||
* @param connectionGroupID The ID of the ConnectionGroup to delete.
|
||||
* @throws GuacamoleException If a problem is encountered while deleting the connection group.
|
||||
*/
|
||||
@DELETE
|
||||
@Path("/{connectionGroupID}")
|
||||
@AuthProviderRESTExposure
|
||||
public void deleteConnectionGroup(@QueryParam("token") String authToken,
|
||||
@PathParam("connectionGroupID") String connectionGroupID) throws GuacamoleException {
|
||||
|
||||
UserContext userContext = authenticationService.getUserContext(authToken);
|
||||
|
||||
// Get the connection group directory
|
||||
ConnectionGroup rootGroup = userContext.getRootConnectionGroup();
|
||||
|
||||
// Use the root group if it was asked for
|
||||
if (connectionGroupID != null && connectionGroupID.equals(ROOT_CONNECTION_GROUP_ID))
|
||||
connectionGroupID = rootGroup.getIdentifier();
|
||||
|
||||
Directory<String, ConnectionGroup> connectionGroupDirectory =
|
||||
rootGroup.getConnectionGroupDirectory();
|
||||
|
||||
// Make sure the connection is there before trying to delete
|
||||
if (connectionGroupDirectory.get(connectionGroupID) == null)
|
||||
throw new HTTPException(Status.NOT_FOUND, "No ConnectionGroup found with the provided ID.");
|
||||
|
||||
// Delete the connection group
|
||||
connectionGroupDirectory.remove(connectionGroupID);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new connection group and returns the identifier of the new connection group.
|
||||
* If a parentID is provided, the connection group will be created in the
|
||||
* connection group with the parentID. Otherwise, the root connection group
|
||||
* will be used.
|
||||
*
|
||||
* @param authToken The authentication token that is used to authenticate
|
||||
* the user performing the operation.
|
||||
* @param parentID The ID of the ConnectionGroup the connection groups
|
||||
* belong to. If null, the root connection group will be used.
|
||||
* @param connectionGroup The connection group to create.
|
||||
* @return The identifier of the new connection group.
|
||||
* @throws GuacamoleException If a problem is encountered while creating the connection group.
|
||||
*/
|
||||
@POST
|
||||
@AuthProviderRESTExposure
|
||||
public String createConnectionGroup(@QueryParam("token") String authToken,
|
||||
@QueryParam("parentID") String parentID, APIConnectionGroup connectionGroup) throws GuacamoleException {
|
||||
|
||||
UserContext userContext = authenticationService.getUserContext(authToken);
|
||||
|
||||
if (connectionGroup == null)
|
||||
throw new GuacamoleClientException("A connection group is required for this request.");
|
||||
|
||||
// If the parent connection group is passed in, try to find it.
|
||||
ConnectionGroup parentConnectionGroup;
|
||||
if (parentID == null)
|
||||
parentConnectionGroup = userContext.getRootConnectionGroup();
|
||||
|
||||
else {
|
||||
ConnectionGroup rootGroup = userContext.getRootConnectionGroup();
|
||||
Directory<String, ConnectionGroup> connectionGroupDirectory = rootGroup.getConnectionGroupDirectory();
|
||||
parentConnectionGroup = connectionGroupDirectory.get(parentID);
|
||||
}
|
||||
|
||||
if (parentConnectionGroup == null)
|
||||
throw new HTTPException(Status.NOT_FOUND, "No ConnectionGroup found with the provided parentID.");
|
||||
|
||||
Directory<String, ConnectionGroup> connectionGroupDirectory =
|
||||
parentConnectionGroup.getConnectionGroupDirectory();
|
||||
|
||||
// Create the connection group
|
||||
connectionGroupDirectory.add(new APIConnectionGroupWrapper(connectionGroup));
|
||||
|
||||
// Return the new connection group identifier
|
||||
return connectionGroup.getIdentifier();
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates a connection group.
|
||||
*
|
||||
* @param authToken The authentication token that is used to authenticate
|
||||
* the user performing the operation.
|
||||
* @param connectionGroupID The ID of the ConnectionGroup to update.
|
||||
* @param connectionGroup The connection group to update.
|
||||
* @throws GuacamoleException If a problem is encountered while updating the connection group.
|
||||
*/
|
||||
@POST
|
||||
@Path("/{connectionGroupID}")
|
||||
@AuthProviderRESTExposure
|
||||
public void updateConnectionGroup(@QueryParam("token") String authToken,
|
||||
@PathParam("connectionGroupID") String connectionGroupID, APIConnectionGroup connectionGroup)
|
||||
throws GuacamoleException {
|
||||
|
||||
UserContext userContext = authenticationService.getUserContext(authToken);
|
||||
|
||||
if (connectionGroup == null)
|
||||
throw new GuacamoleClientException("A connection group is required for this request.");
|
||||
|
||||
// Get the connection directory
|
||||
ConnectionGroup rootGroup = userContext.getRootConnectionGroup();
|
||||
|
||||
// Use the root group if it was asked for
|
||||
if (connectionGroupID != null && connectionGroupID.equals(ROOT_CONNECTION_GROUP_ID))
|
||||
connectionGroupID = rootGroup.getIdentifier();
|
||||
|
||||
Directory<String, ConnectionGroup> connectionGroupDirectory =
|
||||
rootGroup.getConnectionGroupDirectory();
|
||||
|
||||
// Make sure the connection group is there before trying to update
|
||||
if (connectionGroupDirectory.get(connectionGroupID) == null)
|
||||
throw new HTTPException(Status.NOT_FOUND, "No ConnectionGroup found with the provided ID.");
|
||||
|
||||
// Update the connection group
|
||||
connectionGroupDirectory.update(new APIConnectionGroupWrapper(connectionGroup));
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Moves an individual connection group to a different connection group.
|
||||
*
|
||||
* @param authToken The authentication token that is used to authenticate
|
||||
* the user performing the operation.
|
||||
* @param connectionGroupID The ID of the ConnectionGroup to move.
|
||||
* @param parentID The ID of the ConnectionGroup the connection group is to be moved to.
|
||||
* @throws GuacamoleException If a problem is encountered while moving the connection group.
|
||||
*/
|
||||
@PUT
|
||||
@Path("/{connectionGroupID}")
|
||||
@AuthProviderRESTExposure
|
||||
public void moveConnectionGroup(@QueryParam("token") String authToken,
|
||||
@PathParam("connectionGroupID") String connectionGroupID,
|
||||
@QueryParam("parentID") String parentID) throws GuacamoleException {
|
||||
|
||||
UserContext userContext = authenticationService.getUserContext(authToken);
|
||||
|
||||
// Get the connection group directory
|
||||
ConnectionGroup rootGroup = userContext.getRootConnectionGroup();
|
||||
|
||||
// Use the root group if it was asked for
|
||||
if (connectionGroupID != null && connectionGroupID.equals(ROOT_CONNECTION_GROUP_ID))
|
||||
connectionGroupID = rootGroup.getIdentifier();
|
||||
|
||||
Directory<String, ConnectionGroup> connectionGroupDirectory =
|
||||
rootGroup.getConnectionGroupDirectory();
|
||||
|
||||
// Find the new parent connection group
|
||||
Directory<String, ConnectionGroup> newConnectionGroupDirectory = rootGroup.getConnectionGroupDirectory();
|
||||
ConnectionGroup parentConnectionGroup = newConnectionGroupDirectory.get(parentID);
|
||||
|
||||
if (parentConnectionGroup == null)
|
||||
throw new HTTPException(Status.NOT_FOUND, "No ConnectionGroup found with the provided parentID.");
|
||||
|
||||
// Move the connection group
|
||||
connectionGroupDirectory.move(connectionGroupID, parentConnectionGroup.getConnectionGroupDirectory());
|
||||
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright (C) 2014 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.connectiongroup;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import org.glyptodon.guacamole.GuacamoleException;
|
||||
import org.glyptodon.guacamole.net.auth.ConnectionGroup;
|
||||
import org.glyptodon.guacamole.net.auth.Directory;
|
||||
|
||||
/**
|
||||
* A service for performing useful manipulations on REST ConnectionGroups.
|
||||
*
|
||||
* @author James Muehlner
|
||||
*/
|
||||
public class ConnectionGroupService {
|
||||
|
||||
/**
|
||||
* Converts a ConnectionGroup directory to a list of APIConnectionGroup
|
||||
* objects for exposing with the REST endpoints.
|
||||
*
|
||||
* @param connectionGroupDirectory The ConnectionGroup Directory to convert for REST endpoint use.
|
||||
* @return A List of APIConnectionGroup objects for use with the REST endpoint.
|
||||
* @throws GuacamoleException If an error occurs while converting the
|
||||
* connection group directory.
|
||||
*/
|
||||
public List<APIConnectionGroup> convertConnectionGroupList(
|
||||
Directory<String, ConnectionGroup> connectionGroupDirectory) throws GuacamoleException {
|
||||
|
||||
List<APIConnectionGroup> restConnectionGroups = new ArrayList<APIConnectionGroup>();
|
||||
|
||||
for (String connectionGroupID : connectionGroupDirectory.getIdentifiers())
|
||||
restConnectionGroups.add(new APIConnectionGroup(connectionGroupDirectory.get(connectionGroupID)));
|
||||
|
||||
return restConnectionGroups;
|
||||
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Copyright (C) 2014 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Classes related to the connection group manipulation aspect
|
||||
* of the Guacamole REST API.
|
||||
*/
|
||||
package org.glyptodon.guacamole.net.basic.rest.connectiongroup;
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2013 Glyptodon LLC
|
||||
* Copyright (C) 2014 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
|
||||
@@ -21,7 +21,7 @@
|
||||
*/
|
||||
|
||||
/**
|
||||
* Servlets dedicated to CRUD operations related to Users.
|
||||
* Classes related to the basic Guacamole REST API.
|
||||
*/
|
||||
package org.glyptodon.guacamole.net.basic.crud.users;
|
||||
package org.glyptodon.guacamole.net.basic.rest;
|
||||
|
@@ -0,0 +1,228 @@
|
||||
/*
|
||||
* Copyright (C) 2014 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.permission;
|
||||
|
||||
import org.codehaus.jackson.annotate.JsonIgnoreProperties;
|
||||
import org.codehaus.jackson.map.annotate.JsonSerialize;
|
||||
import org.glyptodon.guacamole.net.auth.permission.ConnectionGroupPermission;
|
||||
import org.glyptodon.guacamole.net.auth.permission.ConnectionPermission;
|
||||
import org.glyptodon.guacamole.net.auth.permission.ObjectPermission;
|
||||
import org.glyptodon.guacamole.net.auth.permission.Permission;
|
||||
import org.glyptodon.guacamole.net.auth.permission.SystemPermission;
|
||||
import org.glyptodon.guacamole.net.auth.permission.UserPermission;
|
||||
|
||||
/**
|
||||
* A simple user permission to expose through the REST endpoints.
|
||||
*
|
||||
* @author James Muehlner
|
||||
*/
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
@JsonSerialize(include=JsonSerialize.Inclusion.NON_NULL)
|
||||
public class APIPermission {
|
||||
|
||||
/**
|
||||
* Create an empty APIPermission.
|
||||
*/
|
||||
public APIPermission() {}
|
||||
|
||||
/**
|
||||
* The type of object that this permission refers to.
|
||||
*/
|
||||
private ObjectType objectType;
|
||||
|
||||
/**
|
||||
* The type of object that a permission can refer to.
|
||||
*/
|
||||
public enum ObjectType {
|
||||
|
||||
/**
|
||||
* A normal connection.
|
||||
*/
|
||||
CONNECTION,
|
||||
|
||||
/**
|
||||
* A connection group.
|
||||
*/
|
||||
CONNECTION_GROUP,
|
||||
|
||||
/**
|
||||
* A Guacamole user.
|
||||
*/
|
||||
USER,
|
||||
|
||||
/**
|
||||
* The Guacamole system itself.
|
||||
*/
|
||||
SYSTEM
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* The identifier of the object that this permission refers to.
|
||||
*/
|
||||
private String objectIdentifier;
|
||||
|
||||
/**
|
||||
* The object permission type for this APIPermission, if relevant. This is
|
||||
* only used if this.objectType is CONNECTION, CONNECTION_GROUP, or USER.
|
||||
*/
|
||||
private ObjectPermission.Type objectPermissionType;
|
||||
|
||||
/**
|
||||
* The system permission type for this APIPermission, if relevant. This is
|
||||
* only used if this.objectType is SYSTEM.
|
||||
*/
|
||||
private SystemPermission.Type systemPermissionType;
|
||||
|
||||
/**
|
||||
* Create an APIConnection from a Connection record.
|
||||
*
|
||||
* @param permission The permission to create this APIPermission from.
|
||||
*/
|
||||
public APIPermission(Permission permission) {
|
||||
|
||||
// Connection permission
|
||||
if (permission instanceof ConnectionPermission) {
|
||||
this.objectType = ObjectType.CONNECTION;
|
||||
this.objectPermissionType = ((ConnectionPermission) permission).getType();
|
||||
this.objectIdentifier = ((ConnectionPermission) permission).getObjectIdentifier();
|
||||
}
|
||||
|
||||
// Connection group permission
|
||||
else if (permission instanceof ConnectionGroupPermission) {
|
||||
this.objectType = ObjectType.CONNECTION_GROUP;
|
||||
this.objectPermissionType = ((ConnectionGroupPermission) permission).getType();
|
||||
this.objectIdentifier = ((ConnectionGroupPermission) permission).getObjectIdentifier();
|
||||
}
|
||||
|
||||
// User permission
|
||||
else if (permission instanceof UserPermission) {
|
||||
this.objectType = ObjectType.USER;
|
||||
this.objectPermissionType = ((UserPermission) permission).getType();
|
||||
this.objectIdentifier = ((UserPermission) permission).getObjectIdentifier();
|
||||
}
|
||||
|
||||
// System permission
|
||||
else if (permission instanceof SystemPermission) {
|
||||
this.objectType = ObjectType.SYSTEM;
|
||||
this.systemPermissionType = ((SystemPermission) permission).getType();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the type of object that this permission refers to.
|
||||
*
|
||||
* @return The type of object that this permission refers to.
|
||||
*/
|
||||
public ObjectType getObjectType() {
|
||||
return objectType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the type of object that this permission refers to.
|
||||
* @param objectType The type of object that this permission refers to.
|
||||
*/
|
||||
public void setObjectType(ObjectType objectType) {
|
||||
this.objectType = objectType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a string representation of the permission type.
|
||||
*
|
||||
* @return A string representation of the permission type.
|
||||
*/
|
||||
public String getPermissionType() {
|
||||
switch(this.objectType) {
|
||||
case CONNECTION:
|
||||
case CONNECTION_GROUP:
|
||||
case USER:
|
||||
return this.objectPermissionType.toString();
|
||||
case SYSTEM:
|
||||
return this.systemPermissionType.toString();
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the permission type from a string representation of that type.
|
||||
* Since it's not clear at this point whether this is an object permission or
|
||||
* system permission, try to set both of them.
|
||||
*
|
||||
* @param permissionType The string representation of the permission type.
|
||||
*/
|
||||
public void setPermissionType(String permissionType) {
|
||||
try {
|
||||
this.objectPermissionType = ObjectPermission.Type.valueOf(permissionType);
|
||||
} catch(IllegalArgumentException e) {}
|
||||
|
||||
try {
|
||||
this.systemPermissionType = SystemPermission.Type.valueOf(permissionType);
|
||||
} catch(IllegalArgumentException e) {}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the identifier of the object that this permission refers to.
|
||||
*
|
||||
* @return The identifier of the object that this permission refers to.
|
||||
*/
|
||||
public String getObjectIdentifier() {
|
||||
return objectIdentifier;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the identifier of the object that this permission refers to.
|
||||
*
|
||||
* @param objectIdentifier The identifier of the object that this permission refers to.
|
||||
*/
|
||||
public void setObjectIdentifier(String objectIdentifier) {
|
||||
this.objectIdentifier = objectIdentifier;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an org.glyptodon.guacamole.net.auth.permission.Permission
|
||||
* representation of this APIPermission.
|
||||
*
|
||||
* @return An org.glyptodon.guacamole.net.auth.permission.Permission
|
||||
* representation of this APIPermission.
|
||||
*/
|
||||
public Permission toPermission() {
|
||||
switch(this.objectType) {
|
||||
case CONNECTION:
|
||||
return new ConnectionPermission
|
||||
(this.objectPermissionType, this.objectIdentifier);
|
||||
case CONNECTION_GROUP:
|
||||
return new ConnectionGroupPermission
|
||||
(this.objectPermissionType, this.objectIdentifier);
|
||||
case USER:
|
||||
return new UserPermission
|
||||
(this.objectPermissionType, this.objectIdentifier);
|
||||
case SYSTEM:
|
||||
return new SystemPermission(this.systemPermissionType);
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,217 @@
|
||||
/*
|
||||
* Copyright (C) 2014 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.permission;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import javax.ws.rs.Consumes;
|
||||
import javax.ws.rs.GET;
|
||||
import javax.ws.rs.POST;
|
||||
import javax.ws.rs.Path;
|
||||
import javax.ws.rs.PathParam;
|
||||
import javax.ws.rs.Produces;
|
||||
import javax.ws.rs.QueryParam;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
import javax.ws.rs.core.Response.Status;
|
||||
import org.glyptodon.guacamole.GuacamoleException;
|
||||
import org.glyptodon.guacamole.net.auth.Directory;
|
||||
import org.glyptodon.guacamole.net.auth.User;
|
||||
import org.glyptodon.guacamole.net.auth.UserContext;
|
||||
import org.glyptodon.guacamole.net.auth.permission.Permission;
|
||||
import org.glyptodon.guacamole.net.basic.rest.APIPatch;
|
||||
import org.glyptodon.guacamole.net.basic.rest.AuthProviderRESTExposure;
|
||||
import org.glyptodon.guacamole.net.basic.rest.HTTPException;
|
||||
import org.glyptodon.guacamole.net.basic.rest.PATCH;
|
||||
import org.glyptodon.guacamole.net.basic.rest.auth.AuthenticationService;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* A REST Service for handling connection CRUD operations.
|
||||
*
|
||||
* @author James Muehlner
|
||||
*/
|
||||
@Path("/permission")
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
public class PermissionRESTService {
|
||||
|
||||
/**
|
||||
* Logger for this class.
|
||||
*/
|
||||
private static final Logger logger = LoggerFactory.getLogger(PermissionRESTService.class);
|
||||
|
||||
/**
|
||||
* A service for authenticating users from auth tokens.
|
||||
*/
|
||||
@Inject
|
||||
private AuthenticationService authenticationService;
|
||||
|
||||
/**
|
||||
* A service for managing the REST endpoint APIPermission objects.
|
||||
*/
|
||||
@Inject
|
||||
private PermissionService permissionService;
|
||||
|
||||
/**
|
||||
* Gets a list of permissions for the user with the given userID.
|
||||
*
|
||||
* @param authToken The authentication token that is used to authenticate
|
||||
* the user performing the operation.
|
||||
* @param userID The ID of the user to retrieve permissions for.
|
||||
* @return The permission list.
|
||||
* @throws GuacamoleException If a problem is encountered while listing permissions.
|
||||
*/
|
||||
@GET
|
||||
@Path("/{userID}")
|
||||
@AuthProviderRESTExposure
|
||||
public List<APIPermission> getPermissions(@QueryParam("token") String authToken, @PathParam("userID") String userID)
|
||||
throws GuacamoleException {
|
||||
|
||||
UserContext userContext = authenticationService.getUserContext(authToken);
|
||||
|
||||
// Get the user
|
||||
User user = userContext.getUserDirectory().get(userID);
|
||||
if (user == null)
|
||||
throw new HTTPException(Status.NOT_FOUND, "User not found with the provided userID.");
|
||||
|
||||
return permissionService.convertPermissionList(user.getPermissions());
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a permissions for a user with the given userID.
|
||||
*
|
||||
* @param authToken The authentication token that is used to authenticate
|
||||
* the user performing the operation.
|
||||
* @param userID The user ID to add the permission for.
|
||||
* @param permission The permission to add for the user with the given userID.
|
||||
* @throws GuacamoleException If a problem is encountered while adding the permission.
|
||||
*/
|
||||
@POST
|
||||
@Path("/{userID}")
|
||||
@AuthProviderRESTExposure
|
||||
public void addPermission(@QueryParam("token") String authToken,
|
||||
@PathParam("userID") String userID, APIPermission permission)
|
||||
throws GuacamoleException {
|
||||
|
||||
UserContext userContext = authenticationService.getUserContext(authToken);
|
||||
|
||||
// Get the user
|
||||
User user = userContext.getUserDirectory().get(userID);
|
||||
if (user == null)
|
||||
throw new HTTPException(Status.NOT_FOUND, "User not found with the provided userID.");
|
||||
|
||||
// Add the new permission
|
||||
user.addPermission(permission.toPermission());
|
||||
userContext.getUserDirectory().update(user);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a permissions for a user with the given userID.
|
||||
*
|
||||
* @param authToken The authentication token that is used to authenticate
|
||||
* the user performing the operation.
|
||||
* @param userID The user ID to remove the permission for.
|
||||
* @param permission The permission to remove for the user with the given userID.
|
||||
* @throws GuacamoleException If a problem is encountered while removing the permission.
|
||||
*/
|
||||
@POST
|
||||
@Path("/remove/{userID}/")
|
||||
@AuthProviderRESTExposure
|
||||
public void removePermission(@QueryParam("token") String authToken,
|
||||
@PathParam("userID") String userID, APIPermission permission)
|
||||
throws GuacamoleException {
|
||||
|
||||
UserContext userContext = authenticationService.getUserContext(authToken);
|
||||
|
||||
// Get the user
|
||||
User user = userContext.getUserDirectory().get(userID);
|
||||
if (user == null)
|
||||
throw new HTTPException(Status.NOT_FOUND, "User not found with the provided userID.");
|
||||
|
||||
// Remove the permission
|
||||
user.removePermission(permission.toPermission());
|
||||
userContext.getUserDirectory().update(user);
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Applies a given list of permission patches.
|
||||
*
|
||||
* @param authToken The authentication token that is used to authenticate
|
||||
* the user performing the operation.
|
||||
* @param patches The permission patches to apply for this request.
|
||||
* @throws GuacamoleException If a problem is encountered while removing the permission.
|
||||
*/
|
||||
@PATCH
|
||||
@AuthProviderRESTExposure
|
||||
public void patchPermissions(@QueryParam("token") String authToken,
|
||||
List<APIPatch<APIPermission>> patches) throws GuacamoleException {
|
||||
|
||||
UserContext userContext = authenticationService.getUserContext(authToken);
|
||||
|
||||
// Get the user directory
|
||||
Directory<String, User> userDirectory = userContext.getUserDirectory();
|
||||
|
||||
// All users who have had permissions added or removed
|
||||
Map<String, User> modifiedUsers = new HashMap<String, User>();
|
||||
|
||||
for (APIPatch<APIPermission> patch : patches) {
|
||||
|
||||
String userID = patch.getPath();
|
||||
Permission permission = patch.getValue().toPermission();
|
||||
|
||||
// See if we've already modified this user in this request
|
||||
User user = modifiedUsers.get(userID);
|
||||
if (user == null)
|
||||
user = userDirectory.get(userID);
|
||||
|
||||
if (user == null)
|
||||
throw new HTTPException(Status.NOT_FOUND, "User not found with userID " + userID + ".");
|
||||
|
||||
// Only the add and remove operations are supported for permissions
|
||||
switch(patch.getOp()) {
|
||||
case add:
|
||||
user.addPermission(permission);
|
||||
modifiedUsers.put(userID, user);
|
||||
break;
|
||||
case remove:
|
||||
user.removePermission(permission);
|
||||
modifiedUsers.put(userID, user);
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Save the permission changes for all modified users
|
||||
for (User user : modifiedUsers.values())
|
||||
userDirectory.update(user);
|
||||
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* Copyright (C) 2014 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.permission;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import org.glyptodon.guacamole.net.auth.permission.Permission;
|
||||
|
||||
/**
|
||||
* A service for performing useful manipulations on REST Permissions.
|
||||
*
|
||||
* @author James Muehlner
|
||||
*/
|
||||
public class PermissionService {
|
||||
|
||||
/**
|
||||
* Converts a list of Permission to a list of APIPermission objects for
|
||||
* exposing with the REST endpoints.
|
||||
*
|
||||
* @param permissions The Connections to convert for REST endpoint use.
|
||||
* @return A List of APIPermission objects for use with the REST endpoint.
|
||||
*/
|
||||
public List<APIPermission> convertPermissionList(Iterable<? extends Permission> permissions) {
|
||||
|
||||
List<APIPermission> restPermissions = new ArrayList<APIPermission>();
|
||||
|
||||
for(Permission permission : permissions)
|
||||
restPermissions.add(new APIPermission(permission));
|
||||
|
||||
return restPermissions;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a list of APIPermission to a set of Permission objects for internal
|
||||
* Guacamole use.
|
||||
*
|
||||
* @param restPermissions The APIPermission objects from the REST endpoints.
|
||||
* @return a List of Permission objects for internal Guacamole use.
|
||||
*/
|
||||
public Set<Permission> convertAPIPermissionList(Iterable<APIPermission> restPermissions) {
|
||||
|
||||
Set<Permission> permissions = new HashSet<Permission>();
|
||||
|
||||
for(APIPermission restPermission : restPermissions)
|
||||
permissions.add(restPermission.toPermission());
|
||||
|
||||
return permissions;
|
||||
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Copyright (C) 2014 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Classes related to the permission manipulation aspect of the Guacamole REST API.
|
||||
*/
|
||||
package org.glyptodon.guacamole.net.basic.rest.permission;
|
||||
|
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
* Copyright (C) 2014 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.protocol;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
import java.util.Map;
|
||||
import javax.ws.rs.Consumes;
|
||||
import javax.ws.rs.GET;
|
||||
import javax.ws.rs.Path;
|
||||
import javax.ws.rs.Produces;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
import org.glyptodon.guacamole.GuacamoleException;
|
||||
import org.glyptodon.guacamole.net.basic.ProtocolInfo;
|
||||
import org.glyptodon.guacamole.net.basic.rest.AuthProviderRESTExposure;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* A REST Service for handling the listing of protocols.
|
||||
*
|
||||
* @author James Muehlner
|
||||
*/
|
||||
@Path("/protocol")
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
public class ProtocolRESTService {
|
||||
|
||||
/**
|
||||
* Logger for this class.
|
||||
*/
|
||||
private static final Logger logger = LoggerFactory.getLogger(ProtocolRESTService.class);
|
||||
|
||||
/**
|
||||
* Service for retrieving protocol definitions.
|
||||
*/
|
||||
@Inject
|
||||
private ProtocolRetrievalService protocolRetrievalservice;
|
||||
|
||||
/**
|
||||
* Gets a map of protocols defined in the system - protocol name to protocol.
|
||||
*
|
||||
* @return The protocol map.
|
||||
* @throws GuacamoleException If a problem is encountered while listing protocols.
|
||||
*/
|
||||
@GET
|
||||
@AuthProviderRESTExposure
|
||||
public Map<String, ProtocolInfo> getProtocols() throws GuacamoleException {
|
||||
|
||||
// Get and return a map of all protocols.
|
||||
return protocolRetrievalservice.getProtocolMap();
|
||||
}
|
||||
|
||||
}
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2013 Glyptodon LLC
|
||||
* Copyright (C) 2014 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
|
||||
@@ -20,7 +20,7 @@
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
package org.glyptodon.guacamole.net.basic.crud.protocols;
|
||||
package org.glyptodon.guacamole.net.basic.rest.protocol;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.File;
|
||||
@@ -30,18 +30,8 @@ import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.xml.stream.XMLOutputFactory;
|
||||
import javax.xml.stream.XMLStreamException;
|
||||
import javax.xml.stream.XMLStreamWriter;
|
||||
import org.glyptodon.guacamole.GuacamoleException;
|
||||
import org.glyptodon.guacamole.GuacamoleServerException;
|
||||
import org.glyptodon.guacamole.net.auth.UserContext;
|
||||
import org.glyptodon.guacamole.net.basic.RestrictedHttpServlet;
|
||||
import org.glyptodon.guacamole.net.basic.ProtocolInfo;
|
||||
import org.glyptodon.guacamole.net.basic.ProtocolParameter;
|
||||
import org.glyptodon.guacamole.net.basic.ProtocolParameterOption;
|
||||
import org.glyptodon.guacamole.net.basic.xml.DocumentHandler;
|
||||
import org.glyptodon.guacamole.net.basic.xml.protocol.ProtocolTagHandler;
|
||||
import org.glyptodon.guacamole.properties.GuacamoleHome;
|
||||
@@ -53,18 +43,18 @@ import org.xml.sax.XMLReader;
|
||||
import org.xml.sax.helpers.XMLReaderFactory;
|
||||
|
||||
/**
|
||||
* Simple HttpServlet which outputs XML containing a list of all visible
|
||||
* protocols.
|
||||
*
|
||||
* @author Michael Jumper
|
||||
* A service for retrieving protocol definitions from the
|
||||
* XML files storing the information.
|
||||
*
|
||||
* @author James Muehlner
|
||||
*/
|
||||
public class List extends RestrictedHttpServlet {
|
||||
public class ProtocolRetrievalService {
|
||||
|
||||
/**
|
||||
* Logger for this class.
|
||||
*/
|
||||
private Logger logger = LoggerFactory.getLogger(List.class);
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(ProtocolRetrievalService.class);
|
||||
|
||||
/**
|
||||
* Array of all known protocol names.
|
||||
*/
|
||||
@@ -108,110 +98,22 @@ public class List extends RestrictedHttpServlet {
|
||||
|
||||
}
|
||||
catch (IOException e) {
|
||||
throw new GuacamoleException("Error reading basic user mapping file.", e);
|
||||
throw new GuacamoleException(e);
|
||||
}
|
||||
catch (SAXException e) {
|
||||
throw new GuacamoleException("Error parsing basic user mapping XML.", e);
|
||||
throw new GuacamoleException(e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Given an XML stream and a fully-populated ProtocolInfo object, writes
|
||||
* out the corresponding protocol XML describing all available parameters.
|
||||
* Retrieves a map of protocol name to ProtocolInfo for all protocols defined
|
||||
* in the XML files.
|
||||
*
|
||||
* @param xml The XMLStreamWriter to use to write the XML.
|
||||
* @param protocol The ProtocolInfo object to read parameters and protocol
|
||||
* information from.
|
||||
* @throws XMLStreamException If an error occurs while writing the XML.
|
||||
* @return A map of all defined protocols.
|
||||
* @throws GuacamoleException If an error occurs while retrieving the protocols.
|
||||
*/
|
||||
private void writeProtocol(XMLStreamWriter xml, ProtocolInfo protocol)
|
||||
throws XMLStreamException {
|
||||
|
||||
// Write protocol
|
||||
xml.writeStartElement("protocol");
|
||||
xml.writeAttribute("name", protocol.getName());
|
||||
xml.writeAttribute("title", protocol.getTitle());
|
||||
|
||||
// Write parameters
|
||||
for (ProtocolParameter param : protocol.getParameters()) {
|
||||
|
||||
// Write param tag
|
||||
xml.writeStartElement("param");
|
||||
xml.writeAttribute("name", param.getName());
|
||||
xml.writeAttribute("title", param.getTitle());
|
||||
|
||||
// Write type
|
||||
switch (param.getType()) {
|
||||
|
||||
// Text parameter
|
||||
case TEXT:
|
||||
xml.writeAttribute("type", "text");
|
||||
break;
|
||||
|
||||
// Password parameter
|
||||
case PASSWORD:
|
||||
xml.writeAttribute("type", "password");
|
||||
break;
|
||||
|
||||
// Numeric parameter
|
||||
case NUMERIC:
|
||||
xml.writeAttribute("type", "numeric");
|
||||
break;
|
||||
|
||||
// Boolean parameter
|
||||
case BOOLEAN:
|
||||
xml.writeAttribute("type", "boolean");
|
||||
xml.writeAttribute("value", param.getValue());
|
||||
break;
|
||||
|
||||
// Enumerated parameter
|
||||
case ENUM:
|
||||
xml.writeAttribute("type", "enum");
|
||||
break;
|
||||
|
||||
// Multiline parameter
|
||||
case MULTILINE:
|
||||
xml.writeAttribute("type", "multiline");
|
||||
break;
|
||||
|
||||
// If unknown, fail explicitly
|
||||
default:
|
||||
throw new UnsupportedOperationException(
|
||||
"Parameter type not supported: " + param.getType());
|
||||
|
||||
}
|
||||
|
||||
// Write options
|
||||
for (ProtocolParameterOption option : param.getOptions()) {
|
||||
xml.writeStartElement("option");
|
||||
xml.writeAttribute("value", option.getValue());
|
||||
xml.writeCharacters(option.getTitle());
|
||||
xml.writeEndElement();
|
||||
}
|
||||
|
||||
// End parameter
|
||||
xml.writeEndElement();
|
||||
|
||||
}
|
||||
|
||||
// End protocol
|
||||
xml.writeEndElement();
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void restrictedService(
|
||||
UserContext context,
|
||||
HttpServletRequest request, HttpServletResponse response)
|
||||
throws GuacamoleException {
|
||||
|
||||
// Do not cache
|
||||
response.setHeader("Cache-Control", "no-cache");
|
||||
|
||||
// Set encoding
|
||||
response.setCharacterEncoding("UTF-8");
|
||||
|
||||
public Map<String, ProtocolInfo> getProtocolMap() throws GuacamoleException {
|
||||
// Map of all available protocols
|
||||
Map<String, ProtocolInfo> protocols = new HashMap<String, ProtocolInfo>();
|
||||
|
||||
@@ -225,20 +127,16 @@ public class List extends RestrictedHttpServlet {
|
||||
// Get all XML files
|
||||
File[] files = protocol_directory.listFiles(
|
||||
new FilenameFilter() {
|
||||
|
||||
@Override
|
||||
public boolean accept(File file, String string) {
|
||||
return string.endsWith(".xml");
|
||||
}
|
||||
|
||||
}
|
||||
);
|
||||
|
||||
// Load each protocol from each file
|
||||
for (File file : files) {
|
||||
|
||||
try {
|
||||
|
||||
// Parse protocol
|
||||
FileInputStream stream = new FileInputStream(file);
|
||||
ProtocolInfo protocol = getProtocol(stream);
|
||||
@@ -252,9 +150,7 @@ public class List extends RestrictedHttpServlet {
|
||||
logger.error("Unable to read connection parameter information from \"{}\": {}", file.getAbsolutePath(), e.getMessage());
|
||||
logger.debug("Error reading protocol XML.", e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// If known protocols are not already defined, read from classpath
|
||||
@@ -262,8 +158,7 @@ public class List extends RestrictedHttpServlet {
|
||||
|
||||
// If protocol not defined yet, attempt to load from classpath
|
||||
if (!protocols.containsKey(protocol)) {
|
||||
|
||||
InputStream stream = List.class.getResourceAsStream(
|
||||
InputStream stream = ProtocolRetrievalService.class.getResourceAsStream(
|
||||
"/net/sourceforge/guacamole/net/protocols/"
|
||||
+ protocol + ".xml");
|
||||
|
||||
@@ -272,39 +167,9 @@ public class List extends RestrictedHttpServlet {
|
||||
protocols.put(protocol, getProtocol(stream));
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Write actual XML
|
||||
try {
|
||||
// Write XML content type
|
||||
response.setHeader("Content-Type", "text/xml");
|
||||
|
||||
XMLOutputFactory outputFactory = XMLOutputFactory.newInstance();
|
||||
XMLStreamWriter xml = outputFactory.createXMLStreamWriter(response.getWriter());
|
||||
|
||||
// Begin document
|
||||
xml.writeStartDocument();
|
||||
xml.writeStartElement("protocols");
|
||||
|
||||
// Write all protocols
|
||||
for (ProtocolInfo protocol : protocols.values())
|
||||
writeProtocol(xml, protocol);
|
||||
|
||||
// End document
|
||||
xml.writeEndElement();
|
||||
xml.writeEndDocument();
|
||||
|
||||
}
|
||||
catch (XMLStreamException e) {
|
||||
throw new GuacamoleServerException(
|
||||
"Unable to write protocol list XML.", e);
|
||||
}
|
||||
catch (IOException e) {
|
||||
throw new GuacamoleServerException(
|
||||
"I/O error writing protocol list XML.", e);
|
||||
}
|
||||
|
||||
|
||||
return protocols;
|
||||
}
|
||||
|
||||
}
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2013 Glyptodon LLC
|
||||
* Copyright (C) 2014 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
|
||||
@@ -21,7 +21,7 @@
|
||||
*/
|
||||
|
||||
/**
|
||||
* Servlets dedicated to CRUD operations related to protocols.
|
||||
* Classes related to the protocol retrieval aspect of the Guacamole REST API.
|
||||
*/
|
||||
package org.glyptodon.guacamole.net.basic.crud.protocols;
|
||||
package org.glyptodon.guacamole.net.basic.rest.protocol;
|
||||
|
@@ -0,0 +1,94 @@
|
||||
/*
|
||||
* Copyright (C) 2014 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.user;
|
||||
|
||||
import org.codehaus.jackson.annotate.JsonIgnoreProperties;
|
||||
import org.codehaus.jackson.map.annotate.JsonSerialize;
|
||||
import org.glyptodon.guacamole.net.auth.User;
|
||||
|
||||
/**
|
||||
* A simple User to expose through the REST endpoints.
|
||||
*
|
||||
* @author James Muehlner
|
||||
*/
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
@JsonSerialize(include=JsonSerialize.Inclusion.NON_NULL)
|
||||
public class APIUser {
|
||||
|
||||
/**
|
||||
* The username of this user.
|
||||
*/
|
||||
private String username;
|
||||
|
||||
/**
|
||||
* The password of this user.
|
||||
*/
|
||||
private String password;
|
||||
|
||||
/**
|
||||
* Construct a new empty APIUser.
|
||||
*/
|
||||
public APIUser() {}
|
||||
|
||||
/**
|
||||
* Construct a new APIUser from the provided User.
|
||||
* @param user The User to construct the APIUser from.
|
||||
*/
|
||||
public APIUser(User user) {
|
||||
this.username = user.getUsername();
|
||||
this.password = user.getPassword();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the username for this user.
|
||||
* @return The username for this user.
|
||||
*/
|
||||
public String getUsername() {
|
||||
return username;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the username for this user.
|
||||
* @param username The username for this user.
|
||||
*/
|
||||
public void setUsername(String username) {
|
||||
this.username = username;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the password for this user.
|
||||
* @return The password for this user.
|
||||
*/
|
||||
public String getPassword() {
|
||||
return password;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the password for this user.
|
||||
* @param password The password for this user.
|
||||
*/
|
||||
public void setPassword(String password) {
|
||||
this.password = password;
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,108 @@
|
||||
/*
|
||||
* Copyright (C) 2014 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.user;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Set;
|
||||
import org.glyptodon.guacamole.GuacamoleException;
|
||||
import org.glyptodon.guacamole.net.auth.User;
|
||||
import org.glyptodon.guacamole.net.auth.permission.Permission;
|
||||
|
||||
/**
|
||||
* A wrapper to make an APIConnection look like a User. Useful where a
|
||||
* org.glyptodon.guacamole.net.auth.User is required.
|
||||
*
|
||||
* @author James Muehlner
|
||||
*/
|
||||
public class APIUserWrapper implements User {
|
||||
|
||||
/**
|
||||
* The wrapped APIUser.
|
||||
*/
|
||||
private final APIUser apiUser;
|
||||
|
||||
/**
|
||||
* The set of permissions for this user.
|
||||
* NOTE: Not exposed by the REST endpoints.
|
||||
*/
|
||||
private Set<Permission> permissionSet = Collections.EMPTY_SET;
|
||||
|
||||
/**
|
||||
* Wrap a given APIUser to expose as a User.
|
||||
* @param apiUser The APIUser to wrap.
|
||||
*/
|
||||
public APIUserWrapper(APIUser apiUser) {
|
||||
this.apiUser = apiUser;
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrap a given APIUser to expose as a User, with the given permission set.
|
||||
* @param apiUser The APIUser to wrap.
|
||||
* @param permissionSet The set of permissions for the wrapped user.
|
||||
*/
|
||||
public APIUserWrapper(APIUser apiUser, Set<Permission> permissionSet) {
|
||||
this.apiUser = apiUser;
|
||||
this.permissionSet = permissionSet;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getUsername() {
|
||||
return apiUser.getUsername();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setUsername(String username) {
|
||||
apiUser.setUsername(username);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPassword() {
|
||||
return apiUser.getPassword();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPassword(String password) {
|
||||
apiUser.setPassword(password);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<Permission> getPermissions() throws GuacamoleException {
|
||||
return permissionSet;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasPermission(Permission permission) throws GuacamoleException {
|
||||
return permissionSet.contains(permission);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addPermission(Permission permission) throws GuacamoleException {
|
||||
throw new UnsupportedOperationException("Operation not supported.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removePermission(Permission permission) throws GuacamoleException {
|
||||
throw new UnsupportedOperationException("Operation not supported.");
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,222 @@
|
||||
/*
|
||||
* Copyright (C) 2014 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.user;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import javax.ws.rs.Consumes;
|
||||
import javax.ws.rs.DELETE;
|
||||
import javax.ws.rs.GET;
|
||||
import javax.ws.rs.POST;
|
||||
import javax.ws.rs.Path;
|
||||
import javax.ws.rs.PathParam;
|
||||
import javax.ws.rs.Produces;
|
||||
import javax.ws.rs.QueryParam;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
import javax.ws.rs.core.Response;
|
||||
import org.glyptodon.guacamole.GuacamoleException;
|
||||
import org.glyptodon.guacamole.net.auth.Directory;
|
||||
import org.glyptodon.guacamole.net.auth.User;
|
||||
import org.glyptodon.guacamole.net.auth.UserContext;
|
||||
import org.glyptodon.guacamole.net.basic.rest.AuthProviderRESTExposure;
|
||||
import org.glyptodon.guacamole.net.basic.rest.HTTPException;
|
||||
import org.glyptodon.guacamole.net.basic.rest.auth.AuthenticationService;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* A REST Service for handling user CRUD operations.
|
||||
*
|
||||
* @author James Muehlner
|
||||
*/
|
||||
@Path("/user")
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
public class UserRESTService {
|
||||
|
||||
/**
|
||||
* Logger for this class.
|
||||
*/
|
||||
private static final Logger logger = LoggerFactory.getLogger(UserRESTService.class);
|
||||
|
||||
/**
|
||||
* A service for authenticating users from auth tokens.
|
||||
*/
|
||||
@Inject
|
||||
private AuthenticationService authenticationService;
|
||||
|
||||
/**
|
||||
* A service for managing the REST endpoint APIPermission objects.
|
||||
*/
|
||||
@Inject
|
||||
private UserService userService;
|
||||
|
||||
/**
|
||||
* Gets a list of users in the system.
|
||||
* @param authToken The authentication token that is used to authenticate
|
||||
* the user performing the operation.
|
||||
* @return The user list.
|
||||
* @throws GuacamoleException If a problem is encountered while listing users.
|
||||
*/
|
||||
@GET
|
||||
@AuthProviderRESTExposure
|
||||
public List<APIUser> getUsers(@QueryParam("token") String authToken) throws GuacamoleException {
|
||||
|
||||
UserContext userContext = authenticationService.getUserContext(authToken);
|
||||
|
||||
// Get the directory
|
||||
Directory<String, User> userDirectory = userContext.getUserDirectory();
|
||||
|
||||
// Convert and return the user directory listing
|
||||
return userService.convertUserList(userDirectory);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an individual user.
|
||||
* @param authToken The authentication token that is used to authenticate
|
||||
* the user performing the operation.
|
||||
* @param userID The ID of the user to retrieve.
|
||||
* @return user The user.
|
||||
* @throws GuacamoleException If a problem is encountered while retrieving the user.
|
||||
*/
|
||||
@GET
|
||||
@Path("/{userID}")
|
||||
@AuthProviderRESTExposure
|
||||
public APIUser getUser(@QueryParam("token") String authToken, @PathParam("userID") String userID)
|
||||
throws GuacamoleException {
|
||||
|
||||
UserContext userContext = authenticationService.getUserContext(authToken);
|
||||
|
||||
// Get the directory
|
||||
Directory<String, User> userDirectory = userContext.getUserDirectory();
|
||||
|
||||
// Get the user
|
||||
User user = userDirectory.get(userID);
|
||||
if (user == null)
|
||||
throw new HTTPException(Response.Status.NOT_FOUND, "User not found with the provided userID.");
|
||||
|
||||
// Return the user
|
||||
return new APIUser(user);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new user and returns the username.
|
||||
* @param authToken The authentication token that is used to authenticate
|
||||
* the user performing the operation.
|
||||
* @param user The new user to create.
|
||||
* @throws GuacamoleException If a problem is encountered while creating the user.
|
||||
*
|
||||
* @return The username of the newly created user.
|
||||
*/
|
||||
@POST
|
||||
@AuthProviderRESTExposure
|
||||
public String createUser(@QueryParam("token") String authToken, APIUser user)
|
||||
throws GuacamoleException {
|
||||
|
||||
UserContext userContext = authenticationService.getUserContext(authToken);
|
||||
|
||||
// Get the directory
|
||||
Directory<String, User> userDirectory = userContext.getUserDirectory();
|
||||
|
||||
// Randomly set the password if it wasn't provided
|
||||
if (user.getPassword() == null)
|
||||
user.setPassword(UUID.randomUUID().toString());
|
||||
|
||||
// Create the user
|
||||
userDirectory.add(new APIUserWrapper(user));
|
||||
|
||||
return user.getUsername();
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates an individual existing user.
|
||||
* @param authToken The authentication token that is used to authenticate
|
||||
* the user performing the operation.
|
||||
* @param userID The unique identifier of the user to update.
|
||||
* @param user The updated user.
|
||||
* @throws GuacamoleException If a problem is encountered while updating the user.
|
||||
*/
|
||||
@POST
|
||||
@Path("/{userID}")
|
||||
@AuthProviderRESTExposure
|
||||
public void updateUser(@QueryParam("token") String authToken, @PathParam("userID") String userID, APIUser user)
|
||||
throws GuacamoleException {
|
||||
|
||||
UserContext userContext = authenticationService.getUserContext(authToken);
|
||||
|
||||
// Get the directory
|
||||
Directory<String, User> userDirectory = userContext.getUserDirectory();
|
||||
|
||||
if (!user.getUsername().equals(userID))
|
||||
throw new HTTPException(Response.Status.BAD_REQUEST, "Username does not match provided userID.");
|
||||
|
||||
// Get the user
|
||||
User existingUser = userDirectory.get(userID);
|
||||
if (existingUser == null)
|
||||
throw new HTTPException(Response.Status.NOT_FOUND, "User not found with the provided userID.");
|
||||
|
||||
// Do not update the user password if no password was provided
|
||||
if (user.getPassword() != null) {
|
||||
/*
|
||||
* Update the user with the permission set from the existing user
|
||||
* since the user REST endpoints do not expose permissions.
|
||||
*/
|
||||
existingUser.setPassword(user.getPassword());
|
||||
userDirectory.update(existingUser);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes an individual existing user.
|
||||
* @param authToken The authentication token that is used to authenticate
|
||||
* the user performing the operation.
|
||||
* @param userID The unique identifier of the user to delete.
|
||||
* @throws GuacamoleException If a problem is encountered while deleting the user.
|
||||
*/
|
||||
@DELETE
|
||||
@Path("/{userID}")
|
||||
@AuthProviderRESTExposure
|
||||
public void deleteUser(@QueryParam("token") String authToken, @PathParam("userID") String userID)
|
||||
throws GuacamoleException {
|
||||
|
||||
UserContext userContext = authenticationService.getUserContext(authToken);
|
||||
|
||||
// Get the directory
|
||||
Directory<String, User> userDirectory = userContext.getUserDirectory();
|
||||
|
||||
// Get the user
|
||||
User existingUser = userDirectory.get(userID);
|
||||
if (existingUser == null)
|
||||
throw new HTTPException(Response.Status.NOT_FOUND, "User not found with the provided userID.");
|
||||
|
||||
// Delete the user
|
||||
userDirectory.remove(userID);
|
||||
|
||||
}
|
||||
|
||||
}
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2013 Glyptodon LLC
|
||||
* Copyright (C) 2014 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
|
||||
@@ -20,39 +20,40 @@
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
package org.glyptodon.guacamole.net.basic.crud.users;
|
||||
package org.glyptodon.guacamole.net.basic.rest.user;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import org.glyptodon.guacamole.GuacamoleException;
|
||||
import org.glyptodon.guacamole.net.auth.Directory;
|
||||
import org.glyptodon.guacamole.net.auth.User;
|
||||
import org.glyptodon.guacamole.net.auth.UserContext;
|
||||
import org.glyptodon.guacamole.net.basic.RestrictedHttpServlet;
|
||||
|
||||
/**
|
||||
* Simple HttpServlet which handles user deletion.
|
||||
*
|
||||
* @author Michael Jumper
|
||||
* A service for performing useful manipulations on REST Users.
|
||||
*
|
||||
* @author James Muehlner
|
||||
*/
|
||||
public class Delete extends RestrictedHttpServlet {
|
||||
public class UserService {
|
||||
|
||||
/**
|
||||
* Converts a user directory to a list of APIUser objects for
|
||||
* exposing with the REST endpoints.
|
||||
*
|
||||
* @param userDirectory The user directory to convert for REST endpoint use.
|
||||
* @return A List of APIUser objects for use with the REST endpoint.
|
||||
* @throws GuacamoleException If an error occurs while converting the
|
||||
* user directory.
|
||||
*/
|
||||
public List<APIUser> convertUserList(Directory<String, User> userDirectory)
|
||||
throws GuacamoleException {
|
||||
|
||||
@Override
|
||||
protected void restrictedService(
|
||||
UserContext context,
|
||||
HttpServletRequest request, HttpServletResponse response)
|
||||
throws GuacamoleException {
|
||||
|
||||
// Get username
|
||||
String username = request.getParameter("name");
|
||||
|
||||
// Attempt to get user directory
|
||||
Directory<String, User> directory = context.getUserDirectory();
|
||||
|
||||
// Remove user
|
||||
directory.remove(username);
|
||||
List<APIUser> restUsers = new ArrayList<APIUser>();
|
||||
|
||||
for(String username : userDirectory.getIdentifiers())
|
||||
restUsers.add(new APIUser(userDirectory.get(username)));
|
||||
|
||||
return restUsers;
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2013 Glyptodon LLC
|
||||
* Copyright (C) 2014 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
|
||||
@@ -21,7 +21,7 @@
|
||||
*/
|
||||
|
||||
/**
|
||||
* Servlets dedicated to CRUD operations related to Permissions.
|
||||
* Classes related to the user manipulation aspect of the Guacamole REST API.
|
||||
*/
|
||||
package org.glyptodon.guacamole.net.basic.crud.permissions;
|
||||
package org.glyptodon.guacamole.net.basic.rest.user;
|
||||
|
@@ -22,25 +22,22 @@
|
||||
|
||||
package org.glyptodon.guacamole.net.basic.websocket;
|
||||
|
||||
import com.google.inject.Provider;
|
||||
import java.util.Map;
|
||||
import javax.websocket.EndpointConfig;
|
||||
import javax.websocket.HandshakeResponse;
|
||||
import javax.websocket.Session;
|
||||
import javax.websocket.server.HandshakeRequest;
|
||||
import javax.websocket.server.ServerEndpoint;
|
||||
import javax.websocket.server.ServerEndpointConfig;
|
||||
import org.glyptodon.guacamole.GuacamoleException;
|
||||
import org.glyptodon.guacamole.net.GuacamoleTunnel;
|
||||
import org.glyptodon.guacamole.net.basic.BasicTunnelRequestUtility;
|
||||
import org.glyptodon.guacamole.net.basic.TunnelRequestService;
|
||||
import org.glyptodon.guacamole.websocket.GuacamoleWebSocketTunnelEndpoint;
|
||||
|
||||
/**
|
||||
* Tunnel implementation which uses WebSocket as a tunnel backend, rather than
|
||||
* HTTP, properly parsing connection IDs included in the connection request.
|
||||
*/
|
||||
@ServerEndpoint(value = "/websocket-tunnel",
|
||||
subprotocols = {"guacamole"},
|
||||
configurator = BasicGuacamoleWebSocketTunnelEndpoint.Configurator.class)
|
||||
public class BasicGuacamoleWebSocketTunnelEndpoint extends GuacamoleWebSocketTunnelEndpoint {
|
||||
|
||||
/**
|
||||
@@ -62,6 +59,25 @@ public class BasicGuacamoleWebSocketTunnelEndpoint extends GuacamoleWebSocketTun
|
||||
*/
|
||||
public static class Configurator extends ServerEndpointConfig.Configurator {
|
||||
|
||||
/**
|
||||
* Provider which provides instances of a service for handling
|
||||
* tunnel requests.
|
||||
*/
|
||||
private final Provider<TunnelRequestService> tunnelRequestServiceProvider;
|
||||
|
||||
/**
|
||||
* Creates a new Configurator which uses the given tunnel request
|
||||
* service provider to retrieve the necessary service to handle new
|
||||
* connections requests.
|
||||
*
|
||||
* @param tunnelRequestServiceProvider The tunnel request service
|
||||
* provider to use for all new
|
||||
* connections.
|
||||
*/
|
||||
public Configurator(Provider<TunnelRequestService> tunnelRequestServiceProvider) {
|
||||
this.tunnelRequestServiceProvider = tunnelRequestServiceProvider;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void modifyHandshake(ServerEndpointConfig config, HandshakeRequest request, HandshakeResponse response) {
|
||||
|
||||
@@ -72,8 +88,11 @@ public class BasicGuacamoleWebSocketTunnelEndpoint extends GuacamoleWebSocketTun
|
||||
userProperties.clear();
|
||||
try {
|
||||
|
||||
// Get tunnel request service
|
||||
TunnelRequestService tunnelRequestService = tunnelRequestServiceProvider.get();
|
||||
|
||||
// Store new tunnel within user properties
|
||||
GuacamoleTunnel tunnel = BasicTunnelRequestUtility.createTunnel(new WebSocketTunnelRequest(request));
|
||||
GuacamoleTunnel tunnel = tunnelRequestService.createTunnel(new WebSocketTunnelRequest(request));
|
||||
if (tunnel != null)
|
||||
userProperties.put(TUNNEL_USER_PROPERTY, tunnel);
|
||||
|
||||
|
@@ -22,10 +22,12 @@
|
||||
|
||||
package org.glyptodon.guacamole.net.basic.websocket.jetty8;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.Singleton;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import org.glyptodon.guacamole.GuacamoleException;
|
||||
import org.glyptodon.guacamole.net.GuacamoleTunnel;
|
||||
import org.glyptodon.guacamole.net.basic.BasicTunnelRequestUtility;
|
||||
import org.glyptodon.guacamole.net.basic.TunnelRequestService;
|
||||
import org.glyptodon.guacamole.net.basic.HTTPTunnelRequest;
|
||||
|
||||
/**
|
||||
@@ -33,12 +35,19 @@ import org.glyptodon.guacamole.net.basic.HTTPTunnelRequest;
|
||||
* rather than HTTP, properly parsing connection IDs included in the connection
|
||||
* request.
|
||||
*/
|
||||
@Singleton
|
||||
public class BasicGuacamoleWebSocketTunnelServlet extends GuacamoleWebSocketTunnelServlet {
|
||||
|
||||
/**
|
||||
* Service for handling tunnel requests.
|
||||
*/
|
||||
@Inject
|
||||
private TunnelRequestService tunnelRequestService;
|
||||
|
||||
@Override
|
||||
protected GuacamoleTunnel doConnect(HttpServletRequest request)
|
||||
throws GuacamoleException {
|
||||
return BasicTunnelRequestUtility.createTunnel(new HTTPTunnelRequest(request));
|
||||
return tunnelRequestService.createTunnel(new HTTPTunnelRequest(request));
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -22,10 +22,12 @@
|
||||
|
||||
package org.glyptodon.guacamole.net.basic.websocket.jetty9;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.Singleton;
|
||||
import org.eclipse.jetty.websocket.api.Session;
|
||||
import org.glyptodon.guacamole.GuacamoleException;
|
||||
import org.glyptodon.guacamole.net.GuacamoleTunnel;
|
||||
import org.glyptodon.guacamole.net.basic.BasicTunnelRequestUtility;
|
||||
import org.glyptodon.guacamole.net.basic.TunnelRequestService;
|
||||
|
||||
/**
|
||||
* WebSocket listener implementation which properly parses connection IDs
|
||||
@@ -33,11 +35,18 @@ import org.glyptodon.guacamole.net.basic.BasicTunnelRequestUtility;
|
||||
*
|
||||
* @author Michael Jumper
|
||||
*/
|
||||
@Singleton
|
||||
public class BasicGuacamoleWebSocketTunnelListener extends GuacamoleWebSocketTunnelListener {
|
||||
|
||||
/**
|
||||
* Service for handling tunnel requests.
|
||||
*/
|
||||
@Inject
|
||||
private TunnelRequestService tunnelRequestService;
|
||||
|
||||
@Override
|
||||
protected GuacamoleTunnel createTunnel(Session session) throws GuacamoleException {
|
||||
return BasicTunnelRequestUtility.createTunnel(new WebSocketTunnelRequest(session.getUpgradeRequest()));
|
||||
return tunnelRequestService.createTunnel(new WebSocketTunnelRequest(session.getUpgradeRequest()));
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -22,10 +22,12 @@
|
||||
|
||||
package org.glyptodon.guacamole.net.basic.websocket.tomcat;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.Singleton;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import org.glyptodon.guacamole.GuacamoleException;
|
||||
import org.glyptodon.guacamole.net.GuacamoleTunnel;
|
||||
import org.glyptodon.guacamole.net.basic.BasicTunnelRequestUtility;
|
||||
import org.glyptodon.guacamole.net.basic.TunnelRequestService;
|
||||
import org.glyptodon.guacamole.net.basic.HTTPTunnelRequest;
|
||||
|
||||
/**
|
||||
@@ -33,12 +35,19 @@ import org.glyptodon.guacamole.net.basic.HTTPTunnelRequest;
|
||||
* rather than HTTP, properly parsing connection IDs included in the connection
|
||||
* request.
|
||||
*/
|
||||
@Singleton
|
||||
public class BasicGuacamoleWebSocketTunnelServlet extends GuacamoleWebSocketTunnelServlet {
|
||||
|
||||
/**
|
||||
* Service for handling tunnel requests.
|
||||
*/
|
||||
@Inject
|
||||
private TunnelRequestService tunnelRequestService;
|
||||
|
||||
@Override
|
||||
protected GuacamoleTunnel doConnect(HttpServletRequest request)
|
||||
throws GuacamoleException {
|
||||
return BasicTunnelRequestUtility.createTunnel(new HTTPTunnelRequest(request));
|
||||
return tunnelRequestService.createTunnel(new HTTPTunnelRequest(request));
|
||||
};
|
||||
|
||||
}
|
||||
|
@@ -20,286 +20,35 @@
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
-->
|
||||
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
|
||||
<web-app version="2.5"
|
||||
xmlns="http://java.sun.com/xml/ns/javaee"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
|
||||
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
|
||||
|
||||
<!-- Basic config -->
|
||||
<welcome-file-list>
|
||||
<welcome-file>index.xhtml</welcome-file>
|
||||
</welcome-file-list>
|
||||
<session-config>
|
||||
<session-timeout>
|
||||
30
|
||||
</session-timeout>
|
||||
<session-timeout>30</session-timeout>
|
||||
</session-config>
|
||||
|
||||
<!-- Automatically detect and load WebSocket support -->
|
||||
<listener>
|
||||
<listener-class>org.glyptodon.guacamole.net.basic.websocket.WebSocketSupportLoader</listener-class>
|
||||
</listener>
|
||||
|
||||
<!-- Init logging on startup -->
|
||||
<listener>
|
||||
<listener-class>org.glyptodon.guacamole.net.basic.log.LogbackInitializer</listener-class>
|
||||
</listener>
|
||||
|
||||
<!-- Authenticate against service calls and pages -->
|
||||
<!-- Guice -->
|
||||
<filter>
|
||||
<filter-name>AuthenticatingFilter</filter-name>
|
||||
<filter-class>org.glyptodon.guacamole.net.basic.AuthenticatingFilter</filter-class>
|
||||
<filter-name>guiceFilter</filter-name>
|
||||
<filter-class>com.google.inject.servlet.GuiceFilter</filter-class>
|
||||
</filter>
|
||||
<filter-mapping>
|
||||
<filter-name>AuthenticatingFilter</filter-name>
|
||||
<url-pattern>*.xhtml</url-pattern>
|
||||
<url-pattern>/login</url-pattern>
|
||||
<url-pattern>/clipboard</url-pattern>
|
||||
<url-pattern>/connections/*</url-pattern>
|
||||
<url-pattern>/connectiongroups/*</url-pattern>
|
||||
<url-pattern>/users/*</url-pattern>
|
||||
<url-pattern>/permissions/*</url-pattern>
|
||||
<url-pattern>/protocols/*</url-pattern>
|
||||
<filter-name>guiceFilter</filter-name>
|
||||
<url-pattern>/*</url-pattern>
|
||||
</filter-mapping>
|
||||
|
||||
<!-- Restrict requests to the WebSocket tunnel -->
|
||||
<filter>
|
||||
<filter-name>RestrictedFilter</filter-name>
|
||||
<filter-class>org.glyptodon.guacamole.net.basic.RestrictedFilter</filter-class>
|
||||
</filter>
|
||||
<filter-mapping>
|
||||
<filter-name>RestrictedFilter</filter-name>
|
||||
<url-pattern>/websocket-tunnel</url-pattern>
|
||||
</filter-mapping>
|
||||
<listener>
|
||||
<listener-class>org.glyptodon.guacamole.net.basic.BasicServletContextListener</listener-class>
|
||||
</listener>
|
||||
|
||||
<!-- Basic Login Servlet -->
|
||||
<servlet>
|
||||
<description>Login servlet.</description>
|
||||
<servlet-name>Login</servlet-name>
|
||||
<servlet-class>org.glyptodon.guacamole.net.basic.BasicLogin</servlet-class>
|
||||
</servlet>
|
||||
<servlet-mapping>
|
||||
<servlet-name>Login</servlet-name>
|
||||
<url-pattern>/login</url-pattern>
|
||||
</servlet-mapping>
|
||||
|
||||
<!-- Basic Logout Servlet -->
|
||||
<servlet>
|
||||
<description>Logout servlet.</description>
|
||||
<servlet-name>Logout</servlet-name>
|
||||
<servlet-class>org.glyptodon.guacamole.net.basic.BasicLogout</servlet-class>
|
||||
</servlet>
|
||||
<servlet-mapping>
|
||||
<servlet-name>Logout</servlet-name>
|
||||
<url-pattern>/logout</url-pattern>
|
||||
</servlet-mapping>
|
||||
|
||||
<!-- Session Keep-Alive Servlet -->
|
||||
<servlet>
|
||||
<description>Session keep-alive servlet.</description>
|
||||
<servlet-name>SessionKeepAlive</servlet-name>
|
||||
<servlet-class>org.glyptodon.guacamole.net.basic.SessionKeepAlive</servlet-class>
|
||||
</servlet>
|
||||
<servlet-mapping>
|
||||
<servlet-name>SessionKeepAlive</servlet-name>
|
||||
<url-pattern>/keep-alive</url-pattern>
|
||||
</servlet-mapping>
|
||||
|
||||
<!-- Clipboard State Servlet -->
|
||||
<servlet>
|
||||
<description>Clipboard state servlet.</description>
|
||||
<servlet-name>Clipboard</servlet-name>
|
||||
<servlet-class>org.glyptodon.guacamole.net.basic.CaptureClipboard</servlet-class>
|
||||
</servlet>
|
||||
<servlet-mapping>
|
||||
<servlet-name>Clipboard</servlet-name>
|
||||
<url-pattern>/clipboard</url-pattern>
|
||||
</servlet-mapping>
|
||||
|
||||
<!-- Connection Creation Servlet -->
|
||||
<servlet>
|
||||
<description>Connection creation servlet.</description>
|
||||
<servlet-name>ConnectionCreate</servlet-name>
|
||||
<servlet-class>org.glyptodon.guacamole.net.basic.crud.connections.Create</servlet-class>
|
||||
</servlet>
|
||||
<servlet-mapping>
|
||||
<servlet-name>ConnectionCreate</servlet-name>
|
||||
<url-pattern>/connections/create</url-pattern>
|
||||
</servlet-mapping>
|
||||
|
||||
<!-- Connection List Servlet -->
|
||||
<servlet>
|
||||
<description>Connection list servlet.</description>
|
||||
<servlet-name>Connections</servlet-name>
|
||||
<servlet-class>org.glyptodon.guacamole.net.basic.crud.connections.List</servlet-class>
|
||||
</servlet>
|
||||
<servlet-mapping>
|
||||
<servlet-name>Connections</servlet-name>
|
||||
<url-pattern>/connections</url-pattern>
|
||||
</servlet-mapping>
|
||||
|
||||
<!-- Connection Update Servlet -->
|
||||
<servlet>
|
||||
<description>Connection update servlet.</description>
|
||||
<servlet-name>ConnectionUpdate</servlet-name>
|
||||
<servlet-class>org.glyptodon.guacamole.net.basic.crud.connections.Update</servlet-class>
|
||||
</servlet>
|
||||
<servlet-mapping>
|
||||
<servlet-name>ConnectionUpdate</servlet-name>
|
||||
<url-pattern>/connections/update</url-pattern>
|
||||
</servlet-mapping>
|
||||
|
||||
<!-- Connection Move Servlet -->
|
||||
<servlet>
|
||||
<description>Connection move servlet.</description>
|
||||
<servlet-name>ConnectionMove</servlet-name>
|
||||
<servlet-class>org.glyptodon.guacamole.net.basic.crud.connections.Move</servlet-class>
|
||||
</servlet>
|
||||
<servlet-mapping>
|
||||
<servlet-name>ConnectionMove</servlet-name>
|
||||
<url-pattern>/connections/move</url-pattern>
|
||||
</servlet-mapping>
|
||||
|
||||
<!-- Connection Deletion Servlet -->
|
||||
<servlet>
|
||||
<description>Connection deletion servlet.</description>
|
||||
<servlet-name>ConnectionDelete</servlet-name>
|
||||
<servlet-class>org.glyptodon.guacamole.net.basic.crud.connections.Delete</servlet-class>
|
||||
</servlet>
|
||||
<servlet-mapping>
|
||||
<servlet-name>ConnectionDelete</servlet-name>
|
||||
<url-pattern>/connections/delete</url-pattern>
|
||||
</servlet-mapping>
|
||||
|
||||
<!-- Connection Group Creation Servlet -->
|
||||
<servlet>
|
||||
<description>ConnectionGroup creation servlet.</description>
|
||||
<servlet-name>ConnectionGroupCreate</servlet-name>
|
||||
<servlet-class>org.glyptodon.guacamole.net.basic.crud.connectiongroups.Create</servlet-class>
|
||||
</servlet>
|
||||
<servlet-mapping>
|
||||
<servlet-name>ConnectionGroupCreate</servlet-name>
|
||||
<url-pattern>/connectiongroups/create</url-pattern>
|
||||
</servlet-mapping>
|
||||
|
||||
<!-- Connection Group List Servlet -->
|
||||
<servlet>
|
||||
<description>ConnectionGroup list servlet.</description>
|
||||
<servlet-name>ConnectionGroups</servlet-name>
|
||||
<servlet-class>org.glyptodon.guacamole.net.basic.crud.connectiongroups.List</servlet-class>
|
||||
</servlet>
|
||||
<servlet-mapping>
|
||||
<servlet-name>ConnectionGroups</servlet-name>
|
||||
<url-pattern>/connectiongroups</url-pattern>
|
||||
</servlet-mapping>
|
||||
|
||||
<!-- Connection Group Update Servlet -->
|
||||
<servlet>
|
||||
<description>ConnectionGroup update servlet.</description>
|
||||
<servlet-name>ConnectionGroupUpdate</servlet-name>
|
||||
<servlet-class>org.glyptodon.guacamole.net.basic.crud.connectiongroups.Update</servlet-class>
|
||||
</servlet>
|
||||
<servlet-mapping>
|
||||
<servlet-name>ConnectionGroupUpdate</servlet-name>
|
||||
<url-pattern>/connectiongroups/update</url-pattern>
|
||||
</servlet-mapping>
|
||||
|
||||
<!-- Connection Group Move Servlet -->
|
||||
<servlet>
|
||||
<description>ConnectionGroup move servlet.</description>
|
||||
<servlet-name>ConnectionGroupMove</servlet-name>
|
||||
<servlet-class>org.glyptodon.guacamole.net.basic.crud.connectiongroups.Move</servlet-class>
|
||||
</servlet>
|
||||
<servlet-mapping>
|
||||
<servlet-name>ConnectionGroupMove</servlet-name>
|
||||
<url-pattern>/connectiongroups/move</url-pattern>
|
||||
</servlet-mapping>
|
||||
|
||||
<!-- Connection Group Deletion Servlet -->
|
||||
<servlet>
|
||||
<description>ConnectionGroup deletion servlet.</description>
|
||||
<servlet-name>ConnectionGroupDelete</servlet-name>
|
||||
<servlet-class>org.glyptodon.guacamole.net.basic.crud.connectiongroups.Delete</servlet-class>
|
||||
</servlet>
|
||||
<servlet-mapping>
|
||||
<servlet-name>ConnectionGroupDelete</servlet-name>
|
||||
<url-pattern>/connectiongroups/delete</url-pattern>
|
||||
</servlet-mapping>
|
||||
|
||||
<!-- User Creation Servlet -->
|
||||
<servlet>
|
||||
<description>User creation servlet.</description>
|
||||
<servlet-name>UserCreate</servlet-name>
|
||||
<servlet-class>org.glyptodon.guacamole.net.basic.crud.users.Create</servlet-class>
|
||||
</servlet>
|
||||
<servlet-mapping>
|
||||
<servlet-name>UserCreate</servlet-name>
|
||||
<url-pattern>/users/create</url-pattern>
|
||||
</servlet-mapping>
|
||||
|
||||
<!-- User List Servlet -->
|
||||
<servlet>
|
||||
<description>User list servlet.</description>
|
||||
<servlet-name>Users</servlet-name>
|
||||
<servlet-class>org.glyptodon.guacamole.net.basic.crud.users.List</servlet-class>
|
||||
</servlet>
|
||||
<servlet-mapping>
|
||||
<servlet-name>Users</servlet-name>
|
||||
<url-pattern>/users</url-pattern>
|
||||
</servlet-mapping>
|
||||
|
||||
<!-- User Update Servlet -->
|
||||
<servlet>
|
||||
<description>User update servlet.</description>
|
||||
<servlet-name>UserUpdate</servlet-name>
|
||||
<servlet-class>org.glyptodon.guacamole.net.basic.crud.users.Update</servlet-class>
|
||||
</servlet>
|
||||
<servlet-mapping>
|
||||
<servlet-name>UserUpdate</servlet-name>
|
||||
<url-pattern>/users/update</url-pattern>
|
||||
</servlet-mapping>
|
||||
|
||||
<!-- User Deletion Servlet -->
|
||||
<servlet>
|
||||
<description>User deletion servlet.</description>
|
||||
<servlet-name>UserDelete</servlet-name>
|
||||
<servlet-class>org.glyptodon.guacamole.net.basic.crud.users.Delete</servlet-class>
|
||||
</servlet>
|
||||
<servlet-mapping>
|
||||
<servlet-name>UserDelete</servlet-name>
|
||||
<url-pattern>/users/delete</url-pattern>
|
||||
</servlet-mapping>
|
||||
|
||||
<!-- Permission List Servlet -->
|
||||
<servlet>
|
||||
<description>Permission list servlet.</description>
|
||||
<servlet-name>Permissions</servlet-name>
|
||||
<servlet-class>org.glyptodon.guacamole.net.basic.crud.permissions.List</servlet-class>
|
||||
</servlet>
|
||||
<servlet-mapping>
|
||||
<servlet-name>Permissions</servlet-name>
|
||||
<url-pattern>/permissions</url-pattern>
|
||||
</servlet-mapping>
|
||||
|
||||
<!-- Protocol List Servlet -->
|
||||
<servlet>
|
||||
<description>Protocol list servlet.</description>
|
||||
<servlet-name>Protocols</servlet-name>
|
||||
<servlet-class>org.glyptodon.guacamole.net.basic.crud.protocols.List</servlet-class>
|
||||
</servlet>
|
||||
<servlet-mapping>
|
||||
<servlet-name>Protocols</servlet-name>
|
||||
<url-pattern>/protocols</url-pattern>
|
||||
</servlet-mapping>
|
||||
|
||||
<!-- Guacamole Tunnel Servlet -->
|
||||
<servlet>
|
||||
<description>Tunnel servlet.</description>
|
||||
<servlet-name>Tunnel</servlet-name>
|
||||
<servlet-class>org.glyptodon.guacamole.net.basic.BasicGuacamoleTunnelServlet</servlet-class>
|
||||
</servlet>
|
||||
<servlet-mapping>
|
||||
<servlet-name>Tunnel</servlet-name>
|
||||
<url-pattern>/tunnel</url-pattern>
|
||||
</servlet-mapping>
|
||||
|
||||
<!-- Audio file mimetype mappings -->
|
||||
<mime-mapping>
|
||||
<extension>mp3</extension>
|
||||
<mime-type>audio/mpeg</mime-type>
|
||||
|
Reference in New Issue
Block a user