protected GuacamoleTunnel createAssociatedTunnel(final GuacamoleTunnel tunnel,
            final String authToken, final GuacamoleSession session,
            final UserContext context, final TunnelRequestType type,
            final String id) throws GuacamoleException {

        // Monitor tunnel closure and data
        UserTunnel monitoredTunnel = new UserTunnel(context, tunnel) {

            /**
             * The time the connection began, measured in milliseconds since
             * midnight, January 1, 1970 UTC.
             */
            private final long connectionStartTime = System.currentTimeMillis();

            @Override
            public void close() throws GuacamoleException {

                // Notify listeners to allow close request to be vetoed
                AuthenticatedUser authenticatedUser = session.getAuthenticatedUser();
                fireTunnelClosedEvent(authenticatedUser,
                    authenticatedUser.getCredentials(), tunnel);

                long connectionEndTime = System.currentTimeMillis();
                long duration = connectionEndTime - connectionStartTime;

                logger.info("User \"{}\" disconnected from {} \"{}\". Duration: {} milliseconds",
                        session.getAuthenticatedUser().getIdentifier(),
                        type.NAME, id, duration);

                try {

                    // Close and clean up tunnel
                    session.removeTunnel(getUUID().toString());
                    super.close();

                }

                // Ensure any associated session is invalidated if unauthorized
                catch (GuacamoleUnauthorizedException e) {

                    // If there is an associated auth token, invalidate it
                    if (authenticationService.destroyGuacamoleSession(authToken))
                        logger.debug("Implicitly invalidated session for token \"{}\".", authToken);

                    // Continue with exception processing
                    throw e;

                }

            }

        };

        // Associate tunnel with session
        session.addTunnel(monitoredTunnel);
        return monitoredTunnel;
        
    }
Associates the given tunnel with the given session, returning a wrapped
version of the same tunnel which automatically handles closure and
removal from the session.

@param tunnel
    The connected tunnel to wrap and monitor.

@param authToken
    The authentication token associated with the given session. If
    provided, this token will be automatically invalidated (and the
    corresponding session destroyed) if tunnel errors imply that the
    user is no longer authorized.

@param session
    The Guacamole session to associate the tunnel with.

@param context
    The UserContext associated with the user for whom the tunnel is
    being created.

@param type
    The type of object being connected to (connection or group).

@param id
    The id of the connection or group being connected to.

@return
    A new tunnel, associated with the given session, which delegates all
    functionality to the given tunnel while monitoring and automatically
    handling closure.

@throws GuacamoleException
    If an error occurs while obtaining the tunnel.
guacamole/src/main/java/org/apache/guacamole/tunnel/TunnelRequestService.java