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:
Michael Bayne
2009-06-20 00:56:01 +00:00
parent 7d125bec73
commit a1aa2d77ae
35 changed files with 622 additions and 656 deletions
@@ -0,0 +1,92 @@
//
// $Id$
//
// Narya library - tools for developing networked games
// Copyright (C) 2002-2009 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.presents.server;
import java.lang.reflect.Constructor;
import com.samskivert.io.PersistenceException;
import com.threerings.util.Name;
import com.threerings.presents.data.AuthCodes;
import com.threerings.presents.net.AuthResponse;
import com.threerings.presents.net.AuthResponseData;
import com.threerings.presents.net.ServiceCreds;
import com.threerings.presents.server.net.AuthingConnection;
import static com.threerings.presents.Log.log;
/**
* Works in conjunction with {@link ServiceCreds} to handle the authentication of service clients
* (bureaus, peers, etc.).
*/
public abstract class ServiceAuthenticator<T extends ServiceCreds> extends ChainedAuthenticator
{
/**
* Creates an authenticator that will handle requests using the supplied credentials class and
* which will create instances of the supplied auth name class to identify those clients. Note
* that the auth name class <em>must</em> have a public constructor that takes a single string.
*/
public ServiceAuthenticator (Class<T> credsClass, Class<? extends Name> authNameClass)
{
_credsClass = credsClass;
try {
_authNamer = authNameClass.getConstructor(String.class);
} catch (NoSuchMethodException nsme) {
throw new IllegalArgumentException("AuthName must have AuthName(String) constructor.");
}
}
@Override // from abstract ChainedAuthenticator
public boolean shouldHandleConnection (AuthingConnection conn)
{
return _credsClass.isInstance(conn.getAuthRequest().getCredentials());
}
@Override // from abstract Authenticator
protected void processAuthentication (AuthingConnection conn, AuthResponse rsp)
throws PersistenceException
{
T creds = _credsClass.cast(conn.getAuthRequest().getCredentials());
if (!areValid(creds)) {
log.warning("Received invalid service auth request?", "creds", creds);
rsp.getData().code = AuthCodes.SERVER_ERROR;
return;
}
try {
conn.setAuthName(_authNamer.newInstance(creds.clientId));
rsp.getData().code = AuthResponseData.SUCCESS;
} catch (Exception e) {
log.warning("Failed to construct auth name", "namer", _authNamer, e);
rsp.getData().code = AuthCodes.SERVER_ERROR;
}
}
/**
* Returns true if the creds in question are valid.
*/
protected abstract boolean areValid (T creds);
protected Class<T> _credsClass;
protected Constructor<? extends Name> _authNamer;
}