| <?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 an API exposed by the Guacamole web application within a separate project such that |
| extensions, specifically authentication providers, can be written to tweak Guacamole to fit |
| well in existing deployments.</para> |
| <para>Extensions to Guacamole can:</para> |
| <orderedlist> |
| <listitem> |
| <para>Provide alternative authentication methods and sources of connection/user |
| data.</para> |
| </listitem> |
| <listitem> |
| <para>Theme or brand Guacamole through additional CSS files and static resources.</para> |
| </listitem> |
| <listitem> |
| <para>Extend Guacamole's JavaScript code by providing JavaScript that will be loaded |
| automatically.</para> |
| </listitem> |
| <listitem> |
| <para>Add additional display languages, or alter the translation strings of existing |
| languages.</para> |
| </listitem> |
| </orderedlist> |
| <section xml:id="ext-file-format"> |
| <title>Guacamole extension format</title> |
| <para>Guacamole extensions are standard Java <filename>.jar</filename> files which contain |
| all classes and resources required by the extension, as well as the Guacamole extension |
| manifest. There is no set structure to an extension except that the manifest must be in |
| the root of the archive. Java classes and packages, if any, will be read from the |
| <filename>.jar</filename> relative to the root, as well.</para> |
| <para>Beyond this, the semantics and locations associated with all other resources within |
| the extension are determined by the extension manifest alone.</para> |
| <section xml:id="ext-manifest"> |
| <title>Extension manifest</title> |
| <para>The Guacamole extension manifest is a single JSON file, |
| <filename>guac-manifest.json</filename>, which describes the location of each |
| resource, the type of each resource, and the version of Guacamole that the extension |
| was built for. The manifest can contain the following properties:</para> |
| <informaltable frame="all"> |
| <tgroup cols="2"> |
| <colspec colname="c1" colnum="1" colwidth="1*"/> |
| <colspec colname="c2" colnum="2" colwidth="3*"/> |
| <thead> |
| <row> |
| <entry>Property</entry> |
| <entry>Description</entry> |
| </row> |
| </thead> |
| <tbody> |
| <row> |
| <entry><property>guacamoleVersion</property></entry> |
| <entry> |
| <para>The version string of the Guacamole release that this |
| extension is written for. <emphasis>This property is required |
| for all extensions.</emphasis> The special version string |
| <code>"*"</code> can be used if the extension does not |
| depend on a particular version of Guacamole, but be careful - |
| this will bypass version compatibility checks, and should never |
| be used if the extension does more than basic theming or |
| branding.</para> |
| </entry> |
| </row> |
| <row> |
| <entry><property>name</property></entry> |
| <entry> |
| <para>A human-readable name for the extension. <emphasis>This |
| property is required for all extensions.</emphasis> When |
| your extension is successfully loaded, a message acknowledging |
| the successful loading of your extension by name will be |
| logged.</para> |
| </entry> |
| </row> |
| <row> |
| <entry><property>namespace</property></entry> |
| <entry> |
| <para>A unique string which identifies your extension. |
| <emphasis>This property is required for all |
| extensions.</emphasis> This string should be unique enough |
| that it is unlikely to collide with the namespace of any other |
| extension.</para> |
| <para>If your extension contains static resources, those resources |
| will be served at a path derived from the namespace provided |
| here.</para> |
| </entry> |
| </row> |
| <row> |
| <entry><property>authProviders</property></entry> |
| <entry> |
| <para>An array of the classnames of all |
| <classname>AuthenticationProvider</classname> subclasses |
| provided by this extension.</para> |
| </entry> |
| </row> |
| <row> |
| <entry><property>js</property></entry> |
| <entry> |
| <para>An array of all JavaScript files within the extension. All |
| paths within this array must be relative paths, and will be |
| interpreted relative to the root of the archive.</para> |
| <para>JavaScript files declared here will be automatically loaded |
| when the web application loads within the user's browser.</para> |
| </entry> |
| </row> |
| <row> |
| <entry><property>css</property></entry> |
| <entry> |
| <para>An array of all CSS files within the extension. All paths |
| within this array must be relative paths, and will be |
| interpreted relative to the root of the archive.</para> |
| <para>CSS files declared here will be automatically applied when the |
| web application loads within the user's browser.</para> |
| </entry> |
| </row> |
| <row> |
| <entry><property>html</property></entry> |
| <entry> |
| <para>An array of all HTML files within the extension that should be |
| used to update or replace existing HTML within the Guacamole |
| interface. All paths within this array must be relative paths, |
| and will be interpreted relative to the root of the |
| archive.</para> |
| <para>HTML files declared here will be automatically applied to |
| other HTML within the Guacamole interface when the web |
| application loads within the user's browser. The manner in which |
| the files are applied is dictated by <tag><meta ...></tag> |
| within those same files.</para> |
| </entry> |
| </row> |
| <row> |
| <entry><property>translations</property></entry> |
| <entry> |
| <para>An array of all translation files within the extension. All |
| paths within this array must be relative paths, and will be |
| interpreted relative to the root of the archive.</para> |
| <para>Translation files declared here will be automatically added to |
| the available languages. If a translation file provides a |
| language that already exists within Guacamole, its strings will |
| override the strings of the existing translation.</para> |
| </entry> |
| </row> |
| <row> |
| <entry><property>resources</property></entry> |
| <entry> |
| <para>An object where each property name is the name of a web |
| resource file, and each value is the mimetype for that resource. |
| All paths within this object must be relative paths, and will be |
| interpreted relative to the root of the archive.</para> |
| <para>Web resources declared here will be made available to the |
| application at |
| <filename>app/ext/<replaceable>NAMESPACE</replaceable>/<replaceable>PATH</replaceable></filename>, |
| where <replaceable>NAMESPACE</replaceable> is the value of the |
| <property>namespace</property> property, and |
| <replaceable>PATH</replaceable> is the declared web resource |
| filename.</para> |
| </entry> |
| </row> |
| </tbody> |
| </tgroup> |
| </informaltable> |
| <para>The only absolutely required properties are <property>guacamoleVersion</property>, |
| <property>name</property>, and <property>namespace</property>, as they are used |
| to identify the extension and for compatibility checks. The most minimal |
| <filename>guac-manifest.json</filename> will look something like this:</para> |
| <informalexample> |
| <programlisting>{ |
| "guacamoleVersion" : "0.9.10-incubating", |
| "name" : "My Extension", |
| "namespace" : "my-extension" |
| }</programlisting> |
| </informalexample> |
| <para>This will allow the extension to load, but does absolutely nothing otherwise. |
| Lacking the semantic information provided by the other properties, no other files |
| within the extension will be used. A typical <filename>guac-manifest.json</filename> |
| for an extension providing theming or branding would be more involved:</para> |
| <informalexample> |
| <programlisting>{ |
| |
| "guacamoleVersion" : "0.9.10-incubating", |
| |
| "name" : "My Extension", |
| "namespace" : "my-extension", |
| |
| "css" : [ "theme.css" ], |
| |
| "html" : [ "loginDisclaimer.html" ], |
| |
| "resources" : { |
| "images/logo.png" : "image/png", |
| "images/cancel.png" : "image/png", |
| "images/delete.png" : "image/png" |
| } |
| |
| }</programlisting> |
| </informalexample> |
| </section> |
| <section xml:id="ext-patch-html"> |
| <title>Updating existing HTML</title> |
| <para>The existing HTML structure of Guacamole's interface can be modified by extensions |
| through special "patch" HTML files declared by the <property>html</property> |
| property in <filename>guac-manifest.json</filename>. These files are HTML fragments |
| and are identical to any other HTML file except that they contain Guacamole-specific |
| <tag>meta</tag> tags that instruct Guacamole to modify its own HTML in a |
| particular way. Each <tag>meta</tag> tag takes the following form:</para> |
| <informalexample> |
| <programlisting><meta name="<replaceable>NAME</replaceable>" content="<replaceable>SELECTOR</replaceable>"></programlisting> |
| </informalexample> |
| <para>where <replaceable>SELECTOR</replaceable> is a CSS selector that matches the |
| elements within the Guacamole interface that serve as a basis for the modification, |
| and <replaceable>NAME</replaceable> is any one of the following defined |
| modifications:</para> |
| <informaltable frame="all"> |
| <tgroup cols="2"> |
| <colspec colname="c1" colnum="1" colwidth="1*"/> |
| <colspec colname="c2" colnum="2" colwidth="4*"/> |
| <thead> |
| <row> |
| <entry>Name</entry> |
| <entry>Description</entry> |
| </row> |
| </thead> |
| <tbody> |
| <row> |
| <entry><property>before</property></entry> |
| <entry> |
| <para>Inserts the specified HTML immediately before any element |
| matching the CSS selector.</para> |
| </entry> |
| </row> |
| <row> |
| <entry><property>after</property></entry> |
| <entry> |
| <para>Inserts the specified HTML immediately after any element |
| matching the CSS selector.</para> |
| </entry> |
| </row> |
| <row> |
| <entry><property>replace</property></entry> |
| <entry> |
| <para>Replaces any element matching the CSS selector with the |
| specified HTML.</para> |
| </entry> |
| </row> |
| <row> |
| <entry><property>before-children</property></entry> |
| <entry> |
| <para>Inserts the specified HTML immediately before the first child |
| (if any) of any element matching the CSS selector. If a matching |
| element has no children, the HTML simply becomes the entire |
| contents of the matching element.</para> |
| </entry> |
| </row> |
| <row> |
| <entry><property>after-children</property></entry> |
| <entry> |
| <para>Inserts the specified HTML immediately after the last child |
| (if any) of any element matching the CSS selector. If a matching |
| element has no children, the HTML simply becomes the entire |
| contents of the matching element.</para> |
| </entry> |
| </row> |
| <row> |
| <entry><property>replace-children</property></entry> |
| <entry> |
| <para>Replaces the entire contents of any element matching the CSS |
| selector with the specified HTML.</para> |
| </entry> |
| </row> |
| </tbody> |
| </tgroup> |
| </informaltable> |
| <para>For example, to add a welcome message and link to some corporate privacy policy (a |
| fairly common need), you would add an HTML file like the following:</para> |
| <informalexample> |
| <programlisting><meta name="after" content=".login-ui .login-dialog"> |
| |
| <div class="welcome"> |
| <h2>Welcome to our Guacamole server!</h2> |
| <p> |
| Please be sure to read our <a href="/path/to/some/privacy.html">privacy |
| policy</a> before continuing. |
| </p> |
| </div></programlisting> |
| </informalexample> |
| <para>After the extension is installed and Guacamole is restarted, the "welcome" div and |
| its contents will automatically be inserted directly below the login dialog (the |
| only element that would match <code>.login-ui .login-dialog</code>) as if they were |
| part of Guacamole's HTML in the first place.</para> |
| </section> |
| </section> |
| <section xml:id="ext-environment"> |
| <title>Accessing the server configuration</title> |
| <para>The configuration of the Guacamole server is exposed through the |
| <classname>Environment</classname> interface, specifically the |
| <classname>LocalEnvironment</classname> implementation of this interface. Through |
| <classname>Environment</classname>, you can access all properties declared within |
| <filename>guacamole.properties</filename>, determine the proper hostname/port of |
| <package>guacd</package>, and access the contents of |
| <varname>GUACAMOLE_HOME</varname>.</para> |
| <section xml:id="ext-simple-config"> |
| <title>Custom properties</title> |
| <para>If your extension requires generic, unstructured configuration parameters, |
| <filename>guacamole.properties</filename> is a reasonable and simple location |
| for them. The <classname>Environment</classname> interface provides direct access to |
| <filename>guacamole.properties</filename> and simple mechanisms for reading and |
| parsing the properties therein. The value of a property can be retrieved calling |
| <methodname>getProperty()</methodname>, which will return |
| <constant>null</constant> or a default value for undefined properties, or |
| <methodname>getRequiredProperty()</methodname>, which will throw an exception |
| for undefined properties.</para> |
| <para>For convenience, guacamole-ext contains several pre-defined property base classes |
| for common types:</para> |
| <informaltable frame="all"> |
| <tgroup cols="3"> |
| <colspec colname="c1" colnum="1" colwidth="2*"/> |
| <colspec colname="c2" colnum="2" colwidth="1*"/> |
| <colspec colname="c3" colnum="3" colwidth="4*"/> |
| <thead> |
| <row> |
| <entry>Class Name</entry> |
| <entry>Value Type</entry> |
| <entry>Interpretation</entry> |
| </row> |
| </thead> |
| <tbody> |
| <row> |
| <entry><classname>BooleanGuacamoleProperty</classname></entry> |
| <entry><classname>Boolean</classname></entry> |
| <entry>The values "true" and "false" are parsed as their corresponding |
| <classname>Boolean</classname> values. Any other value results |
| in a parse error.</entry> |
| </row> |
| <row> |
| <entry><classname>IntegerGuacamoleProperty</classname></entry> |
| <entry><classname>Integer</classname></entry> |
| <entry>Numeric strings are parsed as <classname>Integer</classname> |
| values. Non-numeric strings will result in a parse error.</entry> |
| </row> |
| <row> |
| <entry><classname>LongGuacamoleProperty</classname></entry> |
| <entry><classname>Long</classname></entry> |
| <entry>Numeric strings are parsed as <classname>Long</classname> values. |
| Non-numeric strings will result in a parse error.</entry> |
| </row> |
| <row> |
| <entry><classname>StringGuacamoleProperty</classname></entry> |
| <entry><classname>String</classname></entry> |
| <entry>The property value is returned as an untouched |
| <classname>String</classname>. No parsing is performed, and |
| parse errors cannot occur.</entry> |
| </row> |
| <row> |
| <entry><classname>FileGuacamoleProperty</classname></entry> |
| <entry><classname>File</classname></entry> |
| <entry>The property is interpreted as a filename, and a new |
| <classname>File</classname> pointing to that filename is |
| returned. If the filename is invalid, a parse error will be thrown. |
| Note that the file need not exist or be accessible for the filename |
| to be valid.</entry> |
| </row> |
| </tbody> |
| </tgroup> |
| </informaltable> |
| <para>To use these types, you must extend the base class, implementing the |
| <methodname>getName()</methodname> function to identify your property. |
| Typically, you would declare these properties as static members of some class |
| containing all properties relevant to your extension:</para> |
| <informalexample> |
| <programlisting>public class MyProperties { |
| |
| public static <replaceable>MY_PROPERTY</replaceable> = new IntegerGuacamoleProperty() { |
| |
| @Override |
| public String getName() { return "<replaceable>my-property</replaceable>"; } |
| |
| }; |
| |
| }</programlisting> |
| </informalexample> |
| <para>Your property can then be retrieved with <methodname>getProperty()</methodname> or |
| <methodname>getRequiredProperty()</methodname>:</para> |
| <informalexample> |
| <programlisting>Integer value = environment.getProperty(<replaceable>MyProperties.MY_PROPERTY</replaceable>);</programlisting> |
| </informalexample> |
| <para>If you need more sophisticated parsing, you can also implement your own property |
| types by implementing the <classname>GuacamoleProperty</classname> interface. The |
| only functions to implement are <methodname>getName()</methodname>, which returns |
| the name of the property, and <methodname>parseValue()</methodname>, which parses a |
| given string and returns its value.</para> |
| </section> |
| <section xml:id="ext-advanced-config"> |
| <title>Advanced configuration</title> |
| <para>If you need more structured data than provided by simple properties, you can place |
| completely arbitrary files in a hierarchy of your choosing anywhere within |
| <varname>GUACAMOLE_HOME</varname> as long as you avoid placing your files in |
| directories reserved for other purposes as described above.</para> |
| <para>The Environment interface exposes the location of |
| <varname>GUACAMOLE_HOME</varname> through the |
| <methodname>getGuacamoleHome()</methodname> function. This function returns a |
| standard Java <classname>File</classname> which can then be used to locate other |
| files or directories within <varname>GUACAMOLE_HOME</varname>:</para> |
| <informalexample> |
| <programlisting>File myConfigFile = new File(environment.getGuacamoleHome(), "my-config.xml");</programlisting> |
| <para>There is no guarantee that <varname>GUACAMOLE_HOME</varname> or your file will |
| exist, and you should verify this before proceeding further in your extension's |
| configuration process, but once this is done you can simply parse your file as |
| you see fit.</para> |
| </informalexample> |
| </section> |
| </section> |
| <section xml:id="ext-auth-providers"> |
| <title>Authentication providers</title> |
| <para>Guacamole's authentication system is driven by authentication providers, which are |
| classes which implement the <classname>AuthenticationProvider</classname> interface |
| defined by guacamole-ext. When any page within Guacamole is visited, the following |
| process occurs:</para> |
| <orderedlist> |
| <listitem> |
| <para>All currently installed extensions are polled, in lexicographic order of their |
| filenames, by invoking the <methodname>getAuthenticatedUser()</methodname> |
| function with a <classname>Credentials</classname> object constructed with the |
| contents of the HTTP request.</para> |
| <para>The credentials given are abstract. While the Credentials object provides |
| convenience access to a traditional username and password, |
| <emphasis>implementations are not required to use usernames and |
| passwords</emphasis>. The entire contents of the HTTP request is at your |
| disposal, including parameters, cookies, and SSL information.</para> |
| </listitem> |
| <listitem> |
| <para>If an authentication attempt fails, the extension throws either a |
| <classname>GuacamoleInsufficientCredentialsException</classname> (if more |
| credentials are needed before validity can be determined) or |
| <classname>GuacamoleInvalidCredentialsException</classname> (if the |
| credentials are technically sufficient, but are invalid as provided). If all |
| extensions fail to authenticate the user, the contents of the exception thrown |
| by the first extension to fail are used to produce the user login prompt.</para> |
| <para><emphasis>Note that this means there is no "login screen" in Guacamole per se; |
| the prompt for credentials for unauthenticated users is determined purely |
| based on the needs of the extension as declared within the authentication |
| failure itself.</emphasis></para> |
| <para>If an authentication attempt succeeds, the extension returns an instance of |
| <classname>AuthenticatedUser</classname> describing the identity of the user |
| that just authenticated, and no further extensions are polled.</para> |
| </listitem> |
| <listitem> |
| <para>If authentication has succeeded, and thus an |
| <classname>AuthenticatedUser</classname> is available, that |
| <classname>AuthenticatedUser</classname> is passed to the |
| <methodname>getUserContext()</methodname> function of all extensions' |
| authentication providers. Each extension now has the opportunity to provide |
| access to data for a user, even if that extension did not originally |
| authenticate the user. If no <classname>UserContext</classname> is returned for |
| the given <classname>AuthenticatedUser</classname>, then that extension has |
| simply refused to provide data for that user.</para> |
| <para>The Guacamole interface will transparently unify the data from each extension, |
| providing the user with a view of all available connections. If the user has |
| permission to modify or administer any objects associated with an extension, |
| access to the administrative interface will be exposed as well, again with a |
| unified view of all applicable objects.</para> |
| </listitem> |
| </orderedlist> |
| <important> |
| <para>Because authentication is decoupled from data storage/access, <emphasis>you do not |
| need to implement full-blown data storage if you only wish to provide an |
| additional authentication mechanism</emphasis>. You can instead implement only |
| the authentication portion of an <classname>AuthenticationProvider</classname>, and |
| otherwise rely on the storage and features provided by other extensions, such as the |
| <link xmlns:xlink="http://www.w3.org/1999/xlink" linkend="jdbc-auth">database |
| authentication extension</link>.</para> |
| </important> |
| <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 xml:id="ext-simple-auth"> |
| <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> |
| <section xml:id="ext-user-context"> |
| <title>The <classname>UserContext</classname></title> |
| <para>The <classname>UserContext</classname> is the root of all data-related operations. It |
| is used to list, create, modify, or delete users and connections, as well as to query |
| available permissions. If an extension is going to provide access to data of any sort, |
| it must do so through the <classname>UserContext</classname>.</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 xml:id="ext-object-directories"> |
| <title><classname>Directory</classname> classes</title> |
| <para>Access to objects beneath the <classname>UserContext</classname> is given through |
| <classname>Directory</classname> classes. These <classname>Directory</classname> |
| classes are similar to Java collections, but they also embody update and batching |
| 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 xml:id="ext-permissions"> |
| <title>Permissions</title> |
| <para>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.</para> |
| <para><emphasis>Permissions are not the means by which access is restricted</emphasis>; 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.</para> |
| <para>The permissions available to a user are exposed through the |
| <classname>SystemPermissionSet</classname> and |
| <classname>ObjectPermissionSet</classname> classes which are accessible through the |
| <classname>UserContext</classname>. These classes also serve as the means for |
| manipulating the permissions granted to a user.</para> |
| <section> |
| <title xml:id="ext-system-permissions">System permissions</title> |
| <para>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.</para> |
| <variablelist> |
| <varlistentry> |
| <term><constant>ADMINISTER</constant></term> |
| <listitem> |
| <para>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.</para> |
| </listitem> |
| </varlistentry> |
| <varlistentry> |
| <term><constant>CREATE_CONNECTION</constant></term> |
| <listitem> |
| <para>The user is allowed to create new connections. If a user has this |
| permission, the management interface will display components related to |
| connection creation.</para> |
| </listitem> |
| </varlistentry> |
| <varlistentry> |
| <term><constant>CREATE_CONNECTION_GROUP</constant></term> |
| <listitem> |
| <para>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.</para> |
| </listitem> |
| </varlistentry> |
| <varlistentry> |
| <term><constant>CREATE_SHARING_PROFILE</constant></term> |
| <listitem> |
| <para>The user is allowed to create new sharing profiles. If a user has this |
| permission, the management interface will display components related to |
| sharing profile creation.</para> |
| </listitem> |
| </varlistentry> |
| <varlistentry> |
| <term><constant>CREATE_USER</constant></term> |
| <listitem> |
| <para>The user is allowed to create other users. If a user has this |
| permission, the management interface will display components related to |
| user creation.</para> |
| </listitem> |
| </varlistentry> |
| </variablelist> |
| </section> |
| <section> |
| <title xml:id="ext-object-permissions">Object permissions</title> |
| <para>Object permissions describe access to operations that affect a particular object. |
| Guacamole currently defines four types of objects which can be associated with |
| permissions: users, connections, connection groups, and sharing profiles. Each |
| object permission associates a single user with an action that may be performed on a |
| single object.</para> |
| <variablelist> |
| <varlistentry> |
| <term><constant>ADMINISTER</constant></term> |
| <listitem> |
| <para>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.</para> |
| </listitem> |
| </varlistentry> |
| <varlistentry> |
| <term><constant>DELETE</constant></term> |
| <listitem> |
| <para>The user may delete this object. This is distinct from the |
| <constant>ADMINISTER</constant> permission which deals only with |
| permissions. A user with this permission will see the "Delete" button |
| when applicable.</para> |
| </listitem> |
| </varlistentry> |
| <varlistentry> |
| <term><constant>READ</constant></term> |
| <listitem> |
| <para>The user may see that this object exists and read the properties of |
| that object.</para> |
| <para>Note that the implementation is <emphasis>not required to divulge the |
| true underlying properties of any object</emphasis>. The parameters |
| of a connection or sharing profile, the type or contents of a connection |
| group, the password of a user, etc. all need not be exposed.</para> |
| <para>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.</para> |
| </listitem> |
| </varlistentry> |
| <varlistentry> |
| <term><constant>UPDATE</constant></term> |
| <listitem> |
| <para>The user may change the properties of this object.</para> |
| <para>In the case of users, this means the user's password can be altered. |
| <emphasis>Permissions are not considered properties of a |
| user</emphasis>, nor objects in their own right, but rather |
| associations between a user and an action which may involve another |
| object.</para> |
| <para>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. The |
| properties of a sharing profile include its name, primary connection, |
| and parameters.</para> |
| </listitem> |
| </varlistentry> |
| </variablelist> |
| </section> |
| </section> |
| <section xml:id="ext-connections"> |
| <title>Connections</title> |
| <para>Guacamole connections are organized in a hierarchy made up of connection groups, which |
| each act as folders organizing the connections themselves. The hierarchy is accessed |
| through the root-level connection group, exposed by |
| <methodname>getRootConnectionGroup()</methodname> by the |
| <classname>UserContext</classname>. The connections and connection groups exposed |
| beneath the root connection group must also be accessible directly through the |
| connection and connection group directories exposed by |
| <methodname>getConnectionDirectory()</methodname> and |
| <methodname>getConnectionGroupDirectory()</methodname> of the |
| <classname>UserContext</classname>.</para> |
| <para>When a user attempts to use a connection the <methodname>connect()</methodname> of the |
| associated <classname>Connection</classname> object will be invoked. It is then up to |
| the implementation of this function to establish the TCP connection to guacd, perform |
| the connection handshake (most likely via an <classname>InetGuacamoleSocket</classname> |
| wrapped within a <classname>ConfiguredGuacamoleSocket</classname>), and then return a |
| <classname>GuacamoleTunnel</classname> which controls access to the established |
| socket.</para> |
| <para>Extensions may maintain historical record of connection use via |
| <classname>ConnectionRecord</classname> objects, which are exposed both at the |
| <classname>Connection</classname> level and across all connections via the |
| <classname>UserContext</classname>. Such record maintenance is optional, and it is |
| expected that most implementations will simply return empty lists.</para> |
| <important> |
| <para>If connection state will not be tracked by the extension, and the parameters |
| associated with the connection will be known at the time the connection object is |
| created, the <classname>SimpleConnection</classname> implementation of |
| <classname>Connection</classname> can be used to make life easier.</para> |
| </important> |
| </section> |
| <section xml:id="ext-active-connections"> |
| <title>Managing/sharing active connections</title> |
| <para>After a connection has been established, its underlying |
| <classname>GuacamoleTunnel</classname> can be exposed by a |
| <classname>UserContext</classname> through the <classname>Directory</classname> |
| returned by <methodname>getActiveConnectionDirectory()</methodname>. The |
| <classname>ActiveConnection</classname> objects accessible through this |
| <classname>Directory</classname> are the means by which an administrator may monitor |
| or forcibly terminate another user's connection, ultimately resulting in Guacamole |
| invoking the <methodname>close()</methodname> function of the underlying |
| <classname>GuacamoleTunnel</classname>, and also serve as the basis for screen |
| sharing.</para> |
| <para>Screen sharing is implemented through the use of <classname>SharingProfile</classname> |
| objects, exposed through yet another <classname>Directory</classname> beneath the |
| <classname>UserContext</classname>. Each sharing profile is associated with a single |
| connection that it can be used to share, referred to as the "primary connection". If a |
| user has read access to a sharing profile associated with their current connection, that |
| sharing profile will be displayed as an option within <link |
| xmlns:xlink="http://www.w3.org/1999/xlink" linkend="client-share-menu">the share |
| menu of the Guacamole menu</link>.</para> |
| <para>The overall sharing process is as follows:</para> |
| <orderedlist> |
| <listitem> |
| <para>A user, having access to a sharing profile associated with their current |
| active connection, clicks its option within the <link |
| xmlns:xlink="http://www.w3.org/1999/xlink" linkend="client-share-menu">share |
| menu</link>.</para> |
| </listitem> |
| <listitem> |
| <para>Guacamole locates the <classname>ActiveConnection</classname> and invokes its |
| <methodname>getSharingCredentials()</methodname> function with the |
| identifier of the sharing profile. The contents of the returned |
| <classname>UserCredentials</classname> object is used by Guacamole to |
| generate a sharing link which can be given to other users.</para> |
| </listitem> |
| <listitem> |
| <para>When another user visits the sharing link, the credentials embedded in the |
| link are passed to the authentication providers associated with each installed |
| extension. <emphasis>It is up to the extension that originally provided those |
| credentials to authenticate the user and provide them with access to the |
| shared connection.</emphasis></para> |
| </listitem> |
| <listitem> |
| <para>When the user attempts to connect to the shared connection, the extension |
| establishes the connection using the ID of the connection being joined. |
| <emphasis>This is not the connection identifier as dictated by |
| guacamole-ext, but rather <link xmlns:xlink="http://www.w3.org/1999/xlink" |
| linkend="guacamole-protocol-joining">the unique ID assigned by guacd as |
| required by the Guacamole protocol</link>.</emphasis> This ID can be |
| retrieved from a <methodname>ConfiguredGuacamoleSocket</methodname> via |
| <methodname>getConnectionID()</methodname>, and can be passed through a |
| <methodname>GuacamoleConfiguration</methodname> through |
| <methodname>setConnectionID()</methodname> (instead of specifying a |
| protocol, as would be done for a brand new connection).</para> |
| </listitem> |
| </orderedlist> |
| </section> |
| </chapter> |