mirror of
https://github.com/gyurix1968/guacamole-client.git
synced 2025-09-07 21:51:23 +00:00
Use utility class, not tunnel servlet itself. Init underling auth servlet within websocket auth.
This commit is contained in:
@@ -19,28 +19,12 @@ package org.glyptodon.guacamole.net.basic;
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Collection;
|
|
||||||
import javax.servlet.ServletException;
|
import javax.servlet.ServletException;
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
import javax.servlet.http.HttpServletResponse;
|
import javax.servlet.http.HttpServletResponse;
|
||||||
import javax.servlet.http.HttpSession;
|
|
||||||
import org.glyptodon.guacamole.GuacamoleClientException;
|
|
||||||
import org.glyptodon.guacamole.GuacamoleException;
|
import org.glyptodon.guacamole.GuacamoleException;
|
||||||
import org.glyptodon.guacamole.GuacamoleSecurityException;
|
|
||||||
import org.glyptodon.guacamole.net.GuacamoleSocket;
|
|
||||||
import org.glyptodon.guacamole.net.GuacamoleTunnel;
|
import org.glyptodon.guacamole.net.GuacamoleTunnel;
|
||||||
import org.glyptodon.guacamole.net.auth.Connection;
|
|
||||||
import org.glyptodon.guacamole.net.auth.ConnectionGroup;
|
|
||||||
import org.glyptodon.guacamole.net.auth.Credentials;
|
|
||||||
import org.glyptodon.guacamole.net.auth.Directory;
|
|
||||||
import org.glyptodon.guacamole.net.auth.UserContext;
|
import org.glyptodon.guacamole.net.auth.UserContext;
|
||||||
import org.glyptodon.guacamole.net.basic.event.SessionListenerCollection;
|
|
||||||
import org.glyptodon.guacamole.net.event.TunnelCloseEvent;
|
|
||||||
import org.glyptodon.guacamole.net.event.TunnelConnectEvent;
|
|
||||||
import org.glyptodon.guacamole.net.event.listener.TunnelCloseListener;
|
|
||||||
import org.glyptodon.guacamole.net.event.listener.TunnelConnectListener;
|
|
||||||
import org.glyptodon.guacamole.protocol.GuacamoleClientInformation;
|
|
||||||
import org.glyptodon.guacamole.servlet.GuacamoleHTTPTunnelServlet;
|
import org.glyptodon.guacamole.servlet.GuacamoleHTTPTunnelServlet;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
@@ -139,230 +123,6 @@ public class BasicGuacamoleTunnelServlet extends AuthenticatingHttpServlet {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Notifies all listeners in the given collection that a tunnel has been
|
|
||||||
* connected.
|
|
||||||
*
|
|
||||||
* @param listeners A collection of all listeners that should be notified.
|
|
||||||
* @param context The UserContext associated with the current session.
|
|
||||||
* @param credentials The credentials associated with the current session.
|
|
||||||
* @param tunnel The tunnel being connected.
|
|
||||||
* @return true if all listeners are allowing the tunnel to connect,
|
|
||||||
* or if there are no listeners, and false if any listener is
|
|
||||||
* canceling the connection. 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 connect is canceled, and no other
|
|
||||||
* listeners will run.
|
|
||||||
*/
|
|
||||||
public static boolean notifyConnect(Collection listeners, UserContext context,
|
|
||||||
Credentials credentials, GuacamoleTunnel tunnel)
|
|
||||||
throws GuacamoleException {
|
|
||||||
|
|
||||||
// Build event for auth success
|
|
||||||
TunnelConnectEvent event = new TunnelConnectEvent(context,
|
|
||||||
credentials, tunnel);
|
|
||||||
|
|
||||||
// Notify all listeners
|
|
||||||
for (Object listener : listeners) {
|
|
||||||
if (listener instanceof TunnelConnectListener) {
|
|
||||||
|
|
||||||
// Cancel immediately if hook returns false
|
|
||||||
if (!((TunnelConnectListener) listener).tunnelConnected(event))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Notifies all listeners in the given collection that a tunnel has been
|
|
||||||
* closed.
|
|
||||||
*
|
|
||||||
* @param listeners A collection of all listeners that should be notified.
|
|
||||||
* @param context The UserContext associated with the current session.
|
|
||||||
* @param credentials The credentials associated with the current session.
|
|
||||||
* @param tunnel The tunnel being closed.
|
|
||||||
* @return true if all listeners are allowing the tunnel to close,
|
|
||||||
* or if there are no listeners, and false if any listener is
|
|
||||||
* canceling the close. 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 close is canceled, and no other
|
|
||||||
* listeners will run.
|
|
||||||
*/
|
|
||||||
public static boolean notifyClose(Collection listeners, UserContext context,
|
|
||||||
Credentials credentials, GuacamoleTunnel tunnel)
|
|
||||||
throws GuacamoleException {
|
|
||||||
|
|
||||||
// Build event for auth success
|
|
||||||
TunnelCloseEvent event = new TunnelCloseEvent(context,
|
|
||||||
credentials, tunnel);
|
|
||||||
|
|
||||||
// Notify all listeners
|
|
||||||
for (Object listener : listeners) {
|
|
||||||
if (listener instanceof TunnelCloseListener) {
|
|
||||||
|
|
||||||
// Cancel immediately if hook returns false
|
|
||||||
if (!((TunnelCloseListener) listener).tunnelClosed(event))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a new tunnel using the parameters and credentials present in
|
|
||||||
* the given request.
|
|
||||||
*
|
|
||||||
* @param request The HttpServletRequest describing the tunnel to create.
|
|
||||||
* @return The created tunnel, or null if the tunnel could not be created.
|
|
||||||
* @throws GuacamoleException If an error occurs while creating the tunnel.
|
|
||||||
*/
|
|
||||||
public static GuacamoleTunnel createTunnel(HttpServletRequest request)
|
|
||||||
throws GuacamoleException {
|
|
||||||
|
|
||||||
HttpSession httpSession = request.getSession(true);
|
|
||||||
|
|
||||||
// Get listeners
|
|
||||||
final SessionListenerCollection listeners;
|
|
||||||
try {
|
|
||||||
listeners = new SessionListenerCollection(httpSession);
|
|
||||||
}
|
|
||||||
catch (GuacamoleException e) {
|
|
||||||
logger.error("Failed to retrieve listeners. Authentication canceled.", e);
|
|
||||||
throw e;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get ID of connection
|
|
||||||
String id = request.getParameter("id");
|
|
||||||
IdentifierType id_type = IdentifierType.getType(id);
|
|
||||||
|
|
||||||
// Do not continue if unable to determine type
|
|
||||||
if (id_type == null)
|
|
||||||
throw new GuacamoleClientException("Illegal identifier - unknown type.");
|
|
||||||
|
|
||||||
// Remove prefix
|
|
||||||
id = id.substring(id_type.PREFIX.length());
|
|
||||||
|
|
||||||
// Get credentials
|
|
||||||
final Credentials credentials = getCredentials(httpSession);
|
|
||||||
|
|
||||||
// Get context
|
|
||||||
final UserContext context = getUserContext(httpSession);
|
|
||||||
|
|
||||||
// If no context or no credentials, not logged in
|
|
||||||
if (context == null || credentials == null)
|
|
||||||
throw new GuacamoleSecurityException("Cannot connect - user not logged in.");
|
|
||||||
|
|
||||||
// Get client information
|
|
||||||
GuacamoleClientInformation info = new GuacamoleClientInformation();
|
|
||||||
|
|
||||||
// Set width if provided
|
|
||||||
String width = request.getParameter("width");
|
|
||||||
if (width != null)
|
|
||||||
info.setOptimalScreenWidth(Integer.parseInt(width));
|
|
||||||
|
|
||||||
// Set height if provided
|
|
||||||
String height = request.getParameter("height");
|
|
||||||
if (height != null)
|
|
||||||
info.setOptimalScreenHeight(Integer.parseInt(height));
|
|
||||||
|
|
||||||
// Add audio mimetypes
|
|
||||||
String[] audio_mimetypes = request.getParameterValues("audio");
|
|
||||||
if (audio_mimetypes != null)
|
|
||||||
info.getAudioMimetypes().addAll(Arrays.asList(audio_mimetypes));
|
|
||||||
|
|
||||||
// Add video mimetypes
|
|
||||||
String[] video_mimetypes = request.getParameterValues("video");
|
|
||||||
if (video_mimetypes != null)
|
|
||||||
info.getVideoMimetypes().addAll(Arrays.asList(video_mimetypes));
|
|
||||||
|
|
||||||
// Create connected socket from identifier
|
|
||||||
GuacamoleSocket socket;
|
|
||||||
switch (id_type) {
|
|
||||||
|
|
||||||
// Connection identifiers
|
|
||||||
case CONNECTION: {
|
|
||||||
|
|
||||||
// Get connection directory
|
|
||||||
Directory<String, Connection> directory =
|
|
||||||
context.getRootConnectionGroup().getConnectionDirectory();
|
|
||||||
|
|
||||||
// Get authorized connection
|
|
||||||
Connection connection = directory.get(id);
|
|
||||||
if (connection == null) {
|
|
||||||
logger.warn("Connection id={} not found.", id);
|
|
||||||
throw new GuacamoleSecurityException("Requested connection is not authorized.");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Connect socket
|
|
||||||
socket = connection.connect(info);
|
|
||||||
logger.info("Successful connection from {} to \"{}\".", request.getRemoteAddr(), id);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Connection group identifiers
|
|
||||||
case CONNECTION_GROUP: {
|
|
||||||
|
|
||||||
// Get connection group directory
|
|
||||||
Directory<String, ConnectionGroup> directory =
|
|
||||||
context.getRootConnectionGroup().getConnectionGroupDirectory();
|
|
||||||
|
|
||||||
// Get authorized connection group
|
|
||||||
ConnectionGroup group = directory.get(id);
|
|
||||||
if (group == null) {
|
|
||||||
logger.warn("Connection group id={} not found.", id);
|
|
||||||
throw new GuacamoleSecurityException("Requested connection group is not authorized.");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Connect socket
|
|
||||||
socket = group.connect(info);
|
|
||||||
logger.info("Successful connection from {} to group \"{}\".", request.getRemoteAddr(), id);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fail if unsupported type
|
|
||||||
default:
|
|
||||||
throw new GuacamoleClientException("Connection not supported for provided identifier type.");
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// Associate socket with tunnel
|
|
||||||
GuacamoleTunnel tunnel = new GuacamoleTunnel(socket) {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void close() throws GuacamoleException {
|
|
||||||
|
|
||||||
// Only close if not canceled
|
|
||||||
if (!notifyClose(listeners, context, credentials, this))
|
|
||||||
throw new GuacamoleException("Tunnel close canceled by listener.");
|
|
||||||
|
|
||||||
// Close if no exception due to listener
|
|
||||||
super.close();
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
// Notify listeners about connection
|
|
||||||
if (!notifyConnect(listeners, context, credentials, tunnel)) {
|
|
||||||
logger.info("Connection canceled by listener.");
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return tunnel;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Wrapped GuacamoleHTTPTunnelServlet which will handle all authenticated
|
* Wrapped GuacamoleHTTPTunnelServlet which will handle all authenticated
|
||||||
* requests.
|
* requests.
|
||||||
@@ -371,7 +131,7 @@ public class BasicGuacamoleTunnelServlet extends AuthenticatingHttpServlet {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected GuacamoleTunnel doConnect(HttpServletRequest request) throws GuacamoleException {
|
protected GuacamoleTunnel doConnect(HttpServletRequest request) throws GuacamoleException {
|
||||||
return createTunnel(request);
|
return BasicTunnelRequestUtility.createTunnel(request);
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
@@ -73,6 +73,11 @@ public abstract class AuthenticatingWebSocketServlet extends WebSocketServlet {
|
|||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void init() throws ServletException {
|
||||||
|
auth_servlet.init();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void service(HttpServletRequest request,
|
protected void service(HttpServletRequest request,
|
||||||
HttpServletResponse response)
|
HttpServletResponse response)
|
||||||
|
@@ -23,7 +23,7 @@ import org.glyptodon.guacamole.GuacamoleException;
|
|||||||
import org.glyptodon.guacamole.net.GuacamoleTunnel;
|
import org.glyptodon.guacamole.net.GuacamoleTunnel;
|
||||||
import org.glyptodon.guacamole.net.auth.UserContext;
|
import org.glyptodon.guacamole.net.auth.UserContext;
|
||||||
import org.eclipse.jetty.websocket.WebSocket;
|
import org.eclipse.jetty.websocket.WebSocket;
|
||||||
import org.glyptodon.guacamole.net.basic.BasicGuacamoleTunnelServlet;
|
import org.glyptodon.guacamole.net.basic.BasicTunnelRequestUtility;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Authenticating tunnel servlet implementation which uses WebSocket as a
|
* Authenticating tunnel servlet implementation which uses WebSocket as a
|
||||||
@@ -41,7 +41,7 @@ public class BasicGuacamoleWebSocketTunnelServlet extends AuthenticatingWebSocke
|
|||||||
@Override
|
@Override
|
||||||
protected GuacamoleTunnel doConnect(HttpServletRequest request)
|
protected GuacamoleTunnel doConnect(HttpServletRequest request)
|
||||||
throws GuacamoleException {
|
throws GuacamoleException {
|
||||||
return BasicGuacamoleTunnelServlet.createTunnel(request);
|
return BasicTunnelRequestUtility.createTunnel(request);
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
@@ -73,6 +73,11 @@ public abstract class AuthenticatingWebSocketServlet extends WebSocketServlet {
|
|||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void init() throws ServletException {
|
||||||
|
auth_servlet.init();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void service(HttpServletRequest request,
|
protected void service(HttpServletRequest request,
|
||||||
HttpServletResponse response)
|
HttpServletResponse response)
|
||||||
|
@@ -23,7 +23,7 @@ import org.glyptodon.guacamole.GuacamoleException;
|
|||||||
import org.glyptodon.guacamole.net.GuacamoleTunnel;
|
import org.glyptodon.guacamole.net.GuacamoleTunnel;
|
||||||
import org.glyptodon.guacamole.net.auth.UserContext;
|
import org.glyptodon.guacamole.net.auth.UserContext;
|
||||||
import org.apache.catalina.websocket.StreamInbound;
|
import org.apache.catalina.websocket.StreamInbound;
|
||||||
import org.glyptodon.guacamole.net.basic.BasicGuacamoleTunnelServlet;
|
import org.glyptodon.guacamole.net.basic.BasicTunnelRequestUtility;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Authenticating tunnel servlet implementation which uses WebSocket as a
|
* Authenticating tunnel servlet implementation which uses WebSocket as a
|
||||||
@@ -41,7 +41,7 @@ public class BasicGuacamoleWebSocketTunnelServlet extends AuthenticatingWebSocke
|
|||||||
@Override
|
@Override
|
||||||
protected GuacamoleTunnel doConnect(HttpServletRequest request)
|
protected GuacamoleTunnel doConnect(HttpServletRequest request)
|
||||||
throws GuacamoleException {
|
throws GuacamoleException {
|
||||||
return BasicGuacamoleTunnelServlet.createTunnel(request);
|
return BasicTunnelRequestUtility.createTunnel(request);
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
Reference in New Issue
Block a user