Chapter 20. guacamole-common

The Java API provided by the Guacamole project is called guacamole-common. It provides a basic means of tunneling data between the JavaScript client provided by guacamole-common-js and the native proxy daemon, guacd, and for dealing with the Guacamole protocol. The purpose of this library is to facilitate the creation of custom tunnels between the JavaScript client and guacd, allowing your Guacamole-driven web application to enforce its own security model, if any, and dictate exactly what connections are established.

HTTP tunnel

The Guacamole Java API implements the HTTP tunnel using a servlet called GuacamoleHTTPTunnelServlet. This servlet handles all requests coming to it over HTTP from the JavaScript client, and translated them into connect, read, or write requests, which each get dispatched to the doConnect(), doRead(), and doWrite() functions accordingly.

Normally, you wouldn't touch the doRead() and doWrite() functions, as these have already been written to properly handle the requests of the JavaScript tunnel, and if you feel the need to touch these functions, you are probably better off writing your own tunnel implementation, although such a thing is difficult to do in a performant way.

When developing an application based on the Guacamole API, you should use GuacamoleHTTPTunnelServlet by extending it, implementing your own version of doConnect(), which is the only abstract function it defines. The tutorial later in this book demonstrating how to write a Guacamole-based web application shows the basics of doing this, but generally, doConnect() is an excellent place for authentication or other validation, as it is the responsibility of doConnect() to create (or not create) the actual tunnel. If doConnect() does not create the tunnel, communication between the JavaScript client and guacd cannot take place, which is an ideal power to have as an authenticator.

The doConnect() function is expected to return a new GuacamoleTunnel, but it is completely up to the implementation to decide how that tunnel is to be created. The already-implemented parts of GuacamoleHTTPTunnelServlet then return the unique identifier of this tunnel to the JavaScript client, allowing its own tunnel implementation to continue to communicate with the tunnel existing on the Java side.

Instances of GuacamoleTunnel are created associated with a GuacamoleSocket, which is the abstract interface surrounding the low-level connection to guacd. Overall, there is a socket (GuacamoleSocket) which provides a TCP connection to guacd. This socket is exposed to GuacamoleTunnel, which provides abstract protocol access around what is actually (but secretly, through the abstraction of the API) a TCP socket.

The Guacamole web application extends this tunnel servlet in order to implement authentication at the lowest possible level, effectively prohibiting communication between the client and any remote desktops unless they have properly authenticated. Your own implementation can be considerably simpler, especially if you don't need authentication:

public class MyGuacamoleTunnelServlet
    extends GuacamoleHTTPTunnelServlet {

    @Override
    protected GuacamoleTunnel doConnect(HttpServletRequest request)
        throws GuacamoleException {

        // Connect to guacd here (this is a STUB)
        GuacamoleSocket socket;

        // Return a new tunnel which uses the connected socket
        return new SimpleGuacamoleTunnel(socket);

    }

}

Using the Guacamole protocol

guacamole-common provides basic low-level support for the Guacamole protocol. This low-level support is leveraged by the HTTP tunnel implementation to satisfy the requirements of the JavaScript client implementation, as the JavaScript client expects the handshake procedure to have already taken place. This support exists through the GuacamoleReader and GuacamoleWriter classes, which are similar to Java's Reader and Writer classes, except that they deal with the Guacamole protocol specifically, and thus have slightly different contracts.

GuacamoleReader

GuacamoleReader provides a very basic read() function which is required to return one or more complete instructions in a char array. It also provides the typical available() function, which informs you whether read() is likely to block the next time it is called, and an even more abstract version of read() called readInstruction() which returns one instruction at a time, wrapped within a GuacamoleInstruction instance.

Normally, you would not need to use this class yourself. It is used by ConfiguredGuacamoleSocket to complete the Guacamole protocol handshake procedure, and it is used by GuacamoleHTTPTunnelServlet within doRead() to implement the reading half of the tunnel.

The only concrete implementation of GuacamoleReader is ReaderGuacamoleReader, which wraps a Java Reader, using that as the source for data to parse into Guacamole instructions. Again, you would not normally directly use this class, nor instantiate it yourself. A working, concrete instance of GuacamoleReader can be retrieved from any GuacamoleSocket or GuacamoleTunnel.

GuacamoleWriter

GuacamoleWriter provides a very basic write() function and a more abstract version called writeInstruction() which writes instances of GuacamoleInstruction. These functions are analogous to the read() and readInstruction() functions provided by GuacamoleReader, and have similar restrictions: the contract imposed by write() requires that written instructions be complete

The only concrete implementation of GuacamoleWriter is WriterGuacamoleWriter, which wraps a Java Writer, using that as the destination for Guacamole instruction data, but you would not normally directly use this class, nor instantiate it yourself. It is used by ConfiguredGuacamoleSocket to complete the Guacamole protocol handshake procedure, and it is used by GuacamoleHTTPTunnelServlet within doWrite() to implement the writing half of the tunnel.

If necessary, a GuacamoleWriter can be retrieved from any GuacamoleSocket or GuacamoleTunnel, but in most cases, the classes provided by the Guacamole Java API which already use GuacamoleWriter will be sufficient.