mirror of
https://github.com/gyurix1968/guacamole-client.git
synced 2025-09-06 05:07: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
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1,2 +1,3 @@
|
|||||||
*~
|
*~
|
||||||
target/
|
target/
|
||||||
|
nb-configuration.xml
|
||||||
|
Binary file not shown.
@@ -185,6 +185,55 @@
|
|||||||
<scope>provided</scope>
|
<scope>provided</scope>
|
||||||
</dependency>
|
</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>
|
</dependencies>
|
||||||
|
|
||||||
</project>
|
</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;
|
package org.glyptodon.guacamole.net.basic;
|
||||||
|
|
||||||
|
import com.google.inject.Inject;
|
||||||
|
import com.google.inject.Singleton;
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
import org.glyptodon.guacamole.GuacamoleException;
|
import org.glyptodon.guacamole.GuacamoleException;
|
||||||
import org.glyptodon.guacamole.net.GuacamoleTunnel;
|
import org.glyptodon.guacamole.net.GuacamoleTunnel;
|
||||||
@@ -35,8 +37,15 @@ import org.slf4j.LoggerFactory;
|
|||||||
*
|
*
|
||||||
* @author Michael Jumper
|
* @author Michael Jumper
|
||||||
*/
|
*/
|
||||||
|
@Singleton
|
||||||
public class BasicGuacamoleTunnelServlet extends GuacamoleHTTPTunnelServlet {
|
public class BasicGuacamoleTunnelServlet extends GuacamoleHTTPTunnelServlet {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Service for handling tunnel requests.
|
||||||
|
*/
|
||||||
|
@Inject
|
||||||
|
private TunnelRequestService tunnelRequestService;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Logger for this class.
|
* Logger for this class.
|
||||||
*/
|
*/
|
||||||
@@ -46,7 +55,7 @@ public class BasicGuacamoleTunnelServlet extends GuacamoleHTTPTunnelServlet {
|
|||||||
protected GuacamoleTunnel doConnect(HttpServletRequest request) throws GuacamoleException {
|
protected GuacamoleTunnel doConnect(HttpServletRequest request) throws GuacamoleException {
|
||||||
|
|
||||||
// Attempt to create HTTP tunnel
|
// 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
|
// If successful, warn of lack of WebSocket
|
||||||
logger.info("Using HTTP tunnel (not WebSocket). Performance may be sub-optimal.");
|
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
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
@@ -22,33 +22,31 @@
|
|||||||
|
|
||||||
package org.glyptodon.guacamole.net.basic;
|
package org.glyptodon.guacamole.net.basic;
|
||||||
|
|
||||||
import java.io.IOException;
|
import com.google.inject.Guice;
|
||||||
import javax.servlet.http.HttpServlet;
|
import com.google.inject.Injector;
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import com.google.inject.servlet.GuiceServletContextListener;
|
||||||
import javax.servlet.http.HttpServletResponse;
|
import org.glyptodon.guacamole.net.basic.log.LogModule;
|
||||||
import javax.servlet.http.HttpSession;
|
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
|
* A ServletContextListener to listen for initialization of the servlet context
|
||||||
* redirecting the user to the login page.
|
* in order to set up dependency injection.
|
||||||
*
|
*
|
||||||
* @author Michael Jumper
|
* @author James Muehlner
|
||||||
*/
|
*/
|
||||||
public class BasicLogout extends HttpServlet {
|
public class BasicServletContextListener extends GuiceServletContextListener {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void service(HttpServletRequest request, HttpServletResponse response)
|
protected Injector getInjector() {
|
||||||
throws IOException {
|
|
||||||
|
|
||||||
// Invalidate session, if any
|
return Guice.createInjector(
|
||||||
HttpSession httpSession = request.getSession(false);
|
new LogModule(),
|
||||||
if (httpSession != null)
|
new RESTServletModule(),
|
||||||
httpSession.invalidate();
|
new RESTModule(),
|
||||||
|
new TunnelModule()
|
||||||
// Redirect to index
|
);
|
||||||
response.sendRedirect("index.xhtml");
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@@ -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;
|
package org.glyptodon.guacamole.net.basic;
|
||||||
|
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import com.google.inject.Inject;
|
||||||
import javax.servlet.http.HttpServletResponse;
|
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.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.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Dummy servlet which provides an endpoint for arbitrary requests intended to
|
* REST service which updates the last access time of the Guacamole session,
|
||||||
* simply keep the HTTP session from expiring.
|
* preventing the session from becoming invalid.
|
||||||
*
|
*
|
||||||
* @author Michael Jumper
|
* @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.
|
* Logger for this class.
|
||||||
*/
|
*/
|
||||||
private final Logger logger = LoggerFactory.getLogger(SessionKeepAlive.class);
|
private final Logger logger = LoggerFactory.getLogger(SessionKeepAlive.class);
|
||||||
|
|
||||||
@Override
|
@GET
|
||||||
protected void restrictedService(
|
@AuthProviderRESTExposure
|
||||||
UserContext context,
|
public void updateSession(@QueryParam("token") String authToken) throws GuacamoleException {
|
||||||
HttpServletRequest request, HttpServletResponse response) {
|
|
||||||
|
// Tickle the session
|
||||||
|
UserContext context = authenticationService.getUserContext(authToken);
|
||||||
|
|
||||||
// Do nothing
|
// Do nothing
|
||||||
logger.debug("Keep-alive signal received from user \"{}\".", context.self().getUsername());
|
logger.debug("Keep-alive signal received from user \"{}\".", context.self().getUsername());
|
||||||
|
@@ -20,36 +20,31 @@
|
|||||||
* THE SOFTWARE.
|
* THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.glyptodon.guacamole.net.basic.websocket;
|
package org.glyptodon.guacamole.net.basic;
|
||||||
|
|
||||||
import java.lang.reflect.InvocationTargetException;
|
import com.google.inject.Provider;
|
||||||
import java.lang.reflect.Method;
|
import com.google.inject.servlet.ServletModule;
|
||||||
import javax.servlet.Servlet;
|
import java.util.Arrays;
|
||||||
import javax.servlet.ServletContext;
|
import javax.servlet.http.HttpServlet;
|
||||||
import javax.servlet.ServletContextEvent;
|
import javax.websocket.DeploymentException;
|
||||||
import javax.servlet.ServletContextListener;
|
import javax.websocket.server.ServerContainer;
|
||||||
|
import javax.websocket.server.ServerEndpointConfig;
|
||||||
import org.glyptodon.guacamole.GuacamoleException;
|
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.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Simple ServletContextListener which loads a WebSocket tunnel implementation
|
* Module which loads tunnel implementations.
|
||||||
* 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.
|
|
||||||
*
|
*
|
||||||
* @author Michael Jumper
|
* @author Michael Jumper
|
||||||
*/
|
*/
|
||||||
public class WebSocketSupportLoader implements ServletContextListener {
|
public class TunnelModule extends ServletModule {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Logger for this class.
|
* 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.
|
* 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 {
|
try {
|
||||||
|
|
||||||
// Attempt to find WebSocket servlet
|
// Attempt to find WebSocket servlet
|
||||||
Class<Servlet> servlet = (Class<Servlet>)
|
Class<HttpServlet> servlet = (Class<HttpServlet>)
|
||||||
GuacamoleClassLoader.getInstance().findClass(classname);
|
GuacamoleClassLoader.getInstance().findClass(classname);
|
||||||
|
|
||||||
// Dynamically add servlet IF SERVLET 3.0 API AVAILABLE!
|
// Add WebSocket servlet
|
||||||
try {
|
serve("/websocket-tunnel").with(servlet);
|
||||||
|
return true;
|
||||||
// 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);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -160,21 +120,50 @@ public class WebSocketSupportLoader implements ServletContextListener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void contextDestroyed(ServletContextEvent sce) {
|
protected void configureServlets() {
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
bind(TunnelRequestService.class);
|
||||||
public void contextInitialized(ServletContextEvent sce) {
|
|
||||||
|
// Set up HTTP tunnel
|
||||||
|
serve("/tunnel").with(BasicGuacamoleTunnelServlet.class);
|
||||||
|
|
||||||
// Check for JSR 356 support
|
// Check for JSR 356 support
|
||||||
if (implementsJSR_356()) {
|
if (implementsJSR_356()) {
|
||||||
|
|
||||||
logger.info("JSR-356 WebSocket support present.");
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Try to load each WebSocket tunnel in sequence
|
// Try to load each WebSocket tunnel in sequence
|
||||||
for (String classname : WEBSOCKET_CLASSES) {
|
for (String classname : WEBSOCKET_CLASSES) {
|
||||||
if (loadWebSocketTunnel(sce.getServletContext(), classname)) {
|
if (loadWebSocketTunnel(classname)) {
|
||||||
logger.info("Legacy (non-JSR) WebSocket support loaded: {}", classname);
|
logger.info("Legacy (non-JSR) WebSocket support loaded: {}", classname);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
@@ -22,6 +22,9 @@
|
|||||||
|
|
||||||
package org.glyptodon.guacamole.net.basic;
|
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.Collection;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import javax.servlet.http.HttpSession;
|
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.Directory;
|
||||||
import org.glyptodon.guacamole.net.auth.UserContext;
|
import org.glyptodon.guacamole.net.auth.UserContext;
|
||||||
import org.glyptodon.guacamole.net.basic.event.SessionListenerCollection;
|
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.TunnelCloseEvent;
|
||||||
import org.glyptodon.guacamole.net.event.TunnelConnectEvent;
|
import org.glyptodon.guacamole.net.event.TunnelConnectEvent;
|
||||||
import org.glyptodon.guacamole.net.event.listener.TunnelCloseListener;
|
import org.glyptodon.guacamole.net.event.listener.TunnelCloseListener;
|
||||||
@@ -55,12 +59,19 @@ import org.slf4j.LoggerFactory;
|
|||||||
*
|
*
|
||||||
* @author Michael Jumper
|
* @author Michael Jumper
|
||||||
*/
|
*/
|
||||||
public class BasicTunnelRequestUtility {
|
@Singleton
|
||||||
|
public class TunnelRequestService {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Logger for this class.
|
* 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
|
* 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
|
* error, the connect is canceled, and no other
|
||||||
* listeners will run.
|
* listeners will run.
|
||||||
*/
|
*/
|
||||||
private static boolean notifyConnect(Collection listeners, UserContext context,
|
private boolean notifyConnect(Collection listeners, UserContext context,
|
||||||
Credentials credentials, GuacamoleTunnel tunnel)
|
Credentials credentials, GuacamoleTunnel tunnel)
|
||||||
throws GuacamoleException {
|
throws GuacamoleException {
|
||||||
|
|
||||||
@@ -119,7 +130,7 @@ public class BasicTunnelRequestUtility {
|
|||||||
* error, the close is canceled, and no other
|
* error, the close is canceled, and no other
|
||||||
* listeners will run.
|
* listeners will run.
|
||||||
*/
|
*/
|
||||||
private static boolean notifyClose(Collection listeners, UserContext context,
|
private boolean notifyClose(Collection listeners, UserContext context,
|
||||||
Credentials credentials, GuacamoleTunnel tunnel)
|
Credentials credentials, GuacamoleTunnel tunnel)
|
||||||
throws GuacamoleException {
|
throws GuacamoleException {
|
||||||
|
|
||||||
@@ -151,7 +162,7 @@ public class BasicTunnelRequestUtility {
|
|||||||
* @return The created tunnel, or null if the tunnel could not be created.
|
* @return The created tunnel, or null if the tunnel could not be created.
|
||||||
* @throws GuacamoleException If an error occurs while creating the tunnel.
|
* @throws GuacamoleException If an error occurs while creating the tunnel.
|
||||||
*/
|
*/
|
||||||
public static GuacamoleTunnel createTunnel(TunnelRequest request)
|
public GuacamoleTunnel createTunnel(TunnelRequest request)
|
||||||
throws GuacamoleException {
|
throws GuacamoleException {
|
||||||
|
|
||||||
HttpSession httpSession = request.getSession();
|
HttpSession httpSession = request.getSession();
|
||||||
@@ -169,6 +180,10 @@ public class BasicTunnelRequestUtility {
|
|||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Get auth token and session
|
||||||
|
String authToken = request.getParameter("authToken");
|
||||||
|
GuacamoleSession session = authenticationService.getGuacamoleSession(authToken);
|
||||||
|
|
||||||
// Get ID of connection
|
// Get ID of connection
|
||||||
String id = request.getParameter("id");
|
String id = request.getParameter("id");
|
||||||
TunnelRequest.IdentifierType id_type = TunnelRequest.IdentifierType.getType(id);
|
TunnelRequest.IdentifierType id_type = TunnelRequest.IdentifierType.getType(id);
|
||||||
@@ -181,17 +196,17 @@ public class BasicTunnelRequestUtility {
|
|||||||
id = id.substring(id_type.PREFIX.length());
|
id = id.substring(id_type.PREFIX.length());
|
||||||
|
|
||||||
// Get credentials
|
// Get credentials
|
||||||
final Credentials credentials = AuthenticatingFilter.getCredentials(httpSession);
|
final Credentials credentials = session.getCredentials();
|
||||||
|
|
||||||
// Get context
|
// Get context
|
||||||
final UserContext context = AuthenticatingFilter.getUserContext(httpSession);
|
final UserContext context = session.getUserContext();
|
||||||
|
|
||||||
// If no context or no credentials, not logged in
|
// If no context or no credentials, not logged in
|
||||||
if (context == null || credentials == null)
|
if (context == null || credentials == null)
|
||||||
throw new GuacamoleSecurityException("Cannot connect - user not logged in.");
|
throw new GuacamoleSecurityException("Cannot connect - user not logged in.");
|
||||||
|
|
||||||
// Get clipboard
|
// Get clipboard
|
||||||
final ClipboardState clipboard = AuthenticatingFilter.getClipboardState(httpSession);
|
final ClipboardState clipboard = session.getClipboardState();
|
||||||
|
|
||||||
// Get client information
|
// Get client information
|
||||||
GuacamoleClientInformation info = new GuacamoleClientInformation();
|
GuacamoleClientInformation info = new GuacamoleClientInformation();
|
||||||
@@ -279,7 +294,7 @@ public class BasicTunnelRequestUtility {
|
|||||||
|
|
||||||
// Monitor instructions which pertain to server-side events, if necessary
|
// Monitor instructions which pertain to server-side events, if necessary
|
||||||
try {
|
try {
|
||||||
if (GuacamoleProperties.getProperty(CaptureClipboard.INTEGRATION_ENABLED, false))
|
if (GuacamoleProperties.getProperty(ClipboardRESTService.INTEGRATION_ENABLED, false))
|
||||||
return new MonitoringGuacamoleReader(clipboard, super.acquireReader());
|
return new MonitoringGuacamoleReader(clipboard, super.acquireReader());
|
||||||
}
|
}
|
||||||
catch (GuacamoleException e) {
|
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.classic.joran.JoranConfigurator;
|
||||||
import ch.qos.logback.core.joran.spi.JoranException;
|
import ch.qos.logback.core.joran.spi.JoranException;
|
||||||
import ch.qos.logback.core.util.StatusPrinter;
|
import ch.qos.logback.core.util.StatusPrinter;
|
||||||
|
import com.google.inject.AbstractModule;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import javax.servlet.ServletContextEvent;
|
|
||||||
import javax.servlet.ServletContextListener;
|
|
||||||
import org.glyptodon.guacamole.properties.GuacamoleHome;
|
import org.glyptodon.guacamole.properties.GuacamoleHome;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initializes the logback logging subsystem, used behind SLF4J within
|
* Initializes the logging subsystem.
|
||||||
* Guacamole for all logging.
|
|
||||||
*
|
*
|
||||||
* @author Michael Jumper
|
* @author Michael Jumper
|
||||||
*/
|
*/
|
||||||
public class LogbackInitializer implements ServletContextListener {
|
public class LogModule extends AbstractModule {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Logger for this class.
|
* Logger for this class.
|
||||||
*/
|
*/
|
||||||
private final Logger logger = LoggerFactory.getLogger(LogbackInitializer.class);
|
private final Logger logger = LoggerFactory.getLogger(LogModule.class);
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void contextDestroyed(ServletContextEvent sce) {
|
protected void configure() {
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void contextInitialized(ServletContextEvent sce) {
|
|
||||||
|
|
||||||
// Only load logback configuration if GUACAMOLE_HOME exists
|
// Only load logback configuration if GUACAMOLE_HOME exists
|
||||||
File guacamoleHome = GuacamoleHome.getDirectory();
|
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
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
@@ -20,32 +20,50 @@
|
|||||||
* THE SOFTWARE.
|
* THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.glyptodon.guacamole.net.basic;
|
package org.glyptodon.guacamole.net.basic.rest.auth;
|
||||||
|
|
||||||
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;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Simple dummy AuthenticatingHttpServlet which provides an endpoint for arbitrary
|
* A simple object to represent an auth token/userID pair in the API.
|
||||||
* authentication requests that do not expect a response.
|
|
||||||
*
|
*
|
||||||
* @author Michael Jumper
|
* @author James Muehlner
|
||||||
*/
|
*/
|
||||||
public class BasicLogin extends RestrictedHttpServlet {
|
public class APIAuthToken {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Logger for this class.
|
* The auth token.
|
||||||
*/
|
*/
|
||||||
private final Logger logger = LoggerFactory.getLogger(BasicLogin.class);
|
private final String authToken;
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void restrictedService(
|
/**
|
||||||
UserContext context,
|
* The user ID.
|
||||||
HttpServletRequest request, HttpServletResponse response) {
|
*/
|
||||||
logger.debug("Login was successful for user \"{}\".", context.self().getUsername());
|
private final String userID;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the auth token.
|
||||||
|
* @return The auth token.
|
||||||
|
*/
|
||||||
|
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
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
* 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,25 +20,35 @@
|
|||||||
* THE SOFTWARE.
|
* THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.glyptodon.guacamole.net.basic;
|
package org.glyptodon.guacamole.net.basic.rest.clipboard;
|
||||||
|
|
||||||
import java.io.IOException;
|
import com.google.inject.Inject;
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.ws.rs.GET;
|
||||||
import javax.servlet.http.HttpServletResponse;
|
import javax.ws.rs.Path;
|
||||||
import javax.servlet.http.HttpSession;
|
import javax.ws.rs.QueryParam;
|
||||||
|
import javax.ws.rs.core.Response;
|
||||||
import org.glyptodon.guacamole.GuacamoleException;
|
import org.glyptodon.guacamole.GuacamoleException;
|
||||||
import org.glyptodon.guacamole.GuacamoleServerException;
|
|
||||||
import org.glyptodon.guacamole.GuacamoleUnsupportedException;
|
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.BooleanGuacamoleProperty;
|
||||||
import org.glyptodon.guacamole.properties.GuacamoleProperties;
|
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
|
* @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.
|
* The amount of time to wait for clipboard changes, in milliseconds.
|
||||||
@@ -55,30 +65,23 @@ public class CaptureClipboard extends RestrictedHttpServlet {
|
|||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@GET
|
||||||
@Override
|
@AuthProviderRESTExposure
|
||||||
protected void restrictedService(
|
public Response getClipboard(@QueryParam("token") String authToken)
|
||||||
UserContext context,
|
|
||||||
HttpServletRequest request, HttpServletResponse response)
|
|
||||||
throws GuacamoleException {
|
throws GuacamoleException {
|
||||||
|
|
||||||
// Only bother if actually enabled
|
// Only bother if actually enabled
|
||||||
if (GuacamoleProperties.getProperty(INTEGRATION_ENABLED, false)) {
|
if (GuacamoleProperties.getProperty(INTEGRATION_ENABLED, false)) {
|
||||||
|
|
||||||
// Get clipboard
|
// Get clipboard
|
||||||
final HttpSession session = request.getSession(true);
|
GuacamoleSession session = authenticationService.getGuacamoleSession(authToken);
|
||||||
final ClipboardState clipboard = AuthenticatingFilter.getClipboardState(session);
|
final ClipboardState clipboard = session.getClipboardState();
|
||||||
|
|
||||||
// Send clipboard contents
|
// Send clipboard contents
|
||||||
try {
|
synchronized (clipboard) {
|
||||||
synchronized (clipboard) {
|
clipboard.waitForContents(CLIPBOARD_TIMEOUT);
|
||||||
clipboard.waitForContents(CLIPBOARD_TIMEOUT);
|
return Response.ok(clipboard.getContents(),
|
||||||
response.setContentType(clipboard.getMimetype());
|
clipboard.getMimetype()).build();
|
||||||
response.getOutputStream().write(clipboard.getContents());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (IOException e) {
|
|
||||||
throw new GuacamoleServerException("Unable to send clipboard contents", e);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@@ -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
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
@@ -20,40 +20,40 @@
|
|||||||
* THE SOFTWARE.
|
* THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.glyptodon.guacamole.net.basic.crud.connections;
|
package org.glyptodon.guacamole.net.basic.rest.connection;
|
||||||
|
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import java.util.ArrayList;
|
||||||
import javax.servlet.http.HttpServletResponse;
|
import java.util.List;
|
||||||
import org.glyptodon.guacamole.GuacamoleException;
|
import org.glyptodon.guacamole.GuacamoleException;
|
||||||
import org.glyptodon.guacamole.net.auth.Connection;
|
import org.glyptodon.guacamole.net.auth.Connection;
|
||||||
import org.glyptodon.guacamole.net.auth.Directory;
|
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.
|
* A service for performing useful manipulations on REST Connections.
|
||||||
*
|
*
|
||||||
* @author Michael Jumper
|
* @author James Muehlner
|
||||||
*/
|
*/
|
||||||
public class Delete extends RestrictedHttpServlet {
|
public class ConnectionService {
|
||||||
|
|
||||||
@Override
|
/**
|
||||||
protected void restrictedService(
|
* Converts a Connection Directory to a list of APIConnection objects for
|
||||||
UserContext context,
|
* exposing with the REST endpoints.
|
||||||
HttpServletRequest request, HttpServletResponse response)
|
*
|
||||||
throws GuacamoleException {
|
* @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 {
|
||||||
|
|
||||||
// Get ID
|
List<APIConnection> restConnections = new ArrayList<APIConnection>();
|
||||||
String identifier = request.getParameter("id");
|
|
||||||
|
|
||||||
// Attempt to get connection directory
|
for (String connectionID : connectionDirectory.getIdentifiers())
|
||||||
Directory<String, Connection> directory =
|
restConnections.add(new APIConnection(connectionDirectory.get(connectionID)));
|
||||||
context.getRootConnectionGroup().getConnectionDirectory();
|
|
||||||
|
|
||||||
// Remove connection
|
return restConnections;
|
||||||
directory.remove(identifier);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@@ -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
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
* 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
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
* 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
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
@@ -20,7 +20,7 @@
|
|||||||
* THE SOFTWARE.
|
* 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.BufferedInputStream;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
@@ -30,18 +30,8 @@ import java.io.IOException;
|
|||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
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.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.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.DocumentHandler;
|
||||||
import org.glyptodon.guacamole.net.basic.xml.protocol.ProtocolTagHandler;
|
import org.glyptodon.guacamole.net.basic.xml.protocol.ProtocolTagHandler;
|
||||||
import org.glyptodon.guacamole.properties.GuacamoleHome;
|
import org.glyptodon.guacamole.properties.GuacamoleHome;
|
||||||
@@ -53,17 +43,17 @@ import org.xml.sax.XMLReader;
|
|||||||
import org.xml.sax.helpers.XMLReaderFactory;
|
import org.xml.sax.helpers.XMLReaderFactory;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Simple HttpServlet which outputs XML containing a list of all visible
|
* A service for retrieving protocol definitions from the
|
||||||
* protocols.
|
* XML files storing the information.
|
||||||
*
|
*
|
||||||
* @author Michael Jumper
|
* @author James Muehlner
|
||||||
*/
|
*/
|
||||||
public class List extends RestrictedHttpServlet {
|
public class ProtocolRetrievalService {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Logger for this class.
|
* 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.
|
* Array of all known protocol names.
|
||||||
@@ -108,110 +98,22 @@ public class List extends RestrictedHttpServlet {
|
|||||||
|
|
||||||
}
|
}
|
||||||
catch (IOException e) {
|
catch (IOException e) {
|
||||||
throw new GuacamoleException("Error reading basic user mapping file.", e);
|
throw new GuacamoleException(e);
|
||||||
}
|
}
|
||||||
catch (SAXException 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
|
* Retrieves a map of protocol name to ProtocolInfo for all protocols defined
|
||||||
* out the corresponding protocol XML describing all available parameters.
|
* in the XML files.
|
||||||
*
|
*
|
||||||
* @param xml The XMLStreamWriter to use to write the XML.
|
* @return A map of all defined protocols.
|
||||||
* @param protocol The ProtocolInfo object to read parameters and protocol
|
* @throws GuacamoleException If an error occurs while retrieving the protocols.
|
||||||
* information from.
|
|
||||||
* @throws XMLStreamException If an error occurs while writing the XML.
|
|
||||||
*/
|
*/
|
||||||
private void writeProtocol(XMLStreamWriter xml, ProtocolInfo protocol)
|
public Map<String, ProtocolInfo> getProtocolMap() throws GuacamoleException {
|
||||||
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");
|
|
||||||
|
|
||||||
// Map of all available protocols
|
// Map of all available protocols
|
||||||
Map<String, ProtocolInfo> protocols = new HashMap<String, ProtocolInfo>();
|
Map<String, ProtocolInfo> protocols = new HashMap<String, ProtocolInfo>();
|
||||||
|
|
||||||
@@ -225,20 +127,16 @@ public class List extends RestrictedHttpServlet {
|
|||||||
// Get all XML files
|
// Get all XML files
|
||||||
File[] files = protocol_directory.listFiles(
|
File[] files = protocol_directory.listFiles(
|
||||||
new FilenameFilter() {
|
new FilenameFilter() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean accept(File file, String string) {
|
public boolean accept(File file, String string) {
|
||||||
return string.endsWith(".xml");
|
return string.endsWith(".xml");
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
// Load each protocol from each file
|
// Load each protocol from each file
|
||||||
for (File file : files) {
|
for (File file : files) {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
||||||
// Parse protocol
|
// Parse protocol
|
||||||
FileInputStream stream = new FileInputStream(file);
|
FileInputStream stream = new FileInputStream(file);
|
||||||
ProtocolInfo protocol = getProtocol(stream);
|
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.error("Unable to read connection parameter information from \"{}\": {}", file.getAbsolutePath(), e.getMessage());
|
||||||
logger.debug("Error reading protocol XML.", e);
|
logger.debug("Error reading protocol XML.", e);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// If known protocols are not already defined, read from classpath
|
// 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 protocol not defined yet, attempt to load from classpath
|
||||||
if (!protocols.containsKey(protocol)) {
|
if (!protocols.containsKey(protocol)) {
|
||||||
|
InputStream stream = ProtocolRetrievalService.class.getResourceAsStream(
|
||||||
InputStream stream = List.class.getResourceAsStream(
|
|
||||||
"/net/sourceforge/guacamole/net/protocols/"
|
"/net/sourceforge/guacamole/net/protocols/"
|
||||||
+ protocol + ".xml");
|
+ protocol + ".xml");
|
||||||
|
|
||||||
@@ -272,39 +167,9 @@ public class List extends RestrictedHttpServlet {
|
|||||||
protocols.put(protocol, getProtocol(stream));
|
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
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
* 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
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
@@ -20,39 +20,40 @@
|
|||||||
* THE SOFTWARE.
|
* THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.glyptodon.guacamole.net.basic.crud.users;
|
package org.glyptodon.guacamole.net.basic.rest.user;
|
||||||
|
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import java.util.ArrayList;
|
||||||
import javax.servlet.http.HttpServletResponse;
|
import java.util.List;
|
||||||
import org.glyptodon.guacamole.GuacamoleException;
|
import org.glyptodon.guacamole.GuacamoleException;
|
||||||
import org.glyptodon.guacamole.net.auth.Directory;
|
import org.glyptodon.guacamole.net.auth.Directory;
|
||||||
import org.glyptodon.guacamole.net.auth.User;
|
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.
|
* A service for performing useful manipulations on REST Users.
|
||||||
*
|
*
|
||||||
* @author Michael Jumper
|
* @author James Muehlner
|
||||||
*/
|
*/
|
||||||
public class Delete extends RestrictedHttpServlet {
|
public class UserService {
|
||||||
|
|
||||||
@Override
|
/**
|
||||||
protected void restrictedService(
|
* Converts a user directory to a list of APIUser objects for
|
||||||
UserContext context,
|
* exposing with the REST endpoints.
|
||||||
HttpServletRequest request, HttpServletResponse response)
|
*
|
||||||
throws GuacamoleException {
|
* @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 {
|
||||||
|
|
||||||
// Get username
|
List<APIUser> restUsers = new ArrayList<APIUser>();
|
||||||
String username = request.getParameter("name");
|
|
||||||
|
|
||||||
// Attempt to get user directory
|
for(String username : userDirectory.getIdentifiers())
|
||||||
Directory<String, User> directory = context.getUserDirectory();
|
restUsers.add(new APIUser(userDirectory.get(username)));
|
||||||
|
|
||||||
// Remove user
|
return restUsers;
|
||||||
directory.remove(username);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@@ -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
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
* 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;
|
package org.glyptodon.guacamole.net.basic.websocket;
|
||||||
|
|
||||||
|
import com.google.inject.Provider;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import javax.websocket.EndpointConfig;
|
import javax.websocket.EndpointConfig;
|
||||||
import javax.websocket.HandshakeResponse;
|
import javax.websocket.HandshakeResponse;
|
||||||
import javax.websocket.Session;
|
import javax.websocket.Session;
|
||||||
import javax.websocket.server.HandshakeRequest;
|
import javax.websocket.server.HandshakeRequest;
|
||||||
import javax.websocket.server.ServerEndpoint;
|
|
||||||
import javax.websocket.server.ServerEndpointConfig;
|
import javax.websocket.server.ServerEndpointConfig;
|
||||||
import org.glyptodon.guacamole.GuacamoleException;
|
import org.glyptodon.guacamole.GuacamoleException;
|
||||||
import org.glyptodon.guacamole.net.GuacamoleTunnel;
|
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;
|
import org.glyptodon.guacamole.websocket.GuacamoleWebSocketTunnelEndpoint;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tunnel implementation which uses WebSocket as a tunnel backend, rather than
|
* Tunnel implementation which uses WebSocket as a tunnel backend, rather than
|
||||||
* HTTP, properly parsing connection IDs included in the connection request.
|
* 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 {
|
public class BasicGuacamoleWebSocketTunnelEndpoint extends GuacamoleWebSocketTunnelEndpoint {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -62,6 +59,25 @@ public class BasicGuacamoleWebSocketTunnelEndpoint extends GuacamoleWebSocketTun
|
|||||||
*/
|
*/
|
||||||
public static class Configurator extends ServerEndpointConfig.Configurator {
|
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
|
@Override
|
||||||
public void modifyHandshake(ServerEndpointConfig config, HandshakeRequest request, HandshakeResponse response) {
|
public void modifyHandshake(ServerEndpointConfig config, HandshakeRequest request, HandshakeResponse response) {
|
||||||
|
|
||||||
@@ -72,8 +88,11 @@ public class BasicGuacamoleWebSocketTunnelEndpoint extends GuacamoleWebSocketTun
|
|||||||
userProperties.clear();
|
userProperties.clear();
|
||||||
try {
|
try {
|
||||||
|
|
||||||
|
// Get tunnel request service
|
||||||
|
TunnelRequestService tunnelRequestService = tunnelRequestServiceProvider.get();
|
||||||
|
|
||||||
// Store new tunnel within user properties
|
// Store new tunnel within user properties
|
||||||
GuacamoleTunnel tunnel = BasicTunnelRequestUtility.createTunnel(new WebSocketTunnelRequest(request));
|
GuacamoleTunnel tunnel = tunnelRequestService.createTunnel(new WebSocketTunnelRequest(request));
|
||||||
if (tunnel != null)
|
if (tunnel != null)
|
||||||
userProperties.put(TUNNEL_USER_PROPERTY, tunnel);
|
userProperties.put(TUNNEL_USER_PROPERTY, tunnel);
|
||||||
|
|
||||||
|
@@ -22,10 +22,12 @@
|
|||||||
|
|
||||||
package org.glyptodon.guacamole.net.basic.websocket.jetty8;
|
package org.glyptodon.guacamole.net.basic.websocket.jetty8;
|
||||||
|
|
||||||
|
import com.google.inject.Inject;
|
||||||
|
import com.google.inject.Singleton;
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
import org.glyptodon.guacamole.GuacamoleException;
|
import org.glyptodon.guacamole.GuacamoleException;
|
||||||
import org.glyptodon.guacamole.net.GuacamoleTunnel;
|
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;
|
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
|
* rather than HTTP, properly parsing connection IDs included in the connection
|
||||||
* request.
|
* request.
|
||||||
*/
|
*/
|
||||||
|
@Singleton
|
||||||
public class BasicGuacamoleWebSocketTunnelServlet extends GuacamoleWebSocketTunnelServlet {
|
public class BasicGuacamoleWebSocketTunnelServlet extends GuacamoleWebSocketTunnelServlet {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Service for handling tunnel requests.
|
||||||
|
*/
|
||||||
|
@Inject
|
||||||
|
private TunnelRequestService tunnelRequestService;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected GuacamoleTunnel doConnect(HttpServletRequest request)
|
protected GuacamoleTunnel doConnect(HttpServletRequest request)
|
||||||
throws GuacamoleException {
|
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;
|
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.eclipse.jetty.websocket.api.Session;
|
||||||
import org.glyptodon.guacamole.GuacamoleException;
|
import org.glyptodon.guacamole.GuacamoleException;
|
||||||
import org.glyptodon.guacamole.net.GuacamoleTunnel;
|
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
|
* WebSocket listener implementation which properly parses connection IDs
|
||||||
@@ -33,11 +35,18 @@ import org.glyptodon.guacamole.net.basic.BasicTunnelRequestUtility;
|
|||||||
*
|
*
|
||||||
* @author Michael Jumper
|
* @author Michael Jumper
|
||||||
*/
|
*/
|
||||||
|
@Singleton
|
||||||
public class BasicGuacamoleWebSocketTunnelListener extends GuacamoleWebSocketTunnelListener {
|
public class BasicGuacamoleWebSocketTunnelListener extends GuacamoleWebSocketTunnelListener {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Service for handling tunnel requests.
|
||||||
|
*/
|
||||||
|
@Inject
|
||||||
|
private TunnelRequestService tunnelRequestService;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected GuacamoleTunnel createTunnel(Session session) throws GuacamoleException {
|
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;
|
package org.glyptodon.guacamole.net.basic.websocket.tomcat;
|
||||||
|
|
||||||
|
import com.google.inject.Inject;
|
||||||
|
import com.google.inject.Singleton;
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
import org.glyptodon.guacamole.GuacamoleException;
|
import org.glyptodon.guacamole.GuacamoleException;
|
||||||
import org.glyptodon.guacamole.net.GuacamoleTunnel;
|
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;
|
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
|
* rather than HTTP, properly parsing connection IDs included in the connection
|
||||||
* request.
|
* request.
|
||||||
*/
|
*/
|
||||||
|
@Singleton
|
||||||
public class BasicGuacamoleWebSocketTunnelServlet extends GuacamoleWebSocketTunnelServlet {
|
public class BasicGuacamoleWebSocketTunnelServlet extends GuacamoleWebSocketTunnelServlet {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Service for handling tunnel requests.
|
||||||
|
*/
|
||||||
|
@Inject
|
||||||
|
private TunnelRequestService tunnelRequestService;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected GuacamoleTunnel doConnect(HttpServletRequest request)
|
protected GuacamoleTunnel doConnect(HttpServletRequest request)
|
||||||
throws GuacamoleException {
|
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
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
THE SOFTWARE.
|
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 -->
|
<!-- Basic config -->
|
||||||
<welcome-file-list>
|
<welcome-file-list>
|
||||||
<welcome-file>index.xhtml</welcome-file>
|
<welcome-file>index.xhtml</welcome-file>
|
||||||
</welcome-file-list>
|
</welcome-file-list>
|
||||||
<session-config>
|
<session-config>
|
||||||
<session-timeout>
|
<session-timeout>30</session-timeout>
|
||||||
30
|
|
||||||
</session-timeout>
|
|
||||||
</session-config>
|
</session-config>
|
||||||
|
|
||||||
<!-- Automatically detect and load WebSocket support -->
|
<!-- Guice -->
|
||||||
<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 -->
|
|
||||||
<filter>
|
<filter>
|
||||||
<filter-name>AuthenticatingFilter</filter-name>
|
<filter-name>guiceFilter</filter-name>
|
||||||
<filter-class>org.glyptodon.guacamole.net.basic.AuthenticatingFilter</filter-class>
|
<filter-class>com.google.inject.servlet.GuiceFilter</filter-class>
|
||||||
</filter>
|
</filter>
|
||||||
<filter-mapping>
|
<filter-mapping>
|
||||||
<filter-name>AuthenticatingFilter</filter-name>
|
<filter-name>guiceFilter</filter-name>
|
||||||
<url-pattern>*.xhtml</url-pattern>
|
<url-pattern>/*</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-mapping>
|
</filter-mapping>
|
||||||
|
|
||||||
<!-- Restrict requests to the WebSocket tunnel -->
|
<listener>
|
||||||
<filter>
|
<listener-class>org.glyptodon.guacamole.net.basic.BasicServletContextListener</listener-class>
|
||||||
<filter-name>RestrictedFilter</filter-name>
|
</listener>
|
||||||
<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>
|
|
||||||
|
|
||||||
<!-- 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>
|
<mime-mapping>
|
||||||
<extension>mp3</extension>
|
<extension>mp3</extension>
|
||||||
<mime-type>audio/mpeg</mime-type>
|
<mime-type>audio/mpeg</mime-type>
|
||||||
|
Reference in New Issue
Block a user