Revamping/cleanup of how we handle authentication usernames as well as chained
authenticators and chained session factories. We can share a lot more code this way and the implicit requirement that the default authenticator/factory had to be configured before anyone else configured a chanied author/factory is gone. The other big change is that Credentials doesn't require a username (UsernamePasswordCreds inherits that username so most derived classes don't notice any difference). Instead we require that a canonical authentication username be determined and configured in AuthingConnection during the authentication process. This canonical username is then used to resolve the client session and map everything in the client manager. This is pretty much exactly what was going on before except that we were doing it all in an ad hoc way by jamming a new name into Credentials during the authentication process and also doing jiggery pokery in PresentsSession.assignStartingUsername. That all goes away and/or becomes cleaner and more explicit. This is going to impact some Yohoho jiggery pokery, which I will shortly commit a patch for, but we're going to need to test it. Omelets, eggs, etc. git-svn-id: svn+ssh://src.earth.threerings.net/narya/trunk@5828 542714f4-19e9-0310-aa3c-eee0fc999fb1
This commit is contained in:
@@ -39,13 +39,11 @@ public abstract class BureauClient extends Client
|
||||
* Creates a new client.
|
||||
* @param runQueue the place to post tasks required by clients
|
||||
*/
|
||||
public BureauClient (String token, String bureauId, RunQueue runQueue)
|
||||
public BureauClient (String bureauId, String sharedSecret, RunQueue runQueue)
|
||||
{
|
||||
super(null, runQueue);
|
||||
_bureauId = bureauId;
|
||||
BureauCredentials creds = new BureauCredentials(_bureauId);
|
||||
creds.sessionToken = token;
|
||||
_creds = creds;
|
||||
_creds = new BureauCredentials(_bureauId, sharedSecret);
|
||||
_ctx = createContext();
|
||||
_director = createDirector();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
//
|
||||
// $Id$
|
||||
//
|
||||
// Narya library - tools for developing networked games
|
||||
// Copyright (C) 2002-2008 Three Rings Design, Inc., All Rights Reserved
|
||||
// http://www.threerings.net/code/narya/
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify it
|
||||
// under the terms of the GNU Lesser General Public License as published
|
||||
// by the Free Software Foundation; either version 2.1 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
package com.threerings.bureau.data;
|
||||
|
||||
import com.threerings.util.Name;
|
||||
|
||||
/**
|
||||
* Represents an authenticated bureau client.
|
||||
*/
|
||||
public class BureauAuthName extends Name
|
||||
{
|
||||
public BureauAuthName (String bureauId)
|
||||
{
|
||||
super(bureauId);
|
||||
}
|
||||
|
||||
// used when unserializing
|
||||
public BureauAuthName ()
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -21,51 +21,19 @@
|
||||
|
||||
package com.threerings.bureau.data;
|
||||
|
||||
import com.threerings.util.Name;
|
||||
|
||||
import com.threerings.presents.net.Credentials;
|
||||
import com.threerings.presents.net.ServiceCreds;
|
||||
|
||||
/**
|
||||
* Extends the basic credentials to provide bureau-specific fields.
|
||||
*/
|
||||
public class BureauCredentials extends Credentials
|
||||
public class BureauCredentials extends ServiceCreds
|
||||
{
|
||||
public static final String PREFIX = "@@bureau:";
|
||||
public static final String SUFFIX = "@@";
|
||||
|
||||
/**
|
||||
* The token to pass to the server when logging in. This is usually just passed to the bureau
|
||||
* on the command line to guard against outside connections being established.
|
||||
* Creates new credentials for a specific bureau.
|
||||
*/
|
||||
public String sessionToken;
|
||||
|
||||
/**
|
||||
* The id of the bureau logging in.
|
||||
*/
|
||||
public String bureauId;
|
||||
|
||||
/**
|
||||
* Test if a given name object matches the name that we generate.
|
||||
*/
|
||||
public static boolean isBureau (Name name)
|
||||
public BureauCredentials (String bureauId, String sharedSecret)
|
||||
{
|
||||
String normal = name.getNormal();
|
||||
return normal.startsWith(PREFIX) && normal.endsWith(SUFFIX);
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract the buerauId from the name that we generate.
|
||||
*/
|
||||
public static String extractBureauId (Name name)
|
||||
{
|
||||
String normal = name.getNormal();
|
||||
int prefixPos = normal.indexOf(PREFIX);
|
||||
int suffixPos = normal.lastIndexOf(SUFFIX);
|
||||
if (prefixPos != 0 || suffixPos != normal.length() - SUFFIX.length()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return normal.substring(prefixPos + PREFIX.length(), suffixPos);
|
||||
super(bureauId, sharedSecret);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -74,21 +42,4 @@ public class BureauCredentials extends Credentials
|
||||
public BureauCredentials ()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new credentials for a specific bureau.
|
||||
*/
|
||||
public BureauCredentials (String bureauId)
|
||||
{
|
||||
super(new Name("@@bureau:" + bureauId + "@@"));
|
||||
this.bureauId = bureauId;
|
||||
}
|
||||
|
||||
@Override // inherit documentation
|
||||
protected void toString (StringBuilder buf)
|
||||
{
|
||||
super.toString(buf);
|
||||
buf.append(" id=").append(bureauId).
|
||||
append(" token=").append(sessionToken);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,53 +0,0 @@
|
||||
package com.threerings.bureau.server;
|
||||
|
||||
import com.threerings.presents.data.AuthCodes;
|
||||
import com.threerings.presents.net.AuthRequest;
|
||||
import com.threerings.presents.net.AuthResponse;
|
||||
import com.threerings.presents.net.AuthResponseData;
|
||||
import com.threerings.presents.server.ChainedAuthenticator;
|
||||
import com.threerings.presents.server.net.AuthingConnection;
|
||||
|
||||
import com.threerings.bureau.data.BureauCredentials;
|
||||
|
||||
import static com.threerings.bureau.Log.log;
|
||||
|
||||
/**
|
||||
* Authenticates bureaus only.
|
||||
*/
|
||||
public class BureauAuthenticator extends ChainedAuthenticator
|
||||
{
|
||||
/**
|
||||
* Creates a new bureau authenticator.
|
||||
*/
|
||||
public BureauAuthenticator (BureauRegistry registry)
|
||||
{
|
||||
_registry = registry;
|
||||
}
|
||||
|
||||
@Override // from abstract ChainedAuthenticator
|
||||
protected boolean shouldHandleConnection (AuthingConnection conn)
|
||||
{
|
||||
return (conn.getAuthRequest().getCredentials() instanceof BureauCredentials);
|
||||
}
|
||||
|
||||
@Override // from Authenticator
|
||||
protected void processAuthentication (
|
||||
AuthingConnection conn,
|
||||
AuthResponse rsp)
|
||||
{
|
||||
AuthRequest req = conn.getAuthRequest();
|
||||
BureauCredentials creds = (BureauCredentials)req.getCredentials();
|
||||
String problem = _registry.checkToken(creds);
|
||||
|
||||
if (problem == null) {
|
||||
rsp.getData().code = AuthResponseData.SUCCESS;
|
||||
|
||||
} else {
|
||||
log.warning("Received invalid bureau auth request",
|
||||
"creds", creds + "], problem: " + problem);
|
||||
rsp.getData().code = AuthCodes.SERVER_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
protected BureauRegistry _registry;
|
||||
}
|
||||
@@ -42,8 +42,12 @@ import com.threerings.presents.dobj.RootDObjectManager;
|
||||
import com.threerings.presents.server.ClientManager;
|
||||
import com.threerings.presents.server.InvocationManager;
|
||||
import com.threerings.presents.server.PresentsSession;
|
||||
import com.threerings.presents.server.ServiceAuthenticator;
|
||||
import com.threerings.presents.server.SessionFactory;
|
||||
import com.threerings.presents.server.net.ConnectionManager;
|
||||
|
||||
import com.threerings.bureau.data.AgentObject;
|
||||
import com.threerings.bureau.data.BureauAuthName;
|
||||
import com.threerings.bureau.data.BureauCodes;
|
||||
import com.threerings.bureau.data.BureauCredentials;
|
||||
import com.threerings.bureau.util.BureauLogRedirector;
|
||||
@@ -95,7 +99,8 @@ public class BureauRegistry
|
||||
/**
|
||||
* Creates an uninitialized registry.
|
||||
*/
|
||||
@Inject public BureauRegistry (InvocationManager invmgr)
|
||||
@Inject public BureauRegistry (
|
||||
InvocationManager invmgr, ConnectionManager conmgr, ClientManager clmgr)
|
||||
{
|
||||
invmgr.registerDispatcher(new BureauDispatcher(new BureauProvider() {
|
||||
public void bureauInitialized (ClientObject client, String bureauId) {
|
||||
@@ -114,59 +119,44 @@ public class BureauRegistry
|
||||
BureauRegistry.this.agentDestroyed(client, agentId);
|
||||
}
|
||||
}), BureauCodes.BUREAU_GROUP);
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides the Bureau registry with necessary runtime configuration. Inserts the bureau
|
||||
* client factory into the client manager and registers observers to track the progress
|
||||
* of launched bureaus.
|
||||
* @see BureauSessionFactory
|
||||
*/
|
||||
public void init ()
|
||||
{
|
||||
_clmgr.addClientObserver(new ClientManager.ClientObserver() {
|
||||
conmgr.addChainedAuthenticator(new ServiceAuthenticator<BureauCredentials>(
|
||||
BureauCredentials.class, BureauAuthName.class) {
|
||||
protected boolean areValid (BureauCredentials creds) {
|
||||
return checkToken(creds) == null;
|
||||
}
|
||||
});
|
||||
clmgr.addSessionFactory(
|
||||
SessionFactory.newSessionFactory(BureauCredentials.class, getSessionClass(),
|
||||
BureauAuthName.class, getClientResolverClass()));
|
||||
clmgr.addClientObserver(new ClientManager.ClientObserver() {
|
||||
public void clientSessionDidStart (PresentsSession client) {
|
||||
String id = BureauCredentials.extractBureauId(client.getUsername());
|
||||
if (id != null) {
|
||||
sessionDidStart(client, id);
|
||||
if (client.getCredentials() instanceof BureauCredentials) {
|
||||
sessionDidStart(client, ((BureauCredentials)client.getCredentials()).clientId);
|
||||
}
|
||||
}
|
||||
public void clientSessionDidEnd (PresentsSession client) {
|
||||
String id = BureauCredentials.extractBureauId(client.getUsername());
|
||||
if (id != null) {
|
||||
sessionDidEnd(client, id);
|
||||
if (client.getCredentials() instanceof BureauCredentials) {
|
||||
sessionDidEnd(client, ((BureauCredentials)client.getCredentials()).clientId);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the delegating client factory. Note this should be called after all application
|
||||
* client factories are in place. The installed factory will simply create presents clients and
|
||||
* client objects for bureaus.
|
||||
*/
|
||||
public void setDefaultSessionFactory ()
|
||||
{
|
||||
// add the client factory, but later, after all the other modules have been initialized
|
||||
_clmgr.setSessionFactory(new BureauSessionFactory(_clmgr.getSessionFactory()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Check the credentials to make sure this is one of our bureaus.
|
||||
* @return null if all's well, otherwise a string describing the authentication failure
|
||||
*/
|
||||
public String checkToken (BureauCredentials creds)
|
||||
{
|
||||
Bureau bureau = _bureaus.get(creds.bureauId);
|
||||
Bureau bureau = _bureaus.get(creds.clientId);
|
||||
if (bureau == null) {
|
||||
return "Bureau " + creds.bureauId + " not found";
|
||||
return "Bureau " + creds.clientId + " not found";
|
||||
}
|
||||
if (bureau.clientObj != null) {
|
||||
return "Bureau " + creds.bureauId + " already logged in";
|
||||
return "Bureau " + creds.clientId + " already logged in";
|
||||
}
|
||||
if (!bureau.token.equals(creds.sessionToken)) {
|
||||
return "Bureau " + creds.bureauId +
|
||||
" does not match credentials token";
|
||||
if (!creds.areValid(bureau.token)) {
|
||||
return "Bureau " + creds.clientId + " does not match credentials token";
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@@ -617,6 +607,22 @@ public class BureauRegistry
|
||||
_bureaus.remove(bureau.bureauId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the class used to handle bureau sessions.
|
||||
*/
|
||||
protected Class<? extends BureauSession> getSessionClass ()
|
||||
{
|
||||
return BureauSession.class;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the class used to resolve bureau client data.
|
||||
*/
|
||||
protected Class<? extends BureauClientResolver> getClientResolverClass ()
|
||||
{
|
||||
return BureauClientResolver.class;
|
||||
}
|
||||
|
||||
/**
|
||||
* Invoker unit to launch a bureau's process, then assign the result on the main thread.
|
||||
*/
|
||||
@@ -795,5 +801,4 @@ public class BureauRegistry
|
||||
|
||||
@Inject protected RootDObjectManager _omgr;
|
||||
@Inject protected @MainInvoker Invoker _invoker;
|
||||
@Inject protected ClientManager _clmgr;
|
||||
}
|
||||
|
||||
@@ -1,68 +0,0 @@
|
||||
//
|
||||
// $Id$
|
||||
//
|
||||
// Narya library - tools for developing networked games
|
||||
// Copyright (C) 2002-2007 Three Rings Design, Inc., All Rights Reserved
|
||||
// http://www.threerings.net/code/narya/
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify it
|
||||
// under the terms of the GNU Lesser General Public License as published
|
||||
// by the Free Software Foundation; either version 2.1 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
package com.threerings.bureau.server;
|
||||
|
||||
import com.threerings.util.Name;
|
||||
|
||||
import com.threerings.presents.net.AuthRequest;
|
||||
import com.threerings.presents.server.SessionFactory;
|
||||
import com.threerings.presents.server.ClientResolver;
|
||||
import com.threerings.presents.server.PresentsSession;
|
||||
|
||||
import com.threerings.bureau.data.BureauCredentials;
|
||||
|
||||
/**
|
||||
* Handles resolution of bureaus and passes non-bureau resolution requests through to a normal
|
||||
* factory. For bureaus, creates base class instances {@link PresentsSession} and
|
||||
* {@link ClientResolver}.
|
||||
* @see BureauRegistry#setDefaultSessionFactory()
|
||||
*/
|
||||
public class BureauSessionFactory implements SessionFactory
|
||||
{
|
||||
public BureauSessionFactory (SessionFactory delegate)
|
||||
{
|
||||
_delegate = delegate;
|
||||
}
|
||||
|
||||
// from interface SessionFactory
|
||||
public Class<? extends PresentsSession> getSessionClass (AuthRequest areq)
|
||||
{
|
||||
// Just give bureaus a vanilla PresentsSession client for now.
|
||||
if (areq.getCredentials() instanceof BureauCredentials) {
|
||||
return BureauSession.class;
|
||||
} else {
|
||||
return _delegate.getSessionClass(areq);
|
||||
}
|
||||
}
|
||||
|
||||
// from interface SessionFactory
|
||||
public Class<? extends ClientResolver> getClientResolverClass (Name username)
|
||||
{
|
||||
if (BureauCredentials.isBureau(username)) {
|
||||
return BureauClientResolver.class;
|
||||
} else {
|
||||
return _delegate.getClientResolverClass(username);
|
||||
}
|
||||
}
|
||||
|
||||
protected SessionFactory _delegate;
|
||||
}
|
||||
Reference in New Issue
Block a user