Skip to content

Commit 2a84701

Browse files
committed
Improve ehs authentication checking
1 parent c497e23 commit 2a84701

File tree

1 file changed

+78
-45
lines changed

1 file changed

+78
-45
lines changed

Server/mods/deathmatch/logic/CHTTPD.cpp

Lines changed: 78 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -208,64 +208,97 @@ ResponseCode CHTTPD::RequestLogin(HttpRequest* ipoHttpRequest, HttpResponse* ipo
208208

209209
CAccount* CHTTPD::CheckAuthentication(HttpRequest* ipoHttpRequest)
210210
{
211-
string authorization = ipoHttpRequest->oRequestHeaders["authorization"];
212-
if (authorization.length() > 6)
211+
const std::string strAuthorization = ipoHttpRequest->oRequestHeaders["authorization"];
212+
213+
if (strAuthorization.length() < 7 || strAuthorization.substr(0, 6) != "Basic ")
214+
{
215+
return m_pGuestAccount;
216+
}
217+
218+
const std::string strAddress = ipoHttpRequest->GetAddress();
219+
const char* szAddress = strAddress.c_str();
220+
const bool bIsFlooding = m_BruteForceProtect.IsFlooding(szAddress);
221+
222+
// Basic auth
223+
SString strAuthName, strAuthPassword;
224+
225+
// If we're not flooding, or authorization header value isn't crazy long, let's parse it to get the username for console logs
226+
if (!bIsFlooding || strAuthorization.length() < 768)
213227
{
214-
if (authorization.substr(0, 6) == "Basic ")
228+
SString strAuthDecoded = SharedUtil::Base64decode(strAuthorization.substr(6));
229+
strAuthDecoded.Split(":", &strAuthName, &strAuthPassword);
230+
}
231+
232+
if (bIsFlooding)
233+
{
234+
if (strAuthName.length() > 0)
215235
{
216-
// Basic auth
217-
SString strAuthDecoded = SharedUtil::Base64decode(authorization.substr(6));
236+
CLogger::AuthPrintf("HTTP: Ignoring login attempt for user '%s' from %s\n", strAuthName.substr(0, CAccountManager::MAX_USERNAME_LENGTH).c_str(),
237+
szAddress);
238+
}
239+
else
240+
{
241+
CLogger::AuthPrintf("HTTP: Ignoring login attempt from %s\n", szAddress);
242+
}
218243

219-
SString authName, authPassword;
220-
strAuthDecoded.Split(":", &authName, &authPassword);
244+
return m_pGuestAccount;
245+
}
221246

222-
if (m_BruteForceProtect.IsFlooding(ipoHttpRequest->GetAddress().c_str()))
223-
{
224-
CLogger::AuthPrintf("HTTP: Ignoring login attempt for user '%s' from %s\n", authName.c_str(), ipoHttpRequest->GetAddress().c_str());
225-
return m_pGuestAccount;
226-
}
247+
if (strAuthName.length() < CAccountManager::MIN_USERNAME_LENGTH || strAuthName.length() > CAccountManager::MAX_USERNAME_LENGTH ||
248+
strAuthPassword.length() < MIN_PASSWORD_LENGTH)
249+
{
250+
m_BruteForceProtect.AddConnect(szAddress);
227251

228-
CAccount* account = g_pGame->GetAccountManager()->Get(authName.c_str());
229-
if (account)
252+
CLogger::AuthPrintf("HTTP: Failed login attempt from %s (bad login)\n", szAddress);
253+
254+
return m_pGuestAccount;
255+
}
256+
257+
if (CAccount* pAccount = g_pGame->GetAccountManager()->Get(strAuthName.c_str()); pAccount)
258+
{
259+
bool bSkipIpCheck;
260+
261+
// Check that the password is right
262+
if (pAccount->IsPassword(strAuthPassword, &bSkipIpCheck))
263+
{
264+
// Check that it isn't the Console account
265+
if (pAccount->GetName() != CONSOLE_ACCOUNT_NAME)
230266
{
231-
// Check that the password is right
232-
bool bSkipIpCheck;
233-
if (account->IsPassword(authPassword.c_str(), &bSkipIpCheck))
267+
// Do IP check if required
268+
if (!bSkipIpCheck && !g_pGame->GetAccountManager()->IsHttpLoginAllowed(pAccount, strAddress))
234269
{
235-
// Check that it isn't the Console account
236-
std::string strAccountName = account->GetName();
237-
if (strAccountName.compare(CONSOLE_ACCOUNT_NAME) != 0)
270+
if (m_WarnMessageTimer.Get() > 8000 || m_strWarnMessageForIp != strAddress)
238271
{
239-
// Do IP check if required
240-
if (!bSkipIpCheck && !g_pGame->GetAccountManager()->IsHttpLoginAllowed(account, ipoHttpRequest->GetAddress()))
241-
{
242-
if (m_WarnMessageTimer.Get() > 8000 || m_strWarnMessageForIp != ipoHttpRequest->GetAddress())
243-
{
244-
m_strWarnMessageForIp = ipoHttpRequest->GetAddress();
245-
m_WarnMessageTimer.Reset();
246-
}
247-
CLogger::AuthPrintf("HTTP: Failed login for user '%s' because %s not associated with authorized serial\n", authName.c_str(),
248-
ipoHttpRequest->GetAddress().c_str());
249-
return m_pGuestAccount;
250-
}
251-
252-
// Handle initial login logging
253-
std::lock_guard<std::mutex> guard(m_mutexLoggedInMap);
254-
if (m_LoggedInMap.find(authName) == m_LoggedInMap.end())
255-
CLogger::AuthPrintf("HTTP: '%s' entered correct password from %s\n", authName.c_str(), ipoHttpRequest->GetAddress().c_str());
256-
m_LoggedInMap[authName] = GetTickCount64_();
257-
account->OnLoginHttpSuccess(ipoHttpRequest->GetAddress());
258-
return account;
272+
m_strWarnMessageForIp = strAddress;
273+
m_WarnMessageTimer.Reset();
259274
}
275+
276+
CLogger::AuthPrintf("HTTP: Failed login for user '%s' because %s not associated with authorized serial\n", strAuthName.c_str(), szAddress);
277+
278+
return m_pGuestAccount;
260279
}
261-
}
262-
if (authName.length() > 0)
263-
{
264-
m_BruteForceProtect.AddConnect(ipoHttpRequest->GetAddress().c_str());
265-
CLogger::AuthPrintf("HTTP: Failed login attempt for user '%s' from %s\n", authName.c_str(), ipoHttpRequest->GetAddress().c_str());
280+
281+
// Handle initial login logging
282+
std::lock_guard guard(m_mutexLoggedInMap);
283+
284+
if (m_LoggedInMap.find(strAuthName) == m_LoggedInMap.end())
285+
{
286+
CLogger::AuthPrintf("HTTP: '%s' entered correct password from %s\n", strAuthName.c_str(), szAddress);
287+
}
288+
289+
m_LoggedInMap[strAuthName] = GetTickCount64_();
290+
291+
pAccount->OnLoginHttpSuccess(strAddress);
292+
293+
return pAccount;
266294
}
267295
}
268296
}
297+
298+
m_BruteForceProtect.AddConnect(szAddress);
299+
300+
CLogger::AuthPrintf("HTTP: Failed login attempt for user '%s' from %s\n", strAuthName.c_str(), szAddress);
301+
269302
return m_pGuestAccount;
270303
}
271304

0 commit comments

Comments
 (0)