blob: 6dec3a2d7f33d8fa264fdbbd38385c0c15853011 [file] [log] [blame]
<?xml version="1.0" encoding="UTF-8"?>
<chapter xml:id="guacamole-ext" xmlns="http://docbook.org/ns/docbook"
version="5.0" xml:lang="en" xmlns:xl="http://www.w3.org/1999/xlink"
xmlns:xi="http://www.w3.org/2001/XInclude">
<title>guacamole-ext</title>
<indexterm>
<primary>API</primary>
<secondary>Java</secondary>
</indexterm>
<indexterm>
<primary>guacamole-ext</primary>
</indexterm>
<para>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.</para>
<section>
<title>Common configuration</title>
<para>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, <filename>guacamole.properties</filename>, and
for accessing the main root directory for housing configuration
files: <varname>GUACAMOLE_HOME</varname>.</para>
<section>
<title><classname>GuacamoleProperties</classname></title>
<para><classname>GuacamoleProperties</classname> is a utility class
for accessing the properties declared within
<filename>guacamole.properties</filename>. Each property is
typesafe and handles its own parsing - retrieving a property is
as simple as calling <methodname>getProperty()</methodname> or
<methodname>getRequiredProperty()</methodname>.</para>
<para>Because of this ease-of-access to guacamole.properties within
Guacamole and all extensions, the
<filename>guacamole.properties</filename> file is an ideal
place to store unstructured, extension-specific configuration
information.</para>
</section>
<section>
<title><classname>GuacamoleHome</classname></title>
<para>If you need more structured data than provided by simple
properties, placing XML or some other separate file within
<varname>GUACAMOLE_HOME</varname> (or a subdirectory
thereof) is a decent way to achieve this. The
<classname>GuacamoleHome</classname> class provides access
to the <varname>GUACAMOLE_HOME</varname> directory, abstracting
away the decision process that determines which directory is
considered <varname>GUACAMOLE_HOME</varname>.</para>
</section>
</section>
<section xml:id="auth-providers">
<title>Authentication providers</title>
<para>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 <classname>AuthenticationProvider</classname> interface,
implementing the only function defined by that interface:
<methodname>getUserContext()</methodname>. 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.</para>
<para>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
<classname>Credentials</classname> class given to the
authentication provider provides access to all HTTP parameters in
general, as well as cookies and SSL information.</para>
<para>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 <filename>user-mapping.xml</filename> file. If you use a custom
authentication provider for your authentication, this file will
probably not be required.</para>
<para>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
<filename>guacamole.properties</filename>.</para>
<para>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.</para>
<section>
<title><classname>SimpleAuthenticationProvider</classname></title>
<para>The <classname>SimpleAuthenticationProvider</classname> 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:
<methodname>getAuthorizedConfigurations()</methodname>.</para>
<para>This function is required to return a
<classname>Map</classname> 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.</para>
<para>The configurations referred to by the function name are
instances of <classname>GuacamoleConfiguration</classname> (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.</para>
<para>When a class that extends
<classname>SimpleAuthenticationProvider</classname> is asked
for more advanced operations by the web application,
<classname>SimpleAuthenticationProvider</classname> simply
returns that there is no permission to do so. This effectively
disables all administrative functionality within the web
interface.</para>
<para>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
<classname>SimpleAuthenticationProvider</classname>.</para>
</section>
<section>
<title>The <classname>UserContext</classname></title>
<para>The <classname>UserContext</classname> 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.</para>
<para>The Guacamole web application uses permissions queries against
the <classname>UserContext</classname> to determine what
operations to present, but <emphasis>beware that it is up to the
<classname>UserContext</classname> to actually enforce
these restrictions</emphasis>. The Guacamole web application
will not enforce restrictions on behalf of the
<classname>UserContext</classname>.</para>
<para>The <classname>UserContext</classname> is the sole means of
entry and the sole means of modification available to a
logged-in user. If the <classname>UserContext</classname>
refuses to perform an operation (by throwing an exception), the
user cannot perform the operation at all.</para>
</section>
<section>
<title><classname>Directory</classname> classes</title>
<para>Access to users and connections is given through
<classname>Directory</classname> classes. These
<classname>Directory</classname> classes are similar to Java
collections, but they also embody object update semantics.
Objects can be retrieved from a <classname>Directory</classname>
using its <methodname>get()</methodname> function and added or
removed with <methodname>add()</methodname> and
<methodname>remove()</methodname> respectively, but objects
already in the set can also be updated by passing an updated
object to its <methodname>update()</methodname> function.</para>
<para>An implementation of a <classname>Directory</classname> can
rely on these functions to define the semantics surrounding all
operations. The <methodname>add()</methodname> function is
called only when creating new objects, the
<methodname>update()</methodname> function is called only
when updating an object previously retrieved with
<methodname>get()</methodname>, and
<methodname>remove()</methodname> is called only when
removing an existing object by its identifier.</para>
<para>When implementing an
<classname>AuthenticationProvider</classname>, you must
ensure that the <classname>UserContext</classname> will only
return <classname>Directory</classname> classes that
automatically enforce the permissions associated with all
objects and the associated user.</para>
</section>
<section>
<title>Permissions</title>
<para>The permissions system within guacamole-ext is the means with
which an authentication module communicates with the web
application, informing it of what the user is allowed to do. The
presence or lack of permissions for certain operations dictates
how the web interface displays itself: whether the "Manage"
button is displayed, whether the user or connection management
sections (or both) are displayed, etc.</para>
<para><emphasis>Permissions are not the means through which access
is restricted</emphasis>. An implementation may 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.</para>
<section>
<title>System permissions</title>
<para>System permissions grant 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.</para>
<variablelist>
<varlistentry>
<term><type>ADMINISTER</type></term>
<listitem>
<para>Allows manipulation of system-level
permissions. The semantics of the system-level
<type>ADMINISTER</type> permission are up to
the implementor of the authentication module,
but in general this permission implies all other
permissions. A user having this permission can
implicitly create and manage any object.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><type>CREATE_CONNECTION</type></term>
<listitem>
<para>Allows creation of new connections. If a user has this permission,
they will see the connection management interface and the "Manage"
button. Within this interface, they will be able to create new
connections.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><type>CREATE_CONNECTION_GROUP</type></term>
<listitem>
<para>Allows creation of new connections groups. If a user has this
permission, they will see the connection management interface and
the "Manage" button. Within this interface, they will be able to
create new connection groups.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><type>CREATE_USER</type></term>
<listitem>
<para>Allows creation of new users. If a user has
this permission, they will see the user
management interface and the "Manage"
button.</para>
</listitem>
</varlistentry>
</variablelist>
</section>
<section>
<title>User permissions</title>
<para>User permissions grant access to operations that affect a
specific user. Each user permission has a definite and
single associated user that is the object of the
operation.</para>
<variablelist>
<varlistentry>
<term><type>ADMINISTER</type></term>
<listitem>
<para>Allows changing visibility of the user. A user
with <type>ADMINISTER</type> permission on
another user can add and remove permissions
related to that user. Note that adding or
removing permissions on a user implicitly
requires <type>UPDATE</type> permission on that
user.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><type>DELETE</type></term>
<listitem>
<para>Allows deletion of the associated user. This
is distinct from the <type>ADMINISTER</type>
permission which deals only with modification to
the permissions associated with a user. A user
with this permission will see the "Delete"
button when editing the corresponding
user.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><type>READ</type></term>
<listitem>
<para>Allows the user to be read. A particular user
will not appear in the user management section
unless the user viewing it has <type>READ</type>
permission on that specific user.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><type>UPDATE</type></term>
<listitem>
<para>Allows the user to be updated. This means altering the user's
password or adding or removing permissions from that user. Note the
difference between <type>UPDATE</type> and <type>ADMINISTER</type>:
the <type>UPDATE</type> permission allows the permissions
<emphasis>of</emphasis> a user to be changed, while
<type>ADMINISTER</type> permission allows permissions
<emphasis>relating to</emphasis> a user to be changed. A user
with this permission will see the "Manage" button.</para>
</listitem>
</varlistentry>
</variablelist>
</section>
<section>
<title>Connection permissions</title>
<para>Connection permissions grant access to operations that
affect a specific connection. Each connection permission has
a definite and single associated connection that is the
object of the operation. The semantics of each operation
differ slightly from the similar user permissions, but the
general principles behind them are the same.</para>
<variablelist>
<varlistentry>
<term><type>ADMINISTER</type></term>
<listitem>
<para>Allows changing visibility of the connection. A user with
<type>ADMINISTER</type> permission on a connection can add and
remove permissions related to that connection, and will see the
"Manage" button.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><type>DELETE</type></term>
<listitem>
<para>Allows deletion of the associated connection.
This is distinct from the
<type>ADMINISTER</type> permission which
deals only with modification to the permissions
associated with a connection. A user with this
permission will see the "Delete" button when
editing the corresponding connection.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><type>READ</type></term>
<listitem>
<para>Allows the connection to be read. A particular connection will not
appear in the connection list nor in the connection management
section unless the user viewing it has <type>READ</type> permission
on that specific connection. <type>READ</type> permission is
required for a user to have permission to actually use a connection,
unless that connection is part of a balancing connection group for
which the user has <type>READ</type> permission.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><type>UPDATE</type></term>
<listitem>
<para>Allows the connection to be updated. This means editing the
connection's parameters or changing the connection's protocol. A
user with this permission will see the "Manage" button.</para>
</listitem>
</varlistentry>
</variablelist>
</section>
<section>
<title>Connection group permissions</title>
<para>Connection group permissions grant access to operations that affect a specific
connection group. Connection group permissions are extremely similar to
connection permissions, with some minor differences.</para>
<variablelist>
<varlistentry>
<term><type>ADMINISTER</type></term>
<listitem>
<para>Allows changing visibility of the connection group. A user with
<type>ADMINISTER</type> permission on a connection group can add
and remove permissions related to that connection group, and will
see the "Manage" button. Users with <type>ADMINISTER</type>
permission on a balancing connection group can see the contents of
that group. To users without <type>ADMINISTER</type> permission, a
balancing group looks like a connection.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><type>DELETE</type></term>
<listitem>
<para>Allows deletion of the associated connection group. This is
distinct from the <type>ADMINISTER</type> permission which deals
only with modification to the permissions associated with a
connection group. A user with this permission will see the "Delete"
button when editing the corresponding connection group.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><type>READ</type></term>
<listitem>
<para>Allows the connection group to be read. A particular connection
group will not appear in the connection list nor in the connection
management section unless the user viewing it has <type>READ</type>
permission on that specific connection group. <type>READ</type>
permission is required for a user to have permission to actually use
a connection.</para>
<para>A user with <type>READ</type> permission on a group will also be
able to see any contained connections or groups for which they also
have <type>READ</type> permission. <type>READ</type> permission is
not sufficient to see the contents of a balancing group.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><type>UPDATE</type></term>
<listitem>
<para>Allows the connection group to be updated. This means editing the
connection group's name, type, or contents. A user with this
permission will see the "Manage" button.</para>
</listitem>
</varlistentry>
</variablelist>
</section>
</section>
<section>
<title>Connections and history</title>
<para>Authentication modules must return <classname>Connection</classname> objects which
each implement a <methodname>connect()</methodname> function. When this function is
called, the connection must be made if permission is available.</para>
<para>This new separation of concerns makes more sense when you
consider that as connecting is an operation on a
<classname>Connection</classname>, access to performing that
operation must be restricted through the
<classname>AuthenticationProvider</classname>, and thus must
be enforced within the
<classname>AuthenticationProvider</classname>. This
separation also opens the door for things like load balancing of
connections and restricting concurrent access to
connections.</para>
<para>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
<classname>ConnectionRecord</classname> 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.</para>
</section>
</section>
<section xml:id="event-listeners">
<title>Event listeners</title>
<para>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.</para>
<para>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.</para>
<section xml:id="tunnel-connect-listener">
<title><classname>TunnelConnectListener</classname></title>
<para>When a tunnel is connected to by the JavaScript client,
Guacamole informs all installed instances of
<classname>TunnelConnectListener</classname> by calling
their <methodname>tunnelConnected()</methodname> function with a
new <classname>TunnelConnectEvent</classname>, which contains
the tunnel that was just connected, as well as any associated
credentials. If <methodname>tunnelConnected()</methodname>
returns <constant>false</constant>, the connect attempt will be
overridden and denied.</para>
</section>
<section xml:id="tunnel-close-listener">
<title><classname>TunnelCloseListener</classname></title>
<para>When a tunnel is connected to by the JavaScript client,
Guacamole informs all installed instances of
<classname>TunnelCloseListener</classname> by calling their
<methodname>tunnelClosed()</methodname> function with a new
<classname>TunnelCloseEvent</classname>, which contains the
tunnel that is about to be closed, as well as any associated
credentials. If <methodname>tunnelClosed()</methodname> returns
<constant>false</constant>, the attempt close the tunnel
will be overridden and denied, and the tunnel will remain
open.</para>
</section>
<section xml:id="authentication-success-listener">
<title><classname>AuthenticationSuccessListener</classname></title>
<para>If a user successfully authenticates with the web application,
Guacamole informs all installed instances of
<classname>AuthenticationSuccessListener</classname> by
calling their <methodname>authenticationSucceeded()</methodname>
function with a new
<classname>AuthenticationSuccessEvent</classname> 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 <constant>false</constant>.</para>
</section>
<section xml:id="authentication-failure-listener">
<title><classname>AuthenticationFailureListener</classname></title>
<para>If a user fails to authenticate with the web application,
Guacamole informs all installed instances of
<classname>AuthenticationFailureListener</classname> by
calling their <methodname>authenticationFailed()</methodname>
function with a new
<classname>AuthenticationFailureEvent</classname> which
contains the credentials used. Unlike other listeners, this
event cannot be canceled by returning
<constant>false</constant>. All failed authentication attempts
"succeed" in failing, and an implementation of
<classname>AuthenticationFailureListener</classname> cannot
force an authentication attempt to succeed by denying that
failure.</para>
</section>
</section>
</chapter>