doc/gug/custom-auth.html (523 lines of code) (raw):
<!DOCTYPE html>
<html class="writer-html5" lang="en" >
<head>
<meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Custom authentication — Apache Guacamole Manual v1.5.5</title>
<link rel="stylesheet" href="_static/pygments.css" type="text/css" />
<link rel="stylesheet" href="_static/css/theme.css" type="text/css" />
<link rel="stylesheet" href="_static/tabs.css" type="text/css" />
<link rel="stylesheet" href="_static/gug.css" type="text/css" />
<!--[if lt IE 9]>
<script src="_static/js/html5shiv.min.js"></script>
<![endif]-->
<script src="_static/jquery.js?v=5d32c60e"></script>
<script src="_static/_sphinx_javascript_frameworks_compat.js?v=2cd50e6c"></script>
<script src="_static/documentation_options.js?v=5929fcd5"></script>
<script src="_static/doctools.js?v=888ff710"></script>
<script src="_static/sphinx_highlight.js?v=dc90522c"></script>
<script src="_static/tabs.js?v=3ee01567"></script>
<script src="_static/js/theme.js"></script>
<link rel="index" title="Index" href="genindex.html" />
<link rel="search" title="Search" href="search.html" />
<link rel="next" title="Event listeners" href="event-listeners.html" />
<link rel="prev" title="Adding new protocols" href="custom-protocols.html" />
</head>
<body class="wy-body-for-nav">
<div class="wy-grid-for-nav">
<nav data-toggle="wy-nav-shift" class="wy-nav-side">
<div class="wy-side-scroll">
<div class="wy-side-nav-search" >
<a href="index.html" class="icon icon-home">
Apache Guacamole
</a>
<div class="version">
1.5.5
</div>
<div role="search">
<form id="rtd-search-form" class="wy-form" action="search.html" method="get">
<input type="text" name="q" placeholder="Search docs" aria-label="Search docs" />
<input type="hidden" name="check_keywords" value="yes" />
<input type="hidden" name="area" value="default" />
</form>
</div>
</div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu">
<p class="caption" role="heading"><span class="caption-text">Overview</span></p>
<ul>
<li class="toctree-l1"><a class="reference internal" href="introduction.html">Introduction</a></li>
</ul>
<p class="caption" role="heading"><span class="caption-text">User's Guide</span></p>
<ul>
<li class="toctree-l1"><a class="reference internal" href="guacamole-architecture.html">Implementation and architecture</a></li>
<li class="toctree-l1"><a class="reference internal" href="installing-guacamole.html">Installing Guacamole natively</a></li>
<li class="toctree-l1"><a class="reference internal" href="guacamole-docker.html">Installing Guacamole with Docker</a></li>
<li class="toctree-l1"><a class="reference internal" href="reverse-proxy.html">Proxying Guacamole</a></li>
<li class="toctree-l1"><a class="reference internal" href="configuring-guacamole.html">Configuring Guacamole</a></li>
<li class="toctree-l1"><a class="reference internal" href="jdbc-auth.html">Database authentication</a></li>
<li class="toctree-l1"><a class="reference internal" href="ldap-auth.html">LDAP authentication</a></li>
<li class="toctree-l1"><a class="reference internal" href="vault.html">Retrieving secrets from a vault</a></li>
<li class="toctree-l1"><a class="reference internal" href="duo-auth.html">Duo two-factor authentication</a></li>
<li class="toctree-l1"><a class="reference internal" href="totp-auth.html">TOTP two-factor authentication</a></li>
<li class="toctree-l1"><a class="reference internal" href="header-auth.html">HTTP header authentication</a></li>
<li class="toctree-l1"><a class="reference internal" href="json-auth.html">Encrypted JSON authentication</a></li>
<li class="toctree-l1"><a class="reference internal" href="cas-auth.html">CAS Authentication</a></li>
<li class="toctree-l1"><a class="reference internal" href="openid-auth.html">OpenID Connect Authentication</a></li>
<li class="toctree-l1"><a class="reference internal" href="saml-auth.html">SAML Authentication</a></li>
<li class="toctree-l1"><a class="reference internal" href="radius-auth.html">RADIUS Authentication</a></li>
<li class="toctree-l1"><a class="reference internal" href="adhoc-connections.html">Ad-hoc Connections</a></li>
<li class="toctree-l1"><a class="reference internal" href="using-guacamole.html">Using Guacamole</a></li>
<li class="toctree-l1"><a class="reference internal" href="recording-playback.html">Viewing session recordings in-browser</a></li>
<li class="toctree-l1"><a class="reference internal" href="administration.html">Administration</a></li>
<li class="toctree-l1"><a class="reference internal" href="troubleshooting.html">Troubleshooting</a></li>
</ul>
<p class="caption" role="heading"><span class="caption-text">Developer's Guide</span></p>
<ul class="current">
<li class="toctree-l1"><a class="reference internal" href="guacamole-protocol.html">The Guacamole protocol</a></li>
<li class="toctree-l1"><a class="reference internal" href="libguac.html">libguac</a></li>
<li class="toctree-l1"><a class="reference internal" href="guacamole-common.html">guacamole-common</a></li>
<li class="toctree-l1"><a class="reference internal" href="guacamole-common-js.html">guacamole-common-js</a></li>
<li class="toctree-l1"><a class="reference internal" href="guacamole-ext.html">guacamole-ext</a></li>
<li class="toctree-l1"><a class="reference internal" href="custom-protocols.html">Adding new protocols</a></li>
<li class="toctree-l1 current"><a class="current reference internal" href="#">Custom authentication</a><ul>
<li class="toctree-l2"><a class="reference internal" href="#guacamoles-authentication-model">Guacamole’s authentication model</a></li>
<li class="toctree-l2"><a class="reference internal" href="#a-guacamole-extension-skeleton">A Guacamole extension skeleton</a></li>
<li class="toctree-l2"><a class="reference internal" href="#building-the-extension">Building the extension</a></li>
<li class="toctree-l2"><a class="reference internal" href="#configuration-and-authentication">Configuration and authentication</a></li>
<li class="toctree-l2"><a class="reference internal" href="#parsing-the-configuration">Parsing the configuration</a></li>
<li class="toctree-l2"><a class="reference internal" href="#installing-the-extension">Installing the extension</a></li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="event-listeners.html">Event listeners</a></li>
<li class="toctree-l1"><a class="reference internal" href="writing-you-own-guacamole-app.html">Writing your own Guacamole application</a></li>
</ul>
<p class="caption" role="heading"><span class="caption-text">Appendices</span></p>
<ul>
<li class="toctree-l1"><a class="reference internal" href="protocol-reference.html">Guacamole protocol reference</a></li>
</ul>
</div>
</div>
</nav>
<section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" >
<i data-toggle="wy-nav-top" class="fa fa-bars"></i>
<a href="index.html">Apache Guacamole</a>
</nav>
<div class="wy-nav-content">
<div class="rst-content">
<div role="navigation" aria-label="Page navigation">
<ul class="wy-breadcrumbs">
<li><a href="index.html" class="icon icon-home" aria-label="Home"></a></li>
<li class="breadcrumb-item active">Custom authentication</li>
<li class="wy-breadcrumbs-aside">
<a href="_sources/custom-auth.md.txt" rel="nofollow"> View page source</a>
</li>
</ul>
<hr/>
</div>
<div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article">
<div itemprop="articleBody">
<section id="custom-authentication">
<h1>Custom authentication<a class="headerlink" href="#custom-authentication" title="Link to this heading"></a></h1>
<p>Guacamole’s authentication layer is designed to be extendable such that users
can integrate Guacamole into existing authentication systems without having to
resort to writing their own web application around the Guacamole API.</p>
<p>The web application comes with a default authentication mechanism which uses an
XML file to associate users with connections. Extensions for Guacamole that
provide LDAP-based authentication or database-based authentication have also
been developed.</p>
<p>To demonstrate the principles involved, we will implement a very simple
authentication extension which associates a single user/password pair with a
single connection, with all this information saved in properties inside the
<code class="docutils literal notranslate"><span class="pre">guacamole.properties</span></code> file.</p>
<p>In general, all other authentication extensions for Guacamole will use the
principles demonstrated here. This tutorial demonstrates the simplest way to
create an authentication extension for Guacamole - an authentication extension
that does not support management of users and connections via the web
interface.</p>
<section id="guacamoles-authentication-model">
<span id="custom-auth-model"></span><h2>Guacamole’s authentication model<a class="headerlink" href="#guacamoles-authentication-model" title="Link to this heading"></a></h2>
<p>When you view any page in Guacamole, whether that be the login screen or the
client interface, the page makes an authentication attempt with the web
application, sending all available credentials. After entering your username
and password, the exact same process occurs, except the web application
receives the username and password as well.</p>
<p>The web application handles this authentication attempt by collecting all
credentials available and passing them to designated classes called
“authentication providers”. Given the set of credentials, authentication
providers return a context object that provides restricted access to other
users and connections, if any.</p>
</section>
<section id="a-guacamole-extension-skeleton">
<span id="custom-auth-skeleton"></span><h2>A Guacamole extension skeleton<a class="headerlink" href="#a-guacamole-extension-skeleton" title="Link to this heading"></a></h2>
<p>For simplicity’s sake, and because this is how things are done upstream in the
Guacamole project, we will use Maven to build our extension.</p>
<p>The bare minimum required for a Guacamole authentication extension is a
<code class="docutils literal notranslate"><span class="pre">pom.xml</span></code> file listing guacamole-ext as a dependency, a single .java file
implementing our stub of an authentication provider, and a <code class="docutils literal notranslate"><span class="pre">guac-manifest.json</span></code>
file describing the extension and pointing to our authentication provider
class.</p>
<p>In our stub, we won’t actually do any authentication yet; we’ll just
universally reject all authentication attempts by returning <code class="docutils literal notranslate"><span class="pre">null</span></code> for any
credentials given. You can verify that this is what happens by checking the
server logs.</p>
<div class="highlight-xml notranslate"><div class="highlight"><pre><span></span><span class="nt"><project</span><span class="w"> </span><span class="na">xmlns=</span><span class="s">"http://maven.apache.org/POM/4.0.0"</span>
<span class="w"> </span><span class="na">xmlns:xsi=</span><span class="s">"http://www.w3.org/2001/XMLSchema-instance"</span>
<span class="w"> </span><span class="na">xsi:schemaLocation=</span><span class="s">"http://maven.apache.org/POM/4.0.0</span>
<span class="s"> http://maven.apache.org/maven-v4_0_0.xsd"</span><span class="nt">></span>
<span class="w"> </span><span class="nt"><modelVersion></span>4.0.0<span class="nt"></modelVersion></span>
<span class="w"> </span><span class="nt"><groupId></span>org.apache.guacamole<span class="nt"></groupId></span>
<span class="w"> </span><span class="nt"><artifactId></span>guacamole-auth-tutorial<span class="nt"></artifactId></span>
<span class="w"> </span><span class="nt"><packaging></span>jar<span class="nt"></packaging></span>
<span class="w"> </span><span class="nt"><version></span>1.5.5<span class="nt"></version></span>
<span class="w"> </span><span class="nt"><name></span>guacamole-auth-tutorial<span class="nt"></name></span>
<span class="w"> </span><span class="nt"><properties></span>
<span class="w"> </span><span class="nt"><project.build.sourceEncoding></span>UTF-8<span class="nt"></project.build.sourceEncoding></span>
<span class="w"> </span><span class="nt"></properties></span>
<span class="w"> </span><span class="nt"><build></span>
<span class="w"> </span><span class="nt"><plugins></span>
<span class="w"> </span><span class="cm"><!-- Written for Java 8 --></span>
<span class="w"> </span><span class="nt"><plugin></span>
<span class="w"> </span><span class="nt"><groupId></span>org.apache.maven.plugins<span class="nt"></groupId></span>
<span class="w"> </span><span class="nt"><artifactId></span>maven-compiler-plugin<span class="nt"></artifactId></span>
<span class="w"> </span><span class="nt"><version></span>3.3<span class="nt"></version></span>
<span class="w"> </span><span class="nt"><configuration></span>
<span class="w"> </span><span class="nt"><source></span>1.8<span class="nt"></source></span>
<span class="w"> </span><span class="nt"><target></span>1.8<span class="nt"></target></span>
<span class="w"> </span><span class="nt"></configuration></span>
<span class="w"> </span><span class="nt"></plugin></span>
<span class="w"> </span><span class="nt"></plugins></span>
<span class="w"> </span><span class="nt"></build></span>
<span class="w"> </span><span class="nt"><dependencies></span>
<span class="w"> </span><span class="cm"><!-- Guacamole Extension API --></span>
<span class="w"> </span><span class="nt"><dependency></span>
<span class="w"> </span><span class="nt"><groupId></span>org.apache.guacamole<span class="nt"></groupId></span>
<span class="w"> </span><span class="nt"><artifactId></span>guacamole-ext<span class="nt"></artifactId></span>
<span class="w"> </span><span class="nt"><version></span>1.5.5<span class="nt"></version></span>
<span class="w"> </span><span class="nt"><scope></span>provided<span class="nt"></scope></span>
<span class="w"> </span><span class="nt"></dependency></span>
<span class="w"> </span><span class="nt"></dependencies></span>
<span class="nt"></project></span>
</pre></div>
</div>
<p>We won’t need to update this <code class="docutils literal notranslate"><span class="pre">pom.xml</span></code> throughout the rest of the tutorial.
Even after adding new files, Maven will just find them and compile as
necessary.</p>
<p>Naturally, we need the actual authentication extension skeleton code. While
you can put this in whatever file and package you want, for the sake of this
tutorial, we will assume you are using
<code class="docutils literal notranslate"><span class="pre">org.apache.guacamole.auth.TutorialAuthenticationProvider</span></code>.</p>
<div class="highlight-java notranslate"><div class="highlight"><pre><span></span><span class="kn">package</span><span class="w"> </span><span class="nn">org.apache.guacamole.auth</span><span class="p">;</span>
<span class="kn">import</span><span class="w"> </span><span class="nn">java.util.Map</span><span class="p">;</span>
<span class="kn">import</span><span class="w"> </span><span class="nn">org.apache.guacamole.GuacamoleException</span><span class="p">;</span>
<span class="kn">import</span><span class="w"> </span><span class="nn">org.apache.guacamole.net.auth.simple.SimpleAuthenticationProvider</span><span class="p">;</span>
<span class="kn">import</span><span class="w"> </span><span class="nn">org.apache.guacamole.net.auth.Credentials</span><span class="p">;</span>
<span class="kn">import</span><span class="w"> </span><span class="nn">org.apache.guacamole.protocol.GuacamoleConfiguration</span><span class="p">;</span>
<span class="cm">/**</span>
<span class="cm"> * Authentication provider implementation intended to demonstrate basic use</span>
<span class="cm"> * of Guacamole's extension API. The credentials and connection information for</span>
<span class="cm"> * a single user are stored directly in guacamole.properties.</span>
<span class="cm"> */</span>
<span class="kd">public</span><span class="w"> </span><span class="kd">class</span> <span class="nc">TutorialAuthenticationProvider</span><span class="w"> </span><span class="kd">extends</span><span class="w"> </span><span class="n">SimpleAuthenticationProvider</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="nd">@Override</span>
<span class="w"> </span><span class="kd">public</span><span class="w"> </span><span class="n">String</span><span class="w"> </span><span class="nf">getIdentifier</span><span class="p">()</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="s">"tutorial"</span><span class="p">;</span>
<span class="w"> </span><span class="p">}</span>
<span class="w"> </span><span class="nd">@Override</span>
<span class="w"> </span><span class="kd">public</span><span class="w"> </span><span class="n">Map</span><span class="o"><</span><span class="n">String</span><span class="p">,</span><span class="w"> </span><span class="n">GuacamoleConfiguration</span><span class="o">></span>
<span class="w"> </span><span class="nf">getAuthorizedConfigurations</span><span class="p">(</span><span class="n">Credentials</span><span class="w"> </span><span class="n">credentials</span><span class="p">)</span>
<span class="w"> </span><span class="kd">throws</span><span class="w"> </span><span class="n">GuacamoleException</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="c1">// Do nothing ... yet</span>
<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="kc">null</span><span class="p">;</span><span class="w"> </span>
<span class="w"> </span><span class="p">}</span>
<span class="p">}</span>
</pre></div>
</div>
<p>To conform with Maven, this skeleton file must be placed within
<code class="docutils literal notranslate"><span class="pre">src/main/java/org/apache/guacamole/auth</span></code> as
<code class="docutils literal notranslate"><span class="pre">TutorialAuthenticationProvider.java</span></code>.</p>
<p>Notice how simple the authentication provider is. The
<code class="docutils literal notranslate"><span class="pre">SimpleAuthenticationProvider</span></code> base class simplifies the
<code class="docutils literal notranslate"><span class="pre">AuthenticationProvider</span></code> interface, requiring nothing more than a unique
identifier (we will use “tutorial”) and a single getAuthorizedConfigurations()
implementation, which must return a <code class="docutils literal notranslate"><span class="pre">Map</span></code> of <code class="docutils literal notranslate"><span class="pre">GuacamoleConfiguration</span></code> each
associated with some arbitrary unique ID. This unique ID will be presented to
the user in the connection list after they log in.</p>
<p>For now, <code class="docutils literal notranslate"><span class="pre">getAuthorizedConfigurations()</span></code> will just return <code class="docutils literal notranslate"><span class="pre">null</span></code>. This will
cause Guacamole to report an invalid login for every attempt. Note that there
is a difference in semantics between returning an empty map and returning
<code class="docutils literal notranslate"><span class="pre">null</span></code>, as the former indicates the credentials are authorized but simply have
no associated configurations, while the latter indicates the credentials are
not authorized at all.</p>
<p>The only remaining piece for the overall skeleton to be complete is a
<code class="docutils literal notranslate"><span class="pre">guac-manifest.json</span></code> file. <em>This file is absolutely required for all Guacamole
extensions.</em> The <code class="docutils literal notranslate"><span class="pre">guac-manifest.json</span></code> format is described in more detail in
<a class="reference internal" href="guacamole-ext.html"><span class="doc std std-doc">guacamole-ext</span></a>. It provides for quite a few properties, but for our
authentication extension we are mainly interested in the Guacamole version
sanity check (to make sure an extension built for the API of Guacamole version
X is not accidentally used against version Y) and telling Guacamole where to
find our authentication provider class.</p>
<p>The Guacamole extension format requires that <code class="docutils literal notranslate"><span class="pre">guac-manifest.json</span></code> be placed in
the root directory of the extension <code class="docutils literal notranslate"><span class="pre">.jar</span></code> file. To accomplish this with Maven,
we place it within the <code class="docutils literal notranslate"><span class="pre">src/main/resources</span></code> directory. Maven will automatically
pick it up during the build and include it within the <code class="docutils literal notranslate"><span class="pre">.jar</span></code>.</p>
<div class="highlight-json notranslate"><div class="highlight"><pre><span></span><span class="p">{</span>
<span class="w"> </span><span class="nt">"guacamoleVersion"</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="s2">"1.5.5"</span><span class="p">,</span>
<span class="w"> </span><span class="nt">"name"</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="s2">"Tutorial Authentication Extension"</span><span class="p">,</span>
<span class="w"> </span><span class="nt">"namespace"</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="s2">"guac-auth-tutorial"</span><span class="p">,</span>
<span class="w"> </span><span class="nt">"authProviders"</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="p">[</span>
<span class="w"> </span><span class="s2">"org.apache.guacamole.auth.TutorialAuthenticationProvider"</span>
<span class="w"> </span><span class="p">]</span>
<span class="p">}</span>
</pre></div>
</div>
</section>
<section id="building-the-extension">
<span id="custom-auth-building"></span><h2>Building the extension<a class="headerlink" href="#building-the-extension" title="Link to this heading"></a></h2>
<p>Once all three of the above files are in place, the extension will build, and
can even be installed within Guacamole (see <a class="reference internal" href="#custom-auth-installing"><span class="std std-ref">Installing the extension</span></a> at the
end of this chapter), even though it is just a skeleton at this point. It won’t
do anything yet other than reject all authentication attempts, but it’s good to
at least try building the extension to make sure nothing is missing and that
all steps have been followed correctly so far:</p>
<div class="highlight-console notranslate"><div class="highlight"><pre><span></span><span class="gp">$ </span>mvn<span class="w"> </span>package
<span class="go">[INFO] Scanning for projects...</span>
<span class="go">[INFO] ------------------------------------------------------------------------</span>
<span class="go">[INFO] Building guacamole-auth-tutorial 1.5.5</span>
<span class="go">[INFO] ------------------------------------------------------------------------</span>
<span class="go">...</span>
<span class="go">[INFO] ------------------------------------------------------------------------</span>
<span class="go">[INFO] BUILD SUCCESS</span>
<span class="go">[INFO] ------------------------------------------------------------------------</span>
<span class="go">[INFO] Total time: 2.345 s</span>
<span class="go">[INFO] Finished at: 2015-12-16T13:39:00-08:00</span>
<span class="go">[INFO] Final Memory: 14M/138M</span>
<span class="go">[INFO] ------------------------------------------------------------------------</span>
<span class="gp">$</span>
</pre></div>
</div>
<p>Assuming you see the “<code class="docutils literal notranslate"><span class="pre">BUILD</span> <span class="pre">SUCCESS</span></code>” message when you build the extension,
there will be a new file, <code class="docutils literal notranslate"><span class="pre">target/guacamole-auth-tutorial-1.5.5.jar</span></code>, which can
be installed within Guacamole and tested. If you changed the name or version of
the project in the <code class="docutils literal notranslate"><span class="pre">pom.xml</span></code> file, the name of this new <code class="docutils literal notranslate"><span class="pre">.jar</span></code> file will be
different, but it can still be found within <code class="docutils literal notranslate"><span class="pre">target/</span></code>.</p>
</section>
<section id="configuration-and-authentication">
<span id="custom-auth-config"></span><h2>Configuration and authentication<a class="headerlink" href="#configuration-and-authentication" title="Link to this heading"></a></h2>
<p>Once we receive credentials, we need to validate those credentials against the
associated properties in <code class="docutils literal notranslate"><span class="pre">guacamole.properties</span></code> (our source of authentication
information for the sake of this tutorial).</p>
<p>We will define four properties:</p>
<dl class="simple myst">
<dt><code class="docutils literal notranslate"><span class="pre">tutorial-user</span></code></dt><dd><p>The name of the only user we accept.</p>
</dd>
<dt><code class="docutils literal notranslate"><span class="pre">tutorial-password</span></code></dt><dd><p>The password we require for the user specified to be authenticated.</p>
</dd>
<dt><code class="docutils literal notranslate"><span class="pre">tutorial-protocol</span></code></dt><dd><p>The protocol of the configuration this user is authorized to use, which
will be sent to guacd when the user logs in and selects their connection.</p>
</dd>
<dt><code class="docutils literal notranslate"><span class="pre">tutorial-parameters</span></code></dt><dd><p>A comma-delimited list of <code class="docutils literal notranslate"><span class="pre">name=value</span></code> pairs. For the sake of simplicity,
we’ll assume there will never be any commas in the values.</p>
</dd>
</dl>
<p>If the username and password match what is stored in the file, we read the
configuration information, store it in a <code class="docutils literal notranslate"><span class="pre">GuacamoleConfiguration</span></code>, and return
the configuration within a set, telling Guacamole that this user is authorized
but only to access the configurations returned.</p>
<p>Upstream, we always place the properties of authentication providers in their
own class, and so we will also do that here in this tutorial, as it keeps
things organized.</p>
<div class="highlight-java notranslate"><div class="highlight"><pre><span></span><span class="kn">package</span><span class="w"> </span><span class="nn">org.apache.guacamole.auth</span><span class="p">;</span>
<span class="kn">import</span><span class="w"> </span><span class="nn">org.apache.guacamole.properties.StringGuacamoleProperty</span><span class="p">;</span>
<span class="cm">/**</span>
<span class="cm"> * Utility class containing all properties used by the custom authentication</span>
<span class="cm"> * tutorial. The properties defined here must be specified within</span>
<span class="cm"> * guacamole.properties to configure the tutorial authentication provider.</span>
<span class="cm"> */</span>
<span class="kd">public</span><span class="w"> </span><span class="kd">class</span> <span class="nc">TutorialGuacamoleProperties</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="cm">/**</span>
<span class="cm"> * This class should not be instantiated.</span>
<span class="cm"> */</span>
<span class="w"> </span><span class="kd">private</span><span class="w"> </span><span class="nf">TutorialGuacamoleProperties</span><span class="p">()</span><span class="w"> </span><span class="p">{}</span>
<span class="w"> </span><span class="cm">/**</span>
<span class="cm"> * The only user to allow.</span>
<span class="cm"> */</span>
<span class="w"> </span><span class="kd">public</span><span class="w"> </span><span class="kd">static</span><span class="w"> </span><span class="kd">final</span><span class="w"> </span><span class="n">StringGuacamoleProperty</span><span class="w"> </span><span class="n">TUTORIAL_USER</span><span class="w"> </span><span class="o">=</span><span class="w"> </span>
<span class="w"> </span><span class="k">new</span><span class="w"> </span><span class="n">StringGuacamoleProperty</span><span class="p">()</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="nd">@Override</span>
<span class="w"> </span><span class="kd">public</span><span class="w"> </span><span class="n">String</span><span class="w"> </span><span class="nf">getName</span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="s">"tutorial-user"</span><span class="p">;</span><span class="w"> </span><span class="p">}</span>
<span class="w"> </span><span class="p">};</span>
<span class="w"> </span><span class="cm">/**</span>
<span class="cm"> * The password required for the specified user.</span>
<span class="cm"> */</span>
<span class="w"> </span><span class="kd">public</span><span class="w"> </span><span class="kd">static</span><span class="w"> </span><span class="kd">final</span><span class="w"> </span><span class="n">StringGuacamoleProperty</span><span class="w"> </span><span class="n">TUTORIAL_PASSWORD</span><span class="w"> </span><span class="o">=</span><span class="w"> </span>
<span class="w"> </span><span class="k">new</span><span class="w"> </span><span class="n">StringGuacamoleProperty</span><span class="p">()</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="nd">@Override</span>
<span class="w"> </span><span class="kd">public</span><span class="w"> </span><span class="n">String</span><span class="w"> </span><span class="nf">getName</span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="s">"tutorial-password"</span><span class="p">;</span><span class="w"> </span><span class="p">}</span>
<span class="w"> </span><span class="p">};</span>
<span class="w"> </span><span class="cm">/**</span>
<span class="cm"> * The protocol to use when connecting.</span>
<span class="cm"> */</span>
<span class="w"> </span><span class="kd">public</span><span class="w"> </span><span class="kd">static</span><span class="w"> </span><span class="kd">final</span><span class="w"> </span><span class="n">StringGuacamoleProperty</span><span class="w"> </span><span class="n">TUTORIAL_PROTOCOL</span><span class="w"> </span><span class="o">=</span><span class="w"> </span>
<span class="w"> </span><span class="k">new</span><span class="w"> </span><span class="n">StringGuacamoleProperty</span><span class="p">()</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="nd">@Override</span>
<span class="w"> </span><span class="kd">public</span><span class="w"> </span><span class="n">String</span><span class="w"> </span><span class="nf">getName</span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="s">"tutorial-protocol"</span><span class="p">;</span><span class="w"> </span><span class="p">}</span>
<span class="w"> </span><span class="p">};</span>
<span class="w"> </span><span class="cm">/**</span>
<span class="cm"> * All parameters associated with the connection, as a comma-delimited</span>
<span class="cm"> * list of name="value" </span>
<span class="cm"> */</span>
<span class="w"> </span><span class="kd">public</span><span class="w"> </span><span class="kd">static</span><span class="w"> </span><span class="kd">final</span><span class="w"> </span><span class="n">StringGuacamoleProperty</span><span class="w"> </span><span class="n">TUTORIAL_PARAMETERS</span><span class="w"> </span><span class="o">=</span><span class="w"> </span>
<span class="w"> </span><span class="k">new</span><span class="w"> </span><span class="n">StringGuacamoleProperty</span><span class="p">()</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="nd">@Override</span>
<span class="w"> </span><span class="kd">public</span><span class="w"> </span><span class="n">String</span><span class="w"> </span><span class="nf">getName</span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="s">"tutorial-parameters"</span><span class="p">;</span><span class="w"> </span><span class="p">}</span>
<span class="w"> </span><span class="p">};</span>
<span class="p">}</span>
</pre></div>
</div>
<p>Normally, we would define a new type of <code class="docutils literal notranslate"><span class="pre">GuacamoleProperty</span></code> to handle the
parsing of the parameters required by <code class="docutils literal notranslate"><span class="pre">TUTORIAL_PARAMETERS</span></code>, but for the sake
of simplicity, parsing of this parameter will be embedded in the authentication
function later.</p>
<p>You will need to modify your existing <code class="docutils literal notranslate"><span class="pre">guacamole.properties</span></code> file, adding each
of the above properties to describe one of your available connections.</p>
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span># Username and password
tutorial-user: tutorial
tutorial-password: password
# Connection information
tutorial-protocol: vnc
tutorial-parameters: hostname=localhost, port=5900
</pre></div>
</div>
<p>Once these properties and their accessor class are in place, it’s simple enough
to read the properties within <code class="docutils literal notranslate"><span class="pre">getAuthorizedConfigurations()</span></code> and authenticate
the user based on their username and password.</p>
<div class="highlight-java notranslate"><div class="highlight"><pre><span></span><span class="nd">@Override</span>
<span class="kd">public</span><span class="w"> </span><span class="n">Map</span><span class="o"><</span><span class="n">String</span><span class="p">,</span><span class="w"> </span><span class="n">GuacamoleConfiguration</span><span class="o">></span>
<span class="w"> </span><span class="nf">getAuthorizedConfigurations</span><span class="p">(</span><span class="n">Credentials</span><span class="w"> </span><span class="n">credentials</span><span class="p">)</span>
<span class="w"> </span><span class="kd">throws</span><span class="w"> </span><span class="n">GuacamoleException</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="c1">// Get the Guacamole server environment</span>
<span class="w"> </span><span class="n">Environment</span><span class="w"> </span><span class="n">environment</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">LocalEnvironment</span><span class="p">.</span><span class="na">getInstance</span><span class="p">();</span>
<span class="w"> </span><span class="c1">// Get username from guacamole.properties</span>
<span class="w"> </span><span class="n">String</span><span class="w"> </span><span class="n">username</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">environment</span><span class="p">.</span><span class="na">getRequiredProperty</span><span class="p">(</span>
<span class="w"> </span><span class="n">TutorialGuacamoleProperties</span><span class="p">.</span><span class="na">TUTORIAL_USER</span>
<span class="w"> </span><span class="p">);</span><span class="w"> </span>
<span class="w"> </span><span class="c1">// If wrong username, fail</span>
<span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="o">!</span><span class="n">username</span><span class="p">.</span><span class="na">equals</span><span class="p">(</span><span class="n">credentials</span><span class="p">.</span><span class="na">getUsername</span><span class="p">()))</span>
<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="kc">null</span><span class="p">;</span>
<span class="w"> </span><span class="c1">// Get password from guacamole.properties</span>
<span class="w"> </span><span class="n">String</span><span class="w"> </span><span class="n">password</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">environment</span><span class="p">.</span><span class="na">getRequiredProperty</span><span class="p">(</span>
<span class="w"> </span><span class="n">TutorialGuacamoleProperties</span><span class="p">.</span><span class="na">TUTORIAL_PASSWORD</span>
<span class="w"> </span><span class="p">);</span><span class="w"> </span>
<span class="w"> </span><span class="c1">// If wrong password, fail</span>
<span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="o">!</span><span class="n">password</span><span class="p">.</span><span class="na">equals</span><span class="p">(</span><span class="n">credentials</span><span class="p">.</span><span class="na">getPassword</span><span class="p">()))</span>
<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="kc">null</span><span class="p">;</span>
<span class="w"> </span><span class="c1">// Successful login. Return configurations (STUB)</span>
<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="k">new</span><span class="w"> </span><span class="n">HashMap</span><span class="o"><</span><span class="n">String</span><span class="p">,</span><span class="w"> </span><span class="n">GuacamoleConfiguration</span><span class="o">></span><span class="p">();</span>
<span class="p">}</span>
</pre></div>
</div>
<p>As is, the authentication provider will work in its current state in that the
correct username and password will authenticate the user, while an incorrect
username or password will not, but we still aren’t returning an actual map of
configurations. We need to construct the configuration based on the properties
in the <code class="docutils literal notranslate"><span class="pre">guacamole.properties</span></code> file after the user has been authenticated, and
return that configuration to the web application.</p>
</section>
<section id="parsing-the-configuration">
<span id="custom-auth-more-config"></span><h2>Parsing the configuration<a class="headerlink" href="#parsing-the-configuration" title="Link to this heading"></a></h2>
<p>The only remaining task before we have a fully-functioning authentication
provider is to actually parse the configuration from the <code class="docutils literal notranslate"><span class="pre">guacamole.properties</span></code>
file.</p>
<div class="highlight-java notranslate"><div class="highlight"><pre><span></span><span class="nd">@Override</span>
<span class="kd">public</span><span class="w"> </span><span class="n">Map</span><span class="o"><</span><span class="n">String</span><span class="p">,</span><span class="w"> </span><span class="n">GuacamoleConfiguration</span><span class="o">></span>
<span class="w"> </span><span class="nf">getAuthorizedConfigurations</span><span class="p">(</span><span class="n">Credentials</span><span class="w"> </span><span class="n">credentials</span><span class="p">)</span>
<span class="w"> </span><span class="kd">throws</span><span class="w"> </span><span class="n">GuacamoleException</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="c1">// Get the Guacamole server environment</span>
<span class="w"> </span><span class="n">Environment</span><span class="w"> </span><span class="n">environment</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">LocalEnvironment</span><span class="p">.</span><span class="na">getInstance</span><span class="p">();</span>
<span class="w"> </span><span class="c1">// Get username from guacamole.properties</span>
<span class="w"> </span><span class="n">String</span><span class="w"> </span><span class="n">username</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">environment</span><span class="p">.</span><span class="na">getRequiredProperty</span><span class="p">(</span>
<span class="w"> </span><span class="n">TutorialGuacamoleProperties</span><span class="p">.</span><span class="na">TUTORIAL_USER</span>
<span class="w"> </span><span class="p">);</span><span class="w"> </span>
<span class="w"> </span><span class="c1">// If wrong username, fail</span>
<span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="o">!</span><span class="n">username</span><span class="p">.</span><span class="na">equals</span><span class="p">(</span><span class="n">credentials</span><span class="p">.</span><span class="na">getUsername</span><span class="p">()))</span>
<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="kc">null</span><span class="p">;</span>
<span class="w"> </span><span class="c1">// Get password from guacamole.properties</span>
<span class="w"> </span><span class="n">String</span><span class="w"> </span><span class="n">password</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">environment</span><span class="p">.</span><span class="na">getRequiredProperty</span><span class="p">(</span>
<span class="w"> </span><span class="n">TutorialGuacamoleProperties</span><span class="p">.</span><span class="na">TUTORIAL_PASSWORD</span>
<span class="w"> </span><span class="p">);</span><span class="w"> </span>
<span class="w"> </span><span class="c1">// If wrong password, fail</span>
<span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="o">!</span><span class="n">password</span><span class="p">.</span><span class="na">equals</span><span class="p">(</span><span class="n">credentials</span><span class="p">.</span><span class="na">getPassword</span><span class="p">()))</span>
<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="kc">null</span><span class="p">;</span>
<span class="w"> </span><span class="c1">// Successful login. Return configurations.</span>
<span class="w"> </span><span class="n">Map</span><span class="o"><</span><span class="n">String</span><span class="p">,</span><span class="w"> </span><span class="n">GuacamoleConfiguration</span><span class="o">></span><span class="w"> </span><span class="n">configs</span><span class="w"> </span><span class="o">=</span><span class="w"> </span>
<span class="w"> </span><span class="k">new</span><span class="w"> </span><span class="n">HashMap</span><span class="o"><</span><span class="n">String</span><span class="p">,</span><span class="w"> </span><span class="n">GuacamoleConfiguration</span><span class="o">></span><span class="p">();</span>
<span class="w"> </span><span class="c1">// Create new configuration</span>
<span class="w"> </span><span class="n">GuacamoleConfiguration</span><span class="w"> </span><span class="n">config</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="k">new</span><span class="w"> </span><span class="n">GuacamoleConfiguration</span><span class="p">();</span>
<span class="w"> </span><span class="c1">// Set protocol specified in properties</span>
<span class="w"> </span><span class="n">config</span><span class="p">.</span><span class="na">setProtocol</span><span class="p">(</span><span class="n">environment</span><span class="p">.</span><span class="na">getRequiredProperty</span><span class="p">(</span>
<span class="w"> </span><span class="n">TutorialGuacamoleProperties</span><span class="p">.</span><span class="na">TUTORIAL_PROTOCOL</span>
<span class="w"> </span><span class="p">));</span>
<span class="w"> </span><span class="c1">// Set all parameters, splitting at commas</span>
<span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="p">(</span><span class="n">String</span><span class="w"> </span><span class="n">parameterValue</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="n">environment</span><span class="p">.</span><span class="na">getRequiredProperty</span><span class="p">(</span>
<span class="w"> </span><span class="n">TutorialGuacamoleProperties</span><span class="p">.</span><span class="na">TUTORIAL_PARAMETERS</span>
<span class="w"> </span><span class="p">).</span><span class="na">split</span><span class="p">(</span><span class="s">",\\s*"</span><span class="p">))</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="c1">// Find the equals sign</span>
<span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="n">equals</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">parameterValue</span><span class="p">.</span><span class="na">indexOf</span><span class="p">(</span><span class="sc">'='</span><span class="p">);</span>
<span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="n">equals</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="o">-</span><span class="mi">1</span><span class="p">)</span>
<span class="w"> </span><span class="k">throw</span><span class="w"> </span><span class="k">new</span><span class="w"> </span><span class="n">GuacamoleServerException</span><span class="p">(</span><span class="s">"Required equals sign missing"</span><span class="p">);</span>
<span class="w"> </span><span class="c1">// Get name and value from parameter string</span>
<span class="w"> </span><span class="n">String</span><span class="w"> </span><span class="n">name</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">parameterValue</span><span class="p">.</span><span class="na">substring</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span><span class="w"> </span><span class="n">equals</span><span class="p">);</span>
<span class="w"> </span><span class="n">String</span><span class="w"> </span><span class="n">value</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">parameterValue</span><span class="p">.</span><span class="na">substring</span><span class="p">(</span><span class="n">equals</span><span class="o">+</span><span class="mi">1</span><span class="p">);</span>
<span class="w"> </span><span class="c1">// Set parameter as specified</span>
<span class="w"> </span><span class="n">config</span><span class="p">.</span><span class="na">setParameter</span><span class="p">(</span><span class="n">name</span><span class="p">,</span><span class="w"> </span><span class="n">value</span><span class="p">);</span>
<span class="w"> </span><span class="p">}</span>
<span class="w"> </span><span class="n">configs</span><span class="p">.</span><span class="na">put</span><span class="p">(</span><span class="s">"Tutorial Connection"</span><span class="p">,</span><span class="w"> </span><span class="n">config</span><span class="p">);</span>
<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="n">configs</span><span class="p">;</span>
<span class="p">}</span>
</pre></div>
</div>
<p>The extension is now complete and can be built as described earlier in
<a class="reference internal" href="#custom-auth-building"><span class="std std-ref">Building the extension</span></a>.</p>
</section>
<section id="installing-the-extension">
<span id="custom-auth-installing"></span><h2>Installing the extension<a class="headerlink" href="#installing-the-extension" title="Link to this heading"></a></h2>
<p>Guacamole extensions are self-contained <code class="docutils literal notranslate"><span class="pre">.jar</span></code> files which are installed by
being placed within <code class="docutils literal notranslate"><span class="pre">GUACAMOLE_HOME/extensions</span></code>, and this extension is no
different. As described in <a class="reference internal" href="configuring-guacamole.html"><span class="doc std std-doc">Configuring Guacamole</span></a>, <code class="docutils literal notranslate"><span class="pre">GUACAMOLE_HOME</span></code> is a
placeholder used to refer to the directory that Guacamole uses to locate its
configuration files and extensions. Typically, this will be the <code class="docutils literal notranslate"><span class="pre">.guacamole</span></code>
directory within the home directory of the user running Tomcat.</p>
<p>To install your extension, ensure that the required properties have been added
to your <code class="docutils literal notranslate"><span class="pre">guacamole.properties</span></code>, copy the
<code class="docutils literal notranslate"><span class="pre">target/guacamole-auth-tutorial-1.5.5.jar</span></code> file into
<code class="docutils literal notranslate"><span class="pre">GUACAMOLE_HOME/extensions</span></code> and restart Tomcat. Guacamole will automatically
load your extension, logging an informative message that it has done so:</p>
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>Extension "Tutorial Authentication Extension" loaded.
</pre></div>
</div>
</section>
</section>
</div>
</div>
<footer><div class="rst-footer-buttons" role="navigation" aria-label="Footer">
<a href="custom-protocols.html" class="btn btn-neutral float-left" title="Adding new protocols" accesskey="p" rel="prev"><span class="fa fa-arrow-circle-left" aria-hidden="true"></span> Previous</a>
<a href="event-listeners.html" class="btn btn-neutral float-right" title="Event listeners" accesskey="n" rel="next">Next <span class="fa fa-arrow-circle-right" aria-hidden="true"></span></a>
</div>
<hr/>
<div role="contentinfo">
<p>Copyright © 2024 <a href="http://www.apache.org/">The Apache Software Foundation</a>,
Licensed under the <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache License, Version 2.0</a>.
Apache Guacamole, Guacamole, Apache, the Apache feather logo, and the Apache Guacamole project logo are
trademarks of The Apache Software Foundation.</p>
</div>
Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a
<a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a>
provided by <a href="https://readthedocs.org">Read the Docs</a>.
</footer>
</div>
</div>
</section>
</div>
<script>
jQuery(function () {
SphinxRtdTheme.Navigation.enable(true);
});
</script>
</body>
</html>