Table of Contents
While not strictly part of the Java API provided by the Guacamole project, guacamole-ext is a subset of the API used by the Guacamole web application, exposed within a separate project such that extensions, specifically authentication providers, can be written to tweak Guacamole to fit well in existing deployments.
For the sake of ease of development and providing a common
location for configuration of both Guacamole and its extensions,
guacamole-ext provides utility classes for accessing the main
configuration file, guacamole.properties
, and
for accessing the main root directory for housing configuration
files: GUACAMOLE_HOME
.
GuacamoleProperties
is a utility class
for accessing the properties declared within
guacamole.properties
. Each property is
typesafe and handles its own parsing - retrieving a property is
as simple as calling getProperty()
or
getRequiredProperty()
.
Because of this ease-of-access to guacamole.properties within
Guacamole and all extensions, the
guacamole.properties
file is an ideal
place to store unstructured, extension-specific configuration
information.
If you need more structured data than provided by simple
properties, placing XML or some other separate file within
GUACAMOLE_HOME
(or a subdirectory
thereof) is a decent way to achieve this. The
GuacamoleHome
class provides access
to the GUACAMOLE_HOME
directory, abstracting
away the decision process that determines which directory is
considered GUACAMOLE_HOME
.
The main use of guacamole-ext is to provide custom authentication
for Guacamole through the implementation of authentication
providers. An authentication provider is any class which implements
the AuthenticationProvider
interface,
implementing the only function defined by that interface:
getUserContext()
. This function is
required to return a "context" which provides access to only those
users and configurations accessible with the given credentials, and
enforces its own security model.
The credentials given are abstract and while Guacamole the web
application implements a username/password driven login screen, you
are not required to user usernames and passwords; the
Credentials
class given to the
authentication provider provides access to all HTTP parameters in
general, as well as cookies and SSL information.
The Guacamole web application includes a basic authentication
provider implementation which parses an XML file to determine which
users exist, their corresponding passwords, and what configurations
those users have access to. This is the part of Guacamole that reads
the user-mapping.xml
file. If you use a custom
authentication provider for your authentication, this file will
probably not be required.
The community has implemented authentication providers which
access databases, use LDAP, or even perform no authentication at
all, redirecting all users to a single configuration specified in
guacamole.properties
.
A minimal authentication provider is implemented in the tutorials later, and the upstream authentication provider implemented within Guacamole, as well as the authentication providers implemented by the community, are good examples for how authentication can be extended without having to implement a whole new web application.
The SimpleAuthenticationProvider
class
provides a much simpler means of implementing authentication
when you do not require the ability to add and remove users and
connections. It is an abstract class and requires only one
function implementation:
getAuthorizedConfigurations()
.
This function is required to return a
Map
of unique IDs to configurations,
where these configurations are all configurations accessible
with the provided credentials. As before, the credentials given
are abstract. You are not required to use usernames and
passwords.
The configurations referred to by the function name are
instances of GuacamoleConfiguration
(part
of guacamole-common), which is just a wrapper around a protocol
name and set of parameter name/value pairs. The name of the
protocol to use and a set of parameters is the minimum
information required for other parts of the Guacamole API to
complete the handshake required by the Guacamole
protocol.
When a class that extends
SimpleAuthenticationProvider
is asked
for more advanced operations by the web application,
SimpleAuthenticationProvider
simply
returns that there is no permission to do so. This effectively
disables all administrative functionality within the web
interface.
If you choose to go the simple route, most of the rest of this
chapter is irrelevant. Permissions, security model, and various
classes will be discussed that are all handled for you
automatically by
SimpleAuthenticationProvider
.
The UserContext
is the root of all
operations. It is used to list, create, modify, or delete users
and connections, as well as to query available
permissions.
The Guacamole web application uses permissions queries against
the UserContext
to determine what
operations to present, but beware that it is up to the
UserContext
to actually enforce
these restrictions. The Guacamole web application
will not enforce restrictions on behalf of the
UserContext
.
The UserContext
is the sole means of
entry and the sole means of modification available to a
logged-in user. If the UserContext
refuses to perform an operation (by throwing an exception), the
user cannot perform the operation at all.
Access to users and connections is given through
Directory
classes. These
Directory
classes are similar to Java
collections, but they also embody object update semantics.
Objects can be retrieved from a Directory
using its get()
function and added or
removed with add()
and
remove()
respectively, but objects
already in the set can also be updated by passing an updated
object to its update()
function.
An implementation of a Directory
can
rely on these functions to define the semantics surrounding all
operations. The add()
function is
called only when creating new objects, the
update()
function is called only
when updating an object previously retrieved with
get()
, and
remove()
is called only when
removing an existing object by its identifier.
When implementing an
AuthenticationProvider
, you must
ensure that the UserContext
will only
return Directory
classes that
automatically enforce the permissions associated with all
objects and the associated user.
The permissions system within guacamole-ext is an advisory system. It is the means by which an authentication module describes to the web application what a user is allowed to do. The body of permissions granted to a user describes which objects that user can see and what they can do to those objects, and thus suggests how the Guacamole interface should appear to that user.
Permissions are not the means by which access is restricted; they are purely a means of describing access level. An implementation may internally use the permission objects to define restrictions, but this is not required. It is up to the implementation to enforce its own restrictions by throwing exceptions when an operation is not allowed, and to correctly communicate the abilities of individual users through these permissions.
System permissions describe access to operations that manipulate the system as a whole, rather than specific objects. This includes the creation of new objects, as object creation directly affects the system, and per-object controls cannot exist before the object is actually created.
ADMINISTER
The user is a super-user - the Guacamole equivalent of root. They are allowed to manipulate of system-level permissions and all other objects. This permission implies all others.
CREATE_CONNECTION
The user is allowed to create new connections. If a user has this permission, the management interface will display components related to connection creation, such as the "Manage" and "New Connection" buttons.
CREATE_CONNECTION_GROUP
The user is allowed to create new connection groups. If a user has this permission, the management interface will display components related to connection group creation, such as the "Manage" and "New Group" buttons.
CREATE_USER
The user is allowed to create other users. If a user has this permission, the management interface will display components related to user creation, such as the "Manage" and "New User" buttons.
Object permissions describe access to operations that affect a particular object. Guacamole currently defines three types of objects which can be associated with permissions: users, connections, and connection groups. Each object permission associates a single user with an action that may be performed on a single object.
ADMINISTER
The user may grant or revoke permissions involving this object. "Involving", in this case, refers to either side of the permission association, and includes both the user to whom the permission is granted and the object the permission affects.
DELETE
The user may delete this object. This is distinct from the
ADMINISTER
permission which deals only with permissions. A user with this permission will see the "Delete" button when applicable.READ
The user may see that this object exists and read the properties of that object.
Note that the implementation is not required to divulge the true underlying properties of any object. The parameters of a connection, the type or contents of a connection group, the password of a user, etc. all need not be exposed.
This is particularly important from the perspective of security when it comes to connections, as the parameters of a connection are only truly needed when a connection is being modified, and likely should not be exposed otherwise. The actual connection operation is always performed internally by the authentication provider, and thus does not require client-side knowledge of anything beyond the connection's existence.
UPDATE
The user may change the properties of this object.
In the case of users, this means the user's password can be altered. Permissions are not considered properties of a user, nor objects in their own right, but rather associations between a user and an action which may involve another object.
The properties of a connection include its name, protocol, parent connection group, and parameters. The properties of a connection group include its name, type, parent connection group, and children.
Authentication modules must return Connection
objects which
each implement a connect()
function. When this function is
called, the connection must be made if permission is available.
This new separation of concerns makes more sense when you
consider that as connecting is an operation on a
Connection
, access to performing that
operation must be restricted through the
AuthenticationProvider
, and thus must
be enforced within the
AuthenticationProvider
. This
separation also opens the door for things like load balancing of
connections and restricting concurrent access to
connections.
When a connection is made or terminated, it is also the duty
of the authentication module to maintain the connection history.
Each connection has a corresponding list of
ConnectionRecord
objects, each of
which is associated with a past connection or a currently-active
connection. This information will ultimately be exposed to the
user as a history list when they view a connection in the
management interface or as a simple active user count on the
connection, advising the user of existing activity.
Although not used internally by the web application, the web application provides an event system which can be hooked into with listener objects, such that a class within the classpath of Guacamole can receive events when something noteworthy happens in the application layer, and take some sort of action.
Currently, the web application provides events for when the tunnel is opened or closed, and when an authentication attempt succeeds or fails. In most cases, the class listening for these events can also cancel whatever action just occurred.
When a tunnel is connected to by the JavaScript client,
Guacamole informs all installed instances of
TunnelConnectListener
by calling
their tunnelConnected()
function with a
new TunnelConnectEvent
, which contains
the tunnel that was just connected, as well as any associated
credentials. If tunnelConnected()
returns false
, the connect attempt will be
overridden and denied.
When a tunnel is connected to by the JavaScript client,
Guacamole informs all installed instances of
TunnelCloseListener
by calling their
tunnelClosed()
function with a new
TunnelCloseEvent
, which contains the
tunnel that is about to be closed, as well as any associated
credentials. If tunnelClosed()
returns
false
, the attempt close the tunnel
will be overridden and denied, and the tunnel will remain
open.
If a user successfully authenticates with the web application,
Guacamole informs all installed instances of
AuthenticationSuccessListener
by
calling their authenticationSucceeded()
function with a new
AuthenticationSuccessEvent
which
contains the credentials used. The implementation of this
function has the opportunity to cancel the authentication
attempt, effectively denying access despite being otherwise
valid, by returning false
.
If a user fails to authenticate with the web application,
Guacamole informs all installed instances of
AuthenticationFailureListener
by
calling their authenticationFailed()
function with a new
AuthenticationFailureEvent
which
contains the credentials used. Unlike other listeners, this
event cannot be canceled by returning
false
. All failed authentication attempts
"succeed" in failing, and an implementation of
AuthenticationFailureListener
cannot
force an authentication attempt to succeed by denying that
failure.