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 " ) ,
2012-03-10 12:37:00 -05:00
m_Server ( DEFAULT_AUTH_SERVER ) ,
m_Address ( DEFAULT_AUTH_ADDRESS ) ,
m_ShouldAuthenticate ( 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 ;
}
2012-03-10 12:37:00 -05:00
m_Server = IniFile . GetValue ( " Authentication " , " Server " ) ;
m_Address = IniFile . GetValue ( " Authentication " , " Address " ) ;
m_ShouldAuthenticate = IniFile . GetValueB ( " Authentication " , " Authenticate " , true ) ;
2012-02-01 17:38:03 -05:00
bool bSave = false ;
2012-03-10 12:37:00 -05:00
if ( m_Server . length ( ) = = 0 )
2012-02-01 17:38:03 -05:00
{
2012-03-10 12:37:00 -05:00
m_Server = DEFAULT_AUTH_SERVER ;
IniFile . SetValue ( " Authentication " , " Server " , m_Server ) ;
2012-02-01 17:38:03 -05:00
bSave = true ;
}
2012-03-10 12:37:00 -05:00
if ( m_Address . length ( ) = = 0 )
2012-02-01 17:38:03 -05:00
{
2012-03-10 12:37:00 -05:00
m_Address = DEFAULT_AUTH_ADDRESS ;
IniFile . SetValue ( " Authentication " , " Address " , m_Address ) ;
2012-02-01 17:38:03 -05:00
bSave = true ;
}
if ( bSave )
{
2012-03-10 12:37:00 -05:00
IniFile . SetValueB ( " Authentication " , " Authenticate " , m_ShouldAuthenticate ) ;
2012-02-01 17:38:03 -05:00
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
2012-03-09 08:42:28 -05:00
void cAuthenticator : : Authenticate ( int a_ClientID , const AString & a_UserName , const AString & a_ServerHash )
2011-10-03 14:41:19 -04:00
{
2012-03-10 12:37:00 -05:00
if ( ! m_ShouldAuthenticate )
2012-02-01 17:38:03 -05:00
{
2012-03-09 08:42:28 -05:00
cRoot : : Get ( ) - > AuthenticateUser ( a_ClientID ) ;
2012-02-01 17:38:03 -05:00
return ;
}
2011-10-03 14:41:19 -04:00
2012-03-10 12:37:00 -05:00
cCSLock Lock ( m_CS ) ;
m_Queue . push_back ( cUser ( a_ClientID , a_UserName , a_ServerHash ) ) ;
m_QueueNonempty . Set ( ) ;
2012-02-01 17:38:03 -05:00
}
2012-02-15 16:47:21 -05:00
void cAuthenticator : : Stop ( void )
{
2012-03-10 12:37:00 -05:00
m_ShouldTerminate = true ;
m_QueueNonempty . Set ( ) ;
2012-02-15 16:47:21 -05:00
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-03-10 12:37:00 -05:00
cCSLock Lock ( m_CS ) ;
while ( ! m_ShouldTerminate & & ( m_Queue . size ( ) = = 0 ) )
2011-10-03 14:41:19 -04:00
{
2012-02-01 17:38:03 -05:00
cCSUnlock Unlock ( Lock ) ;
2012-03-10 12:37:00 -05:00
m_QueueNonempty . Wait ( ) ;
2011-10-03 14:41:19 -04:00
}
2012-03-10 12:37:00 -05:00
if ( m_ShouldTerminate )
2012-02-01 17:38:03 -05:00
{
return ;
}
2012-03-10 12:37:00 -05:00
ASSERT ( m_Queue . size ( ) > 0 ) ;
2012-02-01 17:38:03 -05:00
2012-03-10 12:37:00 -05:00
int ClientID = m_Queue . front ( ) . mClientID ;
AString UserName = m_Queue . front ( ) . mName ;
AString ActualAddress = m_Address ;
2012-02-01 17:38:03 -05:00
ReplaceString ( ActualAddress , " %USERNAME% " , UserName ) ;
ReplaceString ( ActualAddress , " %SERVERID% " , cRoot : : Get ( ) - > GetServer ( ) - > GetServerID ( ) ) ;
2012-03-10 12:37:00 -05:00
m_Queue . pop_front ( ) ;
2012-02-01 17:38:03 -05:00
Lock . Unlock ( ) ;
2012-03-10 12:37:00 -05:00
if ( ! AuthFromAddress ( m_Server , ActualAddress , UserName ) )
2011-10-03 14:41:19 -04:00
{
2012-03-09 08:42:28 -05:00
cRoot : : Get ( ) - > KickUser ( ClientID , " Failed to authenticate account! " ) ;
2011-10-03 14:41:19 -04:00
}
else
{
2012-03-09 08:42:28 -05:00
cRoot : : Get ( ) - > AuthenticateUser ( ClientID ) ;
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
2012-03-09 08:42:28 -05:00
bool cAuthenticator : : AuthFromAddress ( const AString & a_Server , const AString & a_Address , const AString & a_UserName , int a_Level /* = 1 */ )
2012-02-01 17:38:03 -05:00
{
// Returns true if the user authenticated okay, false on error; iLevel is the recursion deptht (bails out if too deep)
cBlockingTCPLink Link ;
2012-03-09 08:42:28 -05:00
if ( ! Link . Connect ( a_Server . c_str ( ) , 80 ) )
2011-10-03 14:41:19 -04:00
{
2012-03-09 08:42:28 -05:00
LOGERROR ( " cAuthenticator: cannot connect to auth server \" %s \" , kicking user \" %s \" " , a_Server . c_str ( ) , a_Server . c_str ( ) ) ;
2011-10-03 14:41:19 -04:00
return false ;
}
2012-02-01 17:38:03 -05:00
2012-03-09 08:42:28 -05:00
Link . SendMessage ( AString ( " GET " + a_Address + " HTTP/1.0 \r \n \r \n " ) . c_str ( ) ) ;
2012-02-01 17:38:03 -05:00
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-03-09 08:42:28 -05:00
if ( a_Level > MAX_REDIRECTS )
2012-02-01 17:38:03 -05:00
{
2012-03-09 08:42:28 -05:00
LOGERROR ( " cAuthenticator: received too many levels of redirection from auth server \" %s \" for user \" %s \" , bailing out and kicking the user " , a_Server . c_str ( ) , a_UserName . c_str ( ) ) ;
2012-02-01 17:38:03 -05:00
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
{
2012-03-09 08:42:28 -05:00
LOGERROR ( " cAuthenticator: cannot parse auth reply from server \" %s \" for user \" %s \" , kicking the user. " , a_Server . c_str ( ) , a_UserName . 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-03-09 08:42:28 -05:00
LOGERROR ( " cAuthenticator: received invalid redirection from auth server \" %s \" for user \" %s \" , kicking user. " , a_Server . c_str ( ) , a_UserName . 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 ) ;
2012-03-09 08:42:28 -05:00
return AuthFromAddress ( Server , Location , a_UserName , a_Level + 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-03-09 08:42:28 -05:00
LOGERROR ( " cAuthenticator: received an error from auth server \" %s \" for user \" %s \" , kicking user. " , a_Server . c_str ( ) , a_UserName . c_str ( ) ) ;
2012-02-01 17:38:03 -05:00
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 ( ) )
{
2012-03-09 08:42:28 -05:00
LOGERROR ( " cAuthenticator: error while parsing response body from auth server \" %s \" for user \" %s \" , kicking user. " , a_Server . c_str ( ) , a_UserName . c_str ( ) ) ;
2012-02-01 17:38:03 -05:00
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