# Guacamole 1.6 Integration

## Design

The SessionGuard Guacamole extension is deliberately **not** an authentication provider in the identity sense. PocketID/header authentication stays responsible for user identity.

The extension subclasses Guacamole's authentication-provider extension point only to decorate the authenticated `UserContext` with a `TokenInjectingUserContext`. At connection time it sends the current Guacamole username plus connection identity to the SessionGuard broker and injects returned tokens.

This avoids:

- writing dynamic hostnames directly into the Guacamole PostgreSQL database;
- reimplementing PocketID authentication in SessionGuard;
- opening a management connection from Master to RDS hosts.

## Build

```bash
cd guacamole-extension
mvn -DskipTests package
```

Or use `deploy/guacamole/Dockerfile.guacamole`, which builds the JAR and copies it to the stock Guacamole extension directory.

## Required Guacamole environment

```yaml
SESSIONGUARD_MASTER_URL: http://sessionguard-master:8080
SESSIONGUARD_BROKER_API_KEY: ${SESSIONGUARD_BROKER_API_KEY}
SESSIONGUARD_BROKER_TIMEOUT_MS: "2500"
```

Use the same broker API key configured on the SessionGuard Master. The URL should preferably be an internal network URL, not the public Internet endpoint.

## Desktop connection

Configure the Guacamole RDP hostname as:

```text
${SESSIONGUARD_HOST}
```

The extension resolves the target host at connection time.

## RemoteApp

Use:

```text
hostname:        ${SESSIONGUARD_HOST}
remote-app:      ${SESSIONGUARD_REMOTE_APP}
remote-app-dir:  ${SESSIONGUARD_REMOTE_APP_DIR}
remote-app-args: ${SESSIONGUARD_REMOTE_APP_ARGS}
```

If your Agents report short Windows computer names and your DNS requires a suffix, a Guacamole hostname such as `${SESSIONGUARD_HOST}.example.org` is valid.

Create a matching Published Resource in SessionGuard by Guacamole connection ID or name. In v0.4 the Resource can optionally enable **Agent-managed RemoteApp publication** and specify the executable path. The Master then distributes the desired alias/path to every Agent in the farm. A managed RemoteApp is not brokered to a host until the Agent reports that it is present and in sync. The broker also aligns `${SESSIONGUARD_REMOTE_APP_ARGS}` with the Windows command-line policy (deny/allow/require).

## Header-auth security boundary

Your Guacamole configuration uses a trusted header such as `X-Guacamole-User`. That is safe only if untrusted requests cannot reach Guacamole directly with an attacker-controlled copy of that header.

Recommended topology:

```text
Internet
   |
Traefik + forward-auth/header scrubber
   |
dedicated trusted Guacamole proxy network
   |
Guacamole
   +--- private backend ---> guacd
   +--- private backend ---> PostgreSQL
   +--- private control ---> SessionGuard Master
```

Do not rely solely on the fact that the public Traefik router strips inbound identity headers if arbitrary unrelated containers can directly connect to Guacamole's port on a shared Docker network.

## Integration with the supplied compose

Your existing PocketID → traefik-forward-auth → Guacamole chain can remain unchanged. The required additions are:

1. build Guacamole using `deploy/guacamole/Dockerfile.guacamole`;
2. add the three `SESSIONGUARD_*` variables above;
3. give Guacamole private reachability to the SessionGuard Master;
4. add SessionGuard Published Resources matching your Guacamole connections;
5. replace fixed RDP hostnames in brokered connections with `${SESSIONGUARD_HOST}`.

`deploy/guacamole/docker-compose.sessionguard.example.yml` provides a focused example rather than replacing your complete existing stack.

## Failure behavior

If the SessionGuard broker is unavailable, the extension fails the brokered connection instead of choosing an arbitrary backend. This is intentional where reconnect affinity/profile concurrency matters. Existing already-established Guacamole/RDP sessions are unaffected.
