2012-01-29 14:28:19 -05:00
# include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
2011-10-03 14:41:19 -04:00
# include "cAuthenticator.h"
# include "cBlockingTCPLink.h"
2012-02-01 17:38:03 -05:00
# include "cRoot.h"
# include "cServer.h"
2011-10-03 14:41:19 -04:00
# include "../iniFile/iniFile.h"
# include <sstream>
2012-02-01 07:46:44 -05:00
2012-02-01 17:38:03 -05:00
# define DEFAULT_AUTH_SERVER "session.minecraft.net"
# define DEFAULT_AUTH_ADDRESS " / game / checkserver.jsp?user=%USERNAME%&serverId=%SERVERID%"
# define MAX_REDIRECTS 10
2011-10-03 14:41:19 -04:00
2012-02-01 07:46:44 -05:00
2012-02-01 17:38:03 -05:00
cAuthenticator : : cAuthenticator ( void ) :
super ( " cAuthenticator " ) ,
mServer ( DEFAULT_AUTH_SERVER ) ,
mAddress ( DEFAULT_AUTH_ADDRESS ) ,
mShouldAuthenticate ( true )
2011-10-03 14:41:19 -04:00
{
2012-02-01 17:38:03 -05:00
ReadINI ( ) ;
2011-10-03 14:41:19 -04:00
}
2012-02-01 17:38:03 -05:00
2012-02-13 16:47:03 -05:00
cAuthenticator : : ~ cAuthenticator ( )
{
2012-02-15 16:47:21 -05:00
Stop ( ) ;
2012-02-13 16:47:03 -05:00
}
2012-02-01 17:38:03 -05:00
/// Read custom values from INI
void cAuthenticator : : ReadINI ( void )
2011-10-03 14:41:19 -04:00
{
2012-02-01 17:38:03 -05:00
cIniFile IniFile ( " settings.ini " ) ;
if ( ! IniFile . ReadFile ( ) )
{
return ;
}
mServer = IniFile . GetValue ( " Authentication " , " Server " ) ;
mAddress = IniFile . GetValue ( " Authentication " , " Address " ) ;
mShouldAuthenticate = IniFile . GetValueB ( " Authentication " , " Authenticate " , true ) ;
bool bSave = false ;
if ( mServer . length ( ) = = 0 )
{
mServer = DEFAULT_AUTH_SERVER ;
IniFile . SetValue ( " Authentication " , " Server " , mServer ) ;
bSave = true ;
}
if ( mAddress . length ( ) = = 0 )
{
mAddress = DEFAULT_AUTH_ADDRESS ;
IniFile . SetValue ( " Authentication " , " Address " , mAddress ) ;
bSave = true ;
}
if ( bSave )
{
IniFile . SetValueB ( " Authentication " , " Authenticate " , mShouldAuthenticate ) ;
IniFile . WriteFile ( ) ;
}
2011-10-03 14:41:19 -04:00
}
2012-02-01 17:38:03 -05:00
/// Queues a request for authenticating a user. If the auth fails, the user is kicked
void cAuthenticator : : Authenticate ( const AString & iUserName , const AString & iServerID )
2011-10-03 14:41:19 -04:00
{
2012-02-01 17:38:03 -05:00
if ( ! mShouldAuthenticate )
{
cRoot : : Get ( ) - > AuthenticateUser ( iUserName ) ;
return ;
}
2011-10-03 14:41:19 -04:00
2012-02-01 17:38:03 -05:00
cCSLock Lock ( mCS ) ;
mQueue . push_back ( cUser ( iUserName , iServerID ) ) ;
mQueueNonempty . Set ( ) ;
}
2012-02-15 16:47:21 -05:00
void cAuthenticator : : Stop ( void )
{
mShouldTerminate = true ;
mQueueNonempty . Set ( ) ;
Wait ( ) ;
}
2012-02-01 17:38:03 -05:00
void cAuthenticator : : Execute ( void )
{
2012-02-18 12:53:22 -05:00
for ( ; ; )
2011-10-03 14:41:19 -04:00
{
2012-02-01 17:38:03 -05:00
cCSLock Lock ( mCS ) ;
while ( ! mShouldTerminate & & ( mQueue . size ( ) = = 0 ) )
2011-10-03 14:41:19 -04:00
{
2012-02-01 17:38:03 -05:00
cCSUnlock Unlock ( Lock ) ;
mQueueNonempty . Wait ( ) ;
2011-10-03 14:41:19 -04:00
}
2012-02-01 17:38:03 -05:00
if ( mShouldTerminate )
{
return ;
}
2012-02-19 18:00:00 -05:00
ASSERT ( mQueue . size ( ) > 0 ) ;
2012-02-01 17:38:03 -05:00
AString UserName = mQueue . front ( ) . mName ;
AString ActualAddress = mAddress ;
ReplaceString ( ActualAddress , " %USERNAME% " , UserName ) ;
ReplaceString ( ActualAddress , " %SERVERID% " , cRoot : : Get ( ) - > GetServer ( ) - > GetServerID ( ) ) ;
mQueue . pop_front ( ) ;
Lock . Unlock ( ) ;
if ( ! AuthFromAddress ( mServer , ActualAddress , UserName ) )
2011-10-03 14:41:19 -04:00
{
2012-02-01 17:38:03 -05:00
cRoot : : Get ( ) - > KickUser ( UserName , " auth failed " ) ;
2011-10-03 14:41:19 -04:00
}
else
{
2012-02-01 17:38:03 -05:00
cRoot : : Get ( ) - > AuthenticateUser ( UserName ) ;
2011-10-03 14:41:19 -04:00
}
2012-02-18 12:53:22 -05:00
} // for (-ever)
2012-02-01 17:38:03 -05:00
}
2011-10-03 14:41:19 -04:00
2012-02-01 17:38:03 -05:00
bool cAuthenticator : : AuthFromAddress ( const AString & iServer , const AString & iAddress , const AString & iUserName , int iLevel )
{
// Returns true if the user authenticated okay, false on error; iLevel is the recursion deptht (bails out if too deep)
cBlockingTCPLink Link ;
if ( ! Link . Connect ( iServer . c_str ( ) , 80 ) )
2011-10-03 14:41:19 -04:00
{
2012-02-01 17:38:03 -05:00
LOGERROR ( " cAuthenticator: cannot connect to auth server \" %s \" , kicking user \" %s \" " , iServer . c_str ( ) , iUserName . c_str ( ) ) ;
2011-10-03 14:41:19 -04:00
return false ;
}
2012-02-01 17:38:03 -05:00
Link . SendMessage ( AString ( " GET " + iAddress + " HTTP/1.0 \r \n \r \n " ) . c_str ( ) ) ;
AString DataRecvd ;
Link . ReceiveData ( DataRecvd ) ;
Link . CloseSocket ( ) ;
2011-10-03 14:41:19 -04:00
2012-02-01 17:38:03 -05:00
std : : stringstream ss ( DataRecvd ) ;
2011-10-03 14:41:19 -04:00
2012-02-01 17:38:03 -05:00
// Parse the data received:
2011-10-03 14:41:19 -04:00
std : : string temp ;
ss > > temp ;
bool bRedirect = false ;
bool bOK = false ;
2012-02-01 17:38:03 -05:00
if ( ( temp . compare ( " HTTP/1.1 " ) = = 0 ) | | ( temp . compare ( " HTTP/1.0 " ) = = 0 ) )
2011-10-03 14:41:19 -04:00
{
int code ;
ss > > code ;
2012-02-01 17:38:03 -05:00
if ( code = = 302 )
2011-10-03 14:41:19 -04:00
{
// redirect blabla
LOGINFO ( " Need to redirect! " ) ;
2012-02-01 17:38:03 -05:00
if ( iLevel > MAX_REDIRECTS )
{
LOGERROR ( " cAuthenticator: received too many levels of redirection from auth server \" %s \" for user \" %s \" , bailing out and kicking the user " , iServer . c_str ( ) , iUserName . c_str ( ) ) ;
return false ;
}
2011-10-03 14:41:19 -04:00
bRedirect = true ;
}
2012-02-01 17:38:03 -05:00
else if ( code = = 200 )
2011-10-03 14:41:19 -04:00
{
LOGINFO ( " Got 200 OK :D " ) ;
bOK = true ;
}
}
else
2012-02-01 17:38:03 -05:00
{
LOGERROR ( " cAuthenticator: cannot parse auth reply from server \" %s \" for user \" %s \" , kicking the user. " , iServer . c_str ( ) , iUserName . c_str ( ) ) ;
2011-10-03 14:41:19 -04:00
return false ;
2012-02-01 17:38:03 -05:00
}
2011-10-03 14:41:19 -04:00
if ( bRedirect )
{
2012-02-01 17:38:03 -05:00
AString Location ;
2011-10-03 14:41:19 -04:00
// Search for "Location:"
bool bFoundLocation = false ;
while ( ! bFoundLocation & & ss . good ( ) )
{
char c = 0 ;
while ( c ! = ' \n ' )
{
ss . get ( c ) ;
}
2012-02-01 17:38:03 -05:00
AString Name ;
2011-10-03 14:41:19 -04:00
ss > > Name ;
2012-02-01 17:38:03 -05:00
if ( Name . compare ( " Location: " ) = = 0 )
2011-10-03 14:41:19 -04:00
{
bFoundLocation = true ;
ss > > Location ;
}
}
2012-02-01 17:38:03 -05:00
if ( ! bFoundLocation )
2011-10-03 14:41:19 -04:00
{
2012-02-01 17:38:03 -05:00
LOGERROR ( " cAuthenticator: received invalid redirection from auth server \" %s \" for user \" %s \" , kicking user. " , iServer . c_str ( ) , iUserName . c_str ( ) ) ;
2011-10-03 14:41:19 -04:00
return false ;
}
2012-02-01 17:38:03 -05:00
Location = Location . substr ( strlen ( " http:// " ) , std : : string : : npos ) ; // Strip http://
2011-10-03 14:41:19 -04:00
std : : string Server = Location . substr ( 0 , Location . find ( " / " ) ) ; // Only leave server address
2012-02-01 17:38:03 -05:00
Location = Location . substr ( Server . length ( ) , std : : string : : npos ) ;
return AuthFromAddress ( Server , Location , iUserName , iLevel + 1 ) ;
2011-10-03 14:41:19 -04:00
}
2012-02-01 17:38:03 -05:00
if ( ! bOK )
2011-10-03 14:41:19 -04:00
{
2012-02-01 17:38:03 -05:00
LOGERROR ( " cAuthenticator: received an error from auth server \" %s \" for user \" %s \" , kicking user. " , iServer . c_str ( ) , iUserName . c_str ( ) ) ;
return false ;
}
2011-10-03 14:41:19 -04:00
2012-02-01 17:38:03 -05:00
// Header says OK, so receive the rest.
// Go past header, double \n means end of headers
char c = 0 ;
while ( ss . good ( ) )
{
while ( c ! = ' \n ' )
2011-10-03 14:41:19 -04:00
{
2012-02-01 17:38:03 -05:00
ss . get ( c ) ;
2011-10-03 14:41:19 -04:00
}
2012-02-01 17:38:03 -05:00
ss . get ( c ) ;
if ( c = = ' \n ' | | c = = ' \r ' | | ss . peek ( ) = = ' \r ' | | ss . peek ( ) = = ' \n ' )
break ;
}
if ( ! ss . good ( ) )
{
LOGERROR ( " cAuthenticator: error while parsing response body from auth server \" %s \" for user \" %s \" , kicking user. " , iServer . c_str ( ) , iUserName . c_str ( ) ) ;
return false ;
}
2011-10-03 14:41:19 -04:00
2012-02-01 17:38:03 -05:00
std : : string Result ;
ss > > Result ;
LOGINFO ( " Got result: %s " , Result . c_str ( ) ) ;
if ( Result . compare ( " YES " ) = = 0 )
{
LOGINFO ( " Result was \" YES \" , so player is authenticated! " ) ;
return true ;
2011-10-03 14:41:19 -04:00
}
2012-02-01 17:38:03 -05:00
LOGINFO ( " Result was \" %s \" , so player is NOT authenticated! " , Result . c_str ( ) ) ;
2011-10-03 14:41:19 -04:00
return false ;
}
2012-02-01 17:38:03 -05:00