From: <z-...@us...> - 2008-01-27 00:28:24
|
Revision: 7650 http://armagetronad.svn.sourceforge.net/armagetronad/?rev=7650&view=rev Author: z-man Date: 2008-01-26 16:28:27 -0800 (Sat, 26 Jan 2008) Log Message: ----------- added authentication reference php script. Added Paths: ----------- armagetronad/branches/0.2.8-auth/armagetronad/batch/authentication_reference.php Added: armagetronad/branches/0.2.8-auth/armagetronad/batch/authentication_reference.php =================================================================== --- armagetronad/branches/0.2.8-auth/armagetronad/batch/authentication_reference.php (rev 0) +++ armagetronad/branches/0.2.8-auth/armagetronad/batch/authentication_reference.php 2008-01-27 00:28:27 UTC (rev 7650) @@ -0,0 +1,220 @@ +<?php + +//////////////////////////////////////////////////// +// +// Authentication server, reference implementation 0.1 +// +// To run authority X, this script needs to be +// adapted and be callable from a web browser as +// http://X/armaauth/0.1 +// +// the easiest way to do so is to name the script index.php +// and place it into an appropriate armaauth/0.1 +// directory on a web server that supports php. +// +//////////////////////////////////////////////////// + +// these two functions return prefix and suffix for the md5 +// hash method. They are prepended/appended to the password +// before md5 is applied on it. Adapt them if you like. + +function getPrefix() +{ + return "%u:aaauth:"; +} + +function getSuffix() +{ + return ""; +} + +// however, before they are used, %u is replaced by the username. + +function substitutions( $fix, $user ) +{ + return str_replace( "%u", $user, $fix ); +} + +//////////////////////////////////////////////////// +// Bits you need to change follow. +//////////////////////////////////////////////////// + +// The user "database": fetch the password for a user. +// If you are fine with storing plaintext passwords, +// adapt this function; otherwise, adapt getPasswordHash(). + +function getPassword( $user ) +{ + // the user/password database. For very small groups + // of users, you may just get away with expanding this + // array. + $passwords= array ( + 'test' => 'password' // clever choice there, test + ); + + return $passwords[$user]; +} + +// You do not need plain text passwords. The +// checks on the passwords are done to a hash function +// thereof. You can just as well precompute the +// work of this function and store the result, +// and maybe your user database already contains +// the one or other hash. phpBB, for example, +// stores md5( $password ). + +function getPasswordHash( $user, $method ) +{ + // fetch the plaintext password + $password = getPassword( $user ); + if ( NULL == $password ) + return NULL; + + // two methods are currently supported + // by server and client, bmd5 (broken md5) + // and md5. Both use the md5 hash algorithm. + + // bmd5 quirk: the hash is computed for password + a trailing 0 + if ($method == 'bmd5') + { + $password = "$password" . chr(0); + } + + // md5 adds the prefix and suffix before calculating + // the hash. The example values are chosen so that the + // resulting hash is the same one you find in .htdigest + // files and that is used in the digest http authentication + // method. If you set the prefix and suffix to empty + // strings, the resulting hash will be the one found + // in phpBB user databases. + if ( $method == "md5" ) + { + $password = substitutions( getPrefix(), $user ) . "$password" . substitutions( getSuffix(), $user ); + } + + // after that, both methods just calculate the md5 hash + // and return that. + return md5( $password ); +} + +// comma separated lists of methods you support. If, for example, +// you cannot generate the hash for the bmd5 method, just +// remove it from this list. + +function getMethods() +{ + return "md5, bmd5"; +} + +//////////////////////////////////////////////////// +// The rest of the script should not be changed, +//////////////////////////////////////////////////// + +// this function reports the result of the check back to the +// qerying AA server. + +function conclude($statusCode, $msg) +{ + // report error code in header + header("Status: $statusCode" . '$msg', true, $statusCode); + + // print message + die("$msg\n"); +} + +// Of course, the AA password query passes in some variables. +// The first is the query type; it can either be +// 'methods' for a list of supported methods, +// 'params' for a list of method parameters, or +// 'check' to check a user's identity. + +$query = @$_REQUEST['query'] . ''; + +if ( $query == "methods" ) +{ + // give lists of supported methods. It's supposed to be "methods", + // followed by a comma and/or whitespace separated list of the methods. + conclude(200, 'methods '. getMethods() ); +} + +// the other two queries pass in more parameters, both have +// the 'method' parameter that tells you which method should +// be used. Well behaved servers will pick one of the methods +// you support. + +$method = @$_REQUEST['method'] . ''; + +if ( $query == "params" ) +{ + // give method parameter info + if ( $method == 'md5' ) + { + // give prefix and suffix + conclude( 200, "prefix " . getPrefix() . "\nsuffix " . getSuffix() ); + } + + if ( $method == 'bmd5' ) + { + // bmd5 does not support or need extra parameters. + conclude(200 , '' ); + } + + // we know nothing about this. + conclude(404 , 'UNKNOWN_METHOD' ); +} + +if ( $query == "check" ) +{ + // the last query passes in the username to check, + $user = @$_REQUEST['user'] . ''; + + // a salt value (128 bit hexcoded) + $salt = @$_REQUEST['salt'] . ''; + + // and a hash value the AA client has computed. + $hash = @$_REQUEST['hash'] . ''; + + // we're supposed to check whether that hash is correct; + // to do so, we need to do the same operations to the + // password the client has done. + + // first, the client computed a hash of the password + // with method-specific rules. <TV cook mode> we have + // already prepared that here. </TV cook mode>. + $correctPasswordHash = getPasswordHash( $user, $method ); + + // check if user exists in the first place. + if ( $correctPasswordHash == NULL ) + { + conclude(404, 'UNKNOWN_USER ' . $user ); + } + + // the operations the AA client did were not on the hex-encoded + // hashes we have so far, but on binary packed variants thereof: + $packedSalt = pack("H*", $salt); + $correctPackedPasswordHash = pack('H*', $correctPasswordHash); + + // the client then simply calculated the MD5 sum of the two + // concatenated packed values. + $correctHash = md5($correctPackedPasswordHash . $packedSalt); + + // well, let's see if the client got it right! + if (strcasecmp($hash, $correctHash) === 0) + { + // he did! + conclude(200, 'PASSWORD_OK'); + } + + // he didn't. + conclude(401, 'PASSWORD_FAIL' ); + + // That's it. Note that any response other that a text beginning + // with "PASSWORD_OK" and a 200 return code will be interpreted + // by the server as an error and authentication will fail. +} + +// we don't know what the server wants from us +// if execution ends up here. +conclude(404, 'UNKNOWN_QUERY' ); + +?> Property changes on: armagetronad/branches/0.2.8-auth/armagetronad/batch/authentication_reference.php ___________________________________________________________________ Name: svn:executable + * This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <z-...@us...> - 2008-01-27 13:31:27
|
Revision: 7662 http://armagetronad.svn.sourceforge.net/armagetronad/?rev=7662&view=rev Author: z-man Date: 2008-01-27 05:31:32 -0800 (Sun, 27 Jan 2008) Log Message: ----------- All response keywords transformed to CAPS. Modified Paths: -------------- armagetronad/branches/0.2.8-auth/armagetronad/batch/authentication_reference.php Modified: armagetronad/branches/0.2.8-auth/armagetronad/batch/authentication_reference.php =================================================================== --- armagetronad/branches/0.2.8-auth/armagetronad/batch/authentication_reference.php 2008-01-27 13:31:00 UTC (rev 7661) +++ armagetronad/branches/0.2.8-auth/armagetronad/batch/authentication_reference.php 2008-01-27 13:31:32 UTC (rev 7662) @@ -74,22 +74,23 @@ // by server and client, bmd5 (broken md5) // and md5. Both use the md5 hash algorithm. - // bmd5 quirk: the hash is computed for password + a trailing 0 - if ($method == 'bmd5') + switch( $method ) { + case 'bmd5': + // bmd5 quirk: the hash is computed for password + a trailing 0 $password = "$password" . chr(0); - } + break; - // md5 adds the prefix and suffix before calculating - // the hash. The example values are chosen so that the - // resulting hash is the same one you find in .htdigest - // files and that is used in the digest http authentication - // method. If you set the prefix and suffix to empty - // strings, the resulting hash will be the one found - // in phpBB user databases. - if ( $method == "md5" ) - { + case "md5": + // md5 adds the prefix and suffix before calculating + // the hash. The example values are chosen so that the + // resulting hash is the same one you find in .htdigest + // files and that is used in the digest http authentication + // method. If you set the prefix and suffix to empty + // strings, the resulting hash will be the one found + // in phpBB user databases. $password = substitutions( getPrefix(), $user ) . "$password" . substitutions( getSuffix(), $user ); + break; } // after that, both methods just calculate the md5 hash @@ -128,29 +129,29 @@ // 'params' for a list of method parameters, or // 'check' to check a user's identity. -$query = @$_REQUEST['query'] . ''; +$query = @strtolower($_REQUEST['query'] . ''); -if ( $query == "methods" ) +switch ( $query ) { +case "methods": // give lists of supported methods. It's supposed to be "methods", // followed by a comma and/or whitespace separated list of the methods. - conclude(200, 'methods '. getMethods() ); -} + conclude(200, 'METHODS '. getMethods() ); + break; // the other two queries pass in more parameters, both have // the 'method' parameter that tells you which method should // be used. Well behaved servers will pick one of the methods // you support. -$method = @$_REQUEST['method'] . ''; +case "params": + $method = @strtolower($_REQUEST['method'] . ''); -if ( $query == "params" ) -{ // give method parameter info if ( $method == 'md5' ) { // give prefix and suffix - conclude( 200, "prefix " . getPrefix() . "\nsuffix " . getSuffix() ); + conclude( 200, "PREFIX " . getPrefix() . "\nSUFFIX " . getSuffix() ); } if ( $method == 'bmd5' ) @@ -161,10 +162,11 @@ // we know nothing about this. conclude(404 , 'UNKNOWN_METHOD' ); -} + break; -if ( $query == "check" ) -{ +case "check": + $method = @strtolower($_REQUEST['method'] . ''); + // the last query passes in the username to check, $user = @$_REQUEST['user'] . ''; @@ -211,10 +213,16 @@ // That's it. Note that any response other that a text beginning // with "PASSWORD_OK" and a 200 return code will be interpreted // by the server as an error and authentication will fail. + + // String comparisons for the control words (METHODS, PASSWORD_OK) + // are case-insensitive on the server. We just like to return them + // as caps becasue that looks more like CONTOL_CODES. + break; + +default: + // we don't know what the server wants from us + // if execution ends up here. + conclude(404, 'UNKNOWN_QUERY' ); } -// we don't know what the server wants from us -// if execution ends up here. -conclude(404, 'UNKNOWN_QUERY' ); - ?> This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <z-...@us...> - 2008-01-27 14:41:50
|
Revision: 7665 http://armagetronad.svn.sourceforge.net/armagetronad/?rev=7665&view=rev Author: z-man Date: 2008-01-27 06:41:54 -0800 (Sun, 27 Jan 2008) Log Message: ----------- added check for wrong hostname. Modified Paths: -------------- armagetronad/branches/0.2.8-auth/armagetronad/batch/authentication_reference.php Modified: armagetronad/branches/0.2.8-auth/armagetronad/batch/authentication_reference.php =================================================================== --- armagetronad/branches/0.2.8-auth/armagetronad/batch/authentication_reference.php 2008-01-27 14:05:11 UTC (rev 7664) +++ armagetronad/branches/0.2.8-auth/armagetronad/batch/authentication_reference.php 2008-01-27 14:41:54 UTC (rev 7665) @@ -35,10 +35,34 @@ return str_replace( "%u", $user, $fix ); } + +// this function reports the result of the check back to the +// qerying AA server. + +function conclude($statusCode, $msg) +{ + // report error code in header + header("Status: $statusCode" . '$msg', true, $statusCode); + + // print message + die("$msg\n"); +} + //////////////////////////////////////////////////// // Bits you need to change follow. //////////////////////////////////////////////////// +// you should definitely check that the hostname the game +// server used to contact you is the one you intend it +// to use; otherwise, there may be problems with web +// servers known under different names. You should uncomment +// this and add your real authority hostname. + +/* +if ( $_SERVER['HTTP_HOST'] != "authority" ) + conclude( 404, "WRONG_HOST" ); +*/ + // The user "database": fetch the password for a user. // If you are fine with storing plaintext passwords, // adapt this function; otherwise, adapt getPasswordHash(). @@ -111,18 +135,6 @@ // The rest of the script should not be changed, //////////////////////////////////////////////////// -// this function reports the result of the check back to the -// qerying AA server. - -function conclude($statusCode, $msg) -{ - // report error code in header - header("Status: $statusCode" . '$msg', true, $statusCode); - - // print message - die("$msg\n"); -} - // Of course, the AA password query passes in some variables. // The first is the query type; it can either be // 'methods' for a list of supported methods, This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <z-...@us...> - 2008-01-28 18:03:16
|
Revision: 7681 http://armagetronad.svn.sourceforge.net/armagetronad/?rev=7681&view=rev Author: z-man Date: 2008-01-28 10:03:09 -0800 (Mon, 28 Jan 2008) Log Message: ----------- also removing newlines from headers. Modified Paths: -------------- armagetronad/branches/0.2.8-auth/armagetronad/batch/authentication_reference.php Modified: armagetronad/branches/0.2.8-auth/armagetronad/batch/authentication_reference.php =================================================================== --- armagetronad/branches/0.2.8-auth/armagetronad/batch/authentication_reference.php 2008-01-28 18:01:41 UTC (rev 7680) +++ armagetronad/branches/0.2.8-auth/armagetronad/batch/authentication_reference.php 2008-01-28 18:03:09 UTC (rev 7681) @@ -51,7 +51,7 @@ // 401: password failure) but still violate the standard. // report error code in header - header("Status: $statusCode" . '$msg', true, $statusCode); + header("Status: $statusCode", true, $statusCode); // print message die("$msg\n"); This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <z-...@us...> - 2008-01-28 23:55:12
|
Revision: 7688 http://armagetronad.svn.sourceforge.net/armagetronad/?rev=7688&view=rev Author: z-man Date: 2008-01-28 15:55:17 -0800 (Mon, 28 Jan 2008) Log Message: ----------- Adding fully qualified user name to the PASSWORD_OK output. Modified Paths: -------------- armagetronad/branches/0.2.8-auth/armagetronad/batch/authentication_reference.php Modified: armagetronad/branches/0.2.8-auth/armagetronad/batch/authentication_reference.php =================================================================== --- armagetronad/branches/0.2.8-auth/armagetronad/batch/authentication_reference.php 2008-01-28 22:19:38 UTC (rev 7687) +++ armagetronad/branches/0.2.8-auth/armagetronad/batch/authentication_reference.php 2008-01-28 23:55:17 UTC (rev 7688) @@ -14,20 +14,6 @@ // //////////////////////////////////////////////////// -// these two functions return prefix and suffix for the md5 -// hash method. They are prepended/appended to the password -// before md5 is applied on it. Adapt them if you like. - -function getPrefix() -{ - return "%u:aaauth:"; -} - -function getSuffix() -{ - return ""; -} - // however, before they are used, %u is replaced by the username. function substitutions( $fix, $user ) @@ -52,23 +38,27 @@ // report error code in header header("Status: $statusCode", true, $statusCode); + header("Content-Type: text/plain"); // print message die("$msg\n"); } +// read authority from gloval variables +$authority = $_SERVER['HTTP_HOST']; + //////////////////////////////////////////////////// // Bits you need to change follow. //////////////////////////////////////////////////// -// you should definitely check that the hostname the game +// You should definitely check that the hostname the game // server used to contact you is the one you intend it // to use; otherwise, there may be problems with web // servers known under different names. You should uncomment // this and add your real authority hostname. /* -if ( $_SERVER['HTTP_HOST'] != "authority" ) +if ( $authority != "authority" ) conclude( 404, "WRONG_HOST" ); */ @@ -84,10 +74,42 @@ $passwords= array ( 'test' => 'password' // clever choice there, test ); - - return $passwords[$user]; + + $password = $passwords[ $user ]; + if ( NULL == $password ) + return NULL; + + // return a pair of username and password. + // it is important that you return the username + // exactly as it appeared in the database. + // If the username lookup is case insensitive, + // the rest of the script and the game servers + // need to know what the correct form of the name + // is. + return array( $user, $password ); } +// these two functions return prefix and suffix for the md5 +// hash method. They are prepended/appended to the password +// before md5 is applied on it. Adapt them to the way your +// md5 password hash is stored in your database. + +// IMPORTANT: if you want to keep the %u (a good idea for +// security, prevents precomputation attacks on the passwords) +// user name lookup needs to be case sensitive, or there will +// be unexplainable password failures. + +function getPrefix() +{ + return "%u:aaauth:"; +} + +function getSuffix() +{ + global $authority; + return ":$authority"; +} + // You do not need plain text passwords. The // checks on the passwords are done to a hash function // thereof. You can just as well precompute the @@ -99,10 +121,20 @@ function getPasswordHash( $user, $method ) { // fetch the plaintext password - $password = getPassword( $user ); - if ( NULL == $password ) + $userInfo = getPassword( $user ); + if ( NULL == $userInfo ) return NULL; + // unpack the data + $trueUser = $userInfo[0]; + $password = $userInfo[1]; + + // check that neither prefix nor suffix conain %u if $trueUser != $user + if ( $trueUser != $user && ( strpos( getPrefix(), '%u' ) !== FALSE || strpos( getPrefix(), '%u' ) !== FALSE ) ) + { + conclude(404, 'UNKNOWN_USER ' . $user . ' Do not use %u in pre/suffix if your user database is making case-insensitive lookups.'); + } + // two methods are currently supported // by server and client, bmd5 (broken md5) // and md5. Both use the md5 hash algorithm. @@ -122,13 +154,13 @@ // method. If you set the prefix and suffix to empty // strings, the resulting hash will be the one found // in phpBB user databases. - $password = substitutions( getPrefix(), $user ) . "$password" . substitutions( getSuffix(), $user ); + $password = substitutions( getPrefix(), $trueUser ) . "$password" . substitutions( getSuffix(), $trueUser ); break; } // after that, both methods just calculate the md5 hash // and return that. - return md5( $password ); + return array( $trueUser, md5( $password ) ); } // comma separated lists of methods you support. If, for example, @@ -204,14 +236,18 @@ // first, the client computed a hash of the password // with method-specific rules. <TV cook mode> we have // already prepared that here. </TV cook mode>. - $correctPasswordHash = getPasswordHash( $user, $method ); + $userInfo = getPasswordHash( $user, $method ); // check if user exists in the first place. - if ( $correctPasswordHash == NULL ) + if ( $userInfo == NULL ) { conclude(404, 'UNKNOWN_USER ' . $user ); } + // unpack user info + $trueUser = $userInfo[0]; + $correctPasswordHash = $userInfo[1]; + // the operations the AA client did were not on the hex-encoded // hashes we have so far, but on binary packed variants thereof: $packedSalt = pack("H*", $salt); @@ -224,8 +260,8 @@ // well, let's see if the client got it right! if (strcasecmp($hash, $correctHash) === 0) { - // he did! - conclude(200, 'PASSWORD_OK'); + // he did! Return OK, followed by the user's full name. + conclude(200, 'PASSWORD_OK ' . $trueUser . '@' . $authority ); } // he didn't. @@ -243,7 +279,7 @@ default: // we don't know what the server wants from us // if execution ends up here. - conclude(404, 'UNKNOWN_QUERY' ); + conclude(404, 'UNKNOWN_QUERY'); } ?> This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |