Hello all,

We operate a shared instrument facility. We would like to provide remote access to some of our instruments to users to allow them to monitor the progress of their experiments, without also allowing them to monitor the progress of other users' experiments.  Our system knows who is signed into a given instrument at any time, and produces "coral tokens" that signify a user's right to connect to a given instrument.  We also need the system to be able to revoke that access, closing any active Guacamole sessions, when the user's instrument session ends and their coral token is destroyed.

I've implemented an auth extension that grants remote access by coral token: that part is working fine. What I don't see is how the auth extension can kick users out. My best guess so far has been to store the AuthenticatedUser and UserContext structures and use them to look up the active connections later; but when I use the stored UserContext to close the active connections, there are none.

My auth provider, reduced to only the parts that store and retrieve those structures and the method that revokes authorization, looks like this:

public class CoralAuthenticationProvider extends AbstractAuthenticationProvider {

// [...]

private class TokenInfo { String m_token = null; // This is the coral token, not guacamole token UserContext m_userContext = null; CoralAuthenticatedUser m_authenticatedUser = *null*;

[...]

}

// A map from "coral token" to TokenInfo

*private static* Map<String, TokenInfo> s_tokenInfo = new HashMap<String, TokenInfo>();

// CoralAuthenticatedUser is a clone of SimpleAuthenticatedUser except for the "coraltoken" field. // (I'd extend SimpleAuthenticatedUser, but it's a private class in an inaccessible scope.)

private class CoralAuthenticatedUser extends AbstractAuthenticatedUser { // [... all of SimpleAuthenticatedUser ...]

private String coraltoken;

public void setCoralToken(String token) {

this.coraltoken = token;

}

public String getCoralToken() {

return this.coraltoken;

}

}

/*

* Authenticate the user, and store the AuthenticatedUser in s_tokenInfo

* so we can look it up by coral token later. * Also store the coral token in the AuthenticatedUser for later consumption by getUserContext().

*/

@Override

public AuthenticatedUser authenticateUser(Credentials credentials) {

// [Actually authenticate the user based on "coral token"; then,]

TokenInfo ti = new TokenInfo();

ti.m_token = [the coral token];

GuacamoleConfigs configs = [the configs available based on the coral token];

CoralAuthenticatedUser sau = new CoralAuthenticatedUser(credentials, configs);

sau.setCoralToken(ti.m_token);

ti.m_authenticatedUser = sau;

s_tokenInfo.put(ti.m_token, ti);

return sau; }

/* * Pull the coral token out of the AuthenticatedUser and use it to store the UserContext * in s_tokenInfo as well. */ @Override

public UserContext getUserContext(AuthenticatedUser authenticatedUser)

throws GuacamoleException {

if (!(authenticatedUser instanceof CoralAuthenticatedUser))

return null;

CoralAuthenticatedUser cau = (CoralAuthenticatedUser)authenticatedUser;

// Return as unauthorized if not authorized to retrieve configs

if (cau.configs == null)

return null;

// Return user context restricted to authorized configs

UserContext userContext = new SimpleUserContext(this, authenticatedUser.getIdentifier(), cau.configs, true); // Retrieve the TokenInfo and store the UserContext in it too

TokenInfo ti = s_tokenInfo.get(cau.getCoralToken());

ti.m_userContext = userContext;

ti.m_authenticatedUser = cau;

return userContext;

}

/* * Revoke authorization using the data stored in the previous two methods. * This should de-authenticate the user, remove all active contexts * and terminate all active sessions. */ public static void revokeToken(TokenInfo ti) throws GuacamoleException {

Directory<ActiveConnection> dac = ti.m_userContext.getActiveConnectionDirectory();

for (String connectionId : dac.getIdentifiers()) {

ActiveConnection ac = dac.get(connectionId);

System.out.println("Disconnect connection " + connectionId);

GuacamoleWriter gw = ac.getTunnel().acquireWriter();

gw.writeInstruction(new GuacamoleInstruction("disconnect", new LinkedList<String>()));

ac.getTunnel().releaseWriter();

System.out.println("Close tunnel for connection " + connectionId);

ac.getTunnel().close();

}

System.out.println("Invalidate AU for user token " + ti.m_token);

ti.m_authenticatedUser.invalidate();

System.out.println("Invalidate UC for user token " + ti.m_token);

ti.m_userContext.invalidate();

}

// [ ... ]

}

When revokeToken() is called, the "Invalidate..." lines print but the "Disconnect connection/Close tunnel" lines don't: there are no active connections attached to the UserContext, despite there being, in fact, active connections. Do I have a simple implementation error, or is this just the wrong way to go about this?

If I did manage to get a valid list of active connections, is this the right way to terminate them, or should I be doing something else?

Thanks,

--
-----------------------------------------------------------------------
Konrad Schroder             Box 352143 -or- 115D Fluke Hall, Mason Road
Software Developer and Sys Admin               University of Washington
College of Engineering                          Seattle, WA, 98195, USA


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to