summaryrefslogblamecommitdiffstats
path: root/source/cAuthenticator.cpp
blob: d45eaa0431cbc473b3386b2b59a8097c74f6870a (plain) (tree)
1
2
3
4
5
6
7
8
9


                                                                                               

                              

                     

                                
 

                   



 


                                                                                         
 



 

                                       


                                         
  
                   

  



 

                                  
                





  

                                   
  





                                          


                                                                                          

                            
                                    
          

                                                                        

                              
                                     
          

                                                                          




                              
                                                                                           

                                     

  




                                                                                      
                                                                                                            
  
                                   
          
                                                            

                        
 


                                                                        





  

                                

                                  






                

                                   
                 
          

                                                                    
                  
                                                
                                                
                  
                                       


                                
                                          
                 


                                                          

                                                                                                      
                                     

                               
                                                                         
                  
                                                                                             

                     
                  
                                                                  
                  
                          
  
 
 

 
 
                                                                                                                                             



                                                                                                                               
                                                 
          
                                                                                                                                           

                              
         
                                                                                        


                                     
 
                                         
 
                                    

                          

                                
                                                                                


                            
                                 


                                                      
                                                     
                          
                                                                                                                                                                                                                     

                                              

                                          
                                      





                                                  
          
                                                                                                                                                                 
                              
          


                        
                                  








                                                      
                                      
                                    
                                                            




                                                       
                                     
                  
                                                                                                                                                                               


                                      
                                                                                                   
                                                                                                              
                                                                                 
                                                                                   
          

                  
          
                                                                                                                                                            

                              
 





                                                          
                  
                                   
                  





                                                                                       
                                                                                                                                                                            

                              
 






                                                                            
          
                                                                                       

                      



 

#include "Globals.h"  // NOTE: MSVC stupidness requires this to be the same across all modules

#include "cAuthenticator.h"
#include "cBlockingTCPLink.h"
#include "cRoot.h"
#include "cServer.h"

#include "../iniFile/iniFile.h"

#include <sstream>





#define DEFAULT_AUTH_SERVER "session.minecraft.net"
#define DEFAULT_AUTH_ADDRESS "/game/checkserver.jsp?user=%USERNAME%&serverId=%SERVERID%"
#define MAX_REDIRECTS 10





cAuthenticator::cAuthenticator(void) :
	super("cAuthenticator"),
	m_Server(DEFAULT_AUTH_SERVER),
	m_Address(DEFAULT_AUTH_ADDRESS),
	m_ShouldAuthenticate(true)
{
	ReadINI();
}





cAuthenticator::~cAuthenticator()
{
	Stop();
}





/// Read custom values from INI
void cAuthenticator::ReadINI(void)
{
	cIniFile IniFile("settings.ini");
	if (!IniFile.ReadFile())
	{
		return;
	}
	
	m_Server  = IniFile.GetValue("Authentication", "Server");
	m_Address = IniFile.GetValue("Authentication", "Address");
	m_ShouldAuthenticate = IniFile.GetValueB("Authentication", "Authenticate", true);
	bool bSave = false;
	
	if (m_Server.length() == 0)
	{
		m_Server = DEFAULT_AUTH_SERVER;
		IniFile.SetValue("Authentication", "Server", m_Server);
		bSave = true;
	}
	if (m_Address.length() == 0)
	{
		m_Address = DEFAULT_AUTH_ADDRESS;
		IniFile.SetValue("Authentication", "Address", m_Address);
		bSave = true;
	}

	if (bSave)
	{
		IniFile.SetValueB("Authentication", "Authenticate", m_ShouldAuthenticate);
		IniFile.WriteFile();
	}
}





/// Queues a request for authenticating a user. If the auth fails, the user is kicked
void cAuthenticator::Authenticate(int a_ClientID, const AString & a_UserName, const AString & a_ServerHash)
{
	if (!m_ShouldAuthenticate)
	{
		cRoot::Get()->AuthenticateUser(a_ClientID);
		return;
	}

	cCSLock Lock(m_CS);
	m_Queue.push_back(cUser(a_ClientID, a_UserName, a_ServerHash));
	m_QueueNonempty.Set();
}





void cAuthenticator::Stop(void)
{
	m_ShouldTerminate = true;
	m_QueueNonempty.Set();
	Wait();
}





void cAuthenticator::Execute(void)
{
	for (;;)
	{
		cCSLock Lock(m_CS);
		while (!m_ShouldTerminate && (m_Queue.size() == 0))
		{
			cCSUnlock Unlock(Lock);
			m_QueueNonempty.Wait();
		}
		if (m_ShouldTerminate)
		{
			return;
		}
		ASSERT(!m_Queue.empty());
		
		int ClientID = m_Queue.front().mClientID;
		AString UserName = m_Queue.front().mName;
		AString ActualAddress = m_Address;
		ReplaceString(ActualAddress, "%USERNAME%", UserName);
		ReplaceString(ActualAddress, "%SERVERID%", cRoot::Get()->GetServer()->GetServerID());
		m_Queue.pop_front();
		Lock.Unlock();

		if (!AuthFromAddress(m_Server, ActualAddress, UserName))
		{
			cRoot::Get()->KickUser(ClientID, "Failed to authenticate account!");
		}
		else
		{
			cRoot::Get()->AuthenticateUser(ClientID);
		}
	}  // for (-ever)
}





bool cAuthenticator::AuthFromAddress(const AString & a_Server, const AString & a_Address, const AString & a_UserName, int a_Level /* = 1 */)
{
	// 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(a_Server.c_str(), 80))
	{
		LOGERROR("cAuthenticator: cannot connect to auth server \"%s\", kicking user \"%s\"", a_Server.c_str(), a_Server.c_str());
		return false;
	}
	
	Link.SendMessage( AString( "GET " + a_Address + " HTTP/1.0\r\n\r\n" ).c_str());
	AString DataRecvd;
	Link.ReceiveData(DataRecvd);
	Link.CloseSocket();

	std::stringstream ss(DataRecvd);

	// Parse the data received:
	std::string temp;
	ss >> temp;
	bool bRedirect = false;
	bool bOK = false;
	if ((temp.compare("HTTP/1.1") == 0) || (temp.compare("HTTP/1.0") == 0))
	{
		int code;
		ss >> code;
		if (code == 302)
		{
			// redirect blabla
			LOGINFO("Need to redirect!");
			if (a_Level > MAX_REDIRECTS)
			{
				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());
				return false;
			}
			bRedirect = true;
		}
		else if (code == 200)
		{
			LOGINFO("Got 200 OK :D");
			bOK = true;
		}
	}
	else
	{
		LOGERROR("cAuthenticator: cannot parse auth reply from server \"%s\" for user \"%s\", kicking the user.", a_Server.c_str(), a_UserName.c_str());
		return false;
	}

	if( bRedirect )
	{
		AString Location;
		// Search for "Location:"
		bool bFoundLocation = false;
		while( !bFoundLocation && ss.good() )
		{
			char c = 0;
			while( c != '\n' )
			{
				ss.get( c );
			}
			AString Name;
			ss >> Name;
			if (Name.compare("Location:") == 0)
			{
				bFoundLocation = true;
				ss >> Location;
			}
		}
		if (!bFoundLocation)
		{
			LOGERROR("cAuthenticator: received invalid redirection from auth server \"%s\" for user \"%s\", kicking user.", a_Server.c_str(), a_UserName.c_str());
			return false;
		}

		Location = Location.substr(strlen("http://"), std::string::npos); // Strip http://
		std::string Server = Location.substr( 0, Location.find( "/" ) ); // Only leave server address
		Location = Location.substr( Server.length(), std::string::npos);
		return AuthFromAddress(Server, Location, a_UserName, a_Level + 1);
	}

	if (!bOK)
	{
		LOGERROR("cAuthenticator: received an error from auth server \"%s\" for user \"%s\", kicking user.", a_Server.c_str(), a_UserName.c_str());
		return false;
	}

	// 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')
		{
			ss.get(c);
		}
		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.", a_Server.c_str(), a_UserName.c_str());
		return false;
	}

	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;
	}
	LOGINFO("Result was \"%s\", so player is NOT authenticated!", Result.c_str());
	return false;
}