Krawall-based team management and admin logon

What do you want to see in Armagetron soon? Any new feature ideas? Let's ponder these ground breaking ideas...
User avatar
Z-Man
God & Project Admin
Posts: 11748
Joined: Sun Jan 23, 2005 6:01 pm
Location: Cologne
Contact:

Post by Z-Man »

Well, a page you can fetch via http would be enough. That way, all you need to control is a webserver. Say I get renegade and want to authenticate as z-man@moosnet.homelinux.net; the server would then fetch http://moosnet.homelinux.net/armaauth/list. of choice> for the list of further authentication choices, once we support many of them. Right now, it would go straight for http://moosnet.homelinux.net/armaauth/m ... user=z-man&...

Edit: wrtl suggested on IRC to use directories instead of files; that way, the user can put an index.php, index.html, index.whatever into it.

If you can't, for some reason, put the authentication scripts into /armaauth, well, you still should be able to authenticate as user@some.domain/path/to/authentication. Sucks, but nobody forces you to run an authentication server.

Mockup authentication script, usage example:
http://moosnet.homelinux.net/~manuel/sc ... b408fc130e

Code: Select all

<?php
$user = isset($_GET[ "user" ]) ? $_GET[ "user" ] : '';
$salt = isset($_GET[ "salt" ]) ? $_GET[ "salt" ] : '';
$hash = isset($_GET[ "hash" ]) ? $_GET[ "hash" ] : '';

// check whether user is in "database"
if ( $user != "test" )
{
    echo "UNKNOWN_USER";
}
else
{
    // fetch password hash from "database"
    $password = md5("test");
    try
    {
        $packedSalt     = pack("H*", $salt );
        $packedPassword = pack("H*", $password );
    }
    catch( Exception $e )
    {
        echo "PASSWORD_ERROR ", $e->getMessage();
    }

    $correctHash = md5( $packedPassword . $packedSalt );

    if ( $hash == $correctHash )
    {
        echo "PASSWORD_OK";
    }
    else
    {
        // obviously, the $correctHash part would not be kept in a production script :)
        echo "PASSWORD_FAIL " . $correctHash;
    }
}
?>
Umm, it's my first php work. The try{} block was supposed to catch hex-to-binary conversion errors, but those blasted things are just warnings. Any way I can catch and suppress them? Not that it matters much, arma isn't going to pass in invalid salts.

Oh yeah, changed the logic a bit. The description from a few posts ago was too complicated and silly. Now, the game server is supposed to pass the user name, salt, and the scrambled password hash as returned by the user to the authentication script, and the script just tells the server whether the password was correct or not. The script doesn't give out any secret info that way.
User avatar
Jonathan
A Brave Victim
Posts: 3391
Joined: Thu Feb 03, 2005 12:50 am
Location: Not really lurking anymore

Post by Jonathan »

z-man wrote:Umm, it's my first php work. The try{} block was supposed to catch hex-to-binary conversion errors, but those blasted things are just warnings. Any way I can catch and suppress them? Not that it matters much, arma isn't going to pass in invalid salts.
The @ operator suppresses errors and warnings. You can also use it to get rid of the initial isset stuff because nothing can become something in PHP (empty string):

Code: Select all

$user = @$_GET['user'] . '';

Code: Select all

$user = (string)@$_GET['user'];

Code: Select all

$user = @$_GET['user'];
settype($user, 'string');
Type Juggling
settype

If you want to catch errors and warnings (may or may not work with @):
Errors and Logging
set_error_handler

I'm not a PHP expert; all I really knew for certain was the "append empty string" method. The rest is just some stuff I've read about but don't know too well.
User avatar
Lucifer
Project Developer
Posts: 8758
Joined: Sun Aug 15, 2004 3:32 pm
Location: Republic of Texas

Post by Lucifer »

Er, I'm lost again.

To answer the question, web apps generally take one of two approaches to passwords (and I've seen a hybrid approach too).

* Store md5 hashes of the password in the database. When a user logs in, take the password given and do md5sum() on it, then do a query that looks like this: select * from users where user=? and password=?; . If and only if one record is returned, the user is allowed in.

* Store an encrypted version of the password. The login logic itself is identical to the first, the difference here is that it's actually possible to retrieve the password.

* Combination of the two. The query gets the md5 hash record out of the database, but the encrypted version of the password has to check out against the same in the database.

So the user table usually looks something like this:

create_on | last_mod| username | password | first | last | nick

Only identity information is there, all other configuration parameters (like cycle colors, shaving frequency, etc) would be put in different tables.
Check out my YouTube channel: https://youtube.com/@davefancella?si=H--oCK3k_dQ1laDN

Be the devil's own, Lucifer's my name.
- Iron Maiden
User avatar
Lucifer
Project Developer
Posts: 8758
Joined: Sun Aug 15, 2004 3:32 pm
Location: Republic of Texas

Post by Lucifer »

Ok, I read through it again and I'm not so lost anymore. I have a counter-proposal, and for once, it's not a big and hairy counter-proposal. :)

I appreciate you guys wanting more than a basic system, but I have to stand by with "we don't have much idea what the technical requirements are", but aha! we do know that others will be happy to throw on their own additional scripts and whatnot in the way of testing different ideas. I kinda still want to see the rest of the system in place, feature-complete, where we can look at the individual parts, identify the weak parts, and strengthen them. This is leading up to the last or second to last release in 0.2.8 (and if you do the more complex system you're talking, this is the second to last in 0.2.8 because we'll need at least one further bugfix revision on top of this just for this feature, I think).

So, my suggestion is to just do what you were originally going to do in your first post. If you want to throw in some support for authenticating in other servers, here's my suggestions:

* Two of the master servers also run on web servers (at least, that's all I can think of, mine and wrtlprnft's). So make it possible for the master server to ping game servers and ask "Who do you have playing right now?" The server can send back the username and maybe just an md5sum() of the user and password hash together so the master server can identify when the same person is playing on different servers. Then the master only does two things with this information: stick it in a file, sync it with other masters. The rest of us can throw on additional support scripts that'll stretch it into a more useful system than that.

* For servers that want to support the same list of users, they can just sync their own private lists with wget or something. We can host a generic global database and make it available for people to use. If we use a php script to handle that, we can throw on additional features at that link, give the user a webpage that lists servers that sync and let the user choose which ones he wants to join, give server admins another page that lists users that want to join their servers and let them choose yay or nay. We can return the list of users that they'll use in some neutral format so they can lay on their own script to filter out admins and regular players for their server. This is all code that gets written outside of arma, so your original basic idea is all that's needed for this. And of course it's all code the presumably gets released so other people can use it, improve it, etc. You know, where we can really quantify the issues involved in getting all these servers linked together somehow.

It's still decentralized, in that a user can always login to servers that have the latest sync, and if the central server(s) go(es) down, the game servers still have a cached copy of the database. Users get one registration point, maybe two (depending on how the registration system looks) for a generic global registry we run.

So maybe the system will be prone to badmins that want to impersonate other players. That will suck more than a little if it happens. Will it actually happen? We can find out, really. Is there an easy way to throw on preventing this? Maybe the client should instead send the password as md5sum(servername + password) and let the web apps that do the real work here handle encoding the file for each server that syncs. The idea is to offload the code as much as possible to people like ed that will be happy to write it. :) (My own window of opportunity to write any of this code expires tonight, if it hasn't already)

On a different note, I took a look at ggz last night, and I think it gives us everything we want, with several caveats. The first is that ggz requires your game to conform to a room/table model. It uses its own xml-based protocol, and it looks like it's layered on top of http, but I could have misread something there. Anyway, it has support for integrating with IM clients, at least GAIM already has ggz support. And if luke's xmpp integration doesn't depend on an xmpp library (like if he just parses the xml himself), it should be straightforward to support ggz through the same mechanism. I'm more inclined to go to ggz these days and hook into their community. The core ggz project is focusing on games that the msn game network has abandoned so they can pick up all the old msn players, so it would be nice if the other open source multiplayer network games supported ggz.
Check out my YouTube channel: https://youtube.com/@davefancella?si=H--oCK3k_dQ1laDN

Be the devil's own, Lucifer's my name.
- Iron Maiden
User avatar
Tank Program
Forum & Project Admin, PhD
Posts: 6714
Joined: Thu Dec 18, 2003 7:03 pm

Post by Tank Program »

Something like z-man's script up there is what I had in mind. Since phpBB is storying with the same md5() we can easily authenticate users as <username>@forums.armagetronad.net. I would allow server admins to trust only certain login servers. Perhaps authentication.armagetronad.net that combines entries from the forums (one query) with entries from its own table as well (another query). Make sure new users don't already exist on the forums before creating them. Some way to back port users from authentication to the forums if they want to start an account.
Image
User avatar
Tank Program
Forum & Project Admin, PhD
Posts: 6714
Joined: Thu Dec 18, 2003 7:03 pm

Post by Tank Program »

Lucifer wrote:* Two of the master servers also run on web servers (at least, that's all I can think of, mine and wrtlprnft's).
My master also has a web server.
Image
User avatar
wrtlprnft
Reverse Outside Corner Grinder
Posts: 1679
Joined: Wed Jan 04, 2006 4:42 am
Location: 0x08048000
Contact:

Post by wrtlprnft »

There's no place like ::1
User avatar
Z-Man
God & Project Admin
Posts: 11748
Joined: Sun Jan 23, 2005 6:01 pm
Location: Cologne
Contact:

Post by Z-Man »

/me enters luke-jr mode:
Lucifer wrote:This is leading up to the last or second to last release in 0.2.8 (and if you do the more complex system you're talking, this is the second to last in 0.2.8 because we'll need at least one further bugfix revision on top of this just for this feature, I think).
You may be right; I was thinking about doing a reaaally long beta phase.
Lucifer wrote:So make it possible for the master server to ping game servers and ask "Who do you have playing right now?" The server can send back the username and maybe just an md5sum() of the user and password hash together so the master server can identify when the same person is playing on different servers.
That's a nice idea, but that md5sum changes when users change passwords, so in essence, it doesn't give us anything more than we already get by the various server listings we have.
Lucifer wrote:* For servers that want to support the same list of users, they can just sync their own private lists with wget or something.
As you say, this is vulnerable to badmins. The information in these config files can be used to steal logins; we'd need to make the lists only available to trusted server admins.

Also, would get naming collisions from all the Lucifers and Vipers out there; we'd need another way to disambiguate users coming from different source files.

About the GGZ, the last time I looked which wasn't so long ago, the little bit of documentation available all assumed you had the restrictive room/seat/spectator model in your game. I don't know whether it is even possible to attach a continuously running game to it. We'd need to pretend to be in continuous lobby mode, maybe, and treat all players as spectators to GGZ. That may work.
The protocol type they use is well hidden from the games, so it shouldn't matter whether they use UDP, TCP, XML or binary data.

I found a major setback in our backwards compatibility plans :( The password md5, as the client computes it, includes the trailing 0. That means there is no way to compare it to, say, a stored password md5 of phpBB. To support that, and the other shemes where the first step is not to simply take a password md5, we'd need to change the protocol and send strings to the client it should prepend and append to the password before doing the initial md5 sum. That would give us support for phpBB and htdigest files and Lucifer's prepend-password-with-servername suggestion.

Which is good, because that nullifies the main downside of the wget-the-password-tables-around plan. Server admins would register at the password file distribution server with a server(group) name and password and would be able to fetch password files where the md5 sum is build over the server name, the user name (just because we can) and the password. It won't be possible to use it to imposter players on other servers than your own.

I still like the URL based approach better, where users are dynamically authenticated. Partly because I've got it implemented and it works fine, apart from the fact that it is not threaded yet, so bad auth servers lock a server, and that means bad users can lock the server. It simply has less administrative overhead in the background. There are just so many things that can go wrong with a system that relies on pushing files around :) We can still harness the power of ed and the others by letting them write the real world password server scripts.

Jonathan: thanks, works perfectly.
User avatar
Tank Program
Forum & Project Admin, PhD
Posts: 6714
Joined: Thu Dec 18, 2003 7:03 pm

Post by Tank Program »

z-man wrote:so bad auth servers lock a server, and that means bad users can lock the server.
Part of why I suggested letting the admin allow only selected auth servers.

Would individual auth servers be in charge of stats for their users?
Image
User avatar
Z-Man
God & Project Admin
Posts: 11748
Joined: Sun Jan 23, 2005 6:01 pm
Location: Cologne
Contact:

Post by Z-Man »

About the blocking/bad password servers, that can always also happen by accident, and we can't have servers lock up by accident. So we need a solution even if we only accept whitelisted password servers.

What kind of stats are you thinking about? Stats like total number of won matches on all servers combined? Or read-only properties like favorite cycle colors? Read only properties would easily be possible, just define different queries the password server can handle as well. Writable properties could really get abused quickly, I think luke's approach of fetching the ladderlog files from authenticated servers is better for semi-global stats.

The password servers could be used to fetch other information from authorities. Say I run a clan/team, want it to be know as pwnrz@moosnet.homelinux.net. Well, then a query to http://moosnet.homelinux.net/armaauth/i ... team=pwnrz
would return a list of all its members in user@authority form, whether they are authenticated with moosnet.homelinux.net or another place.

Anyway, off to work on threads.
User avatar
Z-Man
God & Project Admin
Posts: 11748
Joined: Sun Jan 23, 2005 6:01 pm
Location: Cologne
Contact:

Post by Z-Man »

Lucifer recommended the ZThread library; apart from two quirks, one solvable, I can pass on that recommendation.
Quirk one is that the installed zthread-config apparently ignores a prefix set in your .site configuration script, which means it will be broken.
Quirk two is that it is leaking a single memory block as soon as you start a thread. Well, not really leaking, probably. According to valgrind, the memory is possibly lost. The custom debugging memory manager reports it as a leak, anyway.

A general problem with multithreading is that it breaks our debug recordings, badly. That's because the debug recording facility relies on the fact that with identical inputs, the program will run the same way again; that assumption breaks down with multithreading.

The http-fetching password check luckily interacts only with two of our systems: the memory manager (easily secured with mutex locks in its main access points) and the tToDo task scheduling system (as soon as the answer from the password server is received, wrapping up the authentication is left to a task called from the main thread and scheduled over tToDo, because that's the easiest way; the alternative would be to make the ePlayerNetID management thread safe). Concurrent password fetches seemed to be no problem.

Everything is optional at compile time. It's possible do enable and disable the krawall authentication alltogether, and without ZThreads, the http based distributed authentication is disabled and only local accounts are available.

So the low level implementation is there and works, let's think about good ways to administer this beast.

For the user, I was thinking about the following chat commands:
/adminlogin <password>: does what /login <password> does now; check ADMIN_PASS and log in.
/login : trigger a krawall login to a local user account or a default password server, depending on what the admin set
/login <password server> : logs in with an account from the given password server.
/logout : log out again.

After you're logged in, your password server or local account type is stored in your ePlayerNetID, and you can appear now as user@<password server> resp. user@local in log files etc. Obviously, we should filter the character @ out of usernames, and refer to unauthenticated users as user@ in the log files, and @local users should be transformed to @local-<servername> users by luke-jr's ranking script.

Now, the commands described in earlier posts are sort of useless. You would want to make an arbitrary user an admin or moderator without forcing him to use a local account, messing up his ranking. You'd want so simply declare that z-man@moosnet.homelinux.net is an admin, for example with the command

Code: Select all

ADMIN z-man@moosnet.homelinux.net
as simple as that. Same for team leaders. What I'm getting at here is that admin, moderator and team leader properties should sit on top of authentication, and not be built into it like in the published version of the patch.

For non-leader team members, we can keep the stuff that's in the first patch; the /pickup chat commnand for team leaders and the local team password, because both may be convenient for certain situations, and also add support for team list fetching over http or from files. So, for example, once everyone has done their homework and an SP vs oops match is scheduled on a server, the admin only should have to add

Code: Select all

ALLOW_TEAM CT@crazy-tronners.com
ALLOW_TEAM oops@armagetronad.net
to the configuration and be set. For clan wars and ladles, that would be the way to go; for AFL like things, the team lists should be fetched from the organizer to avoid teams switching members while they're not allowed to.

I don't think we should go down the road to allow clans and teams to authenticate their members for other purposes than organized matches. I don't want to be drawn into "X is not allowed to wear clan tag Y" debates.

The "who is allowed to play" logic needs a little reworking, too, of course. We want to differentiate
* nonauthenticated players
* authenticated players
* members of teams that are scheduled to play
A server where the ranking script is supposed to give meaningful results could, for example, simply enforce authentication. A tournament server would only let scheduled teams play. There should always be the additional option that if nobody of the required level is online, members of lower level can play anyway.

The current password server test script looks like this:

Code: Select all

<?php
$user = @$_GET[ "user" ] . '';
$salt = @$_GET[ "salt" ] . '';
$hash = @$_GET[ "hash" ] . '';

// check whether user is in "database"
if ( $user != "test" && $user != "test2" )
{
    echo "UNKNOWN_USER " . $user . ".";
}
else
{
    // simulate delay
    sleep(10);

    // fetch password hash from "database"
    $password = md5("test" . pack("H*", "00" ) );

    $packedSalt     = @pack("H*", $salt );
    $packedPassword = @pack("H*", $password );

    $correctHash = md5( $packedPassword . $packedSalt );

    if ( $hash == $correctHash )
    {
        echo "PASSWORD_OK";
    }
    else
    {
        echo "PASSWORD_FAIL "; //  . $correctHash . " " . $password;
    }
}
?>
Attachments
krawall_auth.patch.0.4.bz2
bedtime patch with ZThreads.
You can log in with "/login moosnet.homelinux.net", username test or test2, password test. The login script called by that account has an 10 second artificial delay.
(11.71 KiB) Downloaded 120 times
Luke-Jr
Dr Z Level
Posts: 2246
Joined: Sun Mar 20, 2005 4:03 pm
Location: IM: luke@dashjr.org

Post by Luke-Jr »

First, I think it would be a very bad idea to assume the display name is part of the username. Do we really want people putting clan tags in their account username-part?

On ladderlog recording, the important things to me are:
1. Existing names do not mangle differently
2. Authenticated accounts cannot be generated by servers that do not support authentication
As far as I can tell, this means the only solution is to use a Unicode character in the authenticated usernames. I feel a ® prefix should be quite straightforward. This method requires no modification on the part of ladderlog parsers.

The only way my ratings script could ever handle anything different in its current simplicity stage would be if every line using these new-mangled-form names marked clearly that they were mangled. Even with this, all ladderlog parsers will need to be modified to check for this flag and make adjustments accordingly.
Luke-Jr
Dr Z Level
Posts: 2246
Joined: Sun Mar 20, 2005 4:03 pm
Location: IM: luke@dashjr.org

Post by Luke-Jr »

Code: Select all

<?php 
$user = @$_GET['user'] . '';
$salt = @$_GET['salt'] . '';
$hash = @$_GET['hash'] . '';

// check whether user is in "database" 
if ($user != 'test')
	die('UNKNOWN_USER');

$packedSalt = @pack("H*", $salt);

function checkPass($password) {
	global $packedSalt, $hash;
	$packedPassword = @pack('H*', $password);
	$correctHash = md5($packedPassword . $packedSalt);
	if (strcasecmp($hash, $correctHash) === 0)
		die('PASSWORD_OK');
}

// fetch password hash from "database"
$rawpassword = 'test';
checkPass(md5($password . @pack('H*', '00')));
checkPass(md5($password));

die('PASSWORD_FAIL');
User avatar
Z-Man
God & Project Admin
Posts: 11748
Joined: Sun Jan 23, 2005 6:01 pm
Location: Cologne
Contact:

Post by Z-Man »

Luke-Jr wrote:First, I think it would be a very bad idea to assume the display name is part of the username. Do we really want people putting clan tags in their account username-part?
People are free to choose their username within the limitations we impose on it (ascii only, no @). If they want to put their clan tag in it, so be it. We will recommend them not to do it, of course, and yes, display and username need not match.

About your script, sorry, no, I won't let backwards compatibility problems be solved here by using a character that is not on any of my keyboards. What would be the ideal solution, IMHO, is this:
- at some point in the future, mangle all names in your database by filtering out @ and appending an @.
- from then on, let the server mangle all names that come from the old script in the same fashion
- distribute a new script for users of servers that mangle usernames by themselves, and don't mangle them again on the server
- maybe make sure people can't run the wrong script.

What you're going to have to do anyway is treat authenticated users differently from unauthenticated ones. You don't want authenticated full usernames to get any aliases.
Luke-Jr
Dr Z Level
Posts: 2246
Joined: Sun Mar 20, 2005 4:03 pm
Location: IM: luke@dashjr.org

Post by Luke-Jr »

z-man wrote:
Luke-Jr wrote:First, I think it would be a very bad idea to assume the display name is part of the username. Do we really want people putting clan tags in their account username-part?
People are free to choose their username within the limitations we impose on it (ascii only, no @). If they want to put their clan tag in it, so be it. We will recommend them not to do it, of course, and yes, display and username need not match.
Ok, maybe I was misunderstanding then... I thought z-man was implying the username was copied from the displayed name..
z-man wrote:About your script, sorry, no, I won't let backwards compatibility problems be solved here by using a character that is not on any of my keyboards. What would be the ideal solution, IMHO, is this:
- at some point in the future, mangle all names in your database by filtering out @ and appending an @.
- from then on, let the server mangle all names that come from the old script in the same fashion
- distribute a new script for users of servers that mangle usernames by themselves, and don't mangle them again on the server
- maybe make sure people can't run the wrong script.
Then when people run the wrong script? Also keep in mind you're breaking compatibility for a LOT of scripts and forcing them all to add this. Seeing as we have Unicode support next to the plate already, I don't see how reserving one of these characters hurts anyone.

Edit: new approach: the fact that mangling will change is unavoidable
Can we get ladderlog to record the unmangled names when someone logins in or renames?
z-man wrote:What you're going to have to do anyway is treat authenticated users differently from unauthenticated ones. You don't want authenticated full usernames to get any aliases.
I already have a regex for non-aliasing names (player_[1234]).
Last edited by Luke-Jr on Mon Jan 21, 2008 9:48 am, edited 1 time in total.
Post Reply